@tenphi/glaze 0.18.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -30
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.mts +8 -4
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/docs/api.md +519 -400
- package/docs/methodology.md +125 -50
- package/docs/migration.md +79 -144
- package/docs/okhst.md +116 -254
- package/package.json +1 -1
package/docs/okhst.md
CHANGED
|
@@ -1,308 +1,170 @@
|
|
|
1
|
-
# OKHST
|
|
1
|
+
# OKHST in Glaze
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Glaze uses [OKHST](https://github.com/tenphi/okhst), an OKHSL-derived color
|
|
4
|
+
space with a tone axis for stable palette authoring. This page explains how
|
|
5
|
+
Glaze applies the model. The standalone repository is the canonical
|
|
6
|
+
specification for the transfer functions, derivation, and color-model
|
|
7
|
+
invariants.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
For practical palette design, continue to [methodology.md](methodology.md). For
|
|
10
|
+
every related option and utility, see [api.md](api.md).
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
axis.** It shares OKHSL's hue (`h`, 0–360) and saturation (`s`, 0–1) verbatim;
|
|
11
|
-
only the third coordinate changes:
|
|
12
|
+
## What tone means
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
| OKHSL | `h, s, l` | `l` — perceptual lightness (toe-adjusted OKLab L) |
|
|
16
|
-
| OKHST | `h, s, t` | `t` — tone: a normalized log of luminance |
|
|
14
|
+
OKHST keeps OKHSL hue and saturation and replaces authored lightness with
|
|
15
|
+
**tone**:
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
for free, and dark-mode inversion becomes a single subtraction (`100 - t`)
|
|
23
|
-
instead of a fitted curve.
|
|
17
|
+
| Space | Coordinates | Third coordinate |
|
|
18
|
+
| ----- | ----------- | -------------------- |
|
|
19
|
+
| OKHSL | `h, s, l` | Perceptual lightness |
|
|
20
|
+
| OKHST | `h, s, t` | Contrast-shaped tone |
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
and an `{ h, s, t }` object, but it is **never emitted** — there is no CSS
|
|
27
|
-
`okhst()` function, so output formats stay `okhsl | rgb | hsl | oklch`.
|
|
22
|
+
Tone uses a `0–100` authoring scale. Its primary invariant is:
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
> The same tone maps to the same OKHSL lightness for every hue and saturation.
|
|
30
25
|
|
|
31
|
-
For
|
|
32
|
-
|
|
26
|
+
For neutral colors, equal tone differences produce equal WCAG contrast ratios.
|
|
27
|
+
For chromatic colors, they remain a useful progression but are not exact:
|
|
28
|
+
hue, saturation, and gamut mapping can change the final sRGB luminance.
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
Y = toeInv(l) ** 3 // OKLab L = toeInv(l); luminance ≈ L³
|
|
36
|
-
l = toe(cbrt(Y)) // exact inverse
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
(`toe` / `toeInv` already exist in [okhsl-color-math.ts](../src/okhsl-color-math.ts).)
|
|
40
|
-
|
|
41
|
-
Tone is a normalized natural-log of `Y`, offset by a small `eps`:
|
|
30
|
+
This distinction informs two authoring rules:
|
|
42
31
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
fromTone(T, eps) = exp( (T / 100) * (ln(1 + eps) - ln(eps)) + ln(eps) ) - eps
|
|
46
|
-
```
|
|
32
|
+
- Use **tone deltas** for visual spacing within ramps and related UI colors.
|
|
33
|
+
- Use `contrast` when a rendered color must meet a measured WCAG or APCA floor.
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
to ~1e-15. `toTone(0) = 0` and `toTone(1) = 100` for any `eps`, so tone is always
|
|
50
|
-
a clean 0–100 scale.
|
|
35
|
+
## Tone vocabulary
|
|
51
36
|
|
|
52
|
-
###
|
|
37
|
+
### Absolute tone
|
|
53
38
|
|
|
54
|
-
|
|
55
|
-
tone transfer becomes a normalized `ln(Y + 0.05)`. Two colors that differ by a
|
|
56
|
-
fixed tone delta `ΔT` then differ by a fixed _ratio_ of `(Y + 0.05)` — i.e. a
|
|
57
|
-
fixed WCAG contrast ratio — regardless of where on the scale they sit:
|
|
39
|
+
A numeric `tone` places a color independently on the `0–100` authoring scale:
|
|
58
40
|
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
|
|
41
|
+
```ts
|
|
42
|
+
surface: {
|
|
43
|
+
tone: 97;
|
|
44
|
+
}
|
|
62
45
|
```
|
|
63
46
|
|
|
64
|
-
|
|
65
|
-
a near-constant factor:
|
|
47
|
+
`'max'` and `'min'` select the corresponding end of the active scheme.
|
|
66
48
|
|
|
67
|
-
|
|
68
|
-
|---|---|
|
|
69
|
-
| 10 | 1.36 |
|
|
70
|
-
| 30 | 2.49 |
|
|
71
|
-
| 50 | 4.58 |
|
|
72
|
-
| 70 | 8.43 |
|
|
73
|
-
| 90 | 15.49 |
|
|
74
|
-
| 100 | 21.00 |
|
|
49
|
+
### Tone delta
|
|
75
50
|
|
|
76
|
-
|
|
77
|
-
|
|
51
|
+
A **tone delta** is the signed difference between a dependent color and its
|
|
52
|
+
base. It is authored as a string:
|
|
78
53
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`l = fromTone(t)`. `fromTone` is a pure function of `(t, eps)`; OKHSL's
|
|
83
|
-
`l → OKLab L = toeInv(l)` map has no hue/saturation term — `h`/`s` enter only
|
|
84
|
-
the chroma/cusp math. Therefore:
|
|
85
|
-
|
|
86
|
-
> **A given tone yields the same OKHSL lightness for every hue and saturation.**
|
|
87
|
-
|
|
88
|
-
OKHST inherits OKHSL's gamut and reversibility exactly: every `(h, s, t)` is
|
|
89
|
-
realizable and round-trips.
|
|
90
|
-
|
|
91
|
-
**This uniformity is in lightness, not luminance.** Equal tone gives equal
|
|
92
|
-
OKHSL `L` for all `h`/`s`, but equal _WCAG/APCA contrast_ only for grays.
|
|
93
|
-
A saturated yellow and a saturated blue at the same tone share a lightness yet
|
|
94
|
-
differ in real luminance `Y`. This chromatic drift is the one honest
|
|
95
|
-
approximation in the design — see [§10 Verification](#verification-apca--wcag-drift).
|
|
96
|
-
The single deliberate exception to the invariant is the optional `contrast`
|
|
97
|
-
solver, which shifts a stop's tone per `h`/`s` to meet a luminance-based floor.
|
|
54
|
+
```ts
|
|
55
|
+
border: { base: 'surface', tone: '-8' }
|
|
56
|
+
```
|
|
98
57
|
|
|
99
|
-
|
|
58
|
+
Here, `-8` is the tone delta. The base is resolved separately for every scheme,
|
|
59
|
+
then the delta is applied to that resolved base. This keeps related colors
|
|
60
|
+
visually ordered across light, dark, and high-contrast variants.
|
|
100
61
|
|
|
101
|
-
|
|
62
|
+
### Tone window
|
|
102
63
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`ResolvedColorVariant.t`, relative `tone` offsets, and the contrast solver all
|
|
106
|
-
use the reference eps. This is what makes OKHST stable and scheme-independent.
|
|
107
|
-
- **Per-mode eps (`lightTone.eps`, `darkTone.eps`).** A _rendering_ curvature
|
|
108
|
-
knob per scheme. It only affects how authored tone is mapped through a scheme
|
|
109
|
-
window before the result is stored. Defaults to the reference value, so by
|
|
110
|
-
default the two coincide and there is nothing to reconcile.
|
|
64
|
+
A **tone window** is the scheme-specific render range configured by
|
|
65
|
+
`lightTone` or `darkTone`:
|
|
111
66
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
67
|
+
```ts
|
|
68
|
+
glaze.configure({
|
|
69
|
+
lightTone: [10, 100],
|
|
70
|
+
darkTone: [15, 95],
|
|
71
|
+
});
|
|
72
|
+
```
|
|
115
73
|
|
|
116
|
-
|
|
74
|
+
In Glaze, `lo` and `hi` are OKHSL-lightness boundaries. Authored tone is
|
|
75
|
+
positioned within the corresponding tone interval, then converted back to
|
|
76
|
+
OKHSL lightness for rendering. The object form adds an advanced render
|
|
77
|
+
curvature:
|
|
117
78
|
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
→ mode branch:
|
|
121
|
-
auto + dark : invert T' = 100 - T
|
|
122
|
-
fixed / light: keep T' = T
|
|
123
|
-
static : identity, skip window
|
|
124
|
-
→ window remap: T' into the scheme window [lo, hi] (tone units)
|
|
125
|
-
→ render curvature (mode eps) → OKHSL l
|
|
126
|
-
→ store canonical tone t = toTone(l, REF_EPS) // variant {h, s, t, alpha}
|
|
127
|
-
→ (edge only) fromTone(t, REF_EPS) → l → sRGB / luminance
|
|
128
|
-
optional: contrast floor (wcag/apca) searches in tone, overriding t
|
|
79
|
+
```ts
|
|
80
|
+
lightTone: { lo: 10, hi: 100, eps: 0.05 }
|
|
129
81
|
```
|
|
130
82
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
`darkCurve` and no separate HC curve.
|
|
83
|
+
Pass `false` to use the full range. High-contrast variants always bypass the
|
|
84
|
+
ordinary boundaries and use the full range.
|
|
134
85
|
|
|
135
|
-
|
|
136
|
-
recognizable). `static` skips the window entirely (identity) so the same tone
|
|
137
|
-
renders in every scheme.
|
|
86
|
+
## Scheme adaptation
|
|
138
87
|
|
|
139
|
-
|
|
88
|
+
Each regular color has an adaptation `mode`:
|
|
140
89
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
tone axis stays WCAG-uniform.
|
|
90
|
+
| Mode | Light scheme | Dark scheme |
|
|
91
|
+
| ---------- | ------------------------------ | -------------------------------------------------------------------- |
|
|
92
|
+
| `'auto'` | Map into the light tone window | Apply dark tone inversion (`100 - t`), then map into the dark window |
|
|
93
|
+
| `'fixed'` | Map into the light tone window | Map into the dark window without inversion |
|
|
94
|
+
| `'static'` | Keep the authored tone | Keep the authored tone |
|
|
147
95
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
| `darkTone` | 15 | 95 | 0.05 |
|
|
96
|
+
Use `auto` for surfaces and foregrounds that should exchange light/dark
|
|
97
|
+
positions. Use `fixed` for brand fills and inverse surfaces that should stay on
|
|
98
|
+
the same side of the scale. Reserve `static` for colors that must not adapt.
|
|
152
99
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
100
|
+
**Dark tone inversion** is different from `autoFlip`. Inversion is normal
|
|
101
|
+
scheme adaptation controlled by `mode`. `autoFlip` handles a different local
|
|
102
|
+
problem: it may reverse an overshooting tone delta or let the contrast solver
|
|
103
|
+
try the opposite side of a base.
|
|
157
104
|
|
|
158
|
-
|
|
159
|
-
`autoFlip = true`.
|
|
105
|
+
The regular pipeline is:
|
|
160
106
|
|
|
161
|
-
|
|
107
|
+
```text
|
|
108
|
+
authored tone
|
|
109
|
+
-> choose the color's adaptation mode
|
|
110
|
+
-> invert for dark + auto
|
|
111
|
+
-> map through the active tone window
|
|
112
|
+
-> store canonical tone
|
|
113
|
+
-> convert to OKHSL at the rendering edge
|
|
114
|
+
```
|
|
162
115
|
|
|
163
|
-
|
|
116
|
+
Dark schemes also apply `darkDesaturation` unless the color is `static`.
|
|
164
117
|
|
|
165
|
-
|
|
118
|
+
## Reference and render epsilon
|
|
166
119
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
| number // bare WCAG ratio
|
|
170
|
-
| ContrastPreset // 'AA' | 'AAA' | 'AA-large' | 'AAA-large' (WCAG)
|
|
171
|
-
| { wcag: HCPair<number | ContrastPreset> }
|
|
172
|
-
| { apca: HCPair<number | ApcaPreset> };
|
|
120
|
+
`REF_EPS = 0.05` defines Glaze's canonical tone scale. It is used for OKHST
|
|
121
|
+
input, stored resolved tone, tone deltas, and contrast search.
|
|
173
122
|
|
|
174
|
-
|
|
175
|
-
|
|
123
|
+
An object tone window may supply another `eps` as a scheme-specific rendering
|
|
124
|
+
control. Glaze still converts the result back to the reference scale so tone
|
|
125
|
+
deltas and contrast calculations remain comparable between schemes. Most
|
|
126
|
+
palettes should use the default.
|
|
176
127
|
|
|
177
|
-
|
|
178
|
-
the outer level (`[4.5, 7]`, `[{ wcag: 4.5 }, { wcag: 7 }]`) **or** inside the
|
|
179
|
-
metric (`{ wcag: [4.5, 7] }`, `{ apca: [45, 60] }`, `{ apca: ['content', 'body'] }`). `resolveContrastForMode`
|
|
180
|
-
peels the outer pair by mode, then the inner metric pair by the same mode, then
|
|
181
|
-
resolves presets, returning `{ metric, target }`.
|
|
182
|
-
|
|
183
|
-
The solver searches in **tone** (contrast-uniform → fast convergence and a
|
|
184
|
-
closed-form WCAG seed). For WCAG, the seed is the tone whose gray luminance hits
|
|
185
|
-
`Y = R·(Y_base + 0.05) − 0.05`; chromatic drift is then refined by binary search.
|
|
186
|
-
For APCA, it binary-searches tone against the APCA Lc target.
|
|
187
|
-
|
|
188
|
-
### APCA
|
|
189
|
-
|
|
190
|
-
`apcaContrast(yText, yBg)` implements SAPC/APCA Lc (soft-clamp of low luminances
|
|
191
|
-
plus the polarity exponents for normal vs reverse contrast), returning a signed
|
|
192
|
-
Lc whose magnitude the solver compares against the target. Its inputs are APCA
|
|
193
|
-
*screen* luminances `Ys = 0.2126·R^2.4 + 0.7152·G^2.4 + 0.0722·B^2.4` over the
|
|
194
|
-
gamma-encoded channels (`apcaLuminanceFromLinearRgb`), **not** WCAG relative
|
|
195
|
-
luminance — the soft-clamp constants are calibrated against `Ys`, so the solver
|
|
196
|
-
feeds it the matching basis. This is a faithful-but-simplified APCA (it omits
|
|
197
|
-
the spatial/font-size lookup that maps Lc to a usable text size).
|
|
198
|
-
|
|
199
|
-
#### Polarity (roles)
|
|
200
|
-
|
|
201
|
-
APCA is **asymmetric**: `|apcaContrast(a, b)| ≠ |apcaContrast(b, a)|`, because
|
|
202
|
-
the normal-polarity exponents (dark text on light bg) differ from the
|
|
203
|
-
reverse-polarity exponents (light text on dark bg). Glaze picks the argument
|
|
204
|
-
order from each color's semantic **role** against its base:
|
|
205
|
-
|
|
206
|
-
| Role | Polarity | Argument order | Aliases (name inference) |
|
|
207
|
-
| --------- | -------- | ------------------------------ | ------------------------------------------- |
|
|
208
|
-
| `text` | `fg` | `apcaContrast(candidate, base)`| `text`, `fg`, `foreground`, `content`, `ink`, `label`, `stroke` |
|
|
209
|
-
| `border` | `fg` | `apcaContrast(candidate, base)`| `border`, `divider`, `outline`, `separator`, `hairline`, `rule` |
|
|
210
|
-
| `surface` | `bg` | `apcaContrast(base, candidate)`| `surface`, `bg`, `background`, `fill`, `canvas`, `paper`, `layer` |
|
|
211
|
-
|
|
212
|
-
A color's role is resolved per the chain: explicit `role` → inferred from the
|
|
213
|
-
color name (last recognized token wins, so `button-text` → `text`,
|
|
214
|
-
`input-bg` → `surface`) → the opposite of the base's role → `'text'` (foreground)
|
|
215
|
-
default. Name inference is on by default (`config.inferRole: true`) and can be
|
|
216
|
-
disabled. WCAG is symmetric, so role never changes WCAG results — it only fixes
|
|
217
|
-
APCA argument order.
|
|
218
|
-
|
|
219
|
-
#### APCA presets
|
|
220
|
-
|
|
221
|
-
APCA targets may be a raw Lc number or a named preset (APCA Bronze Simple Mode
|
|
222
|
-
conformance levels), independent of role:
|
|
128
|
+
## Contrast verification
|
|
223
129
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
130
|
+
Tone provides an efficient starting point for contrast solving, but Glaze does
|
|
131
|
+
not assume a chromatic tone has the neutral color's luminance. For a color with
|
|
132
|
+
`base` and `contrast`, Glaze:
|
|
227
133
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
| `'large'` | 45 | Large/bold headlines; fine icons/outlines (~3:1) |
|
|
234
|
-
| `'non-text'` | 30 | Solid icons/controls; placeholder/disabled text |
|
|
235
|
-
| `'min'` | 15 | Dividers/decorative; APCA "point of invisibility" |
|
|
134
|
+
1. resolves both colors for the active scheme;
|
|
135
|
+
2. measures the requested WCAG ratio or APCA Lc;
|
|
136
|
+
3. searches tone when the requested position misses the floor; and
|
|
137
|
+
4. warns when the target is physically unreachable or rendered chroma drifts
|
|
138
|
+
below the expected result.
|
|
236
139
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
contrast
|
|
240
|
-
```
|
|
140
|
+
`contrast` is therefore a floor, not a replacement for tone relationships.
|
|
141
|
+
Detailed presets, HC promotion, polarity, and role inference are documented
|
|
142
|
+
under [`contrast`](api.md#contrast-floor) and [roles](api.md#roles).
|
|
241
143
|
|
|
242
|
-
|
|
144
|
+
## Input and output
|
|
243
145
|
|
|
244
|
-
|
|
245
|
-
either the outer `contrast` level or the inner `apca` level), Glaze
|
|
246
|
-
automatically applies the APCA-W3 "Enhanced Level" delta — **+15 Lc** — in
|
|
247
|
-
high-contrast mode, analogous to WCAG's AAA-over-AA step. This is on by
|
|
248
|
-
default; provide an explicit HC value via either pair to override it.
|
|
146
|
+
Glaze accepts OKHST through:
|
|
249
147
|
|
|
250
148
|
```ts
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
contrast: [{ apca: 60 }, { apca: 90 }] // outer pair: explicit HC, no boost
|
|
255
|
-
contrast: { apca: 'preferred' } // Lc 90 normal, Lc 105 high-contrast (auto)
|
|
256
|
-
contrast: { apca: 100 } // Lc 100 normal, Lc 106 high-contrast (clamped)
|
|
149
|
+
glaze.color('okhst(152 95% 70%)');
|
|
150
|
+
glaze.color({ h: 152, s: 0.95, t: 0.7 });
|
|
151
|
+
glaze.color({ hue: 152, saturation: 95, tone: 70 });
|
|
257
152
|
```
|
|
258
153
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
> very large/bold text (>36px bold) and large areas of color, to prevent
|
|
263
|
-
> excessive glare. The +15 HC boost can therefore push a high baseline (e.g.
|
|
264
|
-
> `preferred` Lc 90 → 105) past that glare ceiling. This is intentional for
|
|
265
|
-
> small/standard text in HC (low-vision readability trumps glare, and small
|
|
266
|
-
> fonts have no APCA maximum), but if your HC tokens serve large/bold text,
|
|
267
|
-
> pass an explicit HC pair (`{ apca: [90, 90] }`) to hold the glare ceiling.
|
|
268
|
-
> Glaze does not model font size, so it can't enforce the large-text cap
|
|
269
|
-
> automatically.
|
|
270
|
-
|
|
271
|
-
#### WCAG HC auto-promotion
|
|
272
|
-
|
|
273
|
-
A bare WCAG preset (no `[normal, hc]` pair at either the outer `contrast` or
|
|
274
|
-
inner `wcag` level) is automatically promoted to its spec-defined "Enhanced"
|
|
275
|
-
successor in high-contrast mode — WCAG SC 1.4.3 (Minimum) → SC 1.4.6
|
|
276
|
-
(Enhanced), the direct analog of APCA's Enhanced Level:
|
|
154
|
+
There is no native CSS `okhst()` function. Native exports use `oklch`, `rgb`,
|
|
155
|
+
or `hsl`. [Tasty](https://tasty.style) integrations may request `format: 'okhst'` because it can
|
|
156
|
+
consume Glaze's custom serialization:
|
|
277
157
|
|
|
278
158
|
```ts
|
|
279
|
-
|
|
280
|
-
contrast: 'AA-large' // 3 normal, 4.5 high-contrast (auto -> AAA-large)
|
|
281
|
-
contrast: 'AAA' // 7 both modes (top tier, unchanged)
|
|
282
|
-
contrast: 'AAA-large' // 4.5 both modes (top tier, unchanged)
|
|
283
|
-
contrast: 5.5 // 5.5 both modes (bare number, no successor tier)
|
|
284
|
-
contrast: { wcag: ['AA', 'AA'] } // 4.5 both modes (explicit HC, no promotion)
|
|
159
|
+
theme.tasty({ format: 'okhst' });
|
|
285
160
|
```
|
|
286
161
|
|
|
287
|
-
|
|
288
|
-
numeric targets have no defined successor tier and are also left unchanged. An
|
|
289
|
-
explicit HC value via either pair overrides and skips the promotion.
|
|
290
|
-
|
|
291
|
-
## Verification (APCA / WCAG drift)
|
|
292
|
-
|
|
293
|
-
Because chromatic swatches inherit gray's tone-derived lightness but drift in
|
|
294
|
-
real luminance, a color resolved with a `base` + `contrast` may land slightly
|
|
295
|
-
under the contrast its tone implies. After resolving such a color, Glaze
|
|
296
|
-
computes the actual WCAG ratio and APCA Lc of the chromatic result against its
|
|
297
|
-
base and emits a deduped `console.warn` when it drifts below the gray-tone
|
|
298
|
-
expectation. This is advisory: it surfaces the one approximation rather than
|
|
299
|
-
hiding it. The dedupe cache is the existing 256-entry cache in
|
|
300
|
-
[warnings.ts](../src/warnings.ts).
|
|
162
|
+
## Bringing existing colors into Glaze
|
|
301
163
|
|
|
302
|
-
|
|
164
|
+
When moving raw CSS colors or design tokens into Glaze, use `fromHex()`,
|
|
165
|
+
`fromRgb()`, or `glaze.color()` to preserve the source color while you establish
|
|
166
|
+
theme seeds and semantic relationships. Then replace one-off values with roots,
|
|
167
|
+
tone deltas, and contrast floors as appropriate.
|
|
303
168
|
|
|
304
|
-
|
|
305
|
-
the
|
|
306
|
-
old absolute `lightness: L` to the equivalent `tone`, use
|
|
307
|
-
`toTone(L/100, 0.05)`. See [migration.md](migration.md) for the full guide and
|
|
308
|
-
a conversion table.
|
|
169
|
+
See [migration.md](migration.md#migrating-from-an-existing-color-system) for
|
|
170
|
+
the implementation workflow.
|
package/package.json
CHANGED