fix(desktop): stop channel switches jittering and flashing - #6524
Open
Maxwellimus wants to merge 2 commits into
Open
fix(desktop): stop channel switches jittering and flashing#6524Maxwellimus wants to merge 2 commits into
Maxwellimus wants to merge 2 commits into
Conversation
Maxwellimus
force-pushed
the
perf/switch-tracing
branch
from
August 22, 2026 00:02
c2e89e6 to
99b0a59
Compare
Maxwellimus
force-pushed
the
fix/switch-visual-stability
branch
from
August 22, 2026 00:04
ee63e04 to
1a1fe23
Compare
Maxwellimus
force-pushed
the
perf/switch-tracing
branch
from
August 22, 2026 16:51
99b0a59 to
03ca3b1
Compare
Maxwellimus
force-pushed
the
fix/switch-visual-stability
branch
from
August 22, 2026 16:53
1a1fe23 to
8067857
Compare
Maxwellimus
force-pushed
the
perf/switch-tracing
branch
from
August 22, 2026 17:19
03ca3b1 to
2a4d128
Compare
Entering a channel whose thread-summary facepiles hydrate after first paint (profiles resolving late) visibly shifted the timeline: every row above a summary slid ~3px per summary a beat after content painted. The summary button was inline-flex, so it participated in its wrapper's line box via its baseline — and that baseline moves when the avatar's content resolves (Radix fallback text appearing after its delay, or the avatar image landing). Make the button a block-level flex row so the wrapper height is padding + button height regardless of avatar state, and render the facepile fallback immediately (fallbackDelayMs=0): the participant starts with no image URL, so the default 200ms delay only left a blank hole where the initials belonged. Regression spec pins the wrapper height from first paint through hydration and the root row's position after the facepile renders, with the users-batch response deliberately delayed past first paint. Signed-off-by: Max Lampert <maxwell@squareup.com>
Two skeleton flashes made switching feel clunky: - Every switch: the deferred timeline snapshot lags the live one for a frame or two, and that gap painted the full skeleton to mask the previous channel's rows — a visible skeleton flash on every switch. The gap is a render-pipeline artifact, not a loading state: it now renders plain background (new "blank" body surface). Blank blocks the same behaviors as the skeleton (autoscroll, jumps, unread pill, scrollback), only the visual differs. Cold loads keep the skeleton. - Stale revisits: the loading latch reset on every switch, so re-entering a channel past the messages staleTime refetched on mount with the unsettled skeleton branch active — a skeleton over a fully cached timeline for the whole relay round-trip. Channels that settled once this session now render their cached rows stale-while-revalidate (session registry, reset via resetCommunityState like every other community-scoped singleton). The revisit spec forces staleness by shifting Date.now past the 5-minute window and asserts the skeleton never mounts over cached rows; the switch-gap behavior is covered by the timelineSnapshot unit suite. Signed-off-by: Max Lampert <maxwell@squareup.com>
Maxwellimus
force-pushed
the
fix/switch-visual-stability
branch
from
August 22, 2026 17:22
8067857 to
aea889c
Compare
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.
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):
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.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) andchannel-revisit-no-skeleton.spec.ts(staleness forced by shiftingDate.now()past the freshness window; skeleton must never mount over cached rows).Measured impact (live community, switch traces)
Recreates #6457, which was accidentally squash-merged into its base branch
perf/switch-tracing(since reverted there). Same content; still stacked on #6455.