Skip to content

Fix scroll jank, which got worse the bigger the window - #32

Merged
MyNamesEMurray merged 1 commit into
mainfrom
claude/live-mic-transcription-accuracy-x5ptio
Sep 7, 2026
Merged

MyNamesEMurray merged 1 commit into
mainfrom
claude/live-mic-transcription-accuracy-x5ptio

Conversation

@MyNamesEMurray

Copy link
Copy Markdown
Owner

Summary

Scrolling was janky, and worse at fullscreen. Two CSS effects were repainting the whole viewport on every scroll frame, on the CPU: the app calls app.disableHardwareAcceleration() on purpose, since it shares a machine and a GPU with OBS and a game. Software rasterisation cost scales with area, so the bigger the window the worse it got — which is exactly the reported symptom.

The measurement

Settings page, 2560×1440, software rasterisation, 135 scroll frames:

p95 max dropped
as shipped 54ms 221ms 80/135
without the backdrop blur 31ms 45ms
without the fixed background 52ms 96ms
without both 17ms 17ms

Neither alone was enough, which is why this presented as "just slow" rather than as one obviously bad effect.

Changes

  • backdrop-filter: blur(14px) on every .card is gone. Blurring a backdrop means re-reading and re-blurring it every frame the card moves — for an effect that is nearly invisible over a dark, low-contrast gradient. A new --glass-card fill carries the panel instead. The deck header's blur goes too: the feed scrolls in its own container below it, so there was never anything moving behind it to blur.
  • background-attachment: fixed is gone. A fixed attachment cannot be scrolled as a layer, so the gradient was recomputed across the viewport every frame. It moves to its own fixed layer (.studio::before), which looks identical and paints once.
  • That layer is opt-in (<body class="studio">), not automatic. The direction is deliberate and is the one thing I'd ask you to sanity-check: the overlay is a transparent guest on someone else's live stream, and its background: transparent !important would not have protected it, because a pseudo-element is not the body's background. A page that forgets the class looks flat; one that inherited an automatic layer could paint over a broadcast.
  • DESIGN.md gains principle 13 ("paint is not free") so these two effects don't grow back: no backdrop-filter and no background-attachment: fixed on anything that scrolls or sits over something that scrolls. Blur stays allowed on a transient overlay above a still page, like the command palette, which is the one place it does visible work.

Verification

  • Full CI reproduced locally: node --check over every JS file, config.example.json parse, npm test (161 pass, 0 fail, 1 pre-existing Windows-only SAPI skip), npm run smoke → SMOKE OK.
  • After the change, at 2560×1440 with software rasterisation: settings p95 16.8ms / max 18.7ms, deck feed p95 16.8ms / max 18.9ms — a held frame on both.
  • Overlay safety checked explicitly: it has no .studio class, its ::before computes to content: none, and its body still composites fully transparent (rgba(0,0,0,0), no background image).
  • Visual A/B on settings, deck and setup at 1280×820: the studio gradient, the panels and the AI badges look the same. No console errors beyond the known /favicon.ico 404.

Caveat on the numbers: these are headless Chromium with --disable-gpu, as the closest available stand-in for Electron's disableHardwareAcceleration on Windows. The relative before/after is solid and the effects removed are well-understood repaint traps, but the absolute milliseconds on your machine will differ.

Risk & rollout

  • CSS only, plus a class on three <body> tags. No server, config, or behaviour change.
  • Visual delta: cards no longer blur what is behind them. Over this background that is close to invisible, but it is a real change to the "glass" treatment and worth your eye.
  • The AI badge and "simulated viewers" watermark are untouched, and the overlay's rendering is unchanged.

Checklist

  • npm run smoke passes locally (or CI is green)
  • Follows the design language in DESIGN.md (if UI changed)
  • AI-labeling / "simulated viewers" guarantees intact (if bot output or overlay changed)
  • Docs updated (README / config reference) if behavior or config changed
  • Targets main

🤖 Generated with Claude Code

https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM


Generated by Claude Code

Two CSS effects were repainting the whole viewport on every scroll frame,
on a CPU: the app disables hardware acceleration on purpose, since it
shares a machine and a GPU with OBS and a game. Cost scales with area, so
the bigger the window the worse it got -- exactly the complaint.

Measured on the settings page at 2560x1440 with software rasterisation,
scrolling 135 frames:

  as shipped                p95 54ms   max 221ms   80/135 frames dropped
  without the backdrop blur p95 31ms   max  45ms
  without the fixed bg      p95 52ms   max  96ms
  without both              p95 17ms   max  17ms

Neither alone was enough, which is why this reads as "just slow" rather
than as one bad effect.

`backdrop-filter: blur(14px)` on every .card meant re-reading and
re-blurring the backdrop every frame the card moved, for an effect that
is nearly invisible over a dark, low-contrast gradient. The card fill
carries the panel instead (--glass-card). The deck header's blur goes
too: the feed scrolls in its own container below it, so there was never
anything moving behind it to blur.

`background-attachment: fixed` cannot be scrolled as a layer, so the
gradient was recomputed across the viewport every frame. It moves to its
own fixed layer, which looks identical and paints once.

That layer is opt-in (`<body class="studio">`) rather than automatic,
and the direction matters: the overlay is a transparent guest on someone
else's live stream, and its `background: transparent !important` would
not have saved it -- a pseudo-element is not the body's background. A
page that forgets the class looks flat; one that inherited it by default
could paint over a broadcast. Verified the overlay has no such layer and
still composites transparent.

Deck feed and settings now hold a 17ms frame at 2560x1440.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
@MyNamesEMurray
MyNamesEMurray merged commit 93a0f1e into main Sep 7, 2026
2 checks passed
@MyNamesEMurray
MyNamesEMurray deleted the claude/live-mic-transcription-accuracy-x5ptio branch September 7, 2026 03:09
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.

2 participants