FX Grid Tap-to-Preview: RAF fires onInteraction before pointerup
Resolved 💬 2 comments Opened Jan 23, 2026 by ben-juodvalkis Closed Feb 27, 2026
Summary
ADR-167 specifies that tapping an FX grid XY pad should only switch the central view (preview mode), NOT create/load the device. Dragging should create the device.
The current implementation has a race condition where the RAF throttle fires onInteraction before pointerup can detect the tap.
Current Behavior
handlePointerDowncallsstartXYThrottle()andupdatePositionRelative(event)- This queues
xyPendingX/Yand starts the RAF loop - RAF fires
sendXYFrame()which callsonInteraction(x, y) - Control components (ReverbControl, DelayControl, etc.) call
triggerLoad()in theironInteractionhandlers - Device loads immediately
handlePointerUpeventually fires and detects it was a tap, but too late
Root Cause
The RAF throttle is started on pointerdown, not on first pointermove. The RAF loop executes at least once before pointerup fires.
Proposed Fix
In DeviceXY.svelte, defer RAF throttle start until first pointermove:
let hasMoved = $state(false);
function handlePointerDown(event: PointerEvent) {
// ... existing setup code ...
hasMoved = false;
// DON'T call startXYThrottle() or updatePositionRelative() here
}
function handlePointerMove(event: PointerEvent) {
if (!isDragging) return;
// Start RAF throttle on first move only
if (!hasMoved) {
hasMoved = true;
startXYThrottle();
}
updatePositionRelative(event);
}
This ensures:
- Taps (pointerdown → pointerup with no move) never fire
onInteraction - Drags (pointerdown → pointermove → pointerup) still work normally
Files to Change
interface/src/lib/components/v6/device-panel/DeviceXY.sveltedocumentation/adr/167-fx-grid-tap-preview-drag-create.md(update with fix details)
Related
- ADR-167: FX Grid Tap-to-Preview, Drag-to-Create
- Previous fix attempt cancelled pending RAF in
handlePointerUpbut was insufficient because RAF already executed
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗