Skip to content

fix: measure timeline rows so the virtual window tracks real heights - #415

Merged
kevinswiber merged 1 commit into
mainfrom
fix/issue-412-timeline-row-measure
Jul 7, 2026
Merged

fix: measure timeline rows so the virtual window tracks real heights#415
kevinswiber merged 1 commit into
mainfrom
fix/issue-412-timeline-row-measure

Conversation

@kevinswiber

Copy link
Copy Markdown
Member

Closes #412.

The timeline virtualizer sized its window, spacers, and reveal math from a fixed 52px row
estimate. Real rows render systematically taller when the master pane is narrow (the .event
meta line wraps — easy to hit since the #411 divider) and shorter under compact density, so the
reveal path's post-scrollIntoView repaint re-anchored rows against wrong spacer heights and
pushed the cursor row out of the viewport ("the cursor gets lost in the stack").

Direction (from the issue's three candidates): measure a representative painted row — the
uniform-estimate window model is kept intact, and the estimate is made true.

  • ROW_H = 52 stays as the fallback; a live rowH estimate — the mean measured
    getBoundingClientRect().height of painted rows, unrounded — feeds visibleRange, both
    spacers, and scrollTimelineSelectionIntoView. Guards keep the current estimate when there is
    nothing to measure (empty state, no layout).
  • Triggers: a debounced (150ms trailing) ResizeObserver on #timeline covers every
    width-changing signal in one place (divider release, window resize, the narrow media query,
    pane open/close, reading mode, and feat: add h/l keys to resize the inspector split from anywhere #414's h/l keys via the same applySplit write); the
    composition root routes the density toggle explicitly (height-only, no width signal); the first
    laid-out paint seeds the estimate; the reveal re-measures synchronously before seeding scroll
    (the load path measures at full width, then the route opens the split and reflows rows before
    the deep-link reveal runs).
  • Estimate changes anchor the reading position from real row geometry (anchoredScrollTop):
    the painted row straddling the viewport top keeps its exact offset, with index-space scaling as
    the no-layout fallback — a density flip no longer teleports the content.

Verification: 9 new vitest specs (642 total green), full just check (2172), and live Chrome
against a 3000+-event store — divider at ~406px with wrapped ~126px rows, 40×j/20×k cursor
stepping stays centered; density flip re-derives 126→100 and keeps the cursor visible; fresh
deep-link load reveals centered.

Shoreline: revision rev:2f669a77 was re-captured as rev:73ed4615 (supersedes) after rebasing
onto #414; Codex reviewer agent:codex-412 accepted with independent gate re-runs; the one
advisory (residual density-flip nudge) was owner-approved and closed.

The timeline virtualizer sized its window, spacers, and reveal math from a
fixed 52px row estimate. Real rows render systematically taller when the
master pane is narrow (the meta line wraps) and shorter under compact
density, so the post-reveal repaint re-anchored rows against wrong spacer
heights and pushed the cursor row out of the viewport.

The lens now re-derives its estimate from the mean measured height of the
painted rows, keeping 52px as the guarded fallback when there is no layout.
A debounced ResizeObserver on the timeline element re-measures on every
width-changing trigger (divider release, window resize, the narrow media
query, pane open/close, reading mode); the composition root routes the
density toggle explicitly, since it changes row heights without a width
signal.
@kevinswiber
kevinswiber merged commit 8d8e4c6 into main Jul 7, 2026
9 checks passed
@kevinswiber
kevinswiber deleted the fix/issue-412-timeline-row-measure branch July 7, 2026 05:31
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.

Timeline virtualizer's fixed row-height estimate loses the cursor in narrow panes

1 participant