Skip to content

feat(design): give the chrome a deliberate cool identity, and gate it on contrast - #33

Merged
DX23876 merged 1 commit into
mainfrom
redesign/h-chrome-tokens
Sep 17, 2026
Merged

DX23876 merged 1 commit into
mainfrom
redesign/h-chrome-tokens

Conversation

@DX23876

@DX23876 DX23876 commented Sep 17, 2026 •

Copy link
Copy Markdown
Owner

Warum die App blass wirkt — gemessen, nicht geschätzt

NoopVisualStyle war 1:1 die Apple-Systemgrau-Treppe (#000000 / #1C1C1E / #2C2C2E, Border #38383A). Die Zahlen dazu:

Paar alt Problem
border auf surface 1,45:1 Trenner und Kachelränder lösen sich in der Fläche auf
tertiaryText (dark) 2,50:1 Einheiten und Sektionslabels, unter der AA-Schwelle 4,5:1
tertiaryText (light) 1,74:1 praktisch unsichtbar
secondaryText (light) 3,44:1 normaler Fließtext, ebenfalls unter AA
surface-Sättigung 0,034 grau bis auf den Namen

Was dieser PR macht

Wertet den ganzen Satz auf eine kühle Slate-Hierarchie um — fast-schwarz in Dark, Papier in Light, beide mit echtem blau-kühlem Einschlag. Token-Namen bleiben unangetastet, kein Call-Site bewegt sich. Danach: Text ≥ 4,5:1 über Canvas, Surface und Inset in beiden Schemata; Primärtext ≥ 12:1; Border ≥ 1,8:1; die Stufen Surface/Canvas und Inset/Surface ≥ 1,18:1.

Zwei Dinge, die die alten Werte still kaputt gemacht hatten:

  • surfaceTop / surfaceBottom / surface hielten denselben Hex, weshalb der „quiet vertical gradient", den NoopPanelSurface im eigenen Doc-Kommentar verspricht, flach gerendert hat. Jetzt sind sie verschieden.
  • Der Rand wurde mit .opacity(0.72)/.52 gestrichen — der tatsächlich gemalte Kartenrand lag damit bei 1,34:1, obwohl das Token selbst sauber maß. Diese Deckungen sind jetzt benannte Konstanten (0,92 / 0,80), und das Gate prüft, was gemalt wird, nicht nur das Token dahinter.

Das Gate

ChromeContrastTests, 7 Tests. Die Farbmathematik ist lokal reimplementiert — genau wie in LaneColorTests und aus demselben Grund: ein Bug in den App-Helfern darf eine Token-Regression nicht vor dem Test verstecken, der sie fangen soll. Gelesen wird NoopVisualStyle.ChromeHex, dieselbe Tabelle, aus der die Tokens gebaut werden — der Test kann also nicht dadurch bestehen, dass er eine abgetippte Kopie seiner selbst prüft.

Eine Sättigungsuntergrenze ist mit drin, damit ein späteres „Aufräumen" die Flächen nicht zurück ins Neutralgrau schiebt, während jede Kontrast-Assertion weiter grün bleibt.

Die Chrome verzweigt weiterhin bewusst nicht auf ChartStyle. Ein kühler Einschlag ist genau das, was eine Chrome alle sieben Stile tragen lässt; ein grüner oder goldener würde mit Auroras Frost und Forests Erdtönen kollidieren.

Verifikation

  • swift test in StrandDesign: 164 Tests. Die 5 Fehler in PlaceholderTests.testRecoveryStateWords sind vorbestehend und locale-bedingt — auf sauberem Baum identisch.
  • xcodebuild … build für Strand (macOS) und NOOPiOS (iOS) — app-build.yml ist deaktiviert, es kompiliert also kein CI die App-Targets.
  • Im Simulator in Dark und Light angesehen.
  • Gegengeprüft, dass das Gate die alten Werte ablehnt (1,45:1 / 0,034 / 1,74:1 werden namentlich gemeldet) — ein Test, der nicht scheitern kann, ist wertlos.

Analysis migration required: nein — reine Darstellung.

… on contrast

NoopVisualStyle was the Apple system grey ramp verbatim (#000000 / #1C1C1E / #2C2C2E, border
#38383A). Measured, that is why the app read as washed out:

  border on surface        1.45:1   dividers and card rims dissolved into the fill
  tertiaryText  (dark)     2.50:1   units and section labels, under the 4.5:1 AA floor
  tertiaryText  (light)    1.74:1   effectively invisible
  secondaryText (light)    3.44:1   ordinary body copy, also under AA
  surface saturation       0.034    grey in all but name

Re-values the whole set to a cool slate hierarchy — near-black in Dark, paper in Light, both
carrying an actual blue-cool cast. Token NAMES are untouched, so no call site moves. Now:
text clears 4.5:1 over canvas, surface and inset in both schemes; primary copy clears 12:1;
borders clear 1.8:1; the surface/canvas and inset/surface steps clear 1.18:1.

Two things the old values quietly broke and this fixes:

- surfaceTop/surfaceBottom/surface all held the same hex, so NoopPanelSurface's "quiet vertical
  gradient" — promised in its own doc comment — rendered flat. They are distinct now.
- The rim was stroked at .opacity(0.72)/.52, which put the PAINTED card rim at 1.34:1 even where
  the token itself measured fine. Those opacities are now named constants (0.92/0.80) and the
  gate checks what is actually painted, not just the token behind it.

Adds ChromeContrastTests: 7 tests, reimplementing the sRGB/WCAG/HSL math locally the way
LaneColorTests does, and reading NoopVisualStyle.ChromeHex — the same table the tokens are built
from — so it cannot pass by checking a re-typed copy of itself. A saturation floor keeps a later
tidy-up from sliding the surfaces back to neutral with every contrast assertion still green.

Chrome deliberately still does not branch on ChartStyle. A cool cast is what lets one chrome
carry all seven styles; a green or gold one would fight Aurora's frost and Forest's earth.

Verified: swift test in StrandDesign (164 tests; the 5 failures in PlaceholderTests are
pre-existing and locale-bound, identical on a clean tree). xcodebuild build for Strand (macOS)
and NOOPiOS (iOS). Checked on the simulator in both dark and light. Confirmed the gate rejects
the old values rather than merely passing on the new ones.

Analysis migration required: no — presentation only.
Copilot AI balanced review requested due to automatic review settings September 17, 2026 18:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@DX23876
DX23876 merged commit 822fbec into main Sep 17, 2026
21 of 22 checks passed
@DX23876
DX23876 deleted the redesign/h-chrome-tokens branch September 17, 2026 22:13
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.

2 participants