@tenphi/glaze 0.15.1 → 0.16.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 +3 -0
- package/dist/index.cjs +834 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +453 -7
- package/dist/index.d.mts +453 -7
- package/dist/index.mjs +825 -90
- package/dist/index.mjs.map +1 -1
- package/docs/api.md +257 -14
- package/docs/methodology.md +437 -222
- package/docs/migration.md +70 -5
- package/docs/okhst.md +45 -2
- package/package.json +1 -1
package/docs/api.md
CHANGED
|
@@ -115,14 +115,14 @@ Flat token map grouped by scheme variant.
|
|
|
115
115
|
|
|
116
116
|
```ts
|
|
117
117
|
theme.tokens()
|
|
118
|
-
// → { light: { surface: '
|
|
118
|
+
// → { light: { surface: 'oklch(...)' }, dark: { surface: 'oklch(...)' } }
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
`GlazeJsonOptions`:
|
|
122
122
|
|
|
123
123
|
| Option | Default | Description |
|
|
124
124
|
|---|---|---|
|
|
125
|
-
| `format` | `'
|
|
125
|
+
| `format` | `'oklch'` | Output color format. One of `'rgb' \| 'hsl' \| 'oklch'`. `'okhsl'` and `'okhst'` throw — use `tasty()` for those. |
|
|
126
126
|
| `modes` | `{ dark: true, highContrast: false }` (or global config) | Which scheme variants to include. |
|
|
127
127
|
|
|
128
128
|
### `theme.tasty(options?)`
|
|
@@ -141,10 +141,12 @@ theme.tasty()
|
|
|
141
141
|
|
|
142
142
|
| Option | Default | Description |
|
|
143
143
|
|---|---|---|
|
|
144
|
-
| `format` | `'okhsl'` | Output color format. |
|
|
144
|
+
| `format` | `'okhsl'` | Output color format. `'okhsl'` and `'okhst'` are supported here (Tasty-only spaces). |
|
|
145
145
|
| `modes` | global config | Which scheme variants to include. |
|
|
146
146
|
| `states.dark` | `'@dark'` (or global config) | State alias for dark mode tokens. |
|
|
147
147
|
| `states.highContrast` | `'@high-contrast'` (or global config) | State alias for high-contrast tokens. |
|
|
148
|
+
| `splitHue` | `false` | Emit hue as a separate custom property (`#name-hue` token + `var()` in `oklch` values). Requires `format: 'oklch'` and every color to be pastel. |
|
|
149
|
+
| `name` | `'theme'` | Base name for the theme-level hue var (`#theme-hue` / `--theme-hue`). Palette export auto-derives this from the theme name. |
|
|
148
150
|
| `prefix` | (palette only) | See [Palette](#palette). |
|
|
149
151
|
|
|
150
152
|
When both `dark` and `highContrast` modes are enabled, dark high-contrast variants are emitted under the combined key `<dark> & <highContrast>` (e.g. `'@dark & @high-contrast'`).
|
|
@@ -156,8 +158,8 @@ Per-color JSON map.
|
|
|
156
158
|
```ts
|
|
157
159
|
theme.json()
|
|
158
160
|
// → {
|
|
159
|
-
// surface: { light: '
|
|
160
|
-
// text: { light: '
|
|
161
|
+
// surface: { light: 'oklch(...)', dark: 'oklch(...)' },
|
|
162
|
+
// text: { light: 'oklch(...)', dark: 'oklch(...)' },
|
|
161
163
|
// }
|
|
162
164
|
```
|
|
163
165
|
|
|
@@ -181,11 +183,137 @@ theme.css();
|
|
|
181
183
|
|
|
182
184
|
| Option | Default | Description |
|
|
183
185
|
|---|---|---|
|
|
184
|
-
| `format` | `'rgb'` | Output color format. |
|
|
186
|
+
| `format` | `'rgb'` | Output color format. `'okhsl'` and `'okhst'` throw — use `tasty()` for those. |
|
|
185
187
|
| `suffix` | `'-color'` | Suffix appended to each CSS property name. Pass `''` for bare property names. |
|
|
188
|
+
| `splitHue` | `false` | Emit hue as a separate `--*-hue` custom property referenced via `var()` in `oklch` color values. Requires `format: 'oklch'` and every color to be pastel. Shadow/mix colors stay inline (blended hue; they do not follow `--hue` rotation). |
|
|
189
|
+
| `name` | `'theme'` | Base name for the theme-level hue var (`--theme-hue`). Palette export auto-derives this from the theme name. |
|
|
186
190
|
|
|
187
191
|
`GlazeCssResult` always contains all four keys (`light`, `dark`, `lightContrast`, `darkContrast`); empty if no colors are defined for that variant.
|
|
188
192
|
|
|
193
|
+
### `theme.dtcg(options?)`
|
|
194
|
+
|
|
195
|
+
W3C [Design Tokens Format Module (2025.10)](https://www.designtokens.org/) documents — the vendor-neutral JSON format consumed by Figma, Tokens Studio, Style Dictionary v4+, Terrazzo, Penpot, and every DTCG-compatible tool. Returns one spec-conformant token tree per scheme variant.
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
theme.dtcg()
|
|
199
|
+
// → {
|
|
200
|
+
// light: {
|
|
201
|
+
// surface: {
|
|
202
|
+
// $type: 'color',
|
|
203
|
+
// $value: { colorSpace: 'srgb', components: [0.96, 0.94, 0.98], hex: '#f5f0fa' },
|
|
204
|
+
// },
|
|
205
|
+
// },
|
|
206
|
+
// dark: {
|
|
207
|
+
// surface: {
|
|
208
|
+
// $type: 'color',
|
|
209
|
+
// $value: { colorSpace: 'srgb', components: [0.16, 0.14, 0.2], hex: '#292333' },
|
|
210
|
+
// },
|
|
211
|
+
// },
|
|
212
|
+
// }
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Write each document to its own `.tokens.json` file — one file per scheme is the most tool-compatible convention (one per Style Dictionary theme / Tokens Studio set / Figma variable mode).
|
|
216
|
+
|
|
217
|
+
`GlazeDtcgOptions`:
|
|
218
|
+
|
|
219
|
+
| Option | Default | Description |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `colorSpace` | `'srgb'` | Color space for `$value`. `'srgb'` emits gamma sRGB `components` (0–1) plus a `hex` hint — universally understood. `'oklch'` emits `[L, C, H]` components with no hex — Glaze-native, wide-gamut. |
|
|
222
|
+
| `modes` | global config | Which scheme variants to include. `light` is always present. |
|
|
223
|
+
|
|
224
|
+
`alpha` is included on `$value` only when the color's opacity is below 1. `$type` is always `'color'`.
|
|
225
|
+
|
|
226
|
+
### `theme.dtcgResolver(options?)`
|
|
227
|
+
|
|
228
|
+
A single W3C [DTCG Resolver-Module](https://www.designtokens.org/) document describing **every scheme variant in one file** — an alternative to `dtcg()`'s per-scheme files for tools that resolve sets + modifiers (e.g. Dispersa). The light document becomes `sets.base.sources[0]` (the default context); each other variant becomes a context override on a single `scheme` modifier.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
theme.dtcgResolver({ modes: { highContrast: true } })
|
|
232
|
+
// → {
|
|
233
|
+
// version: '2025.10',
|
|
234
|
+
// sets: {
|
|
235
|
+
// base: {
|
|
236
|
+
// sources: [
|
|
237
|
+
// {
|
|
238
|
+
// surface: {
|
|
239
|
+
// $type: 'color',
|
|
240
|
+
// $value: { colorSpace: 'srgb', components: [0.96, 0.94, 0.98], hex: '#f5f0fa' },
|
|
241
|
+
// },
|
|
242
|
+
// },
|
|
243
|
+
// ],
|
|
244
|
+
// },
|
|
245
|
+
// },
|
|
246
|
+
// modifiers: {
|
|
247
|
+
// scheme: {
|
|
248
|
+
// default: 'light',
|
|
249
|
+
// contexts: {
|
|
250
|
+
// light: [],
|
|
251
|
+
// dark: [
|
|
252
|
+
// {
|
|
253
|
+
// surface: {
|
|
254
|
+
// $type: 'color',
|
|
255
|
+
// $value: { colorSpace: 'srgb', components: [0.16, 0.14, 0.2], hex: '#292333' },
|
|
256
|
+
// },
|
|
257
|
+
// },
|
|
258
|
+
// ],
|
|
259
|
+
// lightContrast: [ /* … */ ],
|
|
260
|
+
// darkContrast: [ /* … */ ],
|
|
261
|
+
// },
|
|
262
|
+
// },
|
|
263
|
+
// },
|
|
264
|
+
// resolutionOrder: [
|
|
265
|
+
// { $ref: '#/sets/base' },
|
|
266
|
+
// { $ref: '#/modifiers/scheme' },
|
|
267
|
+
// ],
|
|
268
|
+
// }
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Why one modifier with four contexts.** Glaze resolves `darkContrast` independently — it is not `dark` + `lightContrast` layered. The resolver model composes modifiers additively (last in `resolutionOrder` wins on conflict), so two independent modifiers (`scheme` × `contrast`) would produce wrong values for the dark + high-contrast permutation. One `scheme` modifier with a context per variant keeps every resolved value exact. Choose `dtcgResolver()` when you want single-file theming and feed it to a resolver tool; choose `dtcg()` for maximum per-file tool compatibility.
|
|
272
|
+
|
|
273
|
+
`GlazeDtcgResolverOptions` (extends `GlazeDtcgOptions`, so `modes` and `colorSpace` pass through):
|
|
274
|
+
|
|
275
|
+
| Option | Default | Description |
|
|
276
|
+
|---|---|---|
|
|
277
|
+
| `colorSpace` | `'srgb'` | Same as `dtcg()` — flows through to every source and context. |
|
|
278
|
+
| `modes` | global config | Which scheme variants to emit as contexts. `light` is always present (the default); absent variants are omitted. |
|
|
279
|
+
| `setName` | `'base'` | Name of the single set holding the default (light) token tree. |
|
|
280
|
+
| `modifierName` | `'scheme'` | Name of the modifier describing the scheme axis. |
|
|
281
|
+
| `contextNames` | identity | Override the four context names (`light` / `dark` / `lightContrast` / `darkContrast`) — e.g. `{ dark: 'night' }`. |
|
|
282
|
+
| `version` | `'2025.10'` | Resolver document version. |
|
|
283
|
+
|
|
284
|
+
### `theme.tailwind(options?)`
|
|
285
|
+
|
|
286
|
+
A Tailwind CSS v4 `@theme` block (light baseline) plus dark / high-contrast overrides under configurable selectors. Returns a single ready-to-paste CSS string. The `--color-*` namespace auto-generates `bg-*` / `text-*` / `border-*` utilities.
|
|
287
|
+
|
|
288
|
+
```css
|
|
289
|
+
@theme {
|
|
290
|
+
--color-surface: oklch(0.96 0.01 280);
|
|
291
|
+
--color-text: oklch(0.3 0.05 280);
|
|
292
|
+
}
|
|
293
|
+
.dark {
|
|
294
|
+
--color-surface: oklch(0.16 0.01 280);
|
|
295
|
+
--color-text: oklch(0.85 0.05 280);
|
|
296
|
+
}
|
|
297
|
+
.high-contrast {
|
|
298
|
+
--color-surface: oklch(0.98 0.01 280);
|
|
299
|
+
--color-text: oklch(0.1 0.05 280);
|
|
300
|
+
}
|
|
301
|
+
.dark.high-contrast {
|
|
302
|
+
--color-surface: oklch(0.05 0.01 280);
|
|
303
|
+
--color-text: oklch(0.95 0.05 280);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
`GlazeTailwindOptions`:
|
|
308
|
+
|
|
309
|
+
| Option | Default | Description |
|
|
310
|
+
|---|---|---|
|
|
311
|
+
| `format` | `'oklch'` | Output color format for the values. |
|
|
312
|
+
| `namespace` | `'color-'` | CSS custom property namespace, forming `--<namespace><name>` (e.g. `--color-surface`). Named `namespace` to avoid clashing with the palette theme-prefix option. |
|
|
313
|
+
| `darkSelector` | `'.dark'` | Selector wrapping the dark overrides. Pass an at-rule like `'@media (prefers-color-scheme: dark)'` to drive dark mode from the OS preference (it nests `:root` automatically). |
|
|
314
|
+
| `highContrastSelector` | `'.high-contrast'` | Selector wrapping the light high-contrast overrides. The combined dark + high-contrast block uses `${darkSelector}${highContrastSelector}` (e.g. `.dark.high-contrast`). |
|
|
315
|
+
| `modes` | global config | Which scheme variants to include. The `@theme` block (light) is always emitted when colors exist. |
|
|
316
|
+
|
|
189
317
|
### `theme.export()`
|
|
190
318
|
|
|
191
319
|
```ts
|
|
@@ -220,6 +348,7 @@ type ColorDef = RegularColorDef | ShadowColorDef | MixColorDef;
|
|
|
220
348
|
| `flip` | `boolean` | Flip out-of-bounds results (relative `tone` overshoot / unmet `contrast`) to the opposite side instead of clamping. Default: the global `autoFlip` (`true`). See [`flip`](#flip). |
|
|
221
349
|
| `opacity` | `number` | Fixed alpha 0–1. Output includes alpha in the CSS value. Combining with `contrast` is not recommended (a `console.warn` is emitted). |
|
|
222
350
|
| `pastel` | `boolean` | Per-color override for the hue-independent "safe" chroma limit used in OKHSL↔sRGB conversions (luminance, contrast solving, output formatting). Falls through to the global / per-theme `pastel` config when omitted. Default: unset. See [Per-color `pastel`](#per-color-pastel). |
|
|
351
|
+
| `role` | `RoleInput` | Semantic role against `base` (`'text'` / `'surface'` / `'border'` or an alias). Fixes APCA contrast polarity. Resolved via: explicit `role` → name inference → opposite of the base's role → `'text'`. See [Roles](#roles). |
|
|
223
352
|
| `inherit` | `boolean` | Whether this color is inherited by child themes via `extend()`. Default: `true`. Set to `false` to make the color local to the current theme. |
|
|
224
353
|
|
|
225
354
|
#### Tone values
|
|
@@ -277,8 +406,15 @@ contrast: { wcag: 6 } // WCAG 6
|
|
|
277
406
|
contrast: { wcag: [4.5, 7] } // WCAG 4.5 normal / 7 high-contrast
|
|
278
407
|
contrast: { apca: 60 } // APCA Lc 60
|
|
279
408
|
contrast: { apca: [45, 60] } // APCA Lc 45 normal / 60 high-contrast
|
|
409
|
+
contrast: { apca: 'content' } // APCA preset -> Lc 60
|
|
410
|
+
contrast: { apca: ['content', 'body'] } // Lc 60 normal / 75 high-contrast
|
|
280
411
|
```
|
|
281
412
|
|
|
413
|
+
APCA preset keywords (Bronze Simple Mode conformance levels, role-independent):
|
|
414
|
+
`'preferred'` (Lc 90), `'body'` (75), `'content'` (60, ~AA), `'large'` (45, ~3:1),
|
|
415
|
+
`'non-text'` (30), `'min'` (15, point of invisibility). See
|
|
416
|
+
[`docs/okhst.md`](okhst.md) §APCA.
|
|
417
|
+
|
|
282
418
|
The floor is applied independently per scheme — if the `tone` already satisfies it the tone is kept, otherwise the solver searches in tone (contrast-uniform → a closed-form WCAG seed and fast convergence) until the target is met.
|
|
283
419
|
|
|
284
420
|
By default, the solver crosses to the opposite side of the base color when the requested tone direction cannot satisfy the floor. This is controlled per-color by [`flip`](#flip) (which defaults to the global `autoFlip`). Set `glaze.configure({ autoFlip: false })` — or `flip: false` on a single color — to keep strict directionality: unmet colors pin to that direction's 0 or 100 tone extreme instead of falling back to the original requested value.
|
|
@@ -332,6 +468,36 @@ const child = parent.extend({
|
|
|
332
468
|
>
|
|
333
469
|
> Standalone `glaze.color()` tokens accept the same `pastel` field on both the structured (`GlazeColorInput`) and value-shorthand (`GlazeColorOverrides`) forms, and it survives the `export()` / `glaze.colorFrom()` round-trip.
|
|
334
470
|
|
|
471
|
+
#### Roles
|
|
472
|
+
|
|
473
|
+
A color's `role` describes how it is used against its `base` and fixes **APCA contrast polarity** — which side is the foreground vs the background. APCA is asymmetric (`|apca(a,b)| ≠ |apca(b,a)|`), so the role picks the correct argument order; WCAG is symmetric and unaffected.
|
|
474
|
+
|
|
475
|
+
| Role | Polarity | Use | Aliases (name inference) |
|
|
476
|
+
|---|---|---|---|
|
|
477
|
+
| `'text'` | fg | Text / icons / foreground content | `text`, `fg`, `foreground`, `content`, `ink`, `label`, `stroke` |
|
|
478
|
+
| `'border'` | fg | Non-text spot elements (borders, dividers, outlines) | `border`, `divider`, `outline`, `separator`, `hairline`, `rule` |
|
|
479
|
+
| `'surface'` | bg | Backgrounds / fills | `surface`, `bg`, `background`, `fill`, `canvas`, `paper`, `layer` |
|
|
480
|
+
|
|
481
|
+
Resolution chain (per color):
|
|
482
|
+
|
|
483
|
+
1. Explicit `role` (normalized from an alias) wins.
|
|
484
|
+
2. Else, when `inferRole` is enabled (default), infer from the color name — the **last** recognized token wins (`button-text` → `text`, `input-bg` → `surface`, `card-outline` → `border`).
|
|
485
|
+
3. Else, the opposite of the base's role (a `surface` base ⇒ this is `text`).
|
|
486
|
+
4. Else, `'text'` (foreground) — i.e. the base is treated as the background.
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
const theme = glaze(280, 60);
|
|
490
|
+
theme.colors({
|
|
491
|
+
surface: { tone: 90 },
|
|
492
|
+
text: { base: 'surface', contrast: { apca: 'content' } }, // inferred text
|
|
493
|
+
border: { base: 'surface', tone: '-10' }, // inferred border
|
|
494
|
+
});
|
|
495
|
+
// role fixes APCA polarity; set `pastel: true` explicitly if a border
|
|
496
|
+
// needs the hue-independent safe chroma limit.
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Disable name inference with `glaze.configure({ inferRole: false })` (the base-opposite and foreground-default fallbacks still apply).
|
|
500
|
+
|
|
335
501
|
### `ShadowColorDef`
|
|
336
502
|
|
|
337
503
|
| Field | Type | Description |
|
|
@@ -358,6 +524,7 @@ See [Shadows](#shadows) below for the algorithm and tuning details.
|
|
|
358
524
|
| `space` | `'okhsl' \| 'srgb'` | Interpolation space for opaque blending. Default `'okhsl'`. Ignored for `'transparent'` (always composites in linear sRGB). |
|
|
359
525
|
| `contrast` | `HCPair<ContrastSpec>` | Optional contrast floor against `base` (WCAG or APCA — see [`contrast`](#contrast-floor)). The solver adjusts the mix ratio (opaque) or opacity (transparent). |
|
|
360
526
|
| `pastel` | `boolean` | Per-color `pastel` override. See [Per-color `pastel`](#per-color-pastel). |
|
|
527
|
+
| `role` | `RoleInput` | Semantic role of the mixed result against `base`. Same semantics as `RegularColorDef.role` (see [Roles](#roles)). |
|
|
361
528
|
| `inherit` | `boolean` | Inheritance flag, default `true`. |
|
|
362
529
|
|
|
363
530
|
See [Mix colors](#mix-colors) below.
|
|
@@ -414,6 +581,7 @@ glaze.color(color: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?:
|
|
|
414
581
|
| `base` | `GlazeColorToken \| GlazeColorValue` | Optional dependency. See [Pairing colors](#pairing-colors). |
|
|
415
582
|
| `contrast` | `HCPair<ContrastSpec>` | Contrast floor against `base` (WCAG or APCA). Without `base`, anchored to the literal seed. |
|
|
416
583
|
| `pastel` | `boolean` | Per-color `pastel` override. Falls through to the global / per-theme `pastel` config when omitted. See [Per-color `pastel`](#per-color-pastel). |
|
|
584
|
+
| `role` | `RoleInput` | Semantic role against `base` / the seed (see [Roles](#roles)). Fixes APCA polarity. |
|
|
417
585
|
| `name` | `string` | Debug label for warnings; doesn't change output keys. Reserved names (`'value'`, `'seed'`, `'externalBase'`) are rejected. |
|
|
418
586
|
|
|
419
587
|
`GlazeFromInput` (from form) is `{ from: GlazeColorValue, ...colorOverrides }`:
|
|
@@ -431,6 +599,7 @@ glaze.color(color: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?:
|
|
|
431
599
|
| `base` | `GlazeColorToken` or raw `GlazeColorValue`. See [Pairing colors](#pairing-colors). |
|
|
432
600
|
| `opacity` | Fixed alpha 0–1. Combining with `contrast` is not recommended — `console.warn` is emitted. |
|
|
433
601
|
| `pastel` | Per-color `pastel` override. Falls through to the global / per-theme `pastel` config when omitted. See [Per-color `pastel`](#per-color-pastel). |
|
|
602
|
+
| `role` | Semantic role against `base` / the seed (see [Roles](#roles)). Fixes APCA polarity. |
|
|
434
603
|
| `name` | Debug label only — surfaces in warnings/errors. Does not change output keys. |
|
|
435
604
|
|
|
436
605
|
Named CSS colors (`'red'`, `'blueviolet'`) are not supported.
|
|
@@ -471,9 +640,12 @@ A `GlazeColorToken` exposes:
|
|
|
471
640
|
|---|---|
|
|
472
641
|
| `token.resolve()` | Resolve as a `ResolvedColor` (light/dark/lightContrast/darkContrast variants). |
|
|
473
642
|
| `token.token(options?)` | Flat token map (no color-name key). Options: `format`, `modes`, `states`. |
|
|
474
|
-
| `token.tasty(options?)` | Tasty state map (no color-name key). Same options as `token.token`. |
|
|
643
|
+
| `token.tasty(options?)` | [Tasty](https://tasty.style) state map (no color-name key). Same options as `token.token`. |
|
|
475
644
|
| `token.json(options?)` | JSON map (no color-name key). Options: `format`, `modes`. |
|
|
476
645
|
| `token.css({ name, format?, suffix? })` | CSS custom property declarations grouped by scheme variant. `name` is **required** and becomes the variable identifier (`'brand'` → `--brand-color`). Defaults: `format: 'rgb'`, `suffix: '-color'` (matches `theme.css`). |
|
|
646
|
+
| `token.dtcg(options?)` | DTCG color tokens, one per scheme variant (no color-name key). Each entry is a full `{ $type: 'color', $value }` token. Options: `colorSpace` (`'srgb'` \| `'oklch'`), `modes`. |
|
|
647
|
+
| `token.dtcgResolver({ name, ... })` | A single DTCG Resolver-Module document for this color, keyed by `name` across all scheme variants. `name` is **required**. Same options as `theme.dtcgResolver()` plus `name`. |
|
|
648
|
+
| `token.tailwind({ name, ... })` | Tailwind v4 `@theme` block + dark / high-contrast overrides for this color. `name` is **required** (forms `--color-<name>`). Same options as `theme.tailwind()` plus `name`. |
|
|
477
649
|
| `token.export()` | JSON-safe snapshot — pass to `glaze.colorFrom(...)` to rehydrate. |
|
|
478
650
|
|
|
479
651
|
### Per-instance config override
|
|
@@ -922,6 +1094,56 @@ const stylesheet = `
|
|
|
922
1094
|
`palette.css()` accepts the same `GlazeCssOptions` as `theme.css()` plus `GlazePaletteExportOptions`.
|
|
923
1095
|
It does not accept `modes`; all four result fields are always returned.
|
|
924
1096
|
|
|
1097
|
+
### `palette.dtcg()`
|
|
1098
|
+
|
|
1099
|
+
DTCG export for a palette. Prefix defaults to `true` and the palette-level `primary` is honored (the primary theme's tokens are duplicated without prefix as aliases).
|
|
1100
|
+
|
|
1101
|
+
```ts
|
|
1102
|
+
palette.dtcg()
|
|
1103
|
+
// → {
|
|
1104
|
+
// light: {
|
|
1105
|
+
// 'primary-surface': { $type: 'color', $value: { ... } },
|
|
1106
|
+
// 'surface': { $type: 'color', $value: { ... } }, // unprefixed alias
|
|
1107
|
+
// 'danger-surface': { $type: 'color', $value: { ... } },
|
|
1108
|
+
// },
|
|
1109
|
+
// dark: { ... },
|
|
1110
|
+
// }
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
Accepts `GlazeDtcgOptions` plus `GlazePaletteExportOptions`.
|
|
1114
|
+
|
|
1115
|
+
### `palette.dtcgResolver()`
|
|
1116
|
+
|
|
1117
|
+
Resolver-Module export for a palette. Same as `theme.dtcgResolver()` but merges every theme (with prefix / `primary` aliasing) into the single `sets.base` source and each `scheme` context. Prefix defaults to `true`; the palette-level `primary` is honored.
|
|
1118
|
+
|
|
1119
|
+
```ts
|
|
1120
|
+
palette.dtcgResolver()
|
|
1121
|
+
// → {
|
|
1122
|
+
// version: '2025.10',
|
|
1123
|
+
// sets: { base: { sources: [ { 'primary-surface': {…}, 'surface': {…}, 'danger-surface': {…} } ] } },
|
|
1124
|
+
// modifiers: { scheme: { default: 'light', contexts: { light: [], dark: [ {…} ] } } },
|
|
1125
|
+
// resolutionOrder: [ { $ref: '#/sets/base' }, { $ref: '#/modifiers/scheme' } ],
|
|
1126
|
+
// }
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
Accepts `GlazeDtcgResolverOptions` plus `GlazePaletteExportOptions`.
|
|
1130
|
+
|
|
1131
|
+
### `palette.tailwind()`
|
|
1132
|
+
|
|
1133
|
+
Tailwind export for a palette. All themes are merged into a single `@theme` block (plus dark / high-contrast overrides), so each color is reachable as a Tailwind utility. Prefix defaults to `true`.
|
|
1134
|
+
|
|
1135
|
+
```ts
|
|
1136
|
+
const css = palette.tailwind();
|
|
1137
|
+
// @theme {
|
|
1138
|
+
// --color-primary-surface: oklch(...);
|
|
1139
|
+
// --color-surface: oklch(...); /* unprefixed alias */
|
|
1140
|
+
// --color-danger-surface: oklch(...);
|
|
1141
|
+
// }
|
|
1142
|
+
// .dark { ... }
|
|
1143
|
+
```
|
|
1144
|
+
|
|
1145
|
+
Accepts `GlazeTailwindOptions` plus `GlazePaletteExportOptions`. The palette `prefix` option (theme prefixing) is separate from `GlazeTailwindOptions.namespace` (the `--color-*` CSS namespace).
|
|
1146
|
+
|
|
925
1147
|
---
|
|
926
1148
|
|
|
927
1149
|
## Output formats
|
|
@@ -930,21 +1152,40 @@ Control the color format with the `format` option on any export method:
|
|
|
930
1152
|
|
|
931
1153
|
| Format | Output (alpha = 1) | Output (alpha < 1) | Notes |
|
|
932
1154
|
|---|---|---|---|
|
|
933
|
-
| `'okhsl'` (default for
|
|
934
|
-
| `'
|
|
1155
|
+
| `'okhsl'` (default for `tasty()`) | `okhsl(H S% L%)` | `okhsl(H S% L% / A)` | Glaze's native format, not a CSS function. **Tasty-only** (`tasty()`, `token()`, `.tasty()`). |
|
|
1156
|
+
| `'okhst'` | `okhst(H S% T%)` | `okhst(H S% T% / A)` | OKHST tone axis. **Tasty-only** — same restriction as `okhsl`. |
|
|
1157
|
+
| `'oklch'` (default for `tokens()` / `json()`) | `oklch(L C H)` | `oklch(L C H / A)` | OKLab-based LCH. Native CSS. Required for `splitHue`. |
|
|
1158
|
+
| `'rgb'` (default for `css()`) | `rgb(R G B)` | `rgb(R G B / A)` | Rounded integers, modern space syntax. |
|
|
935
1159
|
| `'hsl'` | `hsl(H S% L%)` | `hsl(H S% L% / A)` | Modern space syntax. |
|
|
936
|
-
| `'oklch'` | `oklch(L C H)` | `oklch(L C H / A)` | OKLab-based LCH. |
|
|
937
1160
|
|
|
938
1161
|
```ts
|
|
939
|
-
theme.tokens(); // '
|
|
1162
|
+
theme.tokens(); // 'oklch(0.965 0.0123 280)' (default)
|
|
940
1163
|
theme.tokens({ format: 'rgb' }); // 'rgb(244 240 250)'
|
|
941
|
-
theme.
|
|
942
|
-
theme.
|
|
1164
|
+
theme.tasty(); // 'okhsl(280 60% 97%)' (default)
|
|
1165
|
+
theme.tasty({ format: 'okhst' }); // 'okhst(280 60% 97%)'
|
|
943
1166
|
```
|
|
944
1167
|
|
|
945
1168
|
All numeric output strips trailing zeros for cleaner CSS (e.g. `95` not `95.0`).
|
|
946
1169
|
|
|
947
|
-
The `format` option works on
|
|
1170
|
+
The `format` option works on CSS-string exports: `theme.tokens()`, `theme.tasty()`, `theme.json()`, `theme.css()`, `theme.tailwind()`, the same on `palette`, and on `token.token()` / `.tasty()` / `.json()` / `.css()` / `.tailwind()`. **`okhsl` and `okhst` throw on non-Tasty exports** (`tokens`, `json`, `css`, `tailwind`) — they are not native CSS color spaces.
|
|
1171
|
+
|
|
1172
|
+
### Hue channel splitting (`splitHue`)
|
|
1173
|
+
|
|
1174
|
+
On `theme.css()`, `theme.tasty()`, `palette.css()`, `palette.tasty()`, and standalone `color.css()` with `format: 'oklch'`, set `splitHue: true` to emit hue as its own custom property so consumers can re-skin at runtime:
|
|
1175
|
+
|
|
1176
|
+
```css
|
|
1177
|
+
/* theme.css({ format: 'oklch', splitHue: true, name: 'brand' }) */
|
|
1178
|
+
--brand-hue: 240;
|
|
1179
|
+
--accent-hue: calc(var(--brand-hue) + 20);
|
|
1180
|
+
--surface-color: oklch(0.52 0.06 var(--brand-hue));
|
|
1181
|
+
--accent-color: oklch(0.62 0.03 var(--accent-hue));
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
**Requirements:** every exported color must be pastel (`pastel: true` globally or per-color). Pastel mode bounds chroma by the hue-independent safe chroma at each lightness, so emitted `C` stays in sRGB for any rotated hue. Non-pastel palettes throw rather than emit values that would clip under rotation.
|
|
1185
|
+
|
|
1186
|
+
**Limitations:** `oklch` only (native CSS `var()` in the hue slot). Shadow and mix colors stay inline (blended hue). Standalone `.token()` / `.tasty()` do not support `splitHue` (return shape cannot carry the `#name-hue` declaration).
|
|
1187
|
+
|
|
1188
|
+
`theme.dtcg()` / `theme.dtcgResolver()` / `palette.dtcg()` / `palette.dtcgResolver()` ignore `format` — DTCG emits structured `$value` objects, not CSS strings. Use the `colorSpace` option (`'srgb'` or `'oklch'`) to pick the color representation instead.
|
|
948
1189
|
|
|
949
1190
|
---
|
|
950
1191
|
|
|
@@ -1064,6 +1305,8 @@ A `ToneWindow` is `[lo, hi]` (OKHSL-lightness endpoints, reference eps — the c
|
|
|
1064
1305
|
| `modes.highContrast` | `false` | Include HC variants. |
|
|
1065
1306
|
| `shadowTuning` | `undefined` | Default tuning for all shadow colors. Per-color tuning merges field-by-field. |
|
|
1066
1307
|
| `autoFlip` | `true` | Default for each color's `flip`. When solving `contrast` (or applying a relative `tone` that overshoots `[0, 100]`), allow crossing to the opposite side instead of clamping. With `false`, only the requested direction is considered; unmet contrasts pin the tone to that direction's extreme (and emit a warning) and overshooting offsets clamp to the boundary. Override per color via [`flip`](#flip). |
|
|
1308
|
+
| `pastel` | `false` | Hue-independent "safe" chroma limit across all colors so scaling saturation never exceeds the sRGB boundary at any hue for the given lightness. Override per color via [`pastel`](#per-color-pastel). |
|
|
1309
|
+
| `inferRole` | `true` | Infer each color's [`role`](#roles) from its name when no explicit `role` is set. Set to `false` to opt out of name-based inference (the base-opposite and foreground-default fallbacks still apply). |
|
|
1067
1310
|
|
|
1068
1311
|
| Method | Description |
|
|
1069
1312
|
|---|---|
|