Skip to content

fix(client): split-view scroll sync tearing in Firefox - #93

Merged
Alimedhat000 merged 2 commits into
developfrom
fix/23-split-view-locked-laggy
Aug 28, 2026
Merged

fix(client): split-view scroll sync tearing in Firefox#93
Alimedhat000 merged 2 commits into
developfrom
fix/23-split-view-locked-laggy

Conversation

@Alimedhat000

Copy link
Copy Markdown
Owner

Problem

With synced scrolling enabled (the link toggle) in split view, Firefox users saw constant tearing: the preview pane trailed the editor and snapped forward repeatedly while scrolling. Chromium was unaffected.

Root cause

The old suppression flag (isSyncingRef, reset in a fresh requestAnimationFrame) races with the mirrored pane's own scroll event:

  • Chromium dispatches the mirrored event before the reset frame → guard holds.
  • Firefox delivers it after the reset → the echo passes the guard, consumes the suppression state, and the next genuine update is swallowed. With Firefox's per-write scroll delivery this drops ~50% of mirror updates (measured: 122 editor events vs 62 preview mirrors), leaving the preview 1–3 frames behind with periodic catch-up snaps.

Fix

New useScrollSync hook replaces the timing flag:

  • Position-based echo suppression — an event whose target already sits at the last-written offset is an echo and is ignored; race-free by construction.
  • One mirror write per animation frame, latest position wins.
  • Handlers are stable callbacks, so listeners stop resubscribing on every render.

Testing

Storybook interaction tests (run via pnpm --filter client test), each verified to fail on the old implementation and pass on the new:

  • SplitSyncMirrorsScroll — baseline mirroring both directions.
  • SplitSyncSurvivesLateEcho — mirrored-pane echo arriving after the guard window must not swallow the next update.
  • SplitSyncMirrorsLatestUnderBurst — two updates delivered separately within one frame must converge on the latest (old code settles stale).

Full client suite: 138 passed. Lint + typecheck clean.

Live validation: Firefox burst-drive went from 62/122 mirrored events and ~330px misalignment to 108/109 events and 0px settled error; Chromium CDP wheel harness shows no regression (0 backward jumps, 0 settled error).

Closes #23

The synced-scroll toggle suppressed mirrored-pane echoes with a flag reset
in a fresh requestAnimationFrame. Chromium dispatches the mirrored pane's
scroll event before that frame, but Firefox delivers it after the reset:
the echo then passes the guard and the next genuine update is swallowed,
so the preview trails and snaps back continuously while scrolling.

Replace the timing flag with position-based echo suppression (an event at
the last-written offset is an echo) and batch mirror writes to one per
animation frame. Handlers are now stable callbacks, so listeners stop
resubscribing on every render.

Covered by interaction stories: baseline mirroring both directions plus a
deterministic late-echo regression test.
Chromium coalesces same-frame scroll events, so no existing story failed
on the old guard when two updates landed in one frame. Deliver the first
update, then add a second within the same frame (Firefox's per-write
delivery): the old code swallows the second and the mirror settles stale;
the new batched mirror converges on the latest position.
@Alimedhat000
Alimedhat000 merged commit 011ba01 into develop Aug 28, 2026
2 checks passed
@Alimedhat000
Alimedhat000 deleted the fix/23-split-view-locked-laggy branch August 28, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant