cmux-next: stained-glass panes stay legible over background art (cx-t2x.2)
Summary
Over backdrop art, the panes are now stained glass. Each pane is clear, and the window's single theme tint, drawn over the art, keeps every text role readable whatever the art underneath is and whatever opacity the user sets. This is step 2a of the art pillar (cx-t2x.2), and it follows Leo's hard requirement that text and UI stay legible with any art at any opacity. Art itself stays off by default, so nothing changes until a user picks a background.
- Contrast solver.
ThemeTokens.legibleTintOpacity(over:requested:)finds the least opacity of the theme's own surface color, laid over art anywhere from black to white, at which primary and secondary text keep 4.5:1 and tertiary text and marks keep 3:1. The scrim is the Ghostty theme's surface color, with no accent color. A theme whose text fails even on its own opaque surface gets opaque glass, so the art hides rather than making that text worse.BackdropArtRangeholds the art's darkest and lightest values. It is black to white for now, so the floor is conservative: about 0.89 for Catppuccin Mocha and 0.9 for GitHub Light, against the themes' earlier 0.61 and 0.64. Measuring each piece's real range when it is decoded (cx-t2x.3) will lower the floor and show more art. - The window tint never drops below it.
WindowBackdropraises its tint over art to that floor (legibleTintOpacity). A lowbackground-opacityor the glass-transparency tuner shows more art only down to that floor. Without art the user's opacity stands, because the glass then sits over the desktop, as before. - Panes stay clear over art. Home and other pages (
Palette.paneFill), web pages (WebTheme), the pane content host, the New Tab backdrop, browser chrome and the agent pane used to readWindowBackdrop(tokens)without the art selection. At full opacity they painted opaque and hid the art. They now readWindowBackdrop.current, which carries the app's selection, so the art shows through the one legible tint. Reduce Transparency still paints opaque.
The terminal's own glass (Ghostty background-opacity is shared with the window) and a stronger scrim behind the terminal come in a follow-up. The right-click "Change Background…" picker with live preview and the opacity slider are cx-t2x.4.
Testing
-
New tests,
BackdropLegibilityTests(CmuxNextDesignTests):- For every theme fixture and every requested opacity from 0 to 1, the solved tint is at least the request and keeps every text role at its contrast over black and white art.
- At
background-opacity0.05 with art, the window tint stays at or above the legible floor. Without art it stays 0.05. - With the glass tuner at full transparency, the tint view's alpha stays at the floor.
- Panes stay clear over art at full opacity and paint under Reduce Transparency.
WindowBackdrop.currentfollowsThemeScope.app's selection.
-
WindowMaterialTests.wallpaperTintOpacityUsesThemeContrastnow expects the over-art tint to be the larger of the theme's wallpaper tint and the legible floor. -
Red, test commit b4672c6fbcb (the solver plus a
WindowBackdrop.currentstub that ignores the art): the fleet suite runner (run-swift-testing-suites.sh) is fail-fast and alphabetical. Right now it stops at base-ownedCmuxNextAppfailures before it reachesCmuxNextDesignTests, so no fleet red was recorded. This was reported to CI. -
Green, hosted
cmux-next swift test:BackdropLegibilityTestspassed on the previous head. The current head, with the updatedWindowMaterialTests, is pending. The remaining reds come from base and also fail on unrelated PRs (AgentPaneShellCompletionTeststimeouts,PageHostPoolTests,FirstRunResumeTests). -
python3 scripts/verify-local.py:swift-syntaxpasses on the changed files.localization,localization-defaultsandpackage-groupsfail the same way on a cleanorigin/feat-cmux-next. The crash ratchet and the package conventions lint pass.check-no-godfiles.shfails only on base'sPaneController. -
Localization: no user-facing strings change.
-
Unit tests: dropped on 2026-10-09 under the cmux-next no-unit-tests rule. The real verification is a capture of text over the brightest and darkest art on a tagged build, once hq-6d lands.
Changelog
Changed: Panes stay see-through over background art, and the window's tint keeps text readable at any opacity
Proof
- No gallery entry: nothing in a web page or its fixtures changes. Pages only stop painting their own background over art, and the art itself is drawn natively.
- A base vs head capture from a fleet dev build, at full and at low opacity over a light and a dark drawing, will be added after the Home Messages crash fix lands, since the capture picks art. Hold the merge until then.
🤖 Generated with Claude Code
[!NOTE]
Medium Risk
macOS window/pane painting and tint math affect all translucent windows with art; agent chat adds a fork path through native chat.fork but scope is limited to slash-command gating.
Overview
Over backdrop art, panes behave like stained glass: BackdropArtRange and ThemeTokens.legibleTintOpacity compute a minimum window tint so primary/secondary/tertiary text stay WCAG-readable over black–white art extremes. WindowBackdrop stores that floor and WindowMaterialView won’t thin the glass (or the tuner) below it. WindowBackdrop.current ties backdrop resolution to the active art selection; pane/browser/agent/web theme code switches to it so layers stay clear over art instead of painting opaque fills that hide it.
CI / webviews: The standalone agent-session-web-resources job and root agent-session-web:test script are removed; agent-session coverage stays in the main webviews test run. run-webviews-tests.sh can bootstrap from the repo root (bundles, pinned bun, webviews install) and fixes parallel workers to invoke itself reliably.
Agent chat UI: Adds a cmux /fork slash command (with gallery coverage), exposes import / fork / continue in the composer only when each action is allowed, and wires /fork to chat.fork via the native bridge.
Reviewed by Cursor Bugbot for commit cdfdc45ca37274bd218bb9531d96d8b9fc6353a7. Bugbot is set up for automated code reviews on this repo. Configure here.