Repository navigation
cmux NEXT theme: Grass and Hot Dog Stand cards stay translucent with AA text (ink takes the higher least contrast) - #23441
Conversation
…d its card text AA CardMaterial draws a card's fill on its glass at the least alpha below 1 that keeps primary and secondary text at 4.5:1 over black and white, and at exactly 1 when none does, which makes the glass solid. Check every bundled theme (Resources/ghostty/themes and Resources/cmux-themes) at the shipped lift and minimum opacity: the card stays below alpha 1, its primary and secondary text keep 4.5:1 on the card and on the pressed row (Grass exempted at its measured 4.41:1, where no single ink reads on both its background and its pressed rows), and only Grass and Hot Dog Stand derive other inks or card fills than the previous rule. Grass should take the light ink, Hot Dog Stand the dark ink with a white-lifted card. The fixture proves the checker reports an opaque card. Red on this commit: Grass and Hot Dog Stand fall back to an opaque card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc6-7623-8ee3-fa94b3900ccd&host=cosmic-gray
… ink lifts the card toward white ThemeTokens.derive walked an unreadable foreground toward white or black by a 0.18 luminance cutoff of the pressed row and checked it on that row only. On Grass (#13773D) that gave near-black text at 3.73:1 on the background, and on Hot Dog Stand (#EA3323) a dark grey that read on the lighter pressed row but not on the red, so both cards fell back to an opaque fill. Walk the foreground toward both poles until it reads on the pressed row and on the background, and keep the candidate whose primary and secondary keep the higher least contrast (capped at 4.5:1, so a reading ink toward the pole that reads better on the row stays first). Grass now takes white, Hot Dog Stand dark text. A dark theme's card fill lifted toward its text; with Hot Dog Stand's dark text that darkened the card under it. opaqueOverlayFill lifts toward white, as on a light theme, when the text is darker than the page. Only Grass and Hot Dog Stand change among the 622 bundled themes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15bf1-fdc6-7623-8ee3-fa94b3900ccd&host=cosmic-gray
|
Owned by palette-audit on cosmic-gray · session |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Tour of The path-selected recorder failed for core; see the run artifact and failed manifests. Path-selected interactions
Core UI (before): PASS — 19 ok
Screenshots (15)1. Launch
Screenshots (15)1. Launch Tours are data in |
|
Found 6 test failures on Blacksmith runners: Failures
|
|
Bead |
|
|
|
Shipped in:
|
… written by the spec tool (#25438) First half of #23517, rebased onto feat-cmux-next. schemas/theme/theme-ink-vectors.json holds what Swift derives for each of the 622 bundled themes (text inks and the popup surface at the shipped lift). derive_theme_tokens.py takes #23441's ink and popup rules and writes the file (--theme-ink-vectors) or checks it (--check-theme-ink-vectors); ThemeInkVectorsTests fails when the file is not Swift's output. The Rust and web ports follow in the second half. Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…pup rules, checked against the Swift vectors Second half of #23517. cmux-theme-tokens (inks, readable_over, opaque_overlay_fill), the web gallery tokens (inks, the see-through surfaces, opaqueOverlayFill) and the agent pane harness take the rules #23441 gave Swift, and each is checked against schemas/theme/theme-ink-vectors.json: Rust spec::tests::derive_matches_the_swift_ink_vectors, and webviews/test/theme-ink-vectors.test.ts for the gallery, the harness and derive_theme_tokens.py --check-theme-ink-vectors. The spec prose states the new rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495
…pup rules, checked against the Swift vectors (#25444) Second half of #23517. cmux-theme-tokens (inks, readable_over, opaque_overlay_fill), the web gallery tokens (inks, the see-through surfaces, opaqueOverlayFill) and the agent pane harness take the rules #23441 gave Swift, and each is checked against schemas/theme/theme-ink-vectors.json: Rust spec::tests::derive_matches_the_swift_ink_vectors, and webviews/test/theme-ink-vectors.test.ts for the gallery, the harness and derive_theme_tokens.py --check-theme-ink-vectors. The spec prose states the new rules. Agent-Session: https://cmux.com/deeplink/agent?id=aid-3891b16636fa80ffc495 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
































On the Grass and Hot Dog Stand themes, every floating glass card (hover cards, popovers, the palette, the update card) drew an opaque fill, and its text still missed 4.5:1.
CardMateriallays the card fill on the glass at the least alpha below 1 that keeps primary and secondary text at 4.5:1 over black and over white. When no alpha does, it falls back to exactly 1, and the glass turns solid. Glass is never opaque, and card text keeps WCAG AA (Lawrence, 2026-10-20). This follows #23366 (the no-opaque-glass guard) and covers every theme cmux ships.The cause was in
ThemeTokens.derive. When a foreground didn't read, the code walked it toward white or toward black, picking by a 0.18 luminance cutoff of the pressed row, and checked the result only on that row.Two fixes:
ThemeTokens.inks): a foreground that already reads keeps its color. Otherwise it is walked toward both white and black until it reads on the pressed row and on the background, and the candidate whose primary and secondary text keep the higher least contrast wins. The score is capped at 4.5:1, so when both candidates read, the one toward the pole that reads better on the pressed row stays first. Grass now takes white and Hot Dog Stand dark text.opaqueOverlayFill): a dark theme's card fill was lifted toward its text. With dark text that darkens the card, so when the text is darker than the page the fill now lifts toward white, as on a light theme.CardMaterial's opacity rule,ChromeTunables, theme files andChiefPetBubble.swiftare unchanged.What changes among the 622 bundled themes: only Grass (ink, and so its card fill, through the unchanged dark lift) and Hot Dog Stand (ink, and its card fill through the white lift).
onlyGrassAndHotDogStandChangere-derives every theme with the previous rule and asserts that this is the whole changed set.One exemption: Grass's pressed and selected rows keep 4.41:1. No single ink reads on both its background and its pressed rows: white gets 5.62:1 on the background and 4.41:1 on a pressed row, black 4.76:1 on a pressed row and 3.73:1 on the background. The test exempts Grass by name at that measured ratio.
Tests
CardNeverOpaqueTests(CmuxNextDesignTests) reads every theme file the app bundles (Resources/ghostty/themes,Resources/cmux-themes) and checks:TooltipSurface.worstContrast, asCardMaterialmeasures) and on the pressed row, with the one Grass exemption;Command (fleet):
Red at the test commit, green at head
86316da761b7(fleet step44b8003d6f549348e6f4e45c,--red, CardNeverOpaqueTests): 4 of 5 tests fail; the fixture test passes. Failure lines:opaque → ["Resources/ghostty/themes/Grass [dark] (fill #13773D, opacity 1.0)", "Resources/ghostty/themes/Hot Dog Stand [dark] (fill #EA3323, opacity 1.0)"]).isEmpty → falsecardInk → [Grass primary 3.53, Grass secondary 3.53, Hot Dog Stand primary 3.94, Hot Dog Stand secondary 3.89]changed → [:]: at this commit the test's copy of the previous rule matchesderiveexactly on all 622 themes, which is what the green changed-set check is measured against.grass.textPrimary.relativeLuminance → 0.0029 > 0.1367(Grass's text was near-black), andhotDog.opaqueOverlayFill → #EA3323where the white lift gives#ED5042.50ea1b1f6c6d(fleet step92ab4af6606130e29bc68d3d): all 20 suites passed, listed below.Observed / Not run
highlightTextandonAccent.Changelog
Captures
The tab hover-card gallery (
debug.hover_cardsgallerytabs) at head, withappearance.themeset to each theme. Both theme names are single themes, so the light and dark stills show the same theme. The sidebar gallery was refused by the privacy check, because one of its fixture cards names a real machine.Grass:
Capture
steps-8a83f81d4dat50ea1b1f6c6d(fleet build, capture mini, text checked for private data)Hot Dog Stand:
Capture
steps-007fc7d0baat50ea1b1f6c6d(fleet build, capture mini, text checked for private data)Agent session: cosmic-gray
🤖 Generated with Claude Code