perf(web): stop rendering hidden terminals - #9718
Conversation
Pause terminal snapshots, canvas paint, queued frames, and cursor timers while the drawer or right-panel terminal is hidden. Keep parsing output and answering VT queries. Refit and repaint current output on reveal. Preserve selection state and read the latest visibility after asynchronous WASM setup. Verify with 73 focused headless tests using the real Ghostty core, plus the web typecheck and targeted lint. Created with GPT-6 Astra (preview) in Codex.
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This performance change alters the lifecycle of mounted terminals by suppressing snapshots, canvas painting, focus, and cursor timers while the existing panel is hidden, while retaining terminal parsing and replies. The behavior is covered by focused WASM-backed tests, but the production render gate changes when substantial existing work occurs and merits human review. You can add or adjust custom eligibility rules. Learn more. |
|
Note 🤖 GPT-6 Astra (preview) responding on behalf of Theo I reviewed both the drawer and right-panel paths, including split terminals and visibility changes during WASM loading. Hidden terminals still parse output and answer VT queries. The new gates stop post-construction snapshots, canvas paint, queued render frames, and cursor timers. Reveal renders the current state once. The existing startup background fill remains. I independently reran all 73 focused surface/core/renderer/drawer tests. Web typecheck, CI, Cursor, and Macroscope correctness/conventions/UI checks pass on 16b81b4. Automatic eligibility is neutral because rendering lifetimes change. No browser, device, or GPU measurement is claimed. The source guard's contributor credit remains intact. |
## What's Changed * perf(server): use one query for buffered provider events by @t3dotgg in pingdotgg/t3code#9706 * perf(relay): avoid repeated activity decoding by @t3dotgg in pingdotgg/t3code#9708 * perf(web): stop continuous chat status animations by @t3dotgg in pingdotgg/t3code#9709 * fix(mobile): preserve saved work after storage read failures by @t3dotgg in pingdotgg/t3code#9710 * perf(web): stop replaying terminal buffers on rollover by @t3dotgg in pingdotgg/t3code#9707 * feat(web): preview pull request links by @maria-rcks in pingdotgg/t3code#9631 * perf(client): reduce thread-list update work by @t3dotgg in pingdotgg/t3code#9716 * fix(server): settle inactive threads with open PRs by @Gigioxx in pingdotgg/t3code#9610 * fix(server): bound slow-client event buffers by @t3dotgg in pingdotgg/t3code#9715 * test(server): allow either valid file-search match by @t3dotgg in pingdotgg/t3code#9720 * fix(web): match provider settings layout for disconnected devices by @flamboh in pingdotgg/t3code#9619 * fix(web): keep the slash menu above the composer when vertical space is short by @Mnigos in pingdotgg/t3code#9625 * fix(mobile): remove provider setup by @juliusmarminge in pingdotgg/t3code#9721 * perf(web): stop rendering hidden terminals by @t3dotgg in pingdotgg/t3code#9718 * fix(mobile): read file-backed image drafts before enabling them by @t3dotgg in pingdotgg/t3code#9713 * perf(server): replay only the selected thread by @t3dotgg in pingdotgg/t3code#9726 * fix(web): mute composer helper text by @jakeleventhal in pingdotgg/t3code#9654 * feat(web): unpin threads from the sidebar multi-select menu by @gsimone in pingdotgg/t3code#9651 * perf(web): reuse timeline rows while text streams by @t3dotgg in pingdotgg/t3code#9725 * fix(relay): bound stalled push requests by @t3dotgg in pingdotgg/t3code#9734 * perf(server): stop caching unused OpenCode tool parts by @t3dotgg in pingdotgg/t3code#9738 * fix(web): fold single trailing activity by @maria-rcks in pingdotgg/t3code#9739 * fix(web): show project settings for new threads by @maria-rcks in pingdotgg/t3code#9743 * perf(mobile): bound the parsed review cache by @t3dotgg in pingdotgg/t3code#9749 **Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260904.1279...v0.0.39-nightly.20260904.1280 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260904.1280
Hidden terminal drawers and panels still build cell snapshots and paint frames for output no one can see.
After construction, pause frame scheduling, snapshots, canvas paint, and cursor timers while hidden. Keep the one-time startup background fill, output parsing, and VT replies. Refit and repaint the current state on reveal, including visibility changes during WASM startup.
Includes Wout Stiens' zero-size canvas guard from PR #9027, with author and co-author credit preserved. Its server and native changes remain separate.
Verified with 73 focused tests, the web typecheck, and targeted lint. Headless tests use the real Ghostty core and renderer to check hidden work, query replies, cursor and selection state, same-size recovery, and delayed WASM initialization. No browser, device, or dev server run.
Refs #9661.
Created with GPT-6 Astra (preview) in Codex.
Note
Medium Risk
Touches the Ghostty render loop and terminal focus/resize behavior in the right panel; regressions could show as stale UI or focus quirks when reopening, though behavior is covered by new tests.
Overview
Hidden thread terminals stay mounted for fast switching, but no longer waste work painting off-screen canvases.
GhosttyTerminalSurfacegains an optionalvisibleflag andsetVisible(), which cancels animation frames, snapshots, and cursor blink timers while hidden while still parsing output and replying to VT queries. On show (or when the mount regains non-zero size), it refits and does a full repaint of the current buffer, including selection state.The chat UI threads
rightPanelOpenintoPersistentThreadTerminalPanel→ThreadTerminalDrawer→TerminalViewport, syncing visibility on layout and skipping focus, fit, and resize-driven layout when the panel is closed. Creation can use a getter for visibility so WASM startup respects toggles that happen mid-load.New headless surface tests cover hidden paint suppression, live query replies, selection preservation/clear-on-reveal, zero-size mounts, and delayed WASM init.
Reviewed by Cursor Bugbot for commit 16b81b4. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Skip rendering and fitting for hidden terminal surfaces in
GhosttyTerminalSurfaceGhosttyTerminalSurfaceso hidden or zero-size surfaces stop snapshotting, painting, fitting, cursor blinking, and focus handling while the terminal core continues to process VT input and replies.ChatViewthroughPersistentThreadTerminalPanelandThreadTerminalDrawerdown to eachTerminalViewport, which syncs visibility to the surface via a ref and layout effect.setVisiblesetter that cancels queued render frames and cursor timers on hide and refits with a full repaint on reveal.surface.test.tswith a real-WASM harness covering hidden paint suppression, selection retention/clear, zero-size mounts, and visibility changes during async core initialization.Macroscope summarized 16b81b4.