# Brush cursor briefly changes to an arrow during UXP pixel capture

**URL:** <https://forums.creativeclouddeveloper.com/t/brush-cursor-briefly-changes-to-an-arrow-during-uxp-pixel-capture/12302>\
**Category:** UXP Plugin API\
**Created:** [October 12, 2026, 8:44pm UTC](https://forums.creativeclouddeveloper.com/t/brush-cursor-briefly-changes-to-an-arrow-during-uxp-pixel-capture/12302 "2026-10-12T20:44:58Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![denis.mitin](https://avatars.discourse-cdn.com/v4/letter/d/d26b3c/32.png) [@denis.mitin](https://forums.creativeclouddeveloper.com/u/denis.mitin)\
**Post date:** [October 12, 2026, 8:44pm UTC](https://forums.creativeclouddeveloper.com/t/brush-cursor-briefly-changes-to-an-arrow-during-uxp-pixel-capture/12302/1 "2026-10-12T20:44:58Z")

</div>

Hello,

I’m developing a Photoshop timelapse plugin that captures the canvas after changes. On Windows with a pen, the brush outline sometimes turns into the system arrow after a stroke. It happens most often during rapid strokes and is distracting while drawing.

We reproduced it in Photoshop 2024 (25.0.0) with a small test document. A separate diagnostic that only calls getPixels inside executeAsModal with interactive:true also shows it, without JPEG encoding, a helper or disk writes. Empty modal calls did not show it in our short control tests. Reading a hidden copy, delaying the capture and specifying historyStateID did not solve it.

We also installed the unmodified OK-Record 1.0.5 release. With our recorder stopped, it saved real frames and the user saw the same visible cursor change. We have not established whether the internal cause is identical.

Can you help us identify what triggers this cursor update and whether there is a supported way to capture the full document composite without disturbing the brush cursor? We need to capture changes rather than periodically sample the screen. If the Imaging API cannot do this reliably, would a traditional C++ export plugin using Channel Ports be a suitable alternative?

I have included the diagnostic plugin and test results below. The forum does not allow attachments for new accounts, so I can supply the ZIP and raw timing logs once uploads are enabled. The extracted example has passed syntax checks; the live results above came from its earlier diagnostic version.

Thank you,  
Den

> **Diagnostic plugin and test results**
>
> manifest.json
> 
> ```auto
> {
> "manifestVersion": 5,
> "id": "com.denmitin.recorder.minimal-cursor-repro",
> "name": "Read pixels cursor reproduction",
> "version": "1.0.0",
> "main": "index.html",
> "host": {"app": "PS", "minVersion": "25.0.0", "data": {"apiVersion": 2}},
> "entrypoints": [{"type": "panel", "id": "repro", "label": {"default": "Cursor reproduction"}}]
> }
> 
> ```
> 
> index.html
> 
> ```auto
> <!doctype html>
> <html><head><meta charset="utf-8"></head><body>
> <p>Use a disposable document named PR_TEST_CURSOR_REPRO. Stop all other recorders first.</p>
> <button id="baseline">Start empty-modal control</button>
> <button id="pixels">Start pixel reads</button>
> <button id="stop">Stop and show counts</button>
> <pre id="status">Not running. No file, preference or document writes.</pre>
> <script src="index.js"></script>
> </body></html>
> 
> ```
> 
> index.js
> 
> ```auto
> 'use strict';
> const ps = require('photoshop');
> let timer = null, busy = false, targetID = null, previousHistory = null;
> let generation = 0, counts = {};
> function show() {
> document.getElementById('status').textContent = JSON.stringify(counts, null, 2);
> }
> function stop() {
> clearInterval(timer); timer = null; generation++;
> counts.running = false;
> // The in-flight scope owns its buffer and releases it in finally.
> if (!busy) show();
> }
> function guardedDocument() {
> const doc = ps.app.activeDocument;
> if (!doc || doc.id !== targetID || doc.name !== 'PR_TEST_CURSOR_REPRO') {
> throw Error('Only the selected PR_TEST_CURSOR_REPRO document is allowed');
> }
> return doc;
> }
> function start(readPixels) {
> stop();
> if (busy) { counts.error = 'Wait for the current read to finish'; show(); return; }
> const doc = ps.app.activeDocument;
> if (!doc || doc.name !== 'PR_TEST_CURSOR_REPRO') {
> counts.error = 'Create a disposable document named PR_TEST_CURSOR_REPRO'; show(); return;
> }
> targetID = doc.id; previousHistory = doc.activeHistoryState.id;
> counts = {host: ps.app.version, mode: readPixels ? 'getPixels' : 'empty modal',
> running: true, observed: 0, completed: 0, errors: 0};
> const run = generation;
> show();
> timer = setInterval(async () => {
> if (busy || run !== generation) return;
> busy = true;
> try {
> const doc = guardedDocument(), history = doc.activeHistoryState.id;
> if (history === previousHistory) return;
> previousHistory = history; counts.observed++;
> await ps.core.executeAsModal(async () => {
> const source = guardedDocument();
> if (!readPixels) return;
> let pixels;
> try {
> pixels = await ps.imaging.getPixels({documentID: source.id,
> targetSize: {width: Math.min(1920, Number(source.width))},
> componentSize: 8, colorSpace: 'RGB',
> colorProfile: 'sRGB IEC61966-2.1', applyAlpha: true});
> counts.lastSize = [pixels.imageData.width, pixels.imageData.height];
> } finally { if (pixels) pixels.imageData.dispose(); }
> }, {commandName: 'Read-only cursor reproduction', interactive: true});
> counts.completed++;
> if (counts.completed >= 128) stop();
> } catch (error) {
> counts.errors++; counts.error = String(error.message || error); stop();
> } finally {
> busy = false;
> // No panel updates while running: avoid UI repaint as a confound.
> if (!timer) show();
> }
> }, 100);
> }
> document.getElementById('baseline').addEventListener('click', () => start(false));
> document.getElementById('pixels').addEventListener('click', () => start(true));
> document.getElementById('stop').addEventListener('click', stop);
> require('uxp').entrypoints.setup({plugin: {destroy: stop}});
> 
> ```
> 
> # Intermittent brush-to-arrow cursor transition during read-only capture
> 
> Prepared 2026-10-10 for this support request.
> 
> ## Observed locally
> 
> Windows, pen input, Photoshop 2024 (25.0.0). The brush outline intermittently  
> changes to the system arrow, especially after a series of rapid strokes.  
> The user has also reported this during recording in Photoshop 26.0 and 27.1;  
> the current controlled stage comparisons below were performed in 25.0.0.
> 
> On the same owned test document, an independent UXP diagnostic performed:
> 
> | Operation | Successful operations | Manual result |
> | --- | --- | --- |
> | Empty interactive modal scope | 17 | No arrow observed |
> | Empty interactive scope with about 60ms elapsed | 19 | No arrow observed |
> | getPixels and dispose, no encoding or helper | 36 in repeated test | Arrow observed |
> | getPixels with retained buffers, no disposal during drawing | 10 | Arrow observed |
> | getPixels from hidden temporary snapshot | 15 | Arrow observed |
> | Read after one second of unchanged history | 9 | Arrow observed after delay |
> 
> Zero cursor sightings in short controls do not prove absence in longer runs.  
> These prototypes coalesce changes and are diagnostic rather than complete  
> stroke recorders. They do not prove a universal Adobe defect or its cause.
> 
> A separate full historical Recorder 0.5.2 comparison saved real JPEG frames  
> in an isolated database. It also showed intermittent arrows. Adding explicit  
> `historyStateID` saved 35 further frames (745 to 780), no errors, but did not  
> eliminate arrows in rapid series. That change was reverted.
> 
> ## Third-party comparison
> 
> The official Windows OK-Record 1.0.5 with FFmpeg package was downloaded from  
> the author’s release. SHA256 matched the published value:  
> `A3E27534754B00252ACA014EE1979FA35FE1C9E85EA22F07C53F594D8249E2A6`.  
> It was installed using Adobe’s normal CCX installer, not loaded as a modified  
> developer copy. On Photoshop 25.0.0, the same disposable test document was  
> saved as PSD, our capture plugins were stopped, and OK-Record was started  
> with its visible 2-second interval, idle delay 0, maximum wait 5 seconds.  
> Two distinct 1920 × 1080 JPEGs were verified after a controlled pixel change.  
> The user then reported seeing the cursor around 1–2 seconds after a stroke.  
> This was a manual observation, without passive cursor tracing during this  
> third-party test. It does not prove the same internal cause or a universal  
> Photoshop bug. OK-Record has now been removed through Adobe UPIA; both the  
> installed-plugin list and active-runtime list confirm its absence.
> 
> ## Passive timing observation (earlier Recorder trace)
> 
> GetCursorInfo sampled every 10ms without setting cursors or injecting input.  
> Five arrow transitions were recorded; two involved entry onto the canvas.  
> The other three, already over the canvas at the preceding sample, occurred  
> 1–4ms after the JS getPixels completion marker or 4ms after modal exit.  
> All three preceded JPEG encoding and buffer disposal for those captures.  
> This is timing association only. Sampling can miss shorter flashes and  
> instrumentation may affect timing; the user reported worse behavior during  
> this run. All tracing has been stopped and removed from the live capture.
> 
> ## Minimal example included
> 
> The included three-file UXP plugin is freshly extracted for this report.  
> Its exact build has passed syntax checks but has not yet had a live pen test.  
> The live stage results above came from the earlier independent diagnostic,  
> not from this new extracted package.
> 
> 1. Stop other capture plugins, including the historical comparison.
> 2. Load this folder through UXP Developer Tools.
> 3. Create a disposable RGB document named exactly `PR_TEST_CURSOR_REPRO`,  
> preferably 1920 × 1080, with two pixel layers. Do not use work documents.
> 4. Start the empty-modal control; draw long strokes and rapid series with a pen.
> 5. Stop and note successful operation counts and observed cursor transitions.
> 6. Start pixel reads and repeat the same drawing pattern, then stop.
> 
> The example only reads the active test document. No files, preferences, XMP,  
> network requests, JPEG encoding, helper, cursor manipulation or PSD writes.  
> It does not change history states. It stops at 128 successful operations or  
> on an error/document switch; one in-flight read completes and is disposed.
> 
> ## Questions for Adobe
> 
> Is there a supported way to retrieve the full document composite for a  
> background recorder without intermittently replacing the painting cursor?  
> Is read-only getPixels expected to require executeAsModal on these hosts?  
> Can getPixels completion trigger a cursor refresh, and is there a supported  
> way to preserve the brush cursor across that refresh?
> 
> API references:
> 
> - [Imaging API](https://developer.adobe.com/photoshop/uxp/2022/ps-reference/media/imaging)
> - [ExecuteAsModal Details](https://developer.adobe.com/photoshop/uxp/2022/ps-reference/media/executeasmodal)
> 
> No credentials or working documents are included.
