Files
buzz/desktop
ae8f130738 fix(desktop): compensate realization jitter on upscroll (T2 writer)
Scrolling UP a fully-loaded channel was subtly jumpy while scrolling down
was smooth. Root cause (Eva's H1): rows above the opening viewport have
never painted, so they sit at their `contain-intrinsic-size` reserve under
`content-visibility: auto`. Scrolling up, each row realizes at its true
height the instant it enters the realization band; the delta (true -
reserve) shifts content above the reading row. On shipped WKWebView there
is no `overflow-anchor` to correct it, so every realization lands raw on
the reading position — one lurch per row.

The fix makes the conversation scroller own its reading position through a
single same-frame compensation writer:

- Snapshot the reading anchor (first fully-visible row + its top offset) on
  every scroll event, before the ResizeObserver fires. The RO runs after
  layout and before paint, so the "before" position can only come from the
  last scroll event — never from inside the RO callback.
- Observe each `.timeline-row-cv` row (CV realization is a resize of the
  row's own box and does not surface as an ancestor resize in Blink), seeded
  at observe time with the browser's current layout height read from
  `contain-intrinsic-block-size` — the reserve for an unpainted row. Seeding
  from the reserve is what turns the first realization into a measurable
  `realized - reserve` delta instead of an unmeasurable first sighting.
- On a real height change, re-pin the reading anchor to its saved offset
  with a same-frame `scrollBy(drift)`. A single measured correction: the
  layout engine already summed the above-anchor deltas into the row's top,
  and rows resizing below the anchor don't move it, so they're excluded for
  free. Re-baseline after the correction.
- Force `overflow-anchor: none` on the scroller so the writer is the single
  scroll authority on every engine — Chromium's native anchoring can't
  double-correct behind the writer's back, and WKWebView has none anyway.
  This also aligns CI (Chromium) with macOS (WKWebView), which ran different
  scroll contracts — how the jitter shipped unseen.

Verified against the committed T1.1 gate (upscroll-jitter.perf.ts) on
jitter-corpus cold-load, sync fixed-step actuation, overflow-anchor forced
off: RED without this writer (peak-dev 46 / rms 23), GREEN with it (peak-dev
0.00 / rms 0.00, reproducible), and the non-gating wheel felt-mode pass also
0.00/0.00. The non-gating estimate-error R diagnostic stays at 75 (T3's lane;
this writer compensates motion, it does not shrink the reserve error).

Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
2026-07-08 15:01:05 -04:00
..
2026-06-11 15:06:24 +00:00

Buzz

Desktop chat shell with:

  • Tauri + React + TypeScript + Vite
  • Tailwind CSS
  • shadcn/ui-ready shared components
  • Biome (lint/format/check)
  • Feature-driven frontend structure

Scripts

  • pnpm dev - run the web frontend
  • pnpm tauri dev - run the desktop app
  • pnpm build - typecheck and build frontend
  • pnpm typecheck - TypeScript checks
  • pnpm lint - Biome lint
  • pnpm format - Biome format (write)
  • pnpm check - Biome check

Structure

  • src/shared - reusable app-wide code (ui, lib, styles)
  • src/features - feature modules (vertical slices)
  • src/app - top-level app composition