Skip to content

fix(desktop): stabilize channel-timeline scrollback with per-row height reserves#1413

Merged
wesbillman merged 1 commit into
mainfrom
brain/image-dim-reserve
Jun 30, 2026
Merged

fix(desktop): stabilize channel-timeline scrollback with per-row height reserves#1413
wesbillman merged 1 commit into
mainfrom
brain/image-dim-reserve

Conversation

@wesbillman

Copy link
Copy Markdown
Collaborator

What & why

Scrolling back through channels with mixed message types (images, code, link previews, video thumbs) jumped hard. Every timeline row used a flat content-visibility: auto 60px placeholder, so never-painted rows snapped from 60px to true height as they realized on scroll-up, shoving the column — the #buzz-bugs scrollback-jump Wes reported.

Changes

Two targeted fixes:

  • Per-row pre-paint height estimate (rowHeightEstimate.ts): reserve a credible contain-intrinsic-size per row derived from its content (text lines, fenced code, imeta media dims, bare media URLs, link-preview cards). Drift through a mixed-media scrollback drops ~20x (1538px flat-60 baseline → ~66–96px).
  • Dim-less image reserve + decoded-size cache + lightbox fix (markdown.tsx / markdown/utils.ts): images without a NIP-92 dim reserve a stable box and cache decoded natural size by URL, so they decode into reserved space instead of popping the row.

TimelineMessageList.tsx wires the per-row estimate into the row reserve style.

Tests

  • rowHeightEstimate unit coverage (11 cases: text, code, imeta with/without dim, bare media URLs, no double-counting, divider sizing).
  • timeline-no-shift mixed-media e2e gate (bounded first-pass prepend drift, no-shift maxDrift 0).
  • Full desktop unit suite green (1391/1391); typecheck, biome, file-sizes, px-text all green.

Not in scope / known follow-up

  • An earlier rendered-floor bottom-pin attempt (in useAnchoredScroll.ts) regressed cold-load "start at bottom" and was reverted — this PR leaves the anchored-scroll path untouched from main.
  • The abandon-mid-fetch edge (abandoning an in-flight older-history fetch by jumping to latest can land slightly above the floor under load) is pre-existing on main and not addressed here; it needs an explicit bottom-intent/loader protocol. The two scroll-history e2e failures observed are pre-existing on main (verified on a pristine main worktree), not regressions from this branch.

…ht reserves

Scrolling back through channels with mixed message types (images, code,
link previews, video thumbs) jumped hard: every row used a flat
`content-visibility: auto 60px` placeholder, so never-painted rows snapped
from 60px to true height as they realized on scroll-up, shoving the column.

Two targeted fixes:
- Per-row pre-paint height estimate (rowHeightEstimate.ts): reserve a
  credible contain-intrinsic-size per row from its content. Drift through a
  mixed-media scrollback drops ~20x (1538px flat-60 baseline -> ~66-96px).
- Dim-less image reserve + decoded-size cache + lightbox fix (markdown):
  images without a NIP-92 dim reserve a stable box and cache decoded natural
  size by URL, so they decode into reserved space instead of popping the row.

Tests: rowHeightEstimate unit coverage; timeline-no-shift mixed-media gate
(bounded first-pass prepend drift, no-shift maxDrift 0).

Known follow-up (pre-existing on main, not addressed here): abandoning an
in-flight older-history fetch by jumping to latest can land slightly above
the floor under load; needs an explicit bottom-intent/loader protocol. An
earlier rendered-floor bottom-pin attempt regressed cold-load "start at
bottom" and was reverted, so this change leaves the anchored-scroll path
untouched from main.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman wesbillman merged commit 4fdc68f into main Jun 30, 2026
45 of 47 checks passed
@wesbillman wesbillman deleted the brain/image-dim-reserve branch June 30, 2026 23:53
tellaho pushed a commit that referenced this pull request Jul 1, 2026
…-preview

* origin/main:
  fix(relay): enable Redis TLS for rediss:// (ElastiCache) (#1417)
  chore(release): release Buzz Desktop version 0.3.40 (#1414)
  fix(desktop): stabilize channel-timeline scrollback with per-row height reserves (#1413)
  fix(sidebar): trim working badge label and name working agents in tooltip (#1408)
  Mobile tab bar polish (#1368)
  feat(desktop): let thread pane expand on ultrawide monitors (#1407)
  chore(release): release Buzz Desktop version 0.3.39 (#1410)
  fix: close cross-process keychain race and namespace dev-build nest (#1409)
  feat(relay): allow agent owners to edit/manage agent-owned content (#1403)
  fix(media): support IRSA/credential-chain S3 auth and configurable signing region (#1406)
  fix(desktop): fold baked build env into in-process model discovery (#1376)
  docs: link VISION_ACTIVITY from the VISION index (#1405)
tellaho pushed a commit that referenced this pull request Jul 1, 2026
…vity-embed

* origin/main:
  fix(relay): enable Redis TLS for rediss:// (ElastiCache) (#1417)
  chore(release): release Buzz Desktop version 0.3.40 (#1414)
  fix(desktop): stabilize channel-timeline scrollback with per-row height reserves (#1413)
  fix(sidebar): trim working badge label and name working agents in tooltip (#1408)
  Mobile tab bar polish (#1368)
  feat(desktop): let thread pane expand on ultrawide monitors (#1407)
  chore(release): release Buzz Desktop version 0.3.39 (#1410)
  fix: close cross-process keychain race and namespace dev-build nest (#1409)
  feat(relay): allow agent owners to edit/manage agent-owned content (#1403)
  fix(media): support IRSA/credential-chain S3 auth and configurable signing region (#1406)
  fix(desktop): fold baked build env into in-process model discovery (#1376)
  docs: link VISION_ACTIVITY from the VISION index (#1405)
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