From 0bc86ecc6d729822420dff1014738f3bac1730ee Mon Sep 17 00:00:00 2001 From: Ty Balascio Date: Fri, 25 Sep 2026 09:19:52 -0700 Subject: [PATCH] fix(fe): debounce mask auto-run 500ms after slider/sheet changes Rapid sensitivity drags triggered a flood of async mask runs; an in-flight run could settle after the owner pressed Approve and clobber the state, so the Approve click read a snapshot with overlay:null and early-returned. Debounce 500ms after the user stops adjusting so the mask settles before any interaction and the click reads a stable state. --- frontend/src/capture/SessionCapture.svelte | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/frontend/src/capture/SessionCapture.svelte b/frontend/src/capture/SessionCapture.svelte index 8e200b4..7f8ae58 100644 --- a/frontend/src/capture/SessionCapture.svelte +++ b/frontend/src/capture/SessionCapture.svelte @@ -71,12 +71,17 @@ let fileInput: HTMLInputElement; // Auto-run the mask so the overlay (and preview) populate without the owner - // pressing Approve first. `controlKey` changes only on sheet/sensitivity - // edits (never on the overlay itself), so this fires on entry and on each - // control change - but not when approveMask settles the overlay (no loop). + // pressing Approve first. Debounced 500ms after the user stops adjusting the + // sheet/sensitivity, so rapid slider drags don't trigger a flood of async + // mask runs (and an in-flight run can't clobber the state around an Approve + // click). Keyed on control values, not the overlay, so settling never loops. + let maskRunTimer = 0; $: controlKey = kind === 'mask' && cap.control ? `${cap.control.sheet}:${cap.control.sensitivity}` : null; $: if (controlKey && cap.source && cap.source.widthPx > 0) { - void session.approveMask(); + clearTimeout(maskRunTimer); + maskRunTimer = setTimeout(() => { + void session.approveMask(); + }, 500); } function pickFiles(e: Event) {