Skip to content

fix: add DOM renderer fallback for Windows compatibility#722

Open
djdarcy wants to merge 2 commits intocharmbracelet:mainfrom
djdarcy:fix/windows-ttyd-rendering
Open

fix: add DOM renderer fallback for Windows compatibility#722
djdarcy wants to merge 2 commits intocharmbracelet:mainfrom
djdarcy:fix/windows-ttyd-rendering

Conversation

@djdarcy
Copy link

@djdarcy djdarcy commented Mar 13, 2026

  • I have read CONTRIBUTING.md.
  • I have created a discussion that was approved by a maintainer (for new features). (not applicable)

Fixes #721. Related: #631, tsl0922/ttyd#1501, tsl0922/ttyd#1502.

VHS on Windows produces blank frames because the canvas renderer fails in headless Chrome when WebGL is unavailable. This is compounded by a ConPTY bug in ttyd's MinGW build on Windows 11 25H2 (tracked separately in tsl0922/ttyd#1501).

Changes

tty.go:

  • Switch default xterm.js renderer from canvas to dom

vhs.go:

  • Add SwiftShader/ANGLE browser flags (use-gl=angle, use-angle=swiftshader, enable-webgl) as WebGL fallback
  • Detect canvas vs DOM renderer at setup: probe for canvas.xterm-text-layer with a 5-second timeout, fall back to .xterm-screen element screenshot
  • Use temporary timeout page for the probe to avoid context deadline errors on stored elements

ttyd dependency

The bundled ttyd.win32.exe (MinGW cross-compiled) fails on Windows 11 25H2 with CreateProcessW error 123. An MSVC-built ttyd resolves this. See:

Notes

Happy to adjust the approach. The DOM renderer fallback could be made configurable via environment variable if preferred, and the SwiftShader flags could be opt-in rather than default.

Tested on Windows 11 Pro 25H2 (build 26200.8037) with MSVC-built ttyd, Chrome 134.

djdarcy added 2 commits March 13, 2026 01:34
The canvas renderer fails in headless Chrome on Windows when WebGL is
unavailable (RDP sessions, headless environments, CI). This causes
CanvasToImage() calls to return empty frames.

Changes:
- Switch default renderer from canvas to DOM (tty.go)
- Add SwiftShader/ANGLE browser flags for WebGL fallback (vhs.go)
- Probe for canvas.xterm-text-layer with timeout; fall back to
  .xterm-screen element screenshot when canvas is absent (vhs.go)
- Use temporary timeout page for probe to avoid context deadline
  errors on stored elements (vhs.go)
- Add diagnostic logging throughout startup, setup, and recording
  pipeline (evaluator.go, vhs.go)

The debug-instrumented version is preserved in this commit for
reference. A follow-up commit strips the diagnostic logging.

Related: charmbracelet#631
Depends on: tsl0922/ttyd#1501 (ConPTY fix for Windows 11)
Remove verbose debug output from evaluator, browser launch, setup,
and recording pipeline. Functional changes preserved: DOM renderer
fallback, SwiftShader browser flags, timeout-based canvas probe.

The debug-instrumented version is preserved in the previous commit
for reference.
@djdarcy djdarcy requested a review from a team as a code owner March 13, 2026 07:40
@djdarcy djdarcy requested review from andreynering and raphamorim and removed request for a team March 13, 2026 07:40
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.

VHS produces blank frames on Windows, canvas renderer fails in headless Chrome

1 participant