Skip to content

fix(desktop): stop channel switches jittering and flashing - #6457

Merged
Maxwellimus merged 2 commits into
perf/switch-tracingfrom
fix/switch-visual-stability
Aug 21, 2026
Merged

fix(desktop): stop channel switches jittering and flashing#6457
Maxwellimus merged 2 commits into
perf/switch-tracingfrom
fix/switch-visual-stability

Conversation

@Maxwellimus

Copy link
Copy Markdown
Contributor

Based on perf/switch-tracing — retarget to main after it merges. (Shares the settle seam in ChannelScreen and the community-reset inventory.)

Two visible artifacts made switching feel clunky (diagnosed by frame-by-frame analysis of a 120fps capture):

  1. Thread-summary rows reflowed ~3px each a beat (~200ms) after paint — measured as a +6px/+3px/0 differential shift across the viewport in consecutive frames. The summary button was inline-flex, so it participated in its wrapper's line box via its baseline — which moves when the avatar's content resolves (Radix fallback delay, or the avatar image landing after profiles hydrate). The button is now a block-level flex row (wrapper height = padding + fixed button height regardless of avatar state: 36px constant, was 39→36) and the facepile renders its fallback immediately — the participant starts with no image URL, so the 200ms fallback delay only left a blank hole.
  2. The timeline skeleton flashed on switches. Two causes: (a) the deferred-snapshot gap — 1–2 frames per switch where the skeleton masked the previous channel's lagging rows — now renders plain background (new "blank" body surface; blocks the same behaviors as the skeleton, only the visual differs; cold loads keep the skeleton); (b) stale revisits — the loading latch reset per switch, so re-entering a channel past the messages staleTime held a skeleton over a fully cached timeline for the whole refetch round-trip. Channels that settled once per session now render cached rows stale-while-revalidate (session registry, reset via resetCommunityState()).

Both are pinned by red-first regression specs: thread-summary-stability.spec.ts (row geometry through delayed profile hydration; failed 39→36px pre-fix) and channel-revisit-no-skeleton.spec.ts (staleness forced by shifting Date.now() past the freshness window; skeleton must never mount over cached rows).

Measured impact (live community, switch traces)

metric before after
warm/rapid switch, click→settled paint (median) 260ms 148ms (−43%)
all switches, p90 994ms 682ms
stale-revisit paint full refetch RTT behind a skeleton immediate (cached rows)
summary-row reflow on hydration 3px per row, every cold entry none (spec-pinned)

Loading
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