Repository navigation
Fix webgl rendering corruption from atlas page merges - #5883
Merged
Tyriar merged 2 commits intoMay 21, 2026
Merged
Conversation
vsych
force-pushed
the
fix-webgl-atlas-merge-stale-vertices
branch
from
May 17, 2026 08:45
e7ccd52 to
15a2469
Compare
vsych
force-pushed
the
fix-webgl-atlas-merge-stale-vertices
branch
from
May 18, 2026 22:58
15a2469 to
ae77634
Compare
vsych
force-pushed
the
fix-webgl-atlas-merge-stale-vertices
branch
2 times, most recently
from
May 18, 2026 23:24
26430b0 to
d9accc4
Compare
This was referenced May 18, 2026
vsych
force-pushed
the
fix-webgl-atlas-merge-stale-vertices
branch
from
May 19, 2026 00:30
d9accc4 to
dc726a2
Compare
hesnotsoharry
added a commit
to hesnotsoharry/Ouroboros
that referenced
this pull request
May 19, 2026
Per ADR Decision 3 (RESOLVED 2026-05-18): keep WebGL, vendor upstream fix via self-contained Node postinstall patcher (no new deps - avoids the per-repo lockfile-sync dance). Root cause (Phase C sonnet-diagnostician, high confidence): - Upstream: xtermjs/xterm.js#5847 (OPEN 2026-04-27) - WebGL atlas page-merge corruption with allowTransparency:true + heavy streaming. - Fix: xtermjs/xterm.js#5883 (OPEN 2026-05-17, NOT MERGED). - Symptom in Ouroboros: ghost cursors in random positions during Claude TUI thinking; ghost in front of typing cursor. - Match: same lib version (@xterm/addon-webgl 0.19.0), same config flag, same workload as the upstream repro. Vendor patch shape: - patches/addon-webgl-0.19.0.original.{mjs,js} - shipped 0.19.0 snapshot. - patches/addon-webgl-0.19.0.patched.{mjs,js} - PR #5883 changes applied: (1) AtlasPage.version becomes monotonic global (5 increment sites); (2) TextureAtlas.beginFrame() resets _requestClearModel before return; (3) WebglRenderer.renderRows() adds bounded retry loop (max 3) after _updateModel to handle mid-update merges. - tools/apply-patches.mjs - SHA-256 based; copies patched bundle if installed matches original. Idempotent. Soft-warns and exits 0 if bundle SHA matches neither (upstream update detected - patch needs re-mapping or removal). Wired into package.json postinstall chain. - patches/README.md - removal flow (bump dep + delete patch files when upstream ships >= 0.19.1). Companion changes: - eslint.config.mjs - tools/**/*.mjs added to Node-globals block. - Terminal/CLAUDE.md - gotcha entry pointing to the patch + removal. - useTerminalSetup.lifecycle.ts - structural baseline trace from diagnostician (3 [xterm-init] log lines, kept per debug-before-fix.md). Live verification by Cole REQUIRED before marking phase resolved - ghost cursor disappearance can only be confirmed by running the IDE against a real Claude TUI streaming workload. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 19, 2026
Tyriar
approved these changes
May 21, 2026
Tyriar
left a comment
Member
There was a problem hiding this comment.
Legend 👏 I can repro the problem on master and not on your branch.
This has been an issue for a long time, I think it's popped up more recently due to agentic CLIs using a much wider range of character styles.
Tyriar
enabled auto-merge
May 21, 2026 09:21
chloehkwong1
added a commit
to chloehkwong1/alfredo
that referenced
this pull request
May 21, 2026
… corruption Upgrades @xterm/xterm and the six addons from 6.0.0 stable to the 6.1.0-beta.220 train, which includes xtermjs/xterm.js#5883 — fixing glyph substitution caused by stale WebGL texture binding after atlas page merges. That corruption hit terminals on WKWebView/Tauri (issue #5847); recovery previously required a manual atlas rebuild via Cmd+Shift+K.
|
This is awesome! |
Merged
3 of 4 tasks
Kitenite
pushed a commit
to ParadevAI/Paradev
that referenced
this pull request
May 24, 2026
…e fix (#4893) * improvement(GH-3572): capture brief * improvement(GH-3572): scope proposal v1 * improvement(GH-3572): scope challenged + user pushback note * improvement(GH-3572): deep-research findings (PR #5883 + beta.220) * fix(desktop): bump @xterm/* to beta.220 for upstream WebGL atlas-merge fix Picks up xtermjs/xterm.js#5883 "Fix webgl rendering corruption from atlas page merges" (merged 2026-05-21 by Tyriar). The PR fixes two atlas-merge bugs that match the reported symptom in #3572 (and the sibling cluster #3527, #3794, #4601, #4639): texture binding stays bound to the old page's canvas after a same-index page swap during merge, so glyphs sample garbage. Maintainer Tyriar on the PR: "This has been an issue for a long time, I think it's popped up more recently due to agentic CLIs using a much wider range of character styles." Also adds a one-line VSCode-pattern (microsoft/vscode#120393) fallback inside both onContextLoss handlers: set the module-local suggestedRendererType = "dom" so subsequent terminals on the same path avoid WebGL after a context-loss event. Defense-in-depth for the rarer GPU-process-death class that bypasses the upstream atlas-merge fix. Refs #3572 * improvement(GH-3572): bind scope to option α (upstream bump + fallback) * fix(web): align @xterm/* to beta.220 (matches desktop) * chore(GH-3572): remove orchestration artifacts before PR push
MocA-Love
pushed a commit
to MocA-Love/superset
that referenced
this pull request
May 25, 2026
…e fix (ParadevAI#4893) * improvement(ParadevAIGH-3572): capture brief * improvement(ParadevAIGH-3572): scope proposal v1 * improvement(ParadevAIGH-3572): scope challenged + user pushback note * improvement(ParadevAIGH-3572): deep-research findings (PR ParadevAI#5883 + beta.220) * fix(desktop): bump @xterm/* to beta.220 for upstream WebGL atlas-merge fix Picks up xtermjs/xterm.js#5883 "Fix webgl rendering corruption from atlas page merges" (merged 2026-05-21 by Tyriar). The PR fixes two atlas-merge bugs that match the reported symptom in ParadevAI#3572 (and the sibling cluster canvas after a same-index page swap during merge, so glyphs sample garbage. Maintainer Tyriar on the PR: "This has been an issue for a long time, I think it's popped up more recently due to agentic CLIs using a much wider range of character styles." Also adds a one-line VSCode-pattern (microsoft/vscode#120393) fallback inside both onContextLoss handlers: set the module-local suggestedRendererType = "dom" so subsequent terminals on the same path avoid WebGL after a context-loss event. Defense-in-depth for the rarer GPU-process-death class that bypasses the upstream atlas-merge fix. Refs ParadevAI#3572 * improvement(ParadevAIGH-3572): bind scope to option α (upstream bump + fallback) * fix(web): align @xterm/* to beta.220 (matches desktop) * chore(ParadevAIGH-3572): remove orchestration artifacts before PR push
This was referenced May 28, 2026
monotykamary
added a commit
to monotykamary/localterm
that referenced
this pull request
Jun 9, 2026
Backport xtermjs/xterm.js#5883 to fix glyph rendering corruption caused by stale texture bindings after atlas page merges: - Make AtlasPage.version globally monotonic so GlyphRenderer detects page swaps at the same texture unit index - Reset _requestClearModel in beginFrame() when read - Extract GlyphRenderer.invalidateAtlasTextures() from setAtlas() - Retry full model update when a merge fires mid-pass (capped at 32) - Fix RectangleRenderer buffer underallocation check Switch from CanvasAddon to WebglAddon with preserveDrawingBuffer:true for correct box-drawing glyph connections and GPU-accelerated rendering.
This was referenced Jun 22, 2026
bang9
added a commit
to bang9/ai-tools
that referenced
this pull request
Jul 15, 2026
…n fixes Stable xterm 6.0.0 ships two texture-atlas bugs that corrupt WebGL panes: atlas page merges leave stale vertices (xtermjs/xterm.js#5883) and shared atlas pages are not invalidated per renderer (#6042) — visible as black cells and scattered glyph fragments while typing. Pin the 6.1.0-beta line (webgl 0.20.0-beta.288 is built at the #6042 merge) and migrate the WebglAddon constructor to its new options-object signature so preserveDrawingBuffer (needed by the broadcast snapshot compositor) stays enabled instead of silently degrading. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shironex
added a commit
to noctcore/nightcore
that referenced
this pull request
Jul 31, 2026
…T yet met (part of #430) (#443) #430 assumed the blocker was `@xterm/xterm`. It isn't: **every file [xtermjs#5883](xtermjs/xterm.js#5883) touches is under `addons/addon-webgl/src`**, so the fix ships in `@xterm/addon-webgl`, which versions independently of the core. "Which xterm release contains it" was the wrong question. **No stable release carries it.** `@xterm/addon-webgl` has three stable versions ever — 0.17.0, 0.18.0, 0.19.0 — and `dist-tags.latest` is still 0.19.0, which this repo already uses. The fix appears only from `0.20.0-beta.219` (published ~1h after the merge), confirmed by grepping the fix's own markers (`AtlasPage.nextVersion`, `invalidateAtlasTextures`, `MERGE_RETRY_LIMIT`) in the published tarballs: absent in 0.19.0 and 0.20.0-beta.218, present from beta.219. Taking that prerelease would move the whole terminal stack to the beta channel — its `peerDependencies` demand `@xterm/xterm@^6.1.0-beta.220` — to fix a visual-only bug on our own development platform, with no gate capable of catching a regression. #430's own bar was "a **released** xterm the repo has taken", so macOS stays on DOM and nothing here changes behavior. **D-010 is amended in place** (original intact, still active): the condition was checked and not met, with the evidence, and the trigger is restated as **a stable `@xterm/addon-webgl` ≥ 0.20.0 carrying #5883** — explicitly *not* "#5816 is closed", because an issue can outlive its fix and this one has. Re-checkable with `npm view @xterm/addon-webgl version`. Also corrects two now-stale "fix PR unmerged" claims (in `platform.ts` and the terminal build spec) that were true when written and would have justified a future flip on a false premise. Recorded on #430: the **WebKit ~16-context cap pooling is a prerequisite of the flip, not a follow-up** — with the 8-tab cap, flipping macOS to GPU walks toward the limit where WebKit force-loses the oldest context unrecoverably. Whoever does the flip should land the pool in the same change. #430 stays open and is now labeled `blocked`.
Merged
1 of 2 tasks
This was referenced Oct 14, 2026
Merged
huangzheng2016
added a commit
to Hello-CTF/NexTerm
that referenced
this pull request
Oct 26, 2026
…ling After a texture atlas page merge, xterm.js 6.0 could skip re-uploading a texture slot whose new page had the same per-page version, so every terminal sharing the atlas drew fragments of other glyphs (xtermjs/xterm.js#5883, #6042). xterm.js moves to 6.1.0-beta.315 and its addons to the matching betas, pinned exactly. overviewRuler.width becomes scrollbar.width. A selection whose start row is trimmed now continues from the start of the first surviving row. Transcript replay continues after a write callback returns, because resize inside one re-parses the finished chunk (xtermjs/xterm.js#6246, still open; a live resize during heavy output can still repeat a chunk). Tests stub a measuring 2D canvas context that jsdom lacks.
JameZUK
pushed a commit
to JameZUK/ccpipe
that referenced
this pull request
Nov 2, 2026
… replay Garbled letters on the phone (Firefox Android): the debug snapshot showed the buffer text intact while screenshots had colour/dim/bold glyphs broken — the WebGL glyph atlas, not the data. It matches the @xterm/addon-webgl page-merge bug (xtermjs/xterm.js#5883, fixed only in the 0.20 betas). Settings -> Display -> WebGL renderer now switches it off per device, live, falling back to the DOM renderer. Soft keyboard: opening it shrank the session (43 -> 22 rows) and closing it grew it back, and every resize makes Claude Code redraw, leaving duplicated / cut-off lines in its history. While the keyboard is up the terminal now keeps its rows and is shifted up so the prompt stays in view; a width change (rotation) still re-fits. History replay: capture-pane -J keeps trailing padding, so lines Claude Code padded to a ~190-column desktop arrived on a 51-column phone as text plus 3-4 blank wrapped rows (measured on a live session: 2,287 of 6,103 rows blank). Padding that would wrap is trimmed, except in the last screenful, which tmux's attach redraw paints over and must keep its rows. Snapshot diff: it compared rows bottom-aligned, which fell out of step wherever tmux and xterm wrapped differently (373/500 "mismatches" on a correct buffer). Schema-3 snapshots send logical lines; the server compares them with -J history plus screen rows, drops tmux's status row, and matches by sequence so a local difference stays local. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
JameZUK
pushed a commit
to JameZUK/ccpipe
that referenced
this pull request
Nov 2, 2026
…porary) @xterm/addon-webgl <= 0.19 garbles glyphs after an atlas page merge (the merged page can reuse an index + version, so the GPU texture isn't re-uploaded) — the garbled colour/bold letters on the phone. Fixed upstream in xtermjs/xterm.js#5883, but only in the 0.20 betas (xterm 6.1). Until then: after each frame, read the atlas page count and, three pages short of the merge point, rebuild the WebGL addon so a fresh atlas starts. clearTextureAtlas() isn't enough — it blanks pages but keeps them, and full pages never become active again. Reads private internals; switches itself off with a warning if they change. The debug snapshot reports terminal.webglAtlas {pages, limit, merged, rebuilds}. Verified at the phone's DPR (3.33) with thousands of distinct coloured glyphs: the atlas grew to 24/32 pages, one rebuild, back to 5, no merge. ROLLBACK when xterm 6.1 / addon-webgl 0.20 ship stable — steps in docs/development.md, "Temporary workarounds". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Two bugs in the webgl renderer cause the corruption from #5847.
1. Texture binding stale after a same-index page swap.
GlyphRenderer.renderonly rebinds a texture unit onversionmismatch, but after_createNewPagemerges 4 pages into 1, the page object at the merged index swaps to a freshmergedPage. With per-page counters the new page'sversionoften coincided with the version we last bound at that index (the freshly-pushed mergedPage always landed on1). The rebind was skipped and the texture kept the old page's canvas, so glyphs sampling that unit got garbage.Make
AtlasPage.versionmonotonic across all pages and the existing comparison detects a same-index swap, no extra bookkeeping required.2. Stale
texturePagein the vertex buffer after a mid-update merge. When a merge fires inside_updateModel, cached glyphs get a newtexturePage. Cells already written in this pass (or carried over via the model-unchanged early-exit) still point at the pre-merge index._requestClearModelwas set on merge butbeginFramenever reset it, so it stayed true forever; andrenderRowsonly checked it before_updateModel, so a mid-pass merge went unhandled._requestClearModelwhenbeginFramereads it_updateModel, re-run a full update if a merge fired during the pass (capped atMERGE_RETRY_LIMIT)Before:


After:
Stress repro with the script from #5847 (full-screen rewrite, many colors, frequent merges):
Before this PR:
After this PR: