@tenphi/cookbook 0.32.0 → 0.33.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/docs/customization-rules.md +7 -5
- package/docs/migration.md +52 -26
- package/docs/theme-and-components.md +32 -15
- package/docs/upstream/glaze/README.md +46 -26
- package/docs/upstream/glaze/docs/contrast.mdx +751 -0
- package/docs/upstream/glaze/docs/exporting.mdx +634 -0
- package/docs/upstream/glaze/docs/getting-started.mdx +489 -0
- package/docs/upstream/glaze/docs/hdr.mdx +523 -0
- package/docs/upstream/glaze/docs/methodology.mdx +922 -0
- package/docs/upstream/glaze/docs/migration.md +477 -286
- package/docs/upstream/glaze/docs/mixes.mdx +348 -0
- package/docs/upstream/glaze/docs/okhst.mdx +679 -0
- package/docs/upstream/glaze/docs/reference/color-definitions.md +552 -0
- package/docs/upstream/glaze/docs/reference/color-tokens.md +420 -0
- package/docs/upstream/glaze/docs/reference/configuration.md +527 -0
- package/docs/upstream/glaze/docs/reference/contrast.md +277 -0
- package/docs/upstream/glaze/docs/reference/index.md +225 -0
- package/docs/upstream/glaze/docs/reference/output.md +713 -0
- package/docs/upstream/glaze/docs/reference/palette.md +434 -0
- package/docs/upstream/glaze/docs/reference/theme.md +331 -0
- package/docs/upstream/glaze/docs/reference/utilities.md +646 -0
- package/docs/upstream/glaze/docs/schemes.mdx +635 -0
- package/docs/upstream/glaze/docs/shadows-and-glows.mdx +519 -0
- package/docs/upstream/manifest.json +2 -2
- package/package.json +3 -3
- package/docs/upstream/glaze/docs/api.md +0 -2021
- package/docs/upstream/glaze/docs/methodology.md +0 -686
- package/docs/upstream/glaze/docs/okhst.md +0 -207
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting started
|
|
3
|
+
description: Install Glaze, build a first theme step by step, and export it.
|
|
4
|
+
---
|
|
5
|
+
import { Callout, Card, CardGrid, CodeGroup } from '@tenphi/cookbook/components';
|
|
6
|
+
import Example from '../docs-site/components/Example.astro';
|
|
7
|
+
import Swatches from '../docs-site/components/Swatches.tsx';
|
|
8
|
+
import UiPreview from '../docs-site/components/UiPreview.tsx';
|
|
9
|
+
import ContrastSamples from '../docs-site/components/home/ContrastSamples.tsx';
|
|
10
|
+
|
|
11
|
+
This guide builds a small, complete theme — a surface, text, an accent, a
|
|
12
|
+
border, and a card shadow — and exports it as CSS. Every example renders live in
|
|
13
|
+
the scheme you're viewing, so switch the site's appearance to dark or high
|
|
14
|
+
contrast as you go.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
<CodeGroup
|
|
19
|
+
label="Install Glaze"
|
|
20
|
+
items={[
|
|
21
|
+
{ label: 'pnpm', language: 'shell', code: 'pnpm add @tenphi/glaze' },
|
|
22
|
+
{ label: 'npm', language: 'shell', code: 'npm install @tenphi/glaze' },
|
|
23
|
+
{ label: 'yarn', language: 'shell', code: 'yarn add @tenphi/glaze' },
|
|
24
|
+
]}
|
|
25
|
+
/>
|
|
26
|
+
|
|
27
|
+
Glaze has no runtime dependencies. It ships ESM and CommonJS builds with type
|
|
28
|
+
definitions and runs in Node.js 20+, browsers, and edge runtimes.
|
|
29
|
+
|
|
30
|
+
## Build a theme
|
|
31
|
+
|
|
32
|
+
### 1. Seed and surface
|
|
33
|
+
|
|
34
|
+
A theme starts from a seed: a hue (0–360) and a saturation (0–100). Colors are
|
|
35
|
+
then defined on the **tone** scale, where 0 is black and 100 is white and equal
|
|
36
|
+
steps give equal contrast for neutrals (see [Tone and OKHST](./okhst.mdx)). The
|
|
37
|
+
page surface is a **root** color: it places itself with an absolute tone.
|
|
38
|
+
|
|
39
|
+
<Example hue={280} saturation={80} colors={{ surface: { tone: 97, saturation: 0.15 } }} />
|
|
40
|
+
|
|
41
|
+
A color's `saturation` is a factor of the seed: `0.15` is 15% of 80. It
|
|
42
|
+
defaults to `1`, the full seed saturation.
|
|
43
|
+
|
|
44
|
+
Each swatch prints the tone the current scheme renders. Ordinary light and dark
|
|
45
|
+
schemes fit tones into a window, so tone 97 renders as 97.1 in light; dark mode
|
|
46
|
+
inverts the scale, so the surface turns dark. High-contrast schemes use the
|
|
47
|
+
full range. [Light, dark, and high contrast](./schemes.mdx) covers the details.
|
|
48
|
+
|
|
49
|
+
### 2. Text with a contrast floor
|
|
50
|
+
|
|
51
|
+
Text is a **dependent** color: it names a `base` and a signed **tone delta**
|
|
52
|
+
from it. `'-1'` means one tone darker than the surface — unreadable on its own.
|
|
53
|
+
The `contrast` floor fixes that: Glaze moves the color away from its base until
|
|
54
|
+
the WCAG ratio passes (`'AA'` is 4.5:1, `'AAA'` is 7:1), and stops at the floor
|
|
55
|
+
or just past it.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
theme.colors({
|
|
59
|
+
'surface-text': {
|
|
60
|
+
base: 'surface',
|
|
61
|
+
tone: '-1',
|
|
62
|
+
saturation: 0.4,
|
|
63
|
+
contrast: 'AAA',
|
|
64
|
+
},
|
|
65
|
+
'surface-text-soft': {
|
|
66
|
+
base: 'surface',
|
|
67
|
+
tone: '-1',
|
|
68
|
+
saturation: 0.3,
|
|
69
|
+
contrast: 'AA',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
<ContrastSamples
|
|
75
|
+
hue={280}
|
|
76
|
+
saturation={80}
|
|
77
|
+
colors={{
|
|
78
|
+
surface: { tone: 97, saturation: 0.15 },
|
|
79
|
+
'surface-text': {
|
|
80
|
+
base: 'surface',
|
|
81
|
+
tone: '-1',
|
|
82
|
+
saturation: 0.4,
|
|
83
|
+
contrast: 'AAA',
|
|
84
|
+
},
|
|
85
|
+
'surface-text-soft': {
|
|
86
|
+
base: 'surface',
|
|
87
|
+
tone: '-1',
|
|
88
|
+
saturation: 0.3,
|
|
89
|
+
contrast: 'AA',
|
|
90
|
+
},
|
|
91
|
+
}}
|
|
92
|
+
samples={[
|
|
93
|
+
{ fg: 'surface-text', bg: 'surface', note: "contrast: 'AAA'" },
|
|
94
|
+
{ fg: 'surface-text-soft', bg: 'surface', note: "contrast: 'AA'" },
|
|
95
|
+
]}
|
|
96
|
+
caption="Each tile measures the resolved text against the surface in the scheme you're viewing."
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
`theme.colors()` merges: it adds new colors and replaces existing ones by name,
|
|
100
|
+
so a theme can grow over several calls.
|
|
101
|
+
|
|
102
|
+
The delta follows its base into every scheme. In dark mode the scale inverts, so
|
|
103
|
+
one tone darker becomes about 0.87 tones lighter (the dark window is a little
|
|
104
|
+
narrower than the full scale) and the text turns light. In high contrast,
|
|
105
|
+
`'AA'` rises to `'AAA'`, so both colors meet 7:1. For APCA instead of WCAG,
|
|
106
|
+
write the floor as `{ apca: 'body' }` — see
|
|
107
|
+
[Contrast solving](./contrast.mdx).
|
|
108
|
+
|
|
109
|
+
### 3. An accent that keeps its contrast
|
|
110
|
+
|
|
111
|
+
A primary button needs a fill and a label that read well together in every
|
|
112
|
+
scheme. Pin the label, then solve the fill against it:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
theme.colors({
|
|
116
|
+
'accent-surface-text': { tone: 100, mode: 'fixed' },
|
|
117
|
+
'accent-surface': {
|
|
118
|
+
base: 'accent-surface-text',
|
|
119
|
+
tone: '-1',
|
|
120
|
+
contrast: 'AA',
|
|
121
|
+
mode: 'fixed',
|
|
122
|
+
},
|
|
123
|
+
'accent-text': { base: 'surface', tone: '-1', contrast: 'AA' },
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
<ContrastSamples
|
|
128
|
+
hue={280}
|
|
129
|
+
saturation={80}
|
|
130
|
+
colors={{
|
|
131
|
+
surface: { tone: 97, saturation: 0.15 },
|
|
132
|
+
'accent-surface-text': { tone: 100, mode: 'fixed' },
|
|
133
|
+
'accent-surface': {
|
|
134
|
+
base: 'accent-surface-text',
|
|
135
|
+
tone: '-1',
|
|
136
|
+
contrast: 'AA',
|
|
137
|
+
mode: 'fixed',
|
|
138
|
+
},
|
|
139
|
+
'accent-text': { base: 'surface', tone: '-1', contrast: 'AA' },
|
|
140
|
+
}}
|
|
141
|
+
samples={[
|
|
142
|
+
{ fg: 'accent-surface-text', bg: 'accent-surface', note: 'button label on fill' },
|
|
143
|
+
{ fg: 'accent-text', bg: 'surface', note: 'link on the surface' },
|
|
144
|
+
]}
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
* The label sits at tone 100: white in light and high contrast, and near-white
|
|
148
|
+
(tone 95.9) in dark, where the dark tone window caps it. The fill starts one
|
|
149
|
+
tone below the label and moves down until the pair clears 4.5:1, landing
|
|
150
|
+
just past the floor at about 4.55:1 (the solver keeps a 1% margin). Because
|
|
151
|
+
the fill depends on the label, the pair passes in every scheme — in high
|
|
152
|
+
contrast the fill darkens further, until the pair clears 7:1.
|
|
153
|
+
* `mode: 'fixed'` keeps both colors on their authored side of the tone scale in
|
|
154
|
+
dark mode, so the button stays a saturated fill with a light label. The
|
|
155
|
+
default, `mode: 'auto'`, inverts.
|
|
156
|
+
* `accent-text` is a link color for the page. It uses the full seed saturation
|
|
157
|
+
and the same `'AA'` floor as the soft text.
|
|
158
|
+
|
|
159
|
+
### 4. A border with a high-contrast pair
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
theme.colors({
|
|
163
|
+
border: {
|
|
164
|
+
base: 'surface',
|
|
165
|
+
tone: ['-8', '-16'],
|
|
166
|
+
saturation: 0.2,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
<Swatches
|
|
172
|
+
hue={280}
|
|
173
|
+
saturation={80}
|
|
174
|
+
colors={{
|
|
175
|
+
surface: { tone: 97, saturation: 0.15 },
|
|
176
|
+
border: { base: 'surface', tone: ['-8', '-16'], saturation: 0.2 },
|
|
177
|
+
}}
|
|
178
|
+
/>
|
|
179
|
+
|
|
180
|
+
Many values accept a `[normal, highContrast]` pair. The border sits 8 tones
|
|
181
|
+
from the surface in light, about 7 in dark (the dark tone window scales relative
|
|
182
|
+
steps down a little), and exactly 16 in both high-contrast schemes. It has no
|
|
183
|
+
contrast floor: a border is a visible step, not text.
|
|
184
|
+
|
|
185
|
+
### 5. A card shadow
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
theme.colors({
|
|
189
|
+
'card-shadow': {
|
|
190
|
+
type: 'shadow',
|
|
191
|
+
bg: 'surface',
|
|
192
|
+
intensity: 8,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
A `shadow` is a translucent overlay, black by default, whose opacity Glaze
|
|
198
|
+
solves so that once the browser composites it over `bg`, the surface lands
|
|
199
|
+
exactly `intensity` tones darker, in every scheme where it has room for the
|
|
200
|
+
step. `bg` is the surface the shadow falls on. Add `fg` — the element casting
|
|
201
|
+
the shadow — and a darker object casts a deeper shadow.
|
|
202
|
+
|
|
203
|
+
That completes the theme. Here it is on a small product card, in the scheme
|
|
204
|
+
you're viewing:
|
|
205
|
+
|
|
206
|
+
<UiPreview
|
|
207
|
+
hue={280}
|
|
208
|
+
saturation={80}
|
|
209
|
+
colors={{
|
|
210
|
+
surface: { tone: 97, saturation: 0.15 },
|
|
211
|
+
'surface-text': {
|
|
212
|
+
base: 'surface',
|
|
213
|
+
tone: '-1',
|
|
214
|
+
saturation: 0.4,
|
|
215
|
+
contrast: 'AAA',
|
|
216
|
+
},
|
|
217
|
+
'surface-text-soft': {
|
|
218
|
+
base: 'surface',
|
|
219
|
+
tone: '-1',
|
|
220
|
+
saturation: 0.3,
|
|
221
|
+
contrast: 'AA',
|
|
222
|
+
},
|
|
223
|
+
'accent-surface-text': { tone: 100, mode: 'fixed' },
|
|
224
|
+
'accent-surface': {
|
|
225
|
+
base: 'accent-surface-text',
|
|
226
|
+
tone: '-1',
|
|
227
|
+
contrast: 'AA',
|
|
228
|
+
mode: 'fixed',
|
|
229
|
+
},
|
|
230
|
+
'accent-text': { base: 'surface', tone: '-1', contrast: 'AA' },
|
|
231
|
+
border: { base: 'surface', tone: ['-8', '-16'], saturation: 0.2 },
|
|
232
|
+
'card-shadow': { type: 'shadow', bg: 'surface', intensity: 8 },
|
|
233
|
+
}}
|
|
234
|
+
roles={{
|
|
235
|
+
page: 'surface',
|
|
236
|
+
card: 'surface',
|
|
237
|
+
border: 'border',
|
|
238
|
+
text: 'surface-text',
|
|
239
|
+
textSoft: 'surface-text-soft',
|
|
240
|
+
link: 'accent-text',
|
|
241
|
+
accent: 'accent-surface',
|
|
242
|
+
accentLabel: 'accent-surface-text',
|
|
243
|
+
shadow: 'card-shadow',
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
|
|
247
|
+
<Callout kind="note" title="The shadow in dark high contrast">
|
|
248
|
+
The dark high-contrast surface renders at tone 3, which leaves room for only
|
|
249
|
+
3 tones of shadow. Glaze uses the strongest shadow it can — opaque black —
|
|
250
|
+
and logs a one-time console warning; on a surface that is already black, the
|
|
251
|
+
shadow would be transparent. Dark interfaces usually show elevation with a
|
|
252
|
+
`glow`, the lightening mirror of a shadow; see
|
|
253
|
+
[Shadows and glows](./shadows-and-glows.mdx).
|
|
254
|
+
</Callout>
|
|
255
|
+
|
|
256
|
+
## See all four schemes
|
|
257
|
+
|
|
258
|
+
Glaze resolves every color in four **scheme variants**: `light`, `dark`,
|
|
259
|
+
`lightContrast`, and `darkContrast`. Here is the whole theme in one place, with
|
|
260
|
+
each scheme on its own background:
|
|
261
|
+
|
|
262
|
+
<Example
|
|
263
|
+
hue={280}
|
|
264
|
+
saturation={80}
|
|
265
|
+
visual="schemes"
|
|
266
|
+
colors={{
|
|
267
|
+
surface: { tone: 97, saturation: 0.15 },
|
|
268
|
+
'surface-text': {
|
|
269
|
+
base: 'surface',
|
|
270
|
+
tone: '-1',
|
|
271
|
+
saturation: 0.4,
|
|
272
|
+
contrast: 'AAA',
|
|
273
|
+
},
|
|
274
|
+
'surface-text-soft': {
|
|
275
|
+
base: 'surface',
|
|
276
|
+
tone: '-1',
|
|
277
|
+
saturation: 0.3,
|
|
278
|
+
contrast: 'AA',
|
|
279
|
+
},
|
|
280
|
+
'accent-surface-text': { tone: 100, mode: 'fixed' },
|
|
281
|
+
'accent-surface': {
|
|
282
|
+
base: 'accent-surface-text',
|
|
283
|
+
tone: '-1',
|
|
284
|
+
contrast: 'AA',
|
|
285
|
+
mode: 'fixed',
|
|
286
|
+
},
|
|
287
|
+
'accent-text': { base: 'surface', tone: '-1', contrast: 'AA' },
|
|
288
|
+
border: { base: 'surface', tone: ['-8', '-16'], saturation: 0.2 },
|
|
289
|
+
'card-shadow': { type: 'shadow', bg: 'surface', intensity: 8 },
|
|
290
|
+
}}
|
|
291
|
+
roles={{
|
|
292
|
+
page: 'surface',
|
|
293
|
+
card: 'surface',
|
|
294
|
+
border: 'border',
|
|
295
|
+
text: 'surface-text',
|
|
296
|
+
textSoft: 'surface-text-soft',
|
|
297
|
+
link: 'accent-text',
|
|
298
|
+
accent: 'accent-surface',
|
|
299
|
+
accentLabel: 'accent-surface-text',
|
|
300
|
+
shadow: 'card-shadow',
|
|
301
|
+
}}
|
|
302
|
+
/>
|
|
303
|
+
|
|
304
|
+
`css()` always returns all four variants. The other output methods include
|
|
305
|
+
`light` and `dark` by default; turn on the high-contrast variants once for the
|
|
306
|
+
whole app:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
glaze.configure({
|
|
310
|
+
modes: { dark: true, highContrast: true },
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
or for one call, with `theme.tokens({ modes: { highContrast: true } })`.
|
|
315
|
+
|
|
316
|
+
## Export it
|
|
317
|
+
|
|
318
|
+
Output methods resolve the theme and return the colors in the shape your stack
|
|
319
|
+
consumes. Colors are native `oklch()` by default; pass `format: 'rgb'` or
|
|
320
|
+
`'hsl'` for other notations.
|
|
321
|
+
|
|
322
|
+
### CSS custom properties
|
|
323
|
+
|
|
324
|
+
`theme.css()` returns one block of declarations per scheme variant. Each color
|
|
325
|
+
becomes a `--<name>-color` property (pass `suffix: ''` to drop `-color`). Wrap
|
|
326
|
+
the blocks in the selectors that switch your schemes — here, the light block on
|
|
327
|
+
`:root` and the dark block in a media query:
|
|
328
|
+
|
|
329
|
+
<Example
|
|
330
|
+
hue={280}
|
|
331
|
+
saturation={80}
|
|
332
|
+
visual="none"
|
|
333
|
+
output="css"
|
|
334
|
+
label="styles.ts"
|
|
335
|
+
colors={{
|
|
336
|
+
surface: { tone: 97, saturation: 0.15 },
|
|
337
|
+
'surface-text': {
|
|
338
|
+
base: 'surface',
|
|
339
|
+
tone: '-1',
|
|
340
|
+
saturation: 0.4,
|
|
341
|
+
contrast: 'AAA',
|
|
342
|
+
},
|
|
343
|
+
'surface-text-soft': {
|
|
344
|
+
base: 'surface',
|
|
345
|
+
tone: '-1',
|
|
346
|
+
saturation: 0.3,
|
|
347
|
+
contrast: 'AA',
|
|
348
|
+
},
|
|
349
|
+
'accent-surface-text': { tone: 100, mode: 'fixed' },
|
|
350
|
+
'accent-surface': {
|
|
351
|
+
base: 'accent-surface-text',
|
|
352
|
+
tone: '-1',
|
|
353
|
+
contrast: 'AA',
|
|
354
|
+
mode: 'fixed',
|
|
355
|
+
},
|
|
356
|
+
'accent-text': { base: 'surface', tone: '-1', contrast: 'AA' },
|
|
357
|
+
border: { base: 'surface', tone: ['-8', '-16'], saturation: 0.2 },
|
|
358
|
+
'card-shadow': { type: 'shadow', bg: 'surface', intensity: 8 },
|
|
359
|
+
}}
|
|
360
|
+
code={[
|
|
361
|
+
"const css = theme.css({ format: 'rgb' });",
|
|
362
|
+
'',
|
|
363
|
+
'const stylesheet = `',
|
|
364
|
+
':root {',
|
|
365
|
+
'${css.light}',
|
|
366
|
+
'}',
|
|
367
|
+
'',
|
|
368
|
+
'@media (prefers-color-scheme: dark) {',
|
|
369
|
+
' :root {',
|
|
370
|
+
'${css.dark}',
|
|
371
|
+
' }',
|
|
372
|
+
'}`;',
|
|
373
|
+
].join('\n')}
|
|
374
|
+
/>
|
|
375
|
+
|
|
376
|
+
Components then read the variables, for example
|
|
377
|
+
`background: var(--surface-color)`.
|
|
378
|
+
|
|
379
|
+
### Other formats
|
|
380
|
+
|
|
381
|
+
Each export is one call:
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
theme.tokens(); // scheme → color → value
|
|
385
|
+
theme.json(); // color → scheme → value
|
|
386
|
+
theme.tasty(); // Tasty '#color' tokens with state maps
|
|
387
|
+
theme.tailwind(); // Tailwind CSS v4 @theme block + overrides
|
|
388
|
+
theme.dtcg(); // one W3C DTCG token tree per scheme
|
|
389
|
+
theme.dtcgResolver(); // one DTCG Resolver-Module document
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
* `tokens()` and `json()` return plain JavaScript data, grouped by scheme or by
|
|
393
|
+
color.
|
|
394
|
+
* `tasty()` returns [Tasty](../../tasty/README.md) `#token` bindings keyed by
|
|
395
|
+
state, and also accepts Tasty's own `okhsl` and `okhst` formats.
|
|
396
|
+
* `tailwind()` returns a Tailwind CSS v4 `@theme` block plus scheme overrides,
|
|
397
|
+
so `bg-surface` and `text-surface-text` work out of the box.
|
|
398
|
+
* `dtcg()` returns one W3C design-token tree per scheme for Figma, Tokens
|
|
399
|
+
Studio, Style Dictionary, and other DTCG tools; `dtcgResolver()` puts every
|
|
400
|
+
scheme in one document.
|
|
401
|
+
|
|
402
|
+
To save the definitions themselves rather than resolved colors, call
|
|
403
|
+
`theme.export()` and restore the snapshot with `glaze.themeFrom()`.
|
|
404
|
+
[Exporting and integration](./exporting.mdx) covers choosing an export, wiring
|
|
405
|
+
it into your app, and multi-theme palettes;
|
|
406
|
+
[Output formats](./reference/output.md) lists every option.
|
|
407
|
+
|
|
408
|
+
## One color without a theme
|
|
409
|
+
|
|
410
|
+
When you need a single adaptive color, or a pair with a contrast floor, skip the
|
|
411
|
+
theme and use `glaze.color()`:
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
import { glaze } from '@tenphi/glaze';
|
|
415
|
+
|
|
416
|
+
const surface = glaze.color('#f6f5fa');
|
|
417
|
+
const brandText = glaze.color({
|
|
418
|
+
from: '#7a4dbf',
|
|
419
|
+
base: surface,
|
|
420
|
+
contrast: 'AA',
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
brandText.css({ name: 'brand-text' });
|
|
424
|
+
// → {
|
|
425
|
+
// light: '--brand-text-color: oklch(0.5276 0.172 298.52);',
|
|
426
|
+
// dark: '--brand-text-color: oklch(0.6588 0.1367 298.52);',
|
|
427
|
+
// lightContrast: '…',
|
|
428
|
+
// darkContrast: '…',
|
|
429
|
+
// }
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
The light variant reproduces `#7a4dbf` exactly because it already passes 4.5:1
|
|
433
|
+
on that surface. The dark and high-contrast variants adapt, and the floor holds
|
|
434
|
+
in each of them. See [Color tokens](./reference/color-tokens.md).
|
|
435
|
+
|
|
436
|
+
## Concepts at a glance
|
|
437
|
+
|
|
438
|
+
1. **A theme has one hue and saturation seed**, optionally with a separate pair
|
|
439
|
+
for the dark schemes ([dark seed](./schemes.mdx#dark-seed)). Status themes
|
|
440
|
+
come from `extend()`: they inherit the same relationships with a different
|
|
441
|
+
hue. See [Designing a palette](./methodology.mdx).
|
|
442
|
+
2. **A color is a root or a dependent.** Roots use an absolute `tone` or the
|
|
443
|
+
scheme extremes `'max'` / `'min'`. Dependents name a `base` and may use a
|
|
444
|
+
signed tone delta such as `'-8'` plus a `contrast` floor.
|
|
445
|
+
3. **Tone is an authoring axis, not a contrast guarantee.** Equal tone deltas
|
|
446
|
+
are exact WCAG steps for neutrals. Chromatic colors can drift in rendered
|
|
447
|
+
luminance, so Glaze measures contrast floors against the resolved colors.
|
|
448
|
+
See [Tone and OKHST](./okhst.mdx).
|
|
449
|
+
4. **`contrast` is a floor.** A bare number or preset means WCAG; `{ wcag }`
|
|
450
|
+
and `{ apca }` pick the metric explicitly. The solver keeps the requested
|
|
451
|
+
tone whenever it already passes with a small margin (1% over a WCAG ratio,
|
|
452
|
+
0.5 Lc over an APCA target). See [Contrast solving](./contrast.mdx).
|
|
453
|
+
5. **Each color chooses its dark adaptation.** `mode: 'auto'` inverts tone
|
|
454
|
+
(`100 − t`), `'fixed'` keeps the authored side of the scale, and `'static'`
|
|
455
|
+
skips scheme adaptation. See
|
|
456
|
+
[Light, dark, and high contrast](./schemes.mdx).
|
|
457
|
+
6. **Tone windows bound the ordinary schemes.** `lightTone` and `darkTone` set
|
|
458
|
+
the light and dark tone windows; high-contrast variants use the full range.
|
|
459
|
+
Values that accept `[normal, highContrast]` pairs can tighten deliberately in
|
|
460
|
+
high contrast.
|
|
461
|
+
|
|
462
|
+
Output `modes` choose which scheme variants an export includes. In Tasty, the
|
|
463
|
+
`states` option chooses how those variants are activated in your app.
|
|
464
|
+
|
|
465
|
+
## Next steps
|
|
466
|
+
|
|
467
|
+
<CardGrid>
|
|
468
|
+
<Card title="Design a palette" href="./methodology.mdx">
|
|
469
|
+
Surface ladders, accents, disabled states, effects, and status themes,
|
|
470
|
+
built up step by step.
|
|
471
|
+
</Card>
|
|
472
|
+
|
|
473
|
+
<Card title="Export and integrate" href="./exporting.mdx">
|
|
474
|
+
Pick an export shape and wire it into CSS, Tailwind, Tasty, JSON, or
|
|
475
|
+
design-token tools.
|
|
476
|
+
</Card>
|
|
477
|
+
|
|
478
|
+
<Card title="Concepts" href="./schemes.mdx">
|
|
479
|
+
How schemes, contrast floors, shadows and glows, and mixes work, down to
|
|
480
|
+
the tone model under them.
|
|
481
|
+
</Card>
|
|
482
|
+
|
|
483
|
+
<Card title="API reference" href="./reference/index.md">
|
|
484
|
+
Every function, method, option, and type.
|
|
485
|
+
</Card>
|
|
486
|
+
</CardGrid>
|
|
487
|
+
|
|
488
|
+
To explore the tone axis interactively, try the
|
|
489
|
+
[ramp explorer](./okhst.mdx#ramp-explorer).
|