Skip to content

fix(desktop): Browser Screenshot saves fresh pixels while T3 Code is hidden - #36671

Merged
juliusmarminge merged 3 commits into
pingdotgg:mainfrom
Quicksaver:fix/desktop-human-background-screenshots
Nov 14, 2026
Merged

juliusmarminge merged 3 commits into
pingdotgg:mainfrom
Quicksaver:fix/desktop-human-background-screenshots

Conversation

@Quicksaver

@Quicksaver Quicksaver commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This is a new PR that replaces #22335, which was closed for staleness. The same single commit is rebased onto upstream main at 13f89ae0a7. git range-diff reports the patch identical to #22335's last head, and all proof below was regenerated at this base and head. Julius has since merged main at 121f0cf014 and trimmed the still-image tests in dab0ad7. Manager.ts is byte-identical to the proven head 932af4cb1d.

On Windows and Linux, clicking the Browser panel's Screenshot button while the T3 Code window is hidden saves nothing. Electron's capturePage never settles for a preview that isn't being presented, so every retry times out. Each human screenshot now keeps the preview rendering for the duration of the request, waits for a paint through the preview's existing debugger session, discards a warmup capture, and saves the final native readback.

This restores the human Screenshot fix from #19931, which #22222 reverted. Julius asked for a fresh PR with real-build before/after proof on every affected platform.

What changed

  • Each Screenshot click becomes its own rendering consumer next to recording and picture-in-picture, so background throttling comes back only after the last consumer finishes. Overlapping clicks run independent paint probes.
  • The paint probe waits for two animation frames in an isolated world, using only the debugger session the preview already owns. It never attaches or displaces a debugger, and it is bounded to one second.
  • If the probe or warmup fails, the capture logs a warning and saves whatever pixels are available, so freshness is not guaranteed in that case. A frozen renderer can delay the probe's page-side timeout, and Electron capture promises cannot be cancelled.
  • Agent/CDP screenshots, annotation screenshots, recording and contracts are unchanged. Only the Electron desktop runs this path; standalone web and mobile do not.

Validation

Tests, checks, control runs and review status at 932af4cb1d, plus dab0ad7

Proof

Native before/after on Windows, Linux and macOS at 13f89ae vs 932af4c

Both revisions ran as complete vp run build:desktop apps (Electron 44.10.1) from clean exact-SHA checkouts. No native build was rerun at dab0ad7, whose merge also changed the desktop build files ensure-electron-runtime.mjs and vite.config.ts. Each run started from a copy of the same existing state: an imported, settled real conversation that was opened before the cases. Every image came from clicking the app's real Capture screenshot button, driven by Playwright Electron. No CDP screenshot was used. The page paints a binary epoch counter and a background color, and a standard-library PNG decoder read each saved file.

Hidden app, requested epoch 5:

Platform Before After
Windows 11 x64 No PNG: three native captures never settled Windows saves fresh epoch 5 while hidden
Linux (Debian 12, Xvfb) No PNG: three native captures never settled Linux saves fresh epoch 5 while hidden
macOS 27.0.1 arm64 macOS before saves fresh epoch 5 macOS after saves fresh epoch 5

The macOS before and after files are byte-identical, so the upload service stored them once. macOS was not affected in these conditions.

Case Windows Linux macOS
Two overlapping hidden clicks Before none, after 2 fresh Before none, after 2 fresh 2 fresh on both
Shown, minimized, PiP open, navigation or early load failure during capture, replacement guest Fresh on both Fresh on both Fresh on both
Busy page (4 s main-thread loop), and navigating away from it during capture Fresh on both; after logged the probe fallback Same Same
Tab closed after the first native capture started No PNG on both No PNG on both Close landed after the save
App closed during a capture Clean exit on both Clean exit on both Clean exit on both

Recording kept throttling disabled after PiP closed, and stopping it restored throttling. After every still capture taken without PiP open, throttling was back on and window focus was unchanged.

Limits:

  • The Windows session was locked with the display off for the entire Windows comparison, confirmed by a native display-state subscription and WTS session flags. An unlocked, display-on Windows run was not done at these revisions.
  • Linux ran in Docker on WSL2 with Xvfb, Openbox, picom and llvmpipe. Physical displays, lock, hardware GPU, Wayland and an installed AppImage are not covered.
  • macOS ran unlocked with the display on and used Electron's mock keychain flag. Display sleep and lock were not run at these revisions.
  • The "close after the second native capture" attempt landed after the save on every platform, so an interrupted final readback was not demonstrated. No frozen renderer was simulated.
  • On Windows, blur() left the window focused, so the "inactive" case there was effectively shown. Linux BEFORE did not register the minimize.

Proof package (zip, SHA-256 fe256a99a2387dedcd57022bdf80bfa7e2fb9dc4d17ab5c28c301d7937214785): every saved PNG, decoder output, native call and throttling observations, Windows display/session events, the driver and decoder scripts, and the Linux container recipe. Profiles, the seed database and app screenshots showing conversation content are excluded.

🤖 Generated by GPT 6.1 Sol in Codex via T3 Code.
🤖 Reviewed until clean on #22335 by GPT 6 Astra, GPT 6.1 Sol, Claude Fable 5.1, Claude Opus 5.5, CodeRabbit. Findings that reach consensus across the majority were addressed by the generation model.
🤖 Replacement PR, rebase validation and native proof by Claude Opus 5.5 in Claude Code via T3 Code.

Keep each human capture rendering through a bounded paint probe and
warmup, then save the final native pixels. Let overlapping probes
progress independently while retaining recording and PiP ownership.

Co-authored-by: Julius Marminge <julius0216@outlook.com>

> 🤖 Generated by GPT 6.1 Sol in Codex via T3 Code.
@github-actions github-actions Bot added vouch:unvouched Author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 14, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 14, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 932af4c

Macroscope's review found this PR approvable — Screenshot capture now briefly keeps previews rendering and waits for fresh paint, including while the desktop window is hidden. The change retains existing artifact handling and uses bounded probes and independent rendering leases to limit interference with recording and picture-in-picture.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

Screenshot capture now uses a dedicated frame-capture lease, checks for paint readiness, and performs warmup and final captures. Tests cover paint timing, overlapping captures, rendering state, and fallback capture behavior.

Changes: Still-image capture

Layer / File(s) Summary
Capture lease and final image
apps/desktop/src/preview/Manager.ts
captureScreenshot calls captureStillImage. The new flow acquires and releases a separate frame-capture lease, checks paint readiness, runs a warmup capture, and performs a final capture.
Capture timing and rendering tests
apps/desktop/src/preview/Manager.test.ts
Tests cover warmup failures, waiting for paint, overlapping captures, picture-in-picture and recording state, and saving available pixels when paint readiness times out.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Suggested reviewers: juliusmarminge, voltcrash

Merge Risk: Minimal · up to dab0a

This change makes the Browser panel's Screenshot button capture reliably when the window is hidden, and it falls back to saving available pixels if the paint check fails. The change is limited to desktop human screenshots, and no concrete merge-blocking problem was identified in the supplied review material.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title names the main change: a fix in the desktop Browser Screenshot path so that it saves fresh pixels while T3 Code is hidden. The raw summary shows the Manager.ts capture flow (captureStillImag…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description is substantive and follows the template's intent. It has a clear Problem (Windows/Linux hidden-window Screenshot saves nothing because capturePage never settles), a Change section desc…
Full details: Title check

Explanation

The title names the main change: a fix in the desktop Browser Screenshot path so that it saves fresh pixels while T3 Code is hidden. The raw summary shows the Manager.ts capture flow (captureStillImage, paint probe, warmup) and the Manager.test.ts paint-readiness tests, which match that title. It is a conventional commit title in plain language, under 80 characters.

Full details: Description check

Explanation

The description is substantive and follows the template's intent. It has a clear Problem (Windows/Linux hidden-window Screenshot saves nothing because capturePage never settles), a Change section describing the paint-wait, warmup discard, and per-click rendering consumer, and a Scope section that links prior issue/PR context (#22335, #19931) and the maintainer request (Julius's comment asking for a fresh PR with before/after proof). Verification is detailed, with focused test counts, the three failing tests and a same-host control, and explicit statements of what was not checked. Native before/after proof is provided for all three platforms with embedded images and a proof package. Minor gaps: the template's header comment asks for a conventional commit title, and the description does not state a title; the 'Problem' and 'Change' sections are not explicitly headed as in the template (they are present as 'Summary' and 'What changed'), and the Verification section is spread across collapsible blocks. The description also ends with the required model/harness attribution. Overall it is mostly complete, so it passes.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 932af4c and dab0ad7.

Files selected for processing: 1

  • apps/desktop/src/preview/Manager.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

@juliusmarminge juliusmarminge added the takeover:in-progress A takeover lead is working on this PR label Nov 14, 2026
juliusmarminge and others added 2 commits November 14, 2026 11:19
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…regressions

Drop cases that re-test existing guest-replacement checks, mock the paint probe's JS through a VM, or assert on debugger ownership the code never takes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Evidence

Linux desktop, Electron 44.10.1, Xvfb, light theme, 1440×840 window; isolated synthetic state on both commits. Open Browser, capture while shown, then hide for 3 seconds, change the page text/color, and activate Capture screenshot while hidden. Check files before restoring after 4.5 seconds. Repeat with two requests 200 ms apart.

Before After
121f0cf014 dab0ad7d71
Visible control saved; all 3 hidden requests timed out without PNGs. Visible control and all 3 hidden requests saved PNGs before restoration.
Before: hidden Browser Screenshot reports capture timeout After: actual saved PNG contains the fresh purple HIDDEN 200 marker
Before recording After recording

The head temporarily disabled background throttling during captures and restored it afterward. Base observations · Head observations.

Actual comparison driver · Counter fixture · Portable launch/setup and scripts · Sanitized runtime/build logs.

The counter was paused at deterministic markers to inspect freshness. Video status strips are driver annotations; application pixels are native screen recordings. Captures were visually inspected.

Not shown:

  • Windows and macOS were not run; the demonstrated before/after result is Linux only.
  • Ownership retention while recording or picture-in-picture remains active was not exercised.
  • The two requests 200 ms apart both succeeded on head, but completed separately; overlapping screenshot consumer lifetimes were not demonstrated.
  • Minimized windows, capture failure cleanup, and debugger-conflict fallback were not exercised.

@juliusmarminge juliusmarminge added takeover:ready Takeover done; auto-lands when gates pass and removed takeover:in-progress A takeover lead is working on this PR labels Nov 14, 2026
@juliusmarminge
juliusmarminge merged commit 8a45c51 into pingdotgg:main Nov 14, 2026
49 checks passed
@juliusmarminge juliusmarminge removed the takeover:ready Takeover done; auto-lands when gates pass label Nov 14, 2026
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Nov 14, 2026
Sync 1114b: 134 upstream commits to ead133c. Two additive conflicts:
desktop preview Manager.ts keeps the fork "automation" frame consumer beside
upstream's per-capture symbol lease (pingdotgg#36671); claudeModelOptions.ts keeps the
fork output style beside pingdotgg#28024 custom-model thinking and pinnedAlias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched Author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants