Skip to content

fix(ui): fix multi-pane WebGL glyph corruption (xterm atlas-merge fix) - #262

Merged
yicheng47 merged 2 commits into
mainfrom
fix/pane-atlas-repaint-flicker
Jul 5, 2026
Merged

yicheng47 merged 2 commits into
mainfrom
fix/pane-atlas-repaint-flicker

Conversation

@yicheng47

Copy link
Copy Markdown
Owner

Bug

In a multi-pane chat tab, sibling panes render correct layout but wrong glyphs ("gibberish" — see below) once an agentic CLI (claude-code / codex) in another pane paints a busy frame. Text stays selectable/correct underneath; only the WebGL render is garbled. It shows up when one pane is starting/busy while a sibling is idle, and per-pane resume/start visibly disturbed siblings.

Root cause

This is an upstream xterm.js WebGL texture-atlas page-merge defect — xtermjs/xterm.js#5883 (merged by Tyriar 2026-05-21), not our code:

  • Two bugs — a stale texture binding after a page swap, and stale vertex-buffer refs when a merge fires mid-update — sample glyphs from the wrong atlas page → correct layout, wrong glyphs.
  • Triggered by "a much wider range of character styles" (Tyriar's words) = exactly agentic CLIs with heavy color/bold/italic/unicode, which grow the glyph atlas until it merges pages.
  • Cross-platform (reproduced on Chromium as well as WKWebView/Tauri), and it predated the in-app atlas workaround — which is why the old clearTextureAtlas shotgun never fixed it and only added sibling flicker.

Fix

Bump @xterm/* to the fixed beta train (the exact set VSCode consumes — microsoft/vscode#317927):

package before after
@xterm/xterm 6.0.0 6.1.0-beta.220
@xterm/addon-webgl 0.19.0 0.20.0-beta.219
@xterm/addon-fit 0.11.0 0.12.0-beta.219
@xterm/addon-web-links 0.11.0 0.13.0-beta.219

Then delete the now-dead cross-pane atlas machinery (atlasPeers fan-out, refreshAllTerminalAtlases, the per-terminal repaint/rebuild hooks, and the redundant activation-path clearTextureAtlas) that only masked the symptom. WebGL is kept per-terminal, along with the onContextLoss → DOM fallback and the font-change atlas rebuild.

Also included (unrelated tidy)

refactor(ui): scope pane-group geometry sync to layout changes — ChatPaneGroup's geometry sync ran on every commit (empty deps), redoing an all-panes getBoundingClientRect + write on unrelated re-renders. Now scoped to [layout.root], with a sync when a terminal wrapper's ref mounts so restored-split hydration still positions late-attaching panes. Separate commit; safe to review independently.

Caveat

@xterm/xterm core is a beta release — the fix is not in a stable tag yet. VSCode ships this same beta, and it's a minor (6.0 → 6.1) bump, so risk is low, but flagging it since it adopts a beta dependency.

Testing

  • pnpm exec tsc --noEmit, pnpm run lint, pnpm run build (tsc && vite build) — all clean.
  • Working-tree diff reviewed clean by the crew reviewer (deps pinned, peer ranges line up, pnpm install --frozen-lockfile --offline clean, git diff --check clean).
  • Runtime visual verification confirmed: the exact 3-pane repro no longer garbles sibling panes.

🤖 Generated with Claude Code

yicheng47 added 2 commits July 5, 2026 22:19
Split-chat WebGL terminals rendered correct layout but WRONG GLYPHS on
sibling panes once agentic CLIs (claude-code/codex) emitted a wide range
of styled cells. Root cause is an upstream xterm.js WebGL texture-atlas
page-merge defect (xtermjs/xterm.js#5883), not our code: it predates the
in-app atlas workaround and is cross-platform (reproduced on Chromium as
well as WKWebView).

Bump @xterm/* to the fixed beta train (xterm 6.1.0-beta.220,
addon-webgl 0.20.0-beta.219, addon-fit 0.12.0-beta.219,
addon-web-links 0.13.0-beta.219 — the set VSCode consumes) and delete the
now-dead cross-pane atlas coordination (atlasPeers fan-out,
refreshAllTerminalAtlases, per-terminal repaint/rebuild hooks, and the
redundant activation-path clearTextureAtlas) that only masked the symptom
and was itself the sibling flicker. Keep per-terminal WebGL plus the
context-loss -> DOM fallback, and the font-change atlas rebuild.
ChatPaneGroup's geometry sync ran on every commit (empty deps), redoing
an all-panes getBoundingClientRect + write on unrelated re-renders. Scope
it to [layout.root] and sync a terminal wrapper when its ref mounts, so a
session attaching into an already-hydrated pane (restored-split
hydration) is still positioned without the per-commit churn.
@yicheng47
yicheng47 merged commit 9ef6ba5 into main Jul 5, 2026
2 checks passed
@yicheng47
yicheng47 deleted the fix/pane-atlas-repaint-flicker branch July 19, 2026 07:00
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