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

  1. handlePointerDown calls startXYThrottle() and updatePositionRelative(event)
  2. This queues xyPendingX/Y and starts the RAF loop
  3. RAF fires sendXYFrame() which calls onInteraction(x, y)
  4. Control components (ReverbControl, DelayControl, etc.) call triggerLoad() in their onInteraction handlers
  5. Device loads immediately
  6. handlePointerUp eventually 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.svelte
  • documentation/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 handlePointerUp but was insufficient because RAF already executed

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗