@tenphi/glaze 0.0.0-snapshot.78261ef → 0.0.0-snapshot.7dca259

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/dist/index.d.cts CHANGED
@@ -1,48 +1,71 @@
1
1
  //#region src/contrast-solver.d.ts
2
- /**
3
- * OKHSL Contrast Solver
4
- *
5
- * Finds the closest OKHSL lightness that satisfies a WCAG 2 contrast target
6
- * against a base color. Used by glaze when resolving dependent colors
7
- * with `contrast`.
8
- */
9
2
  type LinearRgb = [number, number, number];
10
3
  type ContrastPreset = 'AA' | 'AAA' | 'AA-large' | 'AAA-large';
11
4
  type MinContrast$1 = number | ContrastPreset;
12
- interface FindLightnessForContrastOptions {
5
+ /** Metric + numeric target after resolving a `ContrastSpec` for a mode. */
6
+ interface ResolvedContrast {
7
+ metric: 'wcag' | 'apca';
8
+ /** WCAG ratio (>= 1) or APCA Lc magnitude (0–106). */
9
+ target: number;
10
+ }
11
+ declare function resolveMinContrast(value: MinContrast$1): number;
12
+ /**
13
+ * Resolve a `ContrastSpec` (already selected from any outer HC pair) for a
14
+ * given mode into `{ metric, target }`. Handles the inner metric HC pair and
15
+ * preset resolution.
16
+ */
17
+ declare function resolveContrastForMode(spec: ContrastSpec, isHighContrast: boolean): ResolvedContrast;
18
+ /**
19
+ * APCA lightness contrast (Lc), signed: positive for dark text on light bg,
20
+ * negative for light text on dark bg. Inputs are screen luminances (0–1).
21
+ */
22
+ declare function apcaContrast(yText: number, yBg: number): number;
23
+ interface FindToneForContrastOptions {
13
24
  /** Hue of the candidate color (0–360). */
14
25
  hue: number;
15
26
  /** Saturation of the candidate color (0–1). */
16
27
  saturation: number;
17
- /** Preferred lightness of the candidate (0–1). */
18
- preferredLightness: number;
19
- /** Base/reference color as linear sRGB (channels may be outside 0–1 before clamp). */
20
- baseLinearRgb: [number, number, number];
21
- /** WCAG contrast ratio target floor. */
22
- contrast: MinContrast$1;
23
- /** Search bounds for lightness. Default: [0, 1]. */
24
- lightnessRange?: [number, number];
28
+ /** Preferred tone of the candidate (0–1). */
29
+ preferredTone: number;
30
+ /** Base/reference color as linear sRGB. */
31
+ baseLinearRgb: LinearRgb;
32
+ /** Resolved contrast floor (metric + target). */
33
+ contrast: ResolvedContrast;
34
+ /** Search bounds for tone. Default: [0, 1]. */
35
+ toneRange?: [number, number];
25
36
  /** Convergence threshold. Default: 1e-4. */
26
37
  epsilon?: number;
27
- /** Maximum binary-search iterations per branch. Default: 14. */
38
+ /** Maximum binary-search iterations per branch. Default: 18. */
28
39
  maxIterations?: number;
40
+ /** Preferred search direction before auto-flip is considered. */
41
+ initialDirection?: 'lighter' | 'darker';
42
+ /** Auto-flip tone direction when contrast can't be met. Default: false. */
43
+ flip?: boolean;
44
+ /**
45
+ * Saturation taper strength (0–1). When set, candidate saturation is rolled
46
+ * off toward the tone extremes via the same envelope the renderer applies,
47
+ * so the solved tone meets the floor with its *rendered* saturation. Default
48
+ * `0` (no taper) for direct/advanced callers.
49
+ */
50
+ saturationTaper?: number;
29
51
  }
30
- interface FindLightnessForContrastResult {
31
- /** Chosen lightness in 0–1. */
32
- lightness: number;
33
- /** Achieved WCAG contrast ratio. */
52
+ interface FindToneForContrastResult {
53
+ /** Chosen tone in 0–1. */
54
+ tone: number;
55
+ /** Achieved score (WCAG ratio or APCA Lc magnitude). */
34
56
  contrast: number;
35
57
  /** Whether the target was reached. */
36
58
  met: boolean;
37
59
  /** Which branch was selected. */
38
60
  branch: 'lighter' | 'darker' | 'preferred';
61
+ /** Whether the result auto-flipped to the opposite direction. */
62
+ flipped?: boolean;
39
63
  }
40
- declare function resolveMinContrast(value: MinContrast$1): number;
41
64
  /**
42
- * Find the OKHSL lightness that satisfies a WCAG 2 contrast target
43
- * against a base color, staying as close to `preferredLightness` as possible.
65
+ * Find the tone that satisfies a contrast floor against a base color,
66
+ * staying as close to `preferredTone` as possible.
44
67
  */
45
- declare function findLightnessForContrast(options: FindLightnessForContrastOptions): FindLightnessForContrastResult;
68
+ declare function findToneForContrast(options: FindToneForContrastOptions): FindToneForContrastResult;
46
69
  interface FindValueForMixContrastOptions {
47
70
  /** Preferred mix parameter (0–1). */
48
71
  preferredValue: number;
@@ -50,40 +73,69 @@ interface FindValueForMixContrastOptions {
50
73
  baseLinearRgb: LinearRgb;
51
74
  /** Target color as linear sRGB. */
52
75
  targetLinearRgb: LinearRgb;
53
- /** WCAG contrast target. */
54
- contrast: MinContrast$1;
55
- /**
56
- * Compute the luminance of the mixed color at parameter t.
57
- * For opaque: luminance of OKHSL-interpolated color.
58
- * For transparent: luminance of alpha-composited color over base.
59
- */
76
+ /** Resolved contrast floor (metric + target). */
77
+ contrast: ResolvedContrast;
78
+ /** Compute the luminance of the mixed color at parameter t. */
60
79
  luminanceAtValue: (t: number) => number;
61
80
  /** Convergence threshold. Default: 1e-4. */
62
81
  epsilon?: number;
63
82
  /** Maximum binary-search iterations per branch. Default: 20. */
64
83
  maxIterations?: number;
84
+ /** Auto-flip mix direction when contrast can't be met. Default: false. */
85
+ flip?: boolean;
65
86
  }
66
87
  interface FindValueForMixContrastResult {
67
- /** Chosen mix parameter (0–1). */
68
88
  value: number;
69
- /** Achieved WCAG contrast ratio. */
70
89
  contrast: number;
71
- /** Whether the target was reached. */
72
90
  met: boolean;
91
+ flipped?: boolean;
73
92
  }
74
93
  /**
75
- * Find the mix parameter (ratio or opacity) that satisfies a WCAG 2 contrast
76
- * target against a base color, staying as close to `preferredValue` as possible.
94
+ * Find the mix parameter (ratio or opacity) that satisfies a contrast floor
95
+ * against a base color, staying as close to `preferredValue` as possible.
77
96
  */
78
97
  declare function findValueForMixContrast(options: FindValueForMixContrastOptions): FindValueForMixContrastResult;
79
98
  //#endregion
80
99
  //#region src/types.d.ts
81
100
  /** A value or [normal, high-contrast] pair. */
82
101
  type HCPair<T> = T | [T, T];
102
+ /** Bare WCAG contrast target: a ratio number or a named preset. */
83
103
  type MinContrast = number | ContrastPreset;
104
+ /**
105
+ * A contrast floor with a pluggable metric.
106
+ *
107
+ * - `number` / `ContrastPreset`: a WCAG ratio (bare form).
108
+ * - `{ wcag }`: WCAG ratio or preset, optionally an HC pair.
109
+ * - `{ apca }`: APCA Lc target (absolute value), optionally an HC pair.
110
+ *
111
+ * The `[normal, highContrast]` pair may live at the outer level
112
+ * (`[4.5, 7]`, `[{ wcag: 4.5 }, { wcag: 7 }]`) or inside the metric
113
+ * (`{ wcag: [4.5, 7] }`, `{ apca: [45, 60] }`).
114
+ */
115
+ type ContrastSpec = number | ContrastPreset | {
116
+ wcag: HCPair<number | ContrastPreset>;
117
+ } | {
118
+ apca: HCPair<number>;
119
+ };
84
120
  type AdaptationMode = 'auto' | 'fixed' | 'static';
85
121
  /** A signed relative offset string, e.g. '+20' or '-15.5'. */
86
122
  type RelativeValue = `+${number}` | `-${number}`;
123
+ /**
124
+ * Force a color to a tone extreme:
125
+ * - `'max'`: the highest tone in the active scheme range/window.
126
+ * - `'min'`: the lowest tone.
127
+ *
128
+ * Under `mode: 'auto'` the extreme inverts in the dark scheme (so `'max'`
129
+ * tracks the inversion and becomes the darkest tone). No `base` required.
130
+ */
131
+ type ExtremeValue = 'max' | 'min';
132
+ /**
133
+ * A tone value as authored on a color.
134
+ * - Number: absolute tone (0–100).
135
+ * - `'+N'` / `'-N'`: relative to the base's tone (requires `base`).
136
+ * - `'max'` / `'min'`: forced to the scheme's tone extreme (no base needed).
137
+ */
138
+ type ToneValue = number | RelativeValue | ExtremeValue;
87
139
  /** Color format for output. */
88
140
  type GlazeColorFormat = 'okhsl' | 'rgb' | 'hsl' | 'oklch';
89
141
  /**
@@ -104,13 +156,35 @@ interface OkhslColor {
104
156
  s: number;
105
157
  l: number;
106
158
  }
159
+ /**
160
+ * Direct OKHST color input — OKHSL with the lightness axis replaced by the
161
+ * contrast-uniform tone axis. `h`: 0–360, `s`: 0–1, `t`: 0–1 (tone).
162
+ */
163
+ interface OkhstColor {
164
+ h: number;
165
+ s: number;
166
+ t: number;
167
+ }
168
+ /** sRGB components in 0–255 (value-shorthand object form). */
169
+ interface RgbColor {
170
+ r: number;
171
+ g: number;
172
+ b: number;
173
+ }
174
+ /** OKLCh components matching CSS `oklch(L C H)` (L/C: 0–1, H: degrees). */
175
+ interface OklchColor {
176
+ l: number;
177
+ c: number;
178
+ h: number;
179
+ }
107
180
  interface RegularColorDef {
108
181
  /**
109
- * Lightness value (0–100).
110
- * - Number: absolute lightness.
111
- * - String ('+N' / '-N'): relative to base color's lightness (requires `base`).
182
+ * Tone value (0–100, contrast-uniform — see `docs/okhst.md`).
183
+ * - Number: absolute tone.
184
+ * - String ('+N' / '-N'): relative to base color's tone (requires `base`).
185
+ * - `'max'` / `'min'`: force to the scheme's tone extreme (no base needed).
112
186
  */
113
- lightness?: HCPair<number | RelativeValue>;
187
+ tone?: HCPair<ToneValue>;
114
188
  /** Saturation factor applied to the seed saturation (0–1, default: 1). */
115
189
  saturation?: number;
116
190
  /**
@@ -121,15 +195,30 @@ interface RegularColorDef {
121
195
  hue?: number | RelativeValue;
122
196
  /** Name of another color in the same theme (dependent color). */
123
197
  base?: string;
124
- /** WCAG contrast ratio floor against the base color. */
125
- contrast?: HCPair<MinContrast>;
198
+ /**
199
+ * Contrast floor against the base color. A bare number/preset is WCAG;
200
+ * use `{ wcag }` / `{ apca }` to pick the metric. Accepts an HC pair.
201
+ */
202
+ contrast?: HCPair<ContrastSpec>;
126
203
  /** Adaptation mode. Default: 'auto'. */
127
204
  mode?: AdaptationMode;
205
+ /**
206
+ * Whether to flip out-of-bounds results to the opposite side instead of
207
+ * clamping to the extreme. Affects both:
208
+ * - relative `tone`: when `base ± delta` exceeds `[0, 100]`, mirror the
209
+ * delta to the other side of the base.
210
+ * - `contrast`: when the requested direction can't meet the floor, try the
211
+ * opposite side (same as the global `autoFlip`).
212
+ *
213
+ * Defaults to the global `autoFlip` config (default `true`). Set `false`
214
+ * to clamp instead.
215
+ */
216
+ flip?: boolean;
128
217
  /**
129
218
  * Fixed opacity (0–1).
130
219
  * Output includes alpha in the CSS value.
131
220
  * Does not affect contrast resolution — a semi-transparent color
132
- * has no fixed perceived lightness, so `contrast` and `opacity`
221
+ * has no fixed perceived tone, so `contrast` and `opacity`
133
222
  * should not be combined (a console.warn is emitted).
134
223
  */
135
224
  opacity?: number;
@@ -161,12 +250,6 @@ interface ShadowTuning {
161
250
  * 0 = pure fg hue, 1 = pure bg hue. Default: 0.2.
162
251
  */
163
252
  bgHueBlend?: number;
164
- /**
165
- * Power curve for dark-scheme shadow alpha (0-1). Default: 0.4.
166
- * Lower values compress low/mid-intensity shadows more aggressively.
167
- * 1.0 = no dampening (identity).
168
- */
169
- darkShadowCurve?: number;
170
253
  }
171
254
  interface ShadowColorDef {
172
255
  type: 'shadow';
@@ -221,12 +304,13 @@ interface MixColorDef {
221
304
  */
222
305
  space?: 'okhsl' | 'srgb';
223
306
  /**
224
- * Minimum WCAG contrast between the base and the resulting color.
307
+ * Minimum contrast between the base and the resulting color.
225
308
  * In 'opaque' mode, adjusts the mix ratio to meet contrast.
226
309
  * In 'transparent' mode, adjusts opacity to meet contrast against the composite.
227
- * Supports [normal, highContrast] pair.
310
+ * A bare number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the
311
+ * metric. Supports [normal, highContrast] pair.
228
312
  */
229
- contrast?: HCPair<MinContrast>;
313
+ contrast?: HCPair<ContrastSpec>;
230
314
  /**
231
315
  * Whether this color is inherited by child themes created via `extend()`.
232
316
  * Default: true. Set to false to make this color local to the current theme.
@@ -235,14 +319,20 @@ interface MixColorDef {
235
319
  }
236
320
  type ColorDef = RegularColorDef | ShadowColorDef | MixColorDef;
237
321
  type ColorMap = Record<string, ColorDef>;
238
- /** Resolved color for a single scheme variant. */
322
+ /**
323
+ * Resolved color for a single scheme variant.
324
+ *
325
+ * Stored in OKHST: `h` / `s` are OKHSL hue/saturation, `t` is the canonical
326
+ * contrast-uniform tone (0–1, reference eps). Convert to OKHSL lightness via
327
+ * `variantToOkhsl` at the rendering / luminance edges.
328
+ */
239
329
  interface ResolvedColorVariant {
240
330
  /** OKHSL hue (0–360). */
241
331
  h: number;
242
332
  /** OKHSL saturation (0–1). */
243
333
  s: number;
244
- /** OKHSL lightness (0–1). */
245
- l: number;
334
+ /** Canonical tone (0–1, reference eps). */
335
+ t: number;
246
336
  /** Opacity (0–1). Default: 1. */
247
337
  alpha: number;
248
338
  }
@@ -256,20 +346,33 @@ interface ResolvedColor {
256
346
  /** Adaptation mode. Present only for regular colors, omitted for shadows. */
257
347
  mode?: AdaptationMode;
258
348
  }
349
+ /**
350
+ * A scheme tone window.
351
+ * - `[lo, hi]`: OKHSL-lightness endpoints (0–100) the authored tone is
352
+ * remapped into, using the reference eps `0.05`. The common form.
353
+ * - `{ lo, hi, eps }`: same, with an explicit render curvature `eps`
354
+ * (advanced — most palettes never need this).
355
+ * - `false`: disable clamping (full range `[0, 100]` at the reference eps).
356
+ * This removes the *boundaries*, not the tone curve.
357
+ */
358
+ type ToneWindow = false | [number, number] | {
359
+ lo: number;
360
+ hi: number;
361
+ eps: number;
362
+ };
259
363
  interface GlazeConfig {
260
- /** Light scheme lightness window [lo, hi]. Default: [10, 100]. */
261
- lightLightness?: [number, number];
262
- /** Dark scheme lightness window [lo, hi]. Default: [15, 95]. */
263
- darkLightness?: [number, number];
364
+ /** Light scheme tone window — `[lo, hi]` (default `[13, 100]`), `{ lo, hi, eps }` for advanced eps tuning, or `false` to disable clamping. */
365
+ lightTone?: ToneWindow;
366
+ /** Dark scheme tone window — `[lo, hi]` (default `[10, 95]`), `{ lo, hi, eps }`, or `false` to disable clamping. */
367
+ darkTone?: ToneWindow;
264
368
  /** Saturation reduction factor for dark scheme (0–1). Default: 0.1. */
265
369
  darkDesaturation?: number;
266
370
  /**
267
- * Möbius beta for dark auto-inversion (0–1).
268
- * Lower values expand subtle near-white distinctions in dark mode.
269
- * Set to 1 for linear (legacy) behavior. Default: 0.5.
270
- * Accepts [normal, highContrast] pair for separate HC tuning.
371
+ * Saturation taper toward the tone extremes (0–1). The fraction of the
372
+ * tone range over which saturation rolls off at each end, where in-gamut
373
+ * chroma collapses. Default: 0.15. Set to 0 to disable.
271
374
  */
272
- darkCurve?: HCPair<number>;
375
+ saturationTaper?: number;
273
376
  /** State alias names for token export. */
274
377
  states?: {
275
378
  dark?: string;
@@ -279,44 +382,246 @@ interface GlazeConfig {
279
382
  modes?: GlazeOutputModes;
280
383
  /** Default tuning for all shadow colors. Per-color tuning merges field-by-field. */
281
384
  shadowTuning?: ShadowTuning;
385
+ /**
386
+ * Automatically flip tone direction when contrast can't be met.
387
+ *
388
+ * When enabled (default `true`), the solver searches the requested
389
+ * tone direction first. If that direction can't reach the target,
390
+ * it tries the opposite direction and uses it when it passes. If neither
391
+ * side passes, the tone is pinned to the requested-direction
392
+ * extreme and a warning is emitted.
393
+ *
394
+ * Set to `false` for strict "no flip" behavior. The opposite
395
+ * direction is never considered: if the requested direction can't
396
+ * meet the target, the tone is pinned to its extreme (never
397
+ * falls back to the originally requested tone).
398
+ */
399
+ autoFlip?: boolean;
282
400
  }
283
401
  interface GlazeConfigResolved {
284
- lightLightness: [number, number];
285
- darkLightness: [number, number];
402
+ lightTone: ToneWindow;
403
+ darkTone: ToneWindow;
286
404
  darkDesaturation: number;
287
- darkCurve: HCPair<number>;
405
+ saturationTaper: number;
288
406
  states: {
289
407
  dark: string;
290
408
  highContrast: string;
291
409
  };
292
410
  modes: Required<GlazeOutputModes>;
293
411
  shadowTuning?: ShadowTuning;
412
+ autoFlip: boolean;
413
+ }
414
+ /**
415
+ * Per-instance config override for `glaze.color()` and `glaze()` themes.
416
+ * Fields that are set take priority over the live global config. Fields
417
+ * that are omitted fall through to the live global at resolve time.
418
+ *
419
+ * `false` for a tone window disables clamping (full range at reference eps).
420
+ */
421
+ interface GlazeConfigOverride {
422
+ /** Light scheme tone window, or `false` to disable clamping. */
423
+ lightTone?: ToneWindow;
424
+ /** Dark scheme tone window, or `false` to disable clamping. */
425
+ darkTone?: ToneWindow;
426
+ /** Saturation reduction factor for dark scheme (0–1). */
427
+ darkDesaturation?: number;
428
+ /** Saturation taper toward the tone extremes (0–1). */
429
+ saturationTaper?: number;
430
+ /** Whether to auto-flip tone when contrast can't be met. */
431
+ autoFlip?: boolean;
432
+ /**
433
+ * Shadow tuning defaults. Only meaningful for themes; harmless on
434
+ * standalone color tokens.
435
+ */
436
+ shadowTuning?: ShadowTuning;
294
437
  }
295
438
  /** Serialized theme configuration (no resolved values). */
296
439
  interface GlazeThemeExport {
297
440
  hue: number;
298
441
  saturation: number;
299
442
  colors: ColorMap;
443
+ /** Per-theme config override, if any. */
444
+ config?: GlazeConfigOverride;
300
445
  }
301
446
  /** Input for `glaze.shadow()` standalone factory. */
302
447
  interface GlazeShadowInput {
303
- /** Background color — hex string or OKHSL { h, s (0-1), l (0-1) }. */
304
- bg: HexColor | OkhslColor;
305
- /** Foreground color for tinting + intensity modulation. */
306
- fg?: HexColor | OkhslColor;
448
+ /**
449
+ * Background color — accepts any `GlazeColorValue` form: hex
450
+ * (`#rgb` / `#rrggbb` / `#rrggbbaa`), `rgb()` / `hsl()` / `okhsl()`
451
+ * / `oklch()` strings, or literal objects (`{ r, g, b }`, `{ h, s, l }`,
452
+ * `{ l, c, h }`). Alpha components are dropped with a warning.
453
+ */
454
+ bg: GlazeColorValue;
455
+ /**
456
+ * Foreground color for tinting + intensity modulation. Accepts the
457
+ * same forms as `bg`.
458
+ */
459
+ fg?: GlazeColorValue;
307
460
  /** Intensity 0-100. */
308
461
  intensity: number;
309
462
  tuning?: ShadowTuning;
310
- /** Whether to apply dark-scheme dampening. Default: false. */
311
- dark?: boolean;
312
463
  }
313
- /** Input for `glaze.color()` standalone factory. */
464
+ /** Input for the structured `glaze.color()` overload. */
314
465
  interface GlazeColorInput {
315
466
  hue: number;
316
467
  saturation: number;
317
- lightness: HCPair<number>;
468
+ tone: HCPair<number | ExtremeValue>;
469
+ saturationFactor?: number;
470
+ mode?: AdaptationMode;
471
+ /** Flip out-of-bounds results instead of clamping. Default: global `autoFlip`. */
472
+ flip?: boolean;
473
+ /**
474
+ * Fixed opacity (0–1). Output includes alpha in the CSS value.
475
+ * Combining with `contrast` is not recommended (perceived tone
476
+ * becomes unpredictable) — a `console.warn` is emitted in that case.
477
+ */
478
+ opacity?: number;
479
+ /**
480
+ * Optional dependency on another color. Same semantics as
481
+ * `GlazeColorOverrides.base` — `contrast` and relative `tone`
482
+ * anchor to the base per scheme.
483
+ */
484
+ base?: GlazeColorToken | GlazeColorValue;
485
+ /**
486
+ * Contrast floor against `base`. Requires `base` to be set. A bare
487
+ * number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the metric.
488
+ */
489
+ contrast?: HCPair<ContrastSpec>;
490
+ /**
491
+ * Optional human-readable name for the token. Used in error and
492
+ * warning messages (otherwise an internal name like `"value"` is
493
+ * used). Does not affect output keys.
494
+ */
495
+ name?: string;
496
+ }
497
+ /**
498
+ * Any single-color input form accepted by the value-shorthand
499
+ * overload of `glaze.color()`.
500
+ *
501
+ * Strings cover hex (`#rgb` / `#rrggbb` / `#rrggbbaa`, alpha dropped
502
+ * with a warning) and the four CSS color functions Glaze itself emits:
503
+ * `rgb()`, `hsl()`, `okhsl()`, `oklch()` (alpha components also dropped
504
+ * with a warning).
505
+ *
506
+ * Literal object forms:
507
+ * - `{ h, s, l }` — OKHSL (h: 0–360, s/l: 0–1). Passing 0–100 for `s`/`l`
508
+ * throws with a hint to use the structured form.
509
+ * - `{ h, s, t }` — OKHST (h: 0–360, s/t: 0–1). Tone in 0–1.
510
+ * - `{ r, g, b }` — sRGB 0–255.
511
+ * - `{ l, c, h }` — OKLCh (L/C: 0–1, H: degrees), same as `oklch()` strings.
512
+ */
513
+ type GlazeColorValue = string | OkhslColor | OkhstColor | RgbColor | OklchColor;
514
+ /** Color overrides for the `from` and value-shorthand inputs. */
515
+ interface GlazeColorOverrides {
516
+ /**
517
+ * Override hue. Number is absolute (0–360); `'+N'`/`'-N'` is relative
518
+ * to the extracted (or overridden) seed hue — same semantics as
519
+ * `RegularColorDef.hue`.
520
+ */
521
+ hue?: number | RelativeValue;
522
+ /** Override seed saturation (0–100). Default: extracted from value. */
523
+ saturation?: number;
524
+ /**
525
+ * Override tone. Number is absolute (0–100, contrast-uniform); `'+N'`/`'-N'`
526
+ * is relative to the literal seed (the value passed to `glaze.color()`);
527
+ * `'max'` / `'min'` force to the scheme's tone extreme.
528
+ * Supports HCPair for high-contrast.
529
+ */
530
+ tone?: HCPair<ToneValue>;
531
+ /** Saturation multiplier on the seed (0–1). Default: 1. */
318
532
  saturationFactor?: number;
533
+ /**
534
+ * Adaptation mode. Defaults to `'auto'` for every input form, so
535
+ * colors automatically adapt between light and dark like an ordinary
536
+ * theme color. All value-shorthand inputs (strings and literal objects)
537
+ * preserve light tone (`lightTone: false`) and snapshot
538
+ * `globalConfig.darkTone` on the dark side. Only the structured
539
+ * `{ hue, saturation, tone }` form also snapshots
540
+ * `globalConfig.lightTone`.
541
+ *
542
+ * Pass `'fixed'` explicitly to opt back into the linear, non-
543
+ * inverting mapping; pass `'static'` to pin the same tone
544
+ * across every variant.
545
+ */
319
546
  mode?: AdaptationMode;
547
+ /**
548
+ * Flip out-of-bounds results (relative `tone` overshoot / unmet
549
+ * `contrast`) to the opposite side instead of clamping. Defaults to
550
+ * the global `autoFlip`.
551
+ */
552
+ flip?: boolean;
553
+ /**
554
+ * Contrast floor. By default solved against the literal seed
555
+ * (the value itself); when `base` is set, solved against the base's
556
+ * resolved variant per scheme. Same shape as `RegularColorDef.contrast`
557
+ * (bare number/preset = WCAG; `{ wcag }` / `{ apca }` to pick the metric).
558
+ */
559
+ contrast?: HCPair<ContrastSpec>;
560
+ /**
561
+ * Optional dependency on another color. Accepts either a
562
+ * `GlazeColorToken` (returned by another `glaze.color()`) or a raw
563
+ * `GlazeColorValue` (hex / CSS strings / `{ r, g, b }` / `{ h, s, l }` / …),
564
+ * which is automatically wrapped in `glaze.color(value)`.
565
+ *
566
+ * When set:
567
+ * - `contrast` is solved against the base's resolved variant
568
+ * per-scheme (light / dark / lightContrast / darkContrast).
569
+ * - Relative `tone: '+N'` / `'-N'` is anchored to the base's
570
+ * tone per-scheme (matches theme behavior for dependent colors).
571
+ * - Relative `hue: '+N'` / `'-N'` still anchors to the seed (the
572
+ * value passed to `glaze.color()`), not the base.
573
+ * - When the base was created via the structured form (with explicit
574
+ * `hue`/`saturation`/`tone`), it is resolved at full range
575
+ * (`lightTone: false`) for the linking math — ensuring the
576
+ * contrast/tone anchor matches the input tone, not the
577
+ * windowed output. The base's own `.resolve()` output is unaffected.
578
+ *
579
+ * The base token's `.resolve()` is called lazily on first resolve and
580
+ * its result is captured by reference; later mutations to the base's
581
+ * defining call don't apply (matches existing token snapshot semantics).
582
+ */
583
+ base?: GlazeColorToken | GlazeColorValue;
584
+ /**
585
+ * Fixed opacity (0–1). Output includes alpha in the CSS value.
586
+ * Combining with `contrast` is not recommended (perceived tone
587
+ * becomes unpredictable) — a `console.warn` is emitted in that case.
588
+ */
589
+ opacity?: number;
590
+ /**
591
+ * Optional human-readable name for the token. Used in error and
592
+ * warning messages (otherwise an internal name like `"value"` is
593
+ * used). Does not affect output keys.
594
+ */
595
+ name?: string;
596
+ }
597
+ /**
598
+ * Object input for `glaze.color()` that carries a raw color value plus
599
+ * optional color overrides in the same object.
600
+ *
601
+ * ```ts
602
+ * glaze.color({ from: '#1a1a2e', base: bg, contrast: 'AA' })
603
+ * glaze.color({ from: { r: 38, g: 252, b: 178 }, tone: '+10' })
604
+ * ```
605
+ */
606
+ interface GlazeFromInput extends GlazeColorOverrides {
607
+ /** The source color value. Accepts the same forms as a bare `GlazeColorValue`. */
608
+ from: GlazeColorValue;
609
+ }
610
+ /** Options for `GlazeColorToken.css()`. */
611
+ interface GlazeColorCssOptions {
612
+ /**
613
+ * Custom property base name (without leading `--`). Required.
614
+ * Becomes the variable identifier in the output, e.g.
615
+ * `name: 'brand'` → `--brand-color: …`.
616
+ */
617
+ name: string;
618
+ /** Output color format. Default: 'rgb' (matches `theme.css` default). */
619
+ format?: GlazeColorFormat;
620
+ /**
621
+ * Suffix appended to the name. Default: '-color' (matches
622
+ * `theme.css` default).
623
+ */
624
+ suffix?: string;
320
625
  }
321
626
  /** Return type for `glaze.color()`. */
322
627
  interface GlazeColorToken {
@@ -327,11 +632,79 @@ interface GlazeColorToken {
327
632
  /**
328
633
  * Export as a tasty style-to-state binding (no color name key).
329
634
  * Uses `#name` keys and state aliases (`''`, `@dark`, etc.).
330
- * @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
635
+ * @see https://tasty.style/docs
331
636
  */
332
637
  tasty(options?: GlazeTokenOptions): Record<string, string>;
333
638
  /** Export as a flat JSON map (no color name key). */
334
639
  json(options?: GlazeJsonOptions): Record<string, string>;
640
+ /** Export as CSS custom property declarations grouped by scheme variant. */
641
+ css(options: GlazeColorCssOptions): GlazeCssResult;
642
+ /**
643
+ * Serialize the token as a JSON-safe object. Captures the original
644
+ * input value, overrides, and config so it can be rehydrated via
645
+ * `glaze.colorFrom(...)`. `base` is recursively serialized.
646
+ */
647
+ export(): GlazeColorTokenExport;
648
+ }
649
+ /**
650
+ * JSON-safe serialization of a `glaze.color()` token. Pass to
651
+ * `glaze.colorFrom(...)` to rehydrate.
652
+ */
653
+ interface GlazeColorTokenExport {
654
+ /**
655
+ * Discriminator for the source overload that created the token.
656
+ * - `'value'`: created via `glaze.color(value)` or `glaze.color({ from, ...overrides })`.
657
+ * - `'structured'`: created via `glaze.color({ hue, saturation, ... })`.
658
+ */
659
+ form: 'value' | 'structured';
660
+ /** Original input. For `form: 'value'` this is the raw `GlazeColorValue`; for `form: 'structured'` this is the structured input. */
661
+ input: GlazeColorValue | GlazeColorInputExport;
662
+ /**
663
+ * Overrides recorded at creation time. `base` is recursively
664
+ * serialized. Only present for `form: 'value'`.
665
+ */
666
+ overrides?: GlazeColorOverridesExport;
667
+ /**
668
+ * Effective config snapshot at creation time — captures the merged
669
+ * result of the global config + any per-call override at the moment
670
+ * the token was created. Only fields that differ from their
671
+ * post-merge defaults are present. Used by `glaze.colorFrom()` to
672
+ * reproduce deterministic behavior across `configure()` calls.
673
+ */
674
+ config?: GlazeConfigOverride;
675
+ }
676
+ /**
677
+ * Serializable shape of a structured `glaze.color({...})` input.
678
+ * Differs from `GlazeColorInput` only in that `base` is replaced by an
679
+ * `export` instead of a token reference.
680
+ */
681
+ interface GlazeColorInputExport {
682
+ hue: number;
683
+ saturation: number;
684
+ tone: HCPair<number | ExtremeValue>;
685
+ saturationFactor?: number;
686
+ mode?: AdaptationMode;
687
+ flip?: boolean;
688
+ opacity?: number;
689
+ base?: GlazeColorTokenExport | GlazeColorValue;
690
+ contrast?: HCPair<ContrastSpec>;
691
+ name?: string;
692
+ }
693
+ /**
694
+ * Serializable shape of `GlazeColorOverrides`. `base` is replaced by
695
+ * its export (or left as a `GlazeColorValue` if it was originally a value).
696
+ */
697
+ interface GlazeColorOverridesExport {
698
+ hue?: number | RelativeValue;
699
+ saturation?: number;
700
+ tone?: HCPair<ToneValue>;
701
+ saturationFactor?: number;
702
+ mode?: AdaptationMode;
703
+ flip?: boolean;
704
+ contrast?: HCPair<ContrastSpec>;
705
+ base?: GlazeColorTokenExport | GlazeColorValue;
706
+ opacity?: number;
707
+ name?: string;
335
708
  }
336
709
  interface GlazeTheme {
337
710
  /** The hue seed (0–360). */
@@ -371,7 +744,7 @@ interface GlazeTheme {
371
744
  * Export as tasty style-to-state bindings.
372
745
  * Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
373
746
  * Spread into component styles or register as a recipe via `configure({ recipes })`.
374
- * @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
747
+ * @see https://tasty.style/docs
375
748
  */
376
749
  tasty(options?: GlazeTokenOptions): Record<string, Record<string, string>>;
377
750
  /** Export as plain JSON. */
@@ -383,6 +756,8 @@ interface GlazeExtendOptions {
383
756
  hue?: number;
384
757
  saturation?: number;
385
758
  colors?: ColorMap;
759
+ /** Config override for the child theme. Merged with the parent's override. */
760
+ config?: GlazeConfigOverride;
386
761
  }
387
762
  interface GlazeTokenOptions {
388
763
  /** Prefix mode. `true` uses "<themeName>-", or provide a custom map. */
@@ -465,7 +840,7 @@ interface GlazePalette {
465
840
  * Export all themes as tasty style-to-state bindings.
466
841
  * Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
467
842
  * Prefix defaults to `true`. Inherits the palette-level `primary`.
468
- * @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
843
+ * @see https://tasty.style/docs
469
844
  */
470
845
  tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
471
846
  /** Export all themes as plain JSON grouped by theme name. */
@@ -481,44 +856,105 @@ type PaletteInput = Record<string, GlazeTheme>;
481
856
  /**
482
857
  * Create a single-hue glaze theme.
483
858
  *
859
+ * An optional `config` override can be supplied to customize the resolve
860
+ * behavior for this theme (tone windows, saturation taper, etc.). The
861
+ * override is **merged over the live global config at resolve time** —
862
+ * the theme still reacts to later `configure()` calls for fields it
863
+ * didn't override.
864
+ *
484
865
  * @example
485
866
  * ```ts
486
- * const primary = glaze({ hue: 280, saturation: 80 });
487
- * // or shorthand:
488
867
  * const primary = glaze(280, 80);
868
+ * // or shorthand:
869
+ * const primary = glaze({ hue: 280, saturation: 80 });
870
+ * // with config override:
871
+ * const raw = glaze(280, 80, { lightTone: false });
489
872
  * ```
490
873
  */
491
874
  declare function glaze(hueOrOptions: number | {
492
875
  hue: number;
493
876
  saturation: number;
494
- }, saturation?: number): GlazeTheme;
877
+ }, saturation?: number, config?: GlazeConfigOverride): GlazeTheme;
495
878
  declare namespace glaze {
496
879
  var configure: (config: GlazeConfig) => void;
497
- var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => {
498
- tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
499
- tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
500
- json(options?: GlazeJsonOptions & {
501
- prefix?: boolean | Record<string, string>;
502
- }): Record<string, Record<string, Record<string, string>>>;
503
- css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
504
- };
880
+ var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => GlazePalette;
505
881
  var from: (data: GlazeThemeExport) => GlazeTheme;
506
- var color: (input: GlazeColorInput) => GlazeColorToken;
882
+ var color: (input: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?: GlazeConfigOverride) => GlazeColorToken;
507
883
  var shadow: (input: GlazeShadowInput) => ResolvedColorVariant;
508
884
  var format: (variant: ResolvedColorVariant, colorFormat?: GlazeColorFormat) => string;
509
885
  var fromHex: (hex: string) => GlazeTheme;
510
886
  var fromRgb: (r: number, g: number, b: number) => GlazeTheme;
887
+ var colorFrom: (data: GlazeColorTokenExport) => GlazeColorToken;
511
888
  var getConfig: () => GlazeConfigResolved;
512
889
  var resetConfig: () => void;
513
890
  }
514
891
  //#endregion
892
+ //#region src/okhst.d.ts
893
+ /**
894
+ * Reference eps for the OKHST color space. WCAG 2 contrast is
895
+ * `(Y_hi + 0.05) / (Y_lo + 0.05)`, so an eps of `0.05` makes equal tone
896
+ * steps yield equal WCAG contrast. This is the canonical eps used by
897
+ * `okhst()` input, `{ h, s, t }` input, stored `ResolvedColorVariant.t`,
898
+ * relative `tone` offsets, and the contrast solver.
899
+ */
900
+ declare const REF_EPS = 0.05;
901
+ /**
902
+ * Map a luminance `Y` (0–1) to tone (0–100) at the given eps.
903
+ * `toneFromY(0) === 0` and `toneFromY(1) === 100` for any eps.
904
+ */
905
+ declare function toneFromY(y: number, eps?: number): number;
906
+ /** Map a tone (0–100) back to luminance (0–1). Inverse of {@link toneFromY}. */
907
+ declare function yFromTone(t: number, eps?: number): number;
908
+ /** OKHSL lightness (0–1) -> tone (0–100). */
909
+ declare function toTone(l: number, eps?: number): number;
910
+ /** Tone (0–100) -> OKHSL lightness (0–1). Inverse of {@link toTone}. */
911
+ declare function fromTone(t: number, eps?: number): number;
912
+ /** Convert OKHST `{ h, s, t }` (t in 0–1) to OKHSL `{ h, s, l }`. */
913
+ declare function okhstToOkhsl(c: {
914
+ h: number;
915
+ s: number;
916
+ t: number;
917
+ }): {
918
+ h: number;
919
+ s: number;
920
+ l: number;
921
+ };
922
+ /** Convert OKHSL `{ h, s, l }` to OKHST `{ h, s, t }` (t in 0–1). */
923
+ declare function okhslToOkhst(c: {
924
+ h: number;
925
+ s: number;
926
+ l: number;
927
+ }): {
928
+ h: number;
929
+ s: number;
930
+ t: number;
931
+ };
932
+ /**
933
+ * Edge adapter: a resolved variant stores canonical tone `t` (0–1). Convert
934
+ * it to the OKHSL `{ h, s, l }` the formatters and luminance pipeline expect.
935
+ */
936
+ declare function variantToOkhsl(v: {
937
+ h: number;
938
+ s: number;
939
+ t: number;
940
+ }): {
941
+ h: number;
942
+ s: number;
943
+ l: number;
944
+ };
945
+ //#endregion
515
946
  //#region src/okhsl-color-math.d.ts
516
947
  /**
517
948
  * OKHSL color math primitives for the glaze theme generator.
518
949
  *
519
- * Provides bidirectional OKHSL ↔ sRGB conversion, relative luminance
520
- * computation for WCAG 2 contrast calculations, and multi-format output
521
- * (okhsl, rgb, hsl, oklch).
950
+ * Provides bidirectional OKHSL ↔ sRGB conversion, luminance computation
951
+ * for both contrast metrics (WCAG 2 relative luminance and APCA screen
952
+ * luminance `Ys`), and multi-format output (okhsl, rgb, hsl, oklch).
953
+ */
954
+ type Vec3 = [number, number, number];
955
+ /**
956
+ * OKHSL toe function: maps OKLab lightness L to perceptual lightness l.
957
+ * Exported for the OKHST tone transfers in `okhst.ts`.
522
958
  */
523
959
  /**
524
960
  * Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to OKLab [L, a, b].
@@ -548,16 +984,42 @@ declare function okhslToSrgb(h: number, s: number, l: number): [number, number,
548
984
  * This avoids over/under-estimating luminance for out-of-gamut OKHSL colors.
549
985
  */
550
986
  declare function gamutClampedLuminance(linearRgb: [number, number, number]): number;
987
+ /**
988
+ * Convert OKLab to OKHSL.
989
+ * Input: [L, a, b] where L: 0–1, a/b: roughly -0.5 to 0.5.
990
+ * Returns [h, s, l] where h: 0–360, s: 0–1, l: 0–1.
991
+ */
992
+ declare const oklabToOkhsl: (lab: Vec3) => Vec3;
551
993
  /**
552
994
  * Convert gamma-encoded sRGB (0–1 per channel) to OKHSL.
553
995
  * Returns [h, s, l] where h: 0–360, s: 0–1, l: 0–1.
554
996
  */
555
997
  declare function srgbToOkhsl(rgb: [number, number, number]): [number, number, number];
998
+ /**
999
+ * Convert CSS HSL (sRGB-based) to gamma-encoded sRGB [r, g, b] in 0–1 range.
1000
+ * h: 0–360, s: 0–1, l: 0–1.
1001
+ *
1002
+ * Note: CSS HSL is not the same as OKHSL — it's HSL in the sRGB color space.
1003
+ * Use this when parsing `hsl(...)` strings before passing to `srgbToOkhsl`.
1004
+ */
1005
+ declare function hslToSrgb(h: number, s: number, l: number): [number, number, number];
556
1006
  /**
557
1007
  * Parse a hex color string (#rgb or #rrggbb) to sRGB [r, g, b] in 0–1 range.
558
1008
  * Returns null if the string is not a valid hex color.
1009
+ *
1010
+ * For 8-digit hex (`#rrggbbaa`) and 4-digit hex (`#rgba`) with alpha,
1011
+ * use {@link parseHexAlpha}.
559
1012
  */
560
1013
  declare function parseHex(hex: string): [number, number, number] | null;
1014
+ /**
1015
+ * Parse a hex color string (#rgb, #rrggbb, #rgba, or #rrggbbaa) to
1016
+ * sRGB [r, g, b] in 0–1 range plus an optional alpha (0–1).
1017
+ * Returns null if the string is not a valid hex color.
1018
+ */
1019
+ declare function parseHexAlpha(hex: string): {
1020
+ rgb: [number, number, number];
1021
+ alpha?: number;
1022
+ } | null;
561
1023
  /**
562
1024
  * Format OKHSL values as a CSS `okhsl(H S% L%)` string.
563
1025
  * h: 0–360, s: 0–100, l: 0–100 (percentage scale for s and l).
@@ -580,5 +1042,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
580
1042
  */
581
1043
  declare function formatOklch(h: number, s: number, l: number): string;
582
1044
  //#endregion
583
- export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorToken, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, parseHex, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
1045
+ export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type ContrastSpec, type ExtremeValue, type FindToneForContrastOptions, type FindToneForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorCssOptions, type GlazeColorFormat, type GlazeColorInput, type GlazeColorInputExport, type GlazeColorOverrides, type GlazeColorOverridesExport, type GlazeColorToken, type GlazeColorTokenExport, type GlazeColorValue, type GlazeConfig, type GlazeConfigOverride, type GlazeConfigResolved, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeFromInput, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type OkhstColor, type OklchColor, REF_EPS, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ResolvedContrast, type RgbColor, type ShadowColorDef, type ShadowTuning, type ToneValue, type ToneWindow, apcaContrast, contrastRatioFromLuminance, findToneForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, fromTone, gamutClampedLuminance, glaze, hslToSrgb, okhslToLinearSrgb, okhslToOkhst, okhslToOklab, okhslToSrgb, okhstToOkhsl, oklabToOkhsl, parseHex, parseHexAlpha, relativeLuminanceFromLinearRgb, resolveContrastForMode, resolveMinContrast, srgbToOkhsl, toTone, toneFromY, variantToOkhsl, yFromTone };
584
1046
  //# sourceMappingURL=index.d.cts.map