feat(design): give the chrome a deliberate cool identity, and gate it on contrast - #33
Merged
Merged
Conversation
… 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Warum die App blass wirkt — gemessen, nicht geschätzt
NoopVisualStylewar 1:1 die Apple-Systemgrau-Treppe (#000000/#1C1C1E/#2C2C2E, Border#38383A). Die Zahlen dazu:borderaufsurfacetertiaryText(dark)tertiaryText(light)secondaryText(light)surface-SättigungWas 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/surfacehielten denselben Hex, weshalb der „quiet vertical gradient", denNoopPanelSurfaceim eigenen Doc-Kommentar verspricht, flach gerendert hat. Jetzt sind sie verschieden..opacity(0.72)/.52gestrichen — 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 inLaneColorTestsund aus demselben Grund: ein Bug in den App-Helfern darf eine Token-Regression nicht vor dem Test verstecken, der sie fangen soll. Gelesen wirdNoopVisualStyle.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 testinStrandDesign: 164 Tests. Die 5 Fehler inPlaceholderTests.testRecoveryStateWordssind vorbestehend und locale-bedingt — auf sauberem Baum identisch.xcodebuild … buildfür Strand (macOS) und NOOPiOS (iOS) —app-build.ymlist deaktiviert, es kompiliert also kein CI die App-Targets.Analysis migration required: nein — reine Darstellung.