You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(palette): render the brand through Glaze's from
Replaces the derive-then-re-seed workaround with the primitive built for it.
`accentColor` is handed to Glaze as a literal, which supplies the hue, the tone
and an absolute saturation that does not answer to the theme seed.
Three things fall out of that.
The palette-level `saturation` is no longer raised to reach a saturated brand,
because the accent family carries its own chroma. That was the source of the
worst side effect in the previous approach: honoring one brand color
re-chromatized the neutral chrome and all four status themes. `#danger-accent-
surface` is now identical whatever the brand is, and the test asserts it against
the untouched baseline rather than against a saturation-matched reference.
The brand text and icon are now exact too, not just the fill. `from` bypasses
the light tone window per color, so `#2F5BFF` renders `#2f5bff` as the link and
the icon where it used to land on `#3764ff`.
`mode: 'static'` is gone. Exactness is scoped to the light, normal-contrast
variant — which is what `from` guarantees — so the chain goes back to
`mode: 'fixed'` and dark maps through its window like any other fixed color.
Dark and high contrast are where readability outranks fidelity.
Status themes still restore the white-anchored chain, and now must: `extend()`
copies defs, so an inherited `from` would make a danger button the brand color
outright rather than merely a washed-out version of itself.
Pins @tenphi/glaze to the PR snapshot (tenphi/glaze#89) — to be swapped for a
released version before merge.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two are deliberately asymmetric. `accentColor` contributes hue, saturation and **tone**, and the tone is the point: the brand fill was previously authored as a fixed tone step off white, so every accent hue landed at roughly the same lightness and a yellow brand came out olive. `baseColor` contributes **hue only** — its tone and saturation are discarded, because the chrome's lightness ladder and its 0.10–0.20 saturation factors are the design.
12
12
13
-
The requested color is rendered exactly wherever a 3:1 floor against the page allows, and moved only as far as that floor requires. The floor is solved per scheme, so a light brand renders byte-exact on a dark page and darkens on a light one. High contrast keeps its AAA floor regardless — that tier is selected by `prefers-contrast: more` or `data-contrast="high"`, so anyone reading it has asked for separation over brand. Status themes deliberately do **not** inherit the tone: a light brand would otherwise turn `#danger-accent-surface` into a pale pink. `special` does follow it, since it is the brand-on-dark CTA.
13
+
The color is handed to Glaze's `from`, so the **light, normal-contrast** variant reproduces it exactly — the fill, the link and the icon all render the value you passed. Dark and high contrast adapt as every other color does. A 3:1 floor against the page applies everywhere and is a floor rather than a target: `#7A4DBF` measures 5.8:1 and is emitted untouched, while `#FFD400` cannot clear 3:1 on white and darkens to `#b09200` and no further. High contrast tightens back to AAA regardless, since that tier is selected by `prefers-contrast: more` or `data-contrast="high"` and anyone reading it has asked for separation over brand.
14
+
15
+
Because the accent family now carries its own chroma, a brand color no longer raises the palette-level `saturation` to reach it — so it cannot leak into the neutral chrome or the status themes. `#danger-accent-surface` is now identical whatever the brand is. Status themes also do not inherit the literal itself (`extend()` copies defs, so an inherited `from` would make a danger button the brand color outright); `special` does follow it, being the brand-on-dark CTA.
14
16
15
17
`ResolvedPaletteConfig` gains `accentTone`, and `colorSeed()` is exported for reading hue / saturation / tone off a color directly. The shipped palette is unchanged — a config with no color seed resolves bit for bit as before.
0 commit comments