@tenphi/glaze 0.13.0 → 0.14.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/dist/index.d.mts CHANGED
@@ -1,78 +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;
29
- /**
30
- * Preferred search direction before auto-flip is considered.
31
- *
32
- * Theme resolution sets this from the requested lightness relative to
33
- * the base color so `autoFlip: false` preserves the authored direction.
34
- * When omitted, the solver falls back to the side whose extreme has
35
- * higher contrast against the base.
36
- */
40
+ /** Preferred search direction before auto-flip is considered. */
37
41
  initialDirection?: 'lighter' | 'darker';
42
+ /** Auto-flip tone direction when contrast can't be met. Default: false. */
43
+ flip?: boolean;
38
44
  /**
39
- * Auto-flip lightness direction when contrast can't be met.
40
- *
41
- * When `true`, the solver searches the initial direction first. If that side
42
- * doesn't reach the target, it tries the opposite direction and
43
- * uses it when it passes. If neither side passes, it returns the
44
- * extreme lightness of the initial direction.
45
- *
46
- * When `false`, only the initial direction is considered. If it
47
- * doesn't reach the target, the result is pinned to the initial
48
- * direction's extreme — never to the original preferred lightness.
49
- *
50
- * Default: false.
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.
51
49
  */
52
- flip?: boolean;
50
+ saturationTaper?: number;
53
51
  }
54
- interface FindLightnessForContrastResult {
55
- /** Chosen lightness in 0–1. */
56
- lightness: number;
57
- /** 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). */
58
56
  contrast: number;
59
57
  /** Whether the target was reached. */
60
58
  met: boolean;
61
59
  /** Which branch was selected. */
62
60
  branch: 'lighter' | 'darker' | 'preferred';
63
- /**
64
- * Whether the result was auto-flipped to the opposite direction.
65
- * Only set when the initial direction failed and the opposite
66
- * direction satisfied the target.
67
- */
61
+ /** Whether the result auto-flipped to the opposite direction. */
68
62
  flipped?: boolean;
69
63
  }
70
- declare function resolveMinContrast(value: MinContrast$1): number;
71
64
  /**
72
- * Find the OKHSL lightness that satisfies a WCAG 2 contrast target
73
- * 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.
74
67
  */
75
- declare function findLightnessForContrast(options: FindLightnessForContrastOptions): FindLightnessForContrastResult;
68
+ declare function findToneForContrast(options: FindToneForContrastOptions): FindToneForContrastResult;
76
69
  interface FindValueForMixContrastOptions {
77
70
  /** Preferred mix parameter (0–1). */
78
71
  preferredValue: number;
@@ -80,62 +73,69 @@ interface FindValueForMixContrastOptions {
80
73
  baseLinearRgb: LinearRgb;
81
74
  /** Target color as linear sRGB. */
82
75
  targetLinearRgb: LinearRgb;
83
- /** WCAG contrast target. */
84
- contrast: MinContrast$1;
85
- /**
86
- * Compute the luminance of the mixed color at parameter t.
87
- * For opaque: luminance of OKHSL-interpolated color.
88
- * For transparent: luminance of alpha-composited color over base.
89
- */
76
+ /** Resolved contrast floor (metric + target). */
77
+ contrast: ResolvedContrast;
78
+ /** Compute the luminance of the mixed color at parameter t. */
90
79
  luminanceAtValue: (t: number) => number;
91
80
  /** Convergence threshold. Default: 1e-4. */
92
81
  epsilon?: number;
93
82
  /** Maximum binary-search iterations per branch. Default: 20. */
94
83
  maxIterations?: number;
95
- /**
96
- * Auto-flip mix direction when contrast can't be met.
97
- *
98
- * When `true`, the solver searches the initial direction first
99
- * (the side whose extreme has higher contrast against the base).
100
- * If that side doesn't reach the target, it tries the opposite
101
- * direction and uses it when it passes. If neither side passes,
102
- * it returns the extreme mix value of the initial direction.
103
- *
104
- * When `false`, only the initial direction is considered. If it
105
- * doesn't reach the target, the result is pinned to the initial
106
- * direction's extreme — never to the original preferred value.
107
- *
108
- * Default: false.
109
- */
84
+ /** Auto-flip mix direction when contrast can't be met. Default: false. */
110
85
  flip?: boolean;
111
86
  }
112
87
  interface FindValueForMixContrastResult {
113
- /** Chosen mix parameter (0–1). */
114
88
  value: number;
115
- /** Achieved WCAG contrast ratio. */
116
89
  contrast: number;
117
- /** Whether the target was reached. */
118
90
  met: boolean;
119
- /**
120
- * Whether the result was auto-flipped to the opposite direction.
121
- * Only set when the initial direction failed and the opposite
122
- * direction satisfied the target.
123
- */
124
91
  flipped?: boolean;
125
92
  }
126
93
  /**
127
- * Find the mix parameter (ratio or opacity) that satisfies a WCAG 2 contrast
128
- * 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.
129
96
  */
130
97
  declare function findValueForMixContrast(options: FindValueForMixContrastOptions): FindValueForMixContrastResult;
131
98
  //#endregion
132
99
  //#region src/types.d.ts
133
100
  /** A value or [normal, high-contrast] pair. */
134
101
  type HCPair<T> = T | [T, T];
102
+ /** Bare WCAG contrast target: a ratio number or a named preset. */
135
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
+ };
136
120
  type AdaptationMode = 'auto' | 'fixed' | 'static';
137
121
  /** A signed relative offset string, e.g. '+20' or '-15.5'. */
138
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;
139
139
  /** Color format for output. */
140
140
  type GlazeColorFormat = 'okhsl' | 'rgb' | 'hsl' | 'oklch';
141
141
  /**
@@ -156,6 +156,15 @@ interface OkhslColor {
156
156
  s: number;
157
157
  l: number;
158
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
+ }
159
168
  /** sRGB components in 0–255 (value-shorthand object form). */
160
169
  interface RgbColor {
161
170
  r: number;
@@ -170,11 +179,12 @@ interface OklchColor {
170
179
  }
171
180
  interface RegularColorDef {
172
181
  /**
173
- * Lightness value (0–100).
174
- * - Number: absolute lightness.
175
- * - 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).
176
186
  */
177
- lightness?: HCPair<number | RelativeValue>;
187
+ tone?: HCPair<ToneValue>;
178
188
  /** Saturation factor applied to the seed saturation (0–1, default: 1). */
179
189
  saturation?: number;
180
190
  /**
@@ -185,15 +195,30 @@ interface RegularColorDef {
185
195
  hue?: number | RelativeValue;
186
196
  /** Name of another color in the same theme (dependent color). */
187
197
  base?: string;
188
- /** WCAG contrast ratio floor against the base color. */
189
- 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>;
190
203
  /** Adaptation mode. Default: 'auto'. */
191
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;
192
217
  /**
193
218
  * Fixed opacity (0–1).
194
219
  * Output includes alpha in the CSS value.
195
220
  * Does not affect contrast resolution — a semi-transparent color
196
- * has no fixed perceived lightness, so `contrast` and `opacity`
221
+ * has no fixed perceived tone, so `contrast` and `opacity`
197
222
  * should not be combined (a console.warn is emitted).
198
223
  */
199
224
  opacity?: number;
@@ -279,12 +304,13 @@ interface MixColorDef {
279
304
  */
280
305
  space?: 'okhsl' | 'srgb';
281
306
  /**
282
- * Minimum WCAG contrast between the base and the resulting color.
307
+ * Minimum contrast between the base and the resulting color.
283
308
  * In 'opaque' mode, adjusts the mix ratio to meet contrast.
284
309
  * In 'transparent' mode, adjusts opacity to meet contrast against the composite.
285
- * Supports [normal, highContrast] pair.
310
+ * A bare number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the
311
+ * metric. Supports [normal, highContrast] pair.
286
312
  */
287
- contrast?: HCPair<MinContrast>;
313
+ contrast?: HCPair<ContrastSpec>;
288
314
  /**
289
315
  * Whether this color is inherited by child themes created via `extend()`.
290
316
  * Default: true. Set to false to make this color local to the current theme.
@@ -293,14 +319,20 @@ interface MixColorDef {
293
319
  }
294
320
  type ColorDef = RegularColorDef | ShadowColorDef | MixColorDef;
295
321
  type ColorMap = Record<string, ColorDef>;
296
- /** 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
+ */
297
329
  interface ResolvedColorVariant {
298
330
  /** OKHSL hue (0–360). */
299
331
  h: number;
300
332
  /** OKHSL saturation (0–1). */
301
333
  s: number;
302
- /** OKHSL lightness (0–1). */
303
- l: number;
334
+ /** Canonical tone (0–1, reference eps). */
335
+ t: number;
304
336
  /** Opacity (0–1). Default: 1. */
305
337
  alpha: number;
306
338
  }
@@ -315,24 +347,32 @@ interface ResolvedColor {
315
347
  mode?: AdaptationMode;
316
348
  }
317
349
  /**
318
- * Lightness window value. A `[lo, hi]` tuple (0–100) or `false` to disable
319
- * clamping entirely (equivalent to `[0, 100]`).
350
+ * A scheme tone window.
351
+ * - `[lo, hi]`: OKHSL-lightness endpoints (0100) 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.
320
357
  */
321
- type LightnessWindow = false | [number, number];
358
+ type ToneWindow = false | [number, number] | {
359
+ lo: number;
360
+ hi: number;
361
+ eps: number;
362
+ };
322
363
  interface GlazeConfig {
323
- /** Light scheme lightness window [lo, hi]. Default: [10, 100]. Pass `false` to disable clamping. */
324
- lightLightness?: LightnessWindow;
325
- /** Dark scheme lightness window [lo, hi]. Default: [15, 95]. Pass `false` to disable clamping. */
326
- darkLightness?: LightnessWindow;
364
+ /** Light scheme tone window — `[lo, hi]` (default `[10, 100]`), `{ lo, hi, eps }` for advanced eps tuning, or `false` to disable clamping. */
365
+ lightTone?: ToneWindow;
366
+ /** Dark scheme tone window — `[lo, hi]` (default `[15, 95]`), `{ lo, hi, eps }`, or `false` to disable clamping. */
367
+ darkTone?: ToneWindow;
327
368
  /** Saturation reduction factor for dark scheme (0–1). Default: 0.1. */
328
369
  darkDesaturation?: number;
329
370
  /**
330
- * Möbius beta for dark auto-inversion (0–1).
331
- * Lower values expand subtle near-white distinctions in dark mode.
332
- * Set to 1 for linear (legacy) behavior. Default: 0.5.
333
- * 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.
334
374
  */
335
- darkCurve?: HCPair<number>;
375
+ saturationTaper?: number;
336
376
  /** State alias names for token export. */
337
377
  states?: {
338
378
  dark?: string;
@@ -343,26 +383,26 @@ interface GlazeConfig {
343
383
  /** Default tuning for all shadow colors. Per-color tuning merges field-by-field. */
344
384
  shadowTuning?: ShadowTuning;
345
385
  /**
346
- * Automatically flip lightness direction when contrast can't be met.
386
+ * Automatically flip tone direction when contrast can't be met.
347
387
  *
348
388
  * When enabled (default `true`), the solver searches the requested
349
- * lightness direction first. If that direction can't reach the target,
389
+ * tone direction first. If that direction can't reach the target,
350
390
  * it tries the opposite direction and uses it when it passes. If neither
351
- * side passes, the lightness is pinned to the requested-direction
391
+ * side passes, the tone is pinned to the requested-direction
352
392
  * extreme and a warning is emitted.
353
393
  *
354
394
  * Set to `false` for strict "no flip" behavior. The opposite
355
395
  * direction is never considered: if the requested direction can't
356
- * meet the target, the lightness is pinned to its extreme (never
357
- * falls back to the originally requested lightness).
396
+ * meet the target, the tone is pinned to its extreme (never
397
+ * falls back to the originally requested tone).
358
398
  */
359
399
  autoFlip?: boolean;
360
400
  }
361
401
  interface GlazeConfigResolved {
362
- lightLightness: LightnessWindow;
363
- darkLightness: LightnessWindow;
402
+ lightTone: ToneWindow;
403
+ darkTone: ToneWindow;
364
404
  darkDesaturation: number;
365
- darkCurve: HCPair<number>;
405
+ saturationTaper: number;
366
406
  states: {
367
407
  dark: string;
368
408
  highContrast: string;
@@ -376,18 +416,18 @@ interface GlazeConfigResolved {
376
416
  * Fields that are set take priority over the live global config. Fields
377
417
  * that are omitted fall through to the live global at resolve time.
378
418
  *
379
- * `false` for a lightness window disables clamping (equivalent to `[0, 100]`).
419
+ * `false` for a tone window disables clamping (full range at reference eps).
380
420
  */
381
421
  interface GlazeConfigOverride {
382
- /** Light scheme lightness window, or `false` to disable clamping. */
383
- lightLightness?: LightnessWindow;
384
- /** Dark scheme lightness window, or `false` to disable clamping. */
385
- darkLightness?: LightnessWindow;
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;
386
426
  /** Saturation reduction factor for dark scheme (0–1). */
387
427
  darkDesaturation?: number;
388
- /** Möbius beta for dark auto-inversion. Accepts [normal, hc] pair. */
389
- darkCurve?: HCPair<number>;
390
- /** Whether to auto-flip lightness when contrast can't be met. */
428
+ /** Saturation taper toward the tone extremes (0–1). */
429
+ saturationTaper?: number;
430
+ /** Whether to auto-flip tone when contrast can't be met. */
391
431
  autoFlip?: boolean;
392
432
  /**
393
433
  * Shadow tuning defaults. Only meaningful for themes; harmless on
@@ -425,25 +465,28 @@ interface GlazeShadowInput {
425
465
  interface GlazeColorInput {
426
466
  hue: number;
427
467
  saturation: number;
428
- lightness: HCPair<number>;
468
+ tone: HCPair<number | ExtremeValue>;
429
469
  saturationFactor?: number;
430
470
  mode?: AdaptationMode;
471
+ /** Flip out-of-bounds results instead of clamping. Default: global `autoFlip`. */
472
+ flip?: boolean;
431
473
  /**
432
474
  * Fixed opacity (0–1). Output includes alpha in the CSS value.
433
- * Combining with `contrast` is not recommended (perceived lightness
475
+ * Combining with `contrast` is not recommended (perceived tone
434
476
  * becomes unpredictable) — a `console.warn` is emitted in that case.
435
477
  */
436
478
  opacity?: number;
437
479
  /**
438
480
  * Optional dependency on another color. Same semantics as
439
- * `GlazeColorOverrides.base` — `contrast` and relative `lightness`
481
+ * `GlazeColorOverrides.base` — `contrast` and relative `tone`
440
482
  * anchor to the base per scheme.
441
483
  */
442
484
  base?: GlazeColorToken | GlazeColorValue;
443
485
  /**
444
- * WCAG contrast floor against `base`. Requires `base` to be set.
486
+ * Contrast floor against `base`. Requires `base` to be set. A bare
487
+ * number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the metric.
445
488
  */
446
- contrast?: HCPair<MinContrast>;
489
+ contrast?: HCPair<ContrastSpec>;
447
490
  /**
448
491
  * Optional human-readable name for the token. Used in error and
449
492
  * warning messages (otherwise an internal name like `"value"` is
@@ -463,10 +506,11 @@ interface GlazeColorInput {
463
506
  * Literal object forms:
464
507
  * - `{ h, s, l }` — OKHSL (h: 0–360, s/l: 0–1). Passing 0–100 for `s`/`l`
465
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.
466
510
  * - `{ r, g, b }` — sRGB 0–255.
467
511
  * - `{ l, c, h }` — OKLCh (L/C: 0–1, H: degrees), same as `oklch()` strings.
468
512
  */
469
- type GlazeColorValue = string | OkhslColor | RgbColor | OklchColor;
513
+ type GlazeColorValue = string | OkhslColor | OkhstColor | RgbColor | OklchColor;
470
514
  /** Color overrides for the `from` and value-shorthand inputs. */
471
515
  interface GlazeColorOverrides {
472
516
  /**
@@ -478,33 +522,41 @@ interface GlazeColorOverrides {
478
522
  /** Override seed saturation (0–100). Default: extracted from value. */
479
523
  saturation?: number;
480
524
  /**
481
- * Override lightness. Number is absolute (0–100); `'+N'`/`'-N'` is
482
- * relative to the literal seed (the value passed to `glaze.color()`).
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.
483
528
  * Supports HCPair for high-contrast.
484
529
  */
485
- lightness?: HCPair<number | RelativeValue>;
530
+ tone?: HCPair<ToneValue>;
486
531
  /** Saturation multiplier on the seed (0–1). Default: 1. */
487
532
  saturationFactor?: number;
488
533
  /**
489
534
  * Adaptation mode. Defaults to `'auto'` for every input form, so
490
535
  * colors automatically adapt between light and dark like an ordinary
491
536
  * theme color. All value-shorthand inputs (strings and literal objects)
492
- * preserve light lightness (`lightLightness: false`) and snapshot
493
- * `globalConfig.darkLightness` on the dark side. Only the structured
494
- * `{ hue, saturation, lightness }` form also snapshots
495
- * `globalConfig.lightLightness`.
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`.
496
541
  *
497
- * Pass `'fixed'` explicitly to opt back into the legacy linear, non-
498
- * inverting mapping; pass `'static'` to pin the same lightness
542
+ * Pass `'fixed'` explicitly to opt back into the linear, non-
543
+ * inverting mapping; pass `'static'` to pin the same tone
499
544
  * across every variant.
500
545
  */
501
546
  mode?: AdaptationMode;
502
547
  /**
503
- * WCAG contrast floor. By default solved against the literal seed
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
504
555
  * (the value itself); when `base` is set, solved against the base's
505
- * resolved variant per scheme. Same shape as `RegularColorDef.contrast`.
556
+ * resolved variant per scheme. Same shape as `RegularColorDef.contrast`
557
+ * (bare number/preset = WCAG; `{ wcag }` / `{ apca }` to pick the metric).
506
558
  */
507
- contrast?: HCPair<MinContrast>;
559
+ contrast?: HCPair<ContrastSpec>;
508
560
  /**
509
561
  * Optional dependency on another color. Accepts either a
510
562
  * `GlazeColorToken` (returned by another `glaze.color()`) or a raw
@@ -514,14 +566,14 @@ interface GlazeColorOverrides {
514
566
  * When set:
515
567
  * - `contrast` is solved against the base's resolved variant
516
568
  * per-scheme (light / dark / lightContrast / darkContrast).
517
- * - Relative `lightness: '+N'` / `'-N'` is anchored to the base's
518
- * lightness per-scheme (matches theme behavior for dependent colors).
569
+ * - Relative `tone: '+N'` / `'-N'` is anchored to the base's
570
+ * tone per-scheme (matches theme behavior for dependent colors).
519
571
  * - Relative `hue: '+N'` / `'-N'` still anchors to the seed (the
520
572
  * value passed to `glaze.color()`), not the base.
521
573
  * - When the base was created via the structured form (with explicit
522
- * `hue`/`saturation`/`lightness`), it is resolved at full range
523
- * (`lightLightness: false`) for the linking math — ensuring the
524
- * contrast/lightness anchor matches the input lightness, not the
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
525
577
  * windowed output. The base's own `.resolve()` output is unaffected.
526
578
  *
527
579
  * The base token's `.resolve()` is called lazily on first resolve and
@@ -531,7 +583,7 @@ interface GlazeColorOverrides {
531
583
  base?: GlazeColorToken | GlazeColorValue;
532
584
  /**
533
585
  * Fixed opacity (0–1). Output includes alpha in the CSS value.
534
- * Combining with `contrast` is not recommended (perceived lightness
586
+ * Combining with `contrast` is not recommended (perceived tone
535
587
  * becomes unpredictable) — a `console.warn` is emitted in that case.
536
588
  */
537
589
  opacity?: number;
@@ -548,7 +600,7 @@ interface GlazeColorOverrides {
548
600
  *
549
601
  * ```ts
550
602
  * glaze.color({ from: '#1a1a2e', base: bg, contrast: 'AA' })
551
- * glaze.color({ from: { r: 38, g: 252, b: 178 }, lightness: '+10' })
603
+ * glaze.color({ from: { r: 38, g: 252, b: 178 }, tone: '+10' })
552
604
  * ```
553
605
  */
554
606
  interface GlazeFromInput extends GlazeColorOverrides {
@@ -629,12 +681,13 @@ interface GlazeColorTokenExport {
629
681
  interface GlazeColorInputExport {
630
682
  hue: number;
631
683
  saturation: number;
632
- lightness: HCPair<number>;
684
+ tone: HCPair<number | ExtremeValue>;
633
685
  saturationFactor?: number;
634
686
  mode?: AdaptationMode;
687
+ flip?: boolean;
635
688
  opacity?: number;
636
689
  base?: GlazeColorTokenExport | GlazeColorValue;
637
- contrast?: HCPair<MinContrast>;
690
+ contrast?: HCPair<ContrastSpec>;
638
691
  name?: string;
639
692
  }
640
693
  /**
@@ -644,10 +697,11 @@ interface GlazeColorInputExport {
644
697
  interface GlazeColorOverridesExport {
645
698
  hue?: number | RelativeValue;
646
699
  saturation?: number;
647
- lightness?: HCPair<number | RelativeValue>;
700
+ tone?: HCPair<ToneValue>;
648
701
  saturationFactor?: number;
649
702
  mode?: AdaptationMode;
650
- contrast?: HCPair<MinContrast>;
703
+ flip?: boolean;
704
+ contrast?: HCPair<ContrastSpec>;
651
705
  base?: GlazeColorTokenExport | GlazeColorValue;
652
706
  opacity?: number;
653
707
  name?: string;
@@ -803,7 +857,7 @@ type PaletteInput = Record<string, GlazeTheme>;
803
857
  * Create a single-hue glaze theme.
804
858
  *
805
859
  * An optional `config` override can be supplied to customize the resolve
806
- * behavior for this theme (lightness windows, dark curve, etc.). The
860
+ * behavior for this theme (tone windows, saturation taper, etc.). The
807
861
  * override is **merged over the live global config at resolve time** —
808
862
  * the theme still reacts to later `configure()` calls for fields it
809
863
  * didn't override.
@@ -814,7 +868,7 @@ type PaletteInput = Record<string, GlazeTheme>;
814
868
  * // or shorthand:
815
869
  * const primary = glaze({ hue: 280, saturation: 80 });
816
870
  * // with config override:
817
- * const raw = glaze(280, 80, { lightLightness: false });
871
+ * const raw = glaze(280, 80, { lightTone: false });
818
872
  * ```
819
873
  */
820
874
  declare function glaze(hueOrOptions: number | {
@@ -835,15 +889,73 @@ declare namespace glaze {
835
889
  var resetConfig: () => void;
836
890
  }
837
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
838
946
  //#region src/okhsl-color-math.d.ts
839
947
  /**
840
948
  * OKHSL color math primitives for the glaze theme generator.
841
949
  *
842
- * Provides bidirectional OKHSL ↔ sRGB conversion, relative luminance
843
- * computation for WCAG 2 contrast calculations, and multi-format output
844
- * (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).
845
953
  */
846
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`.
958
+ */
847
959
  /**
848
960
  * Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to OKLab [L, a, b].
849
961
  */
@@ -930,5 +1042,5 @@ declare function formatHsl(h: number, s: number, l: number): string;
930
1042
  */
931
1043
  declare function formatOklch(h: number, s: number, l: number): string;
932
1044
  //#endregion
933
- export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, 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 LightnessWindow, type MinContrast, type MixColorDef, type OkhslColor, type OklchColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type RgbColor, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, hslToSrgb, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, oklabToOkhsl, parseHex, parseHexAlpha, 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 };
934
1046
  //# sourceMappingURL=index.d.mts.map