fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back - #38221
Merged
Conversation
…rim scrolls (#37997) The thread scroll-anchor hook in apps/desktop/src/components/assistant-ui/ thread-virtualizer.tsx was disarming sticky-bottom whenever scrollTop decreased by >1px between scroll events. That check was too eager: when content height grows mid-frame (virtualizer measurement of a newly visible turn, streaming token, Streamdown/Shiki re-tokenization, composer chip toggle), the browser emits an interim 'scroll' event whose scrollTop is smaller than the previous frame's because scrollHeight just jumped. The rAF-scheduled pinToBottom hasn't run yet, so programmaticScrollPendingRef is 0 and the disarm fired. With sticky-bottom disarmed the scroller stuck ~50px above bottom — the visible at-rest backward jump that #37997 describes (and the same root cause as the wheel-up variant in #37527). Fix: - Track scrollHeight per frame (lastHeightRef). Disarm on scrollTop decrease ONLY when scrollHeight did not grow this frame. Real upward user intent (scrollbar drag, keyboard PgUp, programmatic scrollIntoView) still disarms because it moves scrollTop without growing the content. Wheel-up and touchmove continue to disarm via their own listeners. - Stop observing the scroller element itself in the ResizeObserver; only observe its content child. Viewport-only resizes (window resize, devtools panel toggle) no longer trigger spurious pins, matching the intent of the auto-stick-to-bottom behavior. Verified: - apps/desktop `tsc -b` clean. - apps/desktop `vitest run src/components/assistant-ui/streaming.test.tsx` passes (9/9), including the existing wheel-up disarm regression test that asserts scrollTop stays at 420 after a wheel-up + content growth.
OutThisLife
self-requested a review
June 3, 2026 13:05
teknium1
added a commit
that referenced
this pull request
Jun 3, 2026
Follow-up to #38221. Users still saw the chat viewport jump up then snap back while reading at the bottom — pinned by one reporter to code/patch blocks being highlighted. PR #38221 fixed the disarm (scrolled-up) path; this is the armed-at-bottom path. Root cause, verified live in headless Chromium (CDP), NOT just modeled: while parked at bottom, Streamdown/Shiki re-tokenizing a code block briefly REPLACES laid-out DOM, so for one frame the content is SHORTER. The browser clamps scrollTop upward the instant content shrinks below the scroll position (1400 -> 1100 with NO pin involved); the next frame content regrows and the rAF pin snaps it back down. A pin cannot prevent the up-jump because the clamp happens at layout, before any pin runs (confirmed: both deferred and synchronous re-pins still show 1400 -> 1100 -> 1480). Fix: keep the content's height MONOTONIC within a turn. The ResizeObserver raises a high-water-mark and reserves it as min-height on the content BEFORE pinning, so a transient shrink never shrinks the scroller and the browser never clamps. scrollHeight still grows under the viewport so streaming tokens follow. Reset the high-water-mark in jumpToBottom (new turn / session / first content) and on user disarm so an old tall thread can't pad a new short one and a finished turn can't leave a dead gap. Live CDP proof (real Chromium native clamping): current main: parked 1400 -> shrink 1100 -> grow 1480 (bounce) this fix: parked 1400 -> shrink 1400 -> grow 1400 (no bounce) Adds a streaming.test.tsx regression that models the browser clamp-on-shrink (scrollHeight = max(measured, reserved min-height); scrollTop clamps on shrink). Armed at bottom, a shrink RO frame must keep scrollTop at 1400 and reserve min-height 2000px. RED on pre-fix main (min-height stays empty).
|
thanks for this! :D |
This was referenced Jun 4, 2026
1 task
davidgut1982
pushed a commit
to davidgut1982/hermes-agent
that referenced
this pull request
Jun 5, 2026
…-45accc84 fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
1 task
alt-glitch
pushed a commit
that referenced
this pull request
Jun 14, 2026
fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
1 task
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
…-45accc84 fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
waefrebeorn
pushed a commit
to waefrebeorn/slermes
that referenced
this pull request
Jul 2, 2026
…-45accc84 fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
…-45accc84 fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
…-45accc84 fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
…-45accc84 fix(desktop): stop chat scroll bounce — at-rest backward jump + wheel-up snap-back
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Desktop chat no longer bounces, jumps backward, or snaps back to the bottom while reading. Two distinct disarm bugs in
useThreadScrollAnchorare fixed together.The Desktop scroll anchor had two independent failure modes, both reported across Win11/macOS/Linux (#37997, #37811, #37527):
scrollevent whosescrollTopis lower than last frame becausescrollHeightjust jumped. This fires before the rAFpinToBottomruns, so it was misread as a user scroll-up → sticky-bottom disarmed permanently → viewport stuck ~50px above bottom.programmaticScrollPendingRefwent stale when the browser was already clamped at bottom (the expected programmatic scroll event never arrived). The user's next real wheel-up was consumed as "ours" → re-armed → next content-growth pin yanked them back down.The two fixes touch disjoint lines of the same hook and are complementary, not competing.
Changes
thread-virtualizer.tsx(onScroll): gate disarm onheightGrew— only disarm whenscrollTopdecreases andscrollHeightdid not grow this frame. Real upward intent (scrollbar drag, PgUp) still disarms; interim content-growth scrolls don't. Also stop observing the scroller element itself in the ResizeObserver (only the content child), so viewport-only resizes don't trigger spurious pins. (fix(desktop): stop chat scroll backward-jump from content-growth interim scrolls (#37997) #38019, @luyao618)thread-virtualizer.tsx(disarm): clear the staleprogrammaticScrollPendingRefon user wheel/touch so the first upward wheel always registers. (fix(desktop): honor upward wheel scroll in long threads #37831, @ferminquant)streaming.test.tsx: regression test for the stale-pending-programmatic-scroll path. (fix(desktop): honor upward wheel scroll in long threads #37831)Validation
npx tsc -beslint(changed files)Closes #37997, #37527, #37811.
Salvage of #38019 (@luyao618) + #37831 (@ferminquant), cherry-picked onto current main with authorship preserved.
Infographic