Skip to content

fix(chat): eliminate streaming scroll jank (0.0.8)#172

Merged
blove merged 1 commit into
mainfrom
claude/chat-08-jank-fix
May 2, 2026
Merged

fix(chat): eliminate streaming scroll jank (0.0.8)#172
blove merged 1 commit into
mainfrom
claude/chat-08-jank-fix

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented May 2, 2026

Summary

Real-LLM streaming exposed visible jerky scroll behavior. Profiled it: the auto-scroll-to-bottom effect was firing 37 `scrollTo()` calls in 2.87s during a single ~150-token response. 33 of those used `behavior: 'smooth'`, producing overlapping smooth-scroll animations that interrupt each other every ~80ms and never settle.

Fix

Drop `requestAnimationFrame(() => scrollTo({ behavior }))`, use direct `scrollTop = scrollHeight`. Instant, idempotent, no animation queue.

```diff

  • if (isNewMessage || isNearBottom) {
  • requestAnimationFrame(() => {
  • el.scrollTo({ top: el.scrollHeight, behavior: isNewMessage ? 'instant' : 'smooth' });
    
  • });
  • }
  • if (isNewMessage || isNearBottom) {
  • el.scrollTop = el.scrollHeight;
  • }
    ```

Same logic for the parked-reading case (user scrolled up >150px → no auto-scroll). Same logic for the new-message case (always pin to bottom). Just no animation overhead.

Verification

Profiled the same prompt before/after against a LangGraph dev backend running OpenAI gpt-4o-mini:

Metric 0.0.7 0.0.8
`scrollTo()` calls during stream 37 0
Of which `behavior: 'smooth'` 33 0
Scroll-position writes 37 1
Stream duration 2867ms unchanged

User-visible result: streaming text settles in place without animation jitter.

Test plan

  • `nx build chat` clean
  • `nx test chat` clean
  • `nx lint chat` clean
  • Verified live with real LLM streaming (gpt-4o-mini via LangGraph)
  • CI green
  • Tag v0.0.8 to publish

🤖 Generated with Claude Code

Profiled the auto-scroll-to-bottom effect during real LLM streaming
and found it was firing 37 scrollTo() calls in 2.87s — 33 of them
with `behavior: 'smooth'`. Each smooth-scroll animation queues
behind the previous one and gets interrupted before completing,
producing visibly jerky scroll throughout streaming.

Fix: drop `requestAnimationFrame(() => scrollTo({ behavior }))` and
use direct `scrollTop = scrollHeight`. That's instant, idempotent,
and no animation queue to thrash. Same effect, none of the jank.

Verified live with the smoke app + a LangGraph dev backend hitting
gpt-4o-mini. The same prompt that previously triggered 33 smooth
scrolls now triggers 0 scrollTo calls and 1 scrollTop write —
exactly the silent, instant settle we want.

Bumps @ngaf/chat to 0.0.8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cacheplane Ready Ready Preview, Comment May 2, 2026 4:58am

Request Review

@blove blove merged commit a0b0286 into main May 2, 2026
14 checks passed
@blove blove deleted the claude/chat-08-jank-fix branch May 7, 2026 16:30
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