@tenphi/glaze 2.0.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -102,9 +102,17 @@ interface FindToneForContrastOptions {
102
102
  epsilon?: number;
103
103
  /** Maximum binary-search iterations per branch. Default: 18. */
104
104
  maxIterations?: number;
105
- /** Preferred search direction before auto-flip is considered. */
105
+ /**
106
+ * Preferred search direction before auto-flip is considered. Default: the
107
+ * side whose bound scores higher (the only open side when `preferredTone`
108
+ * sits on a bound); a tie within float noise starts `'darker'`.
109
+ */
106
110
  initialDirection?: 'lighter' | 'darker';
107
- /** Auto-flip tone direction when contrast can't be met. Default: false. */
111
+ /**
112
+ * Also search the opposite direction. Default: false. When both directions
113
+ * meet the target, the result nearer `preferredTone` wins; a gap within
114
+ * twice the search resolution is a tie and keeps `initialDirection`.
115
+ */
108
116
  flip?: boolean;
109
117
  /**
110
118
  * When `flip` is on and *both* directions meet the target, keep
@@ -129,26 +137,42 @@ interface FindToneForContrastResult {
129
137
  contrast: number;
130
138
  /** Whether the target was reached. */
131
139
  met: boolean;
132
- /** Which branch was selected. */
140
+ /**
141
+ * The side the result was found on. The two sides meet at `preferredTone`,
142
+ * so a met result sits on that side of the base too. `'preferred'` whenever
143
+ * a met result is `preferredTone` itself: it already cleared the
144
+ * overshooting search target, or it clears the bare target and no search
145
+ * could improve on it — no searched side met the floor, or the starting
146
+ * side's only position was `preferredTone` (it sits on that side's bound).
147
+ * Also `'preferred'` when `toneRange` leaves no room to search, met or not.
148
+ * An unmet result otherwise reports the side whose extreme it pinned to.
149
+ */
133
150
  branch: 'lighter' | 'darker' | 'preferred';
134
151
  /** Whether the result auto-flipped to the opposite direction. */
135
152
  flipped?: boolean;
136
153
  }
137
154
  /**
138
155
  * Find the tone that satisfies a contrast floor against a base color,
139
- * staying as close to `preferredTone` as possible.
156
+ * staying as close to `preferredTone` as possible. A searched result keeps the
157
+ * overshoot (1% for WCAG, 0.5 Lc for APCA). When no searched side reaches the
158
+ * floor, the result pins to the initial direction's extreme, unmet — unless
159
+ * `preferredTone` itself clears the bare target, which is then kept as met
160
+ * (`branch: 'preferred'`, the same label a met result gets when the starting
161
+ * side's only position is `preferredTone`).
140
162
  */
141
163
  declare function findToneForContrast(options: FindToneForContrastOptions): FindToneForContrastResult;
142
164
  interface FindValueForMixContrastOptions {
143
165
  /** Preferred mix parameter (0–1). */
144
166
  preferredValue: number;
145
- /** Base color as linear sRGB. */
167
+ /** Base color as linear sRGB — the color the mix is measured against. */
146
168
  baseLinearRgb: LinearRgb;
147
- /** Target color as linear sRGB. */
148
- targetLinearRgb: LinearRgb;
149
169
  /** Resolved contrast floor (metric + target). */
150
170
  contrast: ResolvedContrast;
151
- /** Compute the luminance of the mixed color at parameter t. */
171
+ /**
172
+ * Luminance of the mixed color at parameter t, in the metric's basis
173
+ * ({@link metricLuminance}). This closure is the only view the solver has of
174
+ * the mix's target color, blend, and color space.
175
+ */
152
176
  luminanceAtValue: (t: number) => number;
153
177
  /** Convergence threshold. Default: 1e-4. */
154
178
  epsilon?: number;
@@ -166,6 +190,9 @@ interface FindValueForMixContrastResult {
166
190
  /**
167
191
  * Find the mix parameter (ratio or opacity) that satisfies a contrast floor
168
192
  * against a base color, staying as close to `preferredValue` as possible.
193
+ * Misses pin to the initial direction's end like the tone solver, and a
194
+ * `preferredValue` that clears the bare target is kept as met when no searched
195
+ * side reaches the floor (a value of 1 has no room toward the target).
169
196
  */
170
197
  declare function findValueForMixContrast(options: FindValueForMixContrastOptions): FindValueForMixContrastResult;
171
198
  //#endregion
@@ -224,6 +251,21 @@ type ExtremeValue = 'max' | 'min';
224
251
  type ToneValue = number | RelativeValue | ExtremeValue;
225
252
  /** Color format for output. */
226
253
  type GlazeColorFormat = 'okhsl' | 'okhst' | 'rgb' | 'hsl' | 'oklch';
254
+ /**
255
+ * Output format for an HDR glow value (`glaze.formatHdr()`), its brightest
256
+ * channel past 1 (SDR white):
257
+ * - `'srgb'` (default, and what every exporter writes) — extended
258
+ * `color(srgb R G B)`: the sRGB transfer function continued past 1, the
259
+ * channels a WebGPU `'srgb'` canvas and the platform extended-sRGB color
260
+ * spaces take as they are.
261
+ * - `'srgb-linear'` — `color(srgb-linear R G B)`: the same color in linear
262
+ * light, for consumers that take linear channels.
263
+ *
264
+ * No other form: OKLCH lightness clamps at parse time, `rgb()` / `hsl()`
265
+ * cannot go past white, and the `rec2100-*` spaces would tie the value to an
266
+ * absolute reference white it doesn't need.
267
+ */
268
+ type GlazeHdrFormat = 'srgb' | 'srgb-linear';
227
269
  /**
228
270
  * Controls which scheme variants are generated in the export.
229
271
  * Light is always included (it's the default).
@@ -241,6 +283,25 @@ interface GlazeOutputModes {
241
283
  * @see GlazeConfig.contrastLevel
242
284
  */
243
285
  highContrast?: boolean;
286
+ /**
287
+ * Include the HDR tier of glows past SDR white (`variant.hdr`, set by
288
+ * `GlowTuning.headroom`). Default: false — every exporter's output stays
289
+ * byte-identical to SDR even when a headroom is set.
290
+ *
291
+ * When on, each exporter adds the HDR values next to the SDR ones it
292
+ * already emits (only for the scheme variants the other modes include),
293
+ * always written as extended `color(srgb R G B)`: Tasty `hdr` state keys,
294
+ * `json()` `lightHdr` / `darkHdr` / … keys, `tokens()` `lightHdr` / … maps,
295
+ * Tailwind blocks under `hdrSelector`, DTCG `$extensions`. `css()` reads
296
+ * its own `hdr` option, which falls back to this.
297
+ *
298
+ * The data tiers (DTCG, `json()`, `tokens()`) are what native apps and
299
+ * WebGPU canvases read. The CSS-family tiers (Tasty, `css()`, Tailwind) are
300
+ * experimental: no browser paints a CSS color past SDR white yet. Prefer
301
+ * turning this on per call (`theme.dtcg({ modes: { hdr: true } })`) over
302
+ * globally.
303
+ */
304
+ hdr?: boolean;
244
305
  }
245
306
  /** Hex color string for DX hints. Runtime validation in `parseHex()`. */
246
307
  type HexColor = `#${string}`;
@@ -296,7 +357,7 @@ interface RegularColorDef {
296
357
  */
297
358
  from?: GlazeColorValue;
298
359
  /**
299
- * Tone value (0–100, contrast-uniform — see `docs/okhst.md`).
360
+ * Tone value (0–100, contrast-uniform — see `docs/okhst.mdx`).
300
361
  * - Number: absolute tone.
301
362
  * - String ('+N' / '-N'): relative to base color's tone (requires `base`).
302
363
  * - `'max'` / `'min'`: force to the scheme's tone extreme (no base needed).
@@ -390,44 +451,96 @@ interface RegularColorDef {
390
451
  */
391
452
  inherit?: boolean;
392
453
  }
393
- /** Shadow tuning knobs. All values use the 0–1 scale (OKHSL). */
394
- interface ShadowTuning {
395
- /** Fraction of fg saturation kept in pigment (0-1). Default: 0.18. */
396
- saturationFactor?: number;
397
- /** Upper clamp on pigment saturation (0-1). Default: 0.25. */
398
- maxSaturation?: number;
399
- /** Multiplier for bg lightness → pigment lightness. Default: 0.25. */
400
- lightnessFactor?: number;
401
- /** [min, max] clamp for pigment lightness (0-1). Default: [0.05, 0.20]. */
402
- lightnessBounds?: [number, number];
454
+ /**
455
+ * Tuning shared by `shadow` and `glow`. Global defaults come from
456
+ * `shadowTuning` / `glowTuning`; a per-color `tuning` merges over them field
457
+ * by field.
458
+ */
459
+ interface LightingTuning {
460
+ /**
461
+ * β — how strongly the object (`fg`) scales the step. The step is
462
+ * `intensity × k` with `k = max(0, 1 + β · d · (t_bg − t_fg) / 100)`,
463
+ * `d = +1` for a shadow and `−1` for a glow: a darker object deepens its
464
+ * shadow, a lighter one strengthens its glow. An object at the surface's
465
+ * own tone (or no `fg`) gives exactly `intensity`. `0` ignores the object.
466
+ * Default: 0.5.
467
+ */
468
+ objectInfluence?: number;
403
469
  /**
404
- * Target minimum gap between pigment lightness and bg lightness (0-1).
405
- * Default: 0.05.
470
+ * Pigment saturation (0–1) in the surface's hue. Default: 0 (neutral black /
471
+ * white). Shows only with `reach` below 1 — pure black and white have no hue.
472
+ * A neutral surface has no hue either: there the tint takes the object's
473
+ * hue with `hueBleed` above 0, and the pigment stays neutral otherwise.
406
474
  */
407
- minGapTarget?: number;
408
- /** Max alpha (0-1). Reached at intensity=100 with max contrast. Default: 1.0. */
409
- alphaMax?: number;
475
+ tint?: number;
410
476
  /**
411
- * Blend weight (0-1) pulling pigment hue toward bg hue.
412
- * 0 = pure fg hue, 1 = pure bg hue. Default: 0.2.
477
+ * Where the pigment sits (0–1): the fraction of the way from the surface's
478
+ * tone to black (shadow) / white (glow). Default: 1 (pure black / white),
479
+ * the most reach. Lower values let a `tint` show at the cost of reach.
413
480
  */
414
- bgHueBlend?: number;
481
+ reach?: number;
482
+ /**
483
+ * Pull (0–1) of the pigment hue from the surface's hue toward the object's
484
+ * (`fg`) hue. Default: 0. Needs `fg`, a `tint`, and `reach` below 1 to show.
485
+ */
486
+ hueBleed?: number;
487
+ }
488
+ /**
489
+ * Tuning for `shadow` colors: the shared {@link LightingTuning}. It has no
490
+ * `headroom` — a shadow darkens toward black, and nothing goes below black —
491
+ * so a `headroom` set on a shadow's tuning throws.
492
+ */
493
+ type ShadowTuning = LightingTuning;
494
+ /** Tuning for `glow` colors: the shared {@link LightingTuning} plus HDR `headroom`. */
495
+ interface GlowTuning extends LightingTuning {
496
+ /**
497
+ * Stops above SDR white a glow may use when its step crosses white. Default:
498
+ * 0 (SDR only). Counted in stops — doublings of SDR white's luminance — not
499
+ * as a ratio: `1` allows up to 2× white, `2` up to 4×. Must be a finite
500
+ * number ≥ 0; values above 2 clamp to 2 with a one-time warning.
501
+ *
502
+ * Only a glow whose target tone (surface tone + `intensity × k`) passes 100
503
+ * gets an HDR value: the variant's `hdr`, an opaque exposure of what SDR
504
+ * paints at its brightest — the pigment at full opacity, or a white surface
505
+ * no pigment can lift — plus a gain in stops. A pigment that cannot lift a
506
+ * non-white surface at all (`reach: 0` on a gray surface, say) paints
507
+ * nothing in SDR, so it gets no HDR value either and keeps the SDR "cannot
508
+ * reach" warning. On a chromatic surface a `reach: 0` gray can measure
509
+ * slightly brighter than the surface and pins at full opacity instead.
510
+ * Nothing about the SDR variant changes. The gain lands the exact step when
511
+ * the headroom allows it; the brightest linear channel caps at `2^headroom`.
512
+ * High-contrast schemes use the same headroom.
513
+ *
514
+ * The HDR value lands the whole step, not just the part past white. A
515
+ * full-reach glow (the default `reach: 1`) is pinned at white, so its HDR
516
+ * value starts at white (`exposure` → 0) as the target passes 100. A glow
517
+ * with `reach` below 1 is pinned at its pigment, below white: just under 100
518
+ * it stays short there (and warns), and just past 100 its HDR value jumps to
519
+ * the exact step.
520
+ */
521
+ headroom?: number;
415
522
  }
523
+ /**
524
+ * A translucent dark overlay that lands the surface (`bg`) exactly
525
+ * `intensity` tones darker in every scheme — a shade for state layers and
526
+ * scrims, or, with `fg`, an object-aware drop shadow.
527
+ */
416
528
  interface ShadowColorDef {
417
529
  type: 'shadow';
418
530
  /**
419
- * Background color name — the surface the shadow sits on.
420
- * Must reference a non-shadow color in the same theme.
531
+ * The surface the shadow falls on. Must reference a color that is not a
532
+ * shadow or glow.
421
533
  */
422
534
  bg: string;
423
535
  /**
424
- * Foreground color name for tinting and intensity modulation.
425
- * Must reference a non-shadow color in the same theme.
426
- * Omit for achromatic shadow at full user-specified intensity.
536
+ * The object casting the shadow (e.g. the card). A darker object casts a
537
+ * deeper shadow, a lighter one a softer shadow — see
538
+ * `LightingTuning.objectInfluence`. Omit for an exact shade of `intensity`
539
+ * tones. Must reference a color that is not a shadow or glow.
427
540
  */
428
541
  fg?: string;
429
542
  /**
430
- * Shadow intensity, 0-100.
543
+ * Tone step, 0–100: how many tones darker than `bg` the composite lands.
431
544
  * Supports [normal, highContrast] pair.
432
545
  */
433
546
  intensity: HCPair<number>;
@@ -446,6 +559,44 @@ interface ShadowColorDef {
446
559
  */
447
560
  inherit?: boolean;
448
561
  }
562
+ /**
563
+ * The mirror of {@link ShadowColorDef}: a translucent light overlay that lands
564
+ * the surface (`bg`) exactly `intensity` tones lighter in every scheme — for
565
+ * dark-mode elevation, edge highlights, and lightening state layers.
566
+ */
567
+ interface GlowColorDef {
568
+ type: 'glow';
569
+ /**
570
+ * The surface the glow falls on. Must reference a color that is not a
571
+ * shadow or glow.
572
+ */
573
+ bg: string;
574
+ /**
575
+ * The object emitting the glow. A lighter object glows stronger, a darker
576
+ * one weaker — see `LightingTuning.objectInfluence`. Omit for an exact tint
577
+ * of `intensity` tones. Must reference a color that is not a shadow or glow.
578
+ */
579
+ fg?: string;
580
+ /**
581
+ * Tone step, 0–100: how many tones lighter than `bg` the composite lands.
582
+ * Supports [normal, highContrast] pair.
583
+ */
584
+ intensity: HCPair<number>;
585
+ /** Override default tuning. Merged field-by-field with global `glowTuning`. */
586
+ tuning?: GlowTuning;
587
+ /**
588
+ * Per-color override for the hue-independent "safe" chroma limit used in
589
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
590
+ * Falls through to the per-theme / per-token `pastel` override when omitted.
591
+ * @see GlazeConfigOverride.pastel
592
+ */
593
+ pastel?: boolean;
594
+ /**
595
+ * Whether this color is inherited by child themes created via `extend()`.
596
+ * Default: true. Set to false to make this color local to the current theme.
597
+ */
598
+ inherit?: boolean;
599
+ }
449
600
  interface MixColorDef {
450
601
  type: 'mix';
451
602
  /** Background/base color name — the "from" color. */
@@ -467,9 +618,12 @@ interface MixColorDef {
467
618
  /**
468
619
  * Interpolation color space for opaque blending. Default: 'okhsl'.
469
620
  * - 'okhsl': perceptually uniform, consistent with Glaze's internal model.
470
- * - 'srgb': linear sRGB interpolation, matches browser compositing.
621
+ * - 'srgb': linear-light sRGB interpolation (like CSS
622
+ * `color-mix(in srgb-linear, …)`).
471
623
  *
472
- * Ignored for 'transparent' blend (always composites in linear sRGB).
624
+ * Ignored for 'transparent' blend: the browser composites that one, and
625
+ * its contrast solve models the browser (`source-over` on gamma-encoded
626
+ * sRGB).
473
627
  */
474
628
  space?: 'okhsl' | 'srgb';
475
629
  /**
@@ -499,7 +653,7 @@ interface MixColorDef {
499
653
  */
500
654
  inherit?: boolean;
501
655
  }
502
- type ColorDef = RegularColorDef | ShadowColorDef | MixColorDef;
656
+ type ColorDef = RegularColorDef | ShadowColorDef | GlowColorDef | MixColorDef;
503
657
  type ColorMap = Record<string, ColorDef>;
504
658
  /**
505
659
  * Resolved color for a single scheme variant.
@@ -523,6 +677,36 @@ interface ResolvedColorVariant {
523
677
  * gamut mapping applied during resolution.
524
678
  */
525
679
  pastel?: boolean;
680
+ /**
681
+ * HDR tier of a glow whose step crosses SDR white, present only when the
682
+ * glow's `headroom` is above 0, its target tone passes 100, and SDR is
683
+ * pinned at its brightest — the pigment at full opacity, or a white surface
684
+ * (see `GlowTuning.headroom`). Absent everywhere else — shadows, mixes,
685
+ * regular colors, a glow whose pigment cannot lift a non-white surface, and
686
+ * every glow at the default headroom of 0.
687
+ */
688
+ hdr?: ResolvedHdr;
689
+ }
690
+ /**
691
+ * The HDR value of a glow past SDR white: an opaque base plus a gain. The base
692
+ * is what SDR paints at its brightest — the glow's pigment at full opacity, or
693
+ * the white surface it cannot lift — and the HDR color is that base's linear
694
+ * sRGB times `2^exposure`. Format it with `glaze.formatHdr()`, or read its
695
+ * channels with `hdrToSrgb()` / `hdrToLinearSrgb()`.
696
+ *
697
+ * Stored in OKHST like the variant. `s` is always standard (non-pastel)
698
+ * OKHSL saturation, whatever the variant's `pastel`, since the base is an
699
+ * arbitrary in-gamut composite.
700
+ */
701
+ interface ResolvedHdr {
702
+ /** Base OKHSL hue (0–360). */
703
+ h: number;
704
+ /** Base OKHSL saturation (0–1, non-pastel). */
705
+ s: number;
706
+ /** Base canonical tone (0–1, reference eps). */
707
+ t: number;
708
+ /** Gain over the base in stops (`log2` of the linear factor), above 0. */
709
+ exposure: number;
526
710
  }
527
711
  /** Fully resolved color across all scheme variants. */
528
712
  interface ResolvedColor {
@@ -531,7 +715,7 @@ interface ResolvedColor {
531
715
  dark: ResolvedColorVariant;
532
716
  lightContrast: ResolvedColorVariant;
533
717
  darkContrast: ResolvedColorVariant;
534
- /** Adaptation mode. Present only for regular colors, omitted for shadows. */
718
+ /** Adaptation mode of a regular color; `undefined` for shadow / glow / mix. */
535
719
  mode?: AdaptationMode;
536
720
  }
537
721
  /**
@@ -557,20 +741,32 @@ interface GlazeConfig {
557
741
  darkDesaturation?: number;
558
742
  /**
559
743
  * State alias names for Tasty token export. Default to media-query states
560
- * (`'@media(prefers-color-scheme: dark)'` / `'@media(prefers-contrast: more)'`)
561
- * so tokens react to the OS preference without registering custom states.
744
+ * (`'@media(prefers-color-scheme: dark)'` / `'@media(prefers-contrast: more)'`
745
+ * / `'@media(dynamic-range: high)'`) so tokens react to the OS preference
746
+ * and the display without registering custom states. `hdr` keys an HDR
747
+ * glow value and is used only with `modes.hdr` (experimental, see
748
+ * `GlazeOutputModes.hdr`).
562
749
  */
563
750
  states?: {
564
751
  dark?: string;
565
752
  highContrast?: string;
753
+ hdr?: string;
566
754
  };
567
755
  /**
568
756
  * Which scheme variants to include in exports. Defaults: `dark: true`,
569
- * `highContrast: false`.
757
+ * `highContrast: false`, `hdr: false`.
570
758
  */
571
759
  modes?: GlazeOutputModes;
572
- /** Default tuning for all shadow colors. Per-color tuning merges field-by-field. */
760
+ /**
761
+ * Default tuning for all shadow colors. Per-color tuning merges field-by-field.
762
+ * A `headroom` here throws: it is a glow-only field.
763
+ */
573
764
  shadowTuning?: ShadowTuning;
765
+ /**
766
+ * Default tuning for all glow colors, including HDR `headroom`. Per-color
767
+ * tuning merges field-by-field.
768
+ */
769
+ glowTuning?: GlowTuning;
574
770
  /**
575
771
  * Manual contrast level — a 0–100 slider from normal contrast (`0`) to high
576
772
  * contrast (`100`), or `'auto'` (the default) to take the authored normal
@@ -590,7 +786,7 @@ interface GlazeConfig {
590
786
  * approximation, and a color keeps to one side of its base as the level moves.
591
787
  *
592
788
  * Pass `'auto'` to leave manual mode; `configure()` never clears a field by
593
- * omission. See `docs/api.md` for the ramp's edge cases (un-interpolable
789
+ * omission. See `docs/reference/contrast.md` for the ramp's edge cases (un-interpolable
594
790
  * pairs, side changes) and the export-freeze rule.
595
791
  *
596
792
  * @default 'auto'
@@ -626,9 +822,11 @@ interface GlazeConfigResolved {
626
822
  states: {
627
823
  dark: string;
628
824
  highContrast: string;
825
+ hdr: string;
629
826
  };
630
827
  modes: Required<GlazeOutputModes>;
631
828
  shadowTuning?: ShadowTuning;
829
+ glowTuning?: GlowTuning;
632
830
  autoFlip: boolean;
633
831
  /**
634
832
  * Manual contrast level (0–100) for the normal variants, or `'auto'` to take
@@ -690,12 +888,22 @@ interface GlazeConfigOverride {
690
888
  * standalone color tokens.
691
889
  */
692
890
  shadowTuning?: ShadowTuning;
891
+ /**
892
+ * Glow tuning defaults. Only meaningful for themes; harmless on
893
+ * standalone color tokens.
894
+ */
895
+ glowTuning?: GlowTuning;
693
896
  }
694
897
  /**
695
898
  * Current authoring-export schema version. Bump when the export shape
696
899
  * changes in a non-compatible way. Written on every `.export()` snapshot.
900
+ *
901
+ * - `1` — Glaze 2.x.
902
+ * - `2` — Glaze 3: `shadow` `intensity` / `fg` / `tuning` changed meaning and
903
+ * `glow` was added. Version-1 theme snapshots that carry shadow defs or a
904
+ * `shadowTuning` are rejected on restore.
697
905
  */
698
- declare const GLAZE_EXPORT_VERSION: 1;
906
+ declare const GLAZE_EXPORT_VERSION: 2;
699
907
  /** Literal type of {@link GLAZE_EXPORT_VERSION}. */
700
908
  type GlazeExportVersion = typeof GLAZE_EXPORT_VERSION;
701
909
  /** Discriminator for authoring export snapshots. */
@@ -720,23 +928,27 @@ interface GlazeThemeExport {
720
928
  */
721
929
  config?: GlazeConfigOverride;
722
930
  }
723
- /** Input for `glaze.shadow()` standalone factory. */
724
- interface GlazeShadowInput {
931
+ /** Input for the `glaze.shadow()` and `glaze.glow()` standalone factories. */
932
+ interface GlazeLightingInput {
725
933
  /**
726
- * Background color — accepts any `GlazeColorValue` form: hex
727
- * (`#rgb` / `#rrggbb` / `#rrggbbaa`), `rgb()` / `hsl()` / `okhsl()`
728
- * / `oklch()` strings, or literal objects (`{ r, g, b }`, `{ h, s, l }`,
729
- * `{ l, c, h }`). Alpha components are dropped with a warning.
934
+ * The surface — accepts any `GlazeColorValue` form: hex
935
+ * (`#rgb` / `#rgba` / `#rrggbb` / `#rrggbbaa`), `rgb()` / `hsl()` /
936
+ * `okhsl()` / `okhst()` / `oklch()` strings, or literal objects
937
+ * (`{ r, g, b }`, `{ h, s, l }`, `{ h, s, t }`, `{ l, c, h }`). Alpha
938
+ * components are dropped with a warning.
730
939
  */
731
940
  bg: GlazeColorValue;
732
- /**
733
- * Foreground color for tinting + intensity modulation. Accepts the
734
- * same forms as `bg`.
735
- */
941
+ /** The object casting the shadow / emitting the glow. Same forms as `bg`. */
736
942
  fg?: GlazeColorValue;
737
- /** Intensity 0-100. */
943
+ /** Tone step, 0–100. */
738
944
  intensity: number;
739
- tuning?: ShadowTuning;
945
+ tuning?: LightingTuning;
946
+ }
947
+ /** Input for `glaze.shadow()`. */
948
+ type GlazeShadowInput = GlazeLightingInput;
949
+ /** Input for `glaze.glow()`: the shared input, with glow tuning (`headroom`). */
950
+ interface GlazeGlowInput extends GlazeLightingInput {
951
+ tuning?: GlowTuning;
740
952
  }
741
953
  /** Input for the structured `glaze.color()` overload. */
742
954
  interface GlazeColorInput {
@@ -769,14 +981,17 @@ interface GlazeColorInput {
769
981
  */
770
982
  base?: GlazeColorToken | GlazeColorValue;
771
983
  /**
772
- * Contrast floor against `base`. Requires `base` to be set. A bare
984
+ * Contrast floor. Without `base`, solved against the token's own input
985
+ * color (`hue`, `saturation`, normal `tone`), held fixed in every scheme;
986
+ * with `base`, against the base's resolved variant per scheme. A bare
773
987
  * number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the metric.
774
988
  */
775
989
  contrast?: HCPair<ContrastSpec>;
776
990
  /**
777
991
  * Optional human-readable name for the token. Used in error and
778
992
  * warning messages (otherwise an internal name like `"value"` is
779
- * used). Does not affect output keys.
993
+ * used) and as `resolve().name`. A debug label only: it does not
994
+ * affect output keys or the token's `role`.
780
995
  */
781
996
  name?: string;
782
997
  /**
@@ -787,11 +1002,12 @@ interface GlazeColorInput {
787
1002
  */
788
1003
  pastel?: boolean;
789
1004
  /**
790
- * Semantic role against `base` / the literal seed: how this token is used.
791
- * Fixes APCA contrast polarity. Same resolution chain as
792
- * `RegularColorDef.role` (explicit → name inference → opposite of base →
793
- * `'text'`). For standalone tokens the name is internal, so set `role`
794
- * explicitly or rely on the base-opposite / foreground default.
1005
+ * Semantic role against the token's anchor (`base`, or its own input
1006
+ * color when `contrast` is set without one): how this token is used.
1007
+ * Fixes APCA contrast polarity; WCAG ignores it. Defaults to `'text'` —
1008
+ * the token is the foreground and the anchor the background, with or
1009
+ * without `base`. Unlike a theme color, a token never infers its role
1010
+ * from `name`, so `inferRole` has no effect on it.
795
1011
  */
796
1012
  role?: RoleInput;
797
1013
  }
@@ -799,17 +1015,35 @@ interface GlazeColorInput {
799
1015
  * Any single-color input form accepted by the value-shorthand
800
1016
  * overload of `glaze.color()`.
801
1017
  *
802
- * Strings cover hex (`#rgb` / `#rrggbb` / `#rrggbbaa`, alpha dropped
803
- * with a warning) and the four CSS color functions Glaze itself emits:
804
- * `rgb()`, `hsl()`, `okhsl()`, `oklch()` (alpha components also dropped
805
- * with a warning).
1018
+ * Strings cover hex with a leading `#` (`#rgb` / `#rgba` / `#rrggbb` /
1019
+ * `#rrggbbaa`) and the five color functions Glaze itself emits: `rgb()`,
1020
+ * `hsl()`, `okhsl()`, `okhst()`, `oklch()`, plus the `rgba()` / `hsla()`
1021
+ * aliases. Function names are case-insensitive; components are numbers or
1022
+ * percentages, separated by spaces or commas. Their scales:
1023
+ * - `rgb()` — channels 0–255, or percentages (`100%` is 255).
1024
+ * - `hsl()` / `okhsl()` / `okhst()` — saturation, lightness and tone are
1025
+ * percentages or bare 0–1 fractions: `hsl(120 50% 50%)` or
1026
+ * `hsl(120 0.5 0.5)`. Unlike CSS, a bare `hsl(120 50 50)` does not mean
1027
+ * 50%; it is out of range and resolves to white without a warning.
1028
+ * - `oklch()` — L 0–1 or a percentage; C bare, or a percentage where
1029
+ * `100%` is 0.4.
1030
+ * - Hue is in degrees, bare or with `deg`. Other angle units (`turn`,
1031
+ * `rad`, `grad`) are misread as degrees rather than rejected.
806
1032
  *
807
- * Literal object forms:
808
- * - `{ h, s, l }` — OKHSL (h: 0–360, s/l: 0–1). Passing 0–100 for `s`/`l`
809
- * throws with a hint to use the structured form.
810
- * - `{ h, s, t }` — OKHST (h: 0–360, s/t: 0–1). Tone in 0–1.
1033
+ * An alpha component (hex alpha, `/ A`, or any fourth component) is
1034
+ * dropped with a warning. Named colors, other color functions, and
1035
+ * relative color syntax throw.
1036
+ *
1037
+ * Literal object forms, told apart by their keys:
811
1038
  * - `{ r, g, b }` — sRGB 0–255.
812
1039
  * - `{ l, c, h }` — OKLCh (L/C: 0–1, H: degrees), same as `oklch()` strings.
1040
+ * - `{ h, s, t }` — OKHST (h: 0–360, s/t: 0–1). Tone in 0–1, so `t: 0.7` is
1041
+ * tone 70.
1042
+ * - `{ h, s, l }` — OKHSL (h: 0–360, s/l: 0–1).
1043
+ *
1044
+ * An object `s`, `l`, `t` or `c` above 1.5 throws, which catches 0–100
1045
+ * input; the OKHSL / OKHST errors point to the structured form. String
1046
+ * components have no such check.
813
1047
  */
814
1048
  type GlazeColorValue = string | OkhslColor | OkhstColor | RgbColor | OklchColor;
815
1049
  /** Color overrides for the `from` and value-shorthand inputs. */
@@ -888,11 +1122,10 @@ interface GlazeColorOverrides {
888
1122
  * tone per-scheme (matches theme behavior for dependent colors).
889
1123
  * - Relative `hue: '+N'` / `'-N'` still anchors to the seed (the
890
1124
  * value passed to `glaze.color()`), not the base.
891
- * - When the base was created via the structured form (with explicit
892
- * `hue`/`saturation`/`tone`), it is resolved at full range
893
- * (`lightTone: false`) for the linking math — ensuring the
894
- * contrast/tone anchor matches the input tone, not the
895
- * windowed output. The base's own `.resolve()` output is unaffected.
1125
+ * - The link resolves against the base token's own variants in every
1126
+ * scheme: what the base paints, under its own config, whatever form
1127
+ * the base was made in. A light `'+0'` lands on the base and a light
1128
+ * `contrast` floor is measured against it.
896
1129
  *
897
1130
  * The base token's `.resolve()` is called lazily on first resolve and
898
1131
  * its result is captured by reference; later mutations to the base's
@@ -908,7 +1141,8 @@ interface GlazeColorOverrides {
908
1141
  /**
909
1142
  * Optional human-readable name for the token. Used in error and
910
1143
  * warning messages (otherwise an internal name like `"value"` is
911
- * used). Does not affect output keys.
1144
+ * used) and as `resolve().name`. A debug label only: it does not
1145
+ * affect output keys or the token's `role`.
912
1146
  */
913
1147
  name?: string;
914
1148
  /**
@@ -919,9 +1153,12 @@ interface GlazeColorOverrides {
919
1153
  */
920
1154
  pastel?: boolean;
921
1155
  /**
922
- * Semantic role against `base` / the literal seed: how this token is used.
923
- * Fixes APCA contrast polarity. Same resolution chain as
924
- * `RegularColorDef.role`.
1156
+ * Semantic role against the token's anchor (`base`, or the literal seed
1157
+ * when `contrast` / a relative `tone` is set without one): how this token
1158
+ * is used. Fixes APCA contrast polarity; WCAG ignores it. Defaults to
1159
+ * `'text'` — the token is the foreground and the anchor the background,
1160
+ * with or without `base`. Unlike a theme color, a token never infers its
1161
+ * role from `name`, so `inferRole` has no effect on it.
925
1162
  */
926
1163
  role?: RoleInput;
927
1164
  }
@@ -954,8 +1191,9 @@ interface GlazeColorCssOptions {
954
1191
  */
955
1192
  suffix?: string;
956
1193
  /**
957
- * Emit hue as a separate custom property, referenced via `var()`.
958
- * Requires `format: 'oklch'` and a pastel token. oklch + all-pastel only.
1194
+ * Emit hue as a separate `--{name}-hue` custom property, referenced via
1195
+ * `var()`. Requires `format: 'oklch'` (any other format throws) and a
1196
+ * pastel token.
959
1197
  */
960
1198
  splitHue?: boolean;
961
1199
  }
@@ -1144,16 +1382,26 @@ interface GlazeTheme {
1144
1382
  * theme.tokens()
1145
1383
  * // → { light: { surface: 'okhsl(...)' }, dark: { surface: 'okhsl(...)' } }
1146
1384
  * ```
1385
+ *
1386
+ * With `modes.hdr`, each scheme map is followed by a dense `<scheme>Hdr`
1387
+ * map (`lightHdr`, `darkHdr`, …): every glow with an HDR value in any
1388
+ * emitted scheme, as extended `color(srgb …)`, or its SDR value where
1389
+ * that scheme has none.
1147
1390
  */
1148
1391
  tokens(options?: GlazeJsonOptions): Record<string, Record<string, string>>;
1149
1392
  /**
1150
1393
  * Export as tasty style-to-state bindings.
1151
1394
  * Uses `#name` color token keys and state aliases (`''`, `'@media(prefers-color-scheme: dark)'`, etc.).
1152
1395
  * Spread into component styles or register as a recipe via `configure({ recipes })`.
1396
+ * With `modes.hdr`, a glow's HDR value follows each SDR key that has one,
1397
+ * under `states.hdr` (`'@media(dynamic-range: high)'`) combined with it.
1153
1398
  * @see https://tasty.style/docs
1154
1399
  */
1155
- tasty(options?: GlazeTokenOptions): Record<string, Record<string, string>>;
1156
- /** Export as plain JSON. */
1400
+ tasty(options?: GlazeTastyOptions): Record<string, Record<string, string>>;
1401
+ /**
1402
+ * Export as plain JSON. With `modes.hdr`, a glow variant with an HDR value
1403
+ * adds a `<scheme>Hdr` key (`lightHdr`, …) right after its SDR key.
1404
+ */
1157
1405
  json(options?: GlazeJsonOptions): Record<string, Record<string, string>>;
1158
1406
  /** Export as CSS custom property declarations. */
1159
1407
  css(options?: GlazeCssOptions): GlazeCssResult;
@@ -1190,35 +1438,48 @@ interface GlazeExtendOptions {
1190
1438
  /** Config override for the child theme. Merged with the parent's override. */
1191
1439
  config?: GlazeConfigOverride;
1192
1440
  }
1441
+ /**
1442
+ * Options for `token.token()` / `token.tasty()`, and the base of the theme and
1443
+ * palette `tasty()` options: output format, scheme variants, state aliases.
1444
+ */
1193
1445
  interface GlazeTokenOptions {
1194
- /** Prefix mode. `true` uses "<themeName>-", or provide a custom map. */
1195
- prefix?: boolean | Record<string, string>;
1196
- /** Override state aliases for this export. */
1446
+ /**
1447
+ * Override state aliases for this export. `hdr` keys an HDR glow value
1448
+ * (with `modes.hdr`); a `glaze.color()` token is never a glow, so it never
1449
+ * uses it.
1450
+ */
1197
1451
  states?: {
1198
1452
  dark?: string;
1199
1453
  highContrast?: string;
1454
+ hdr?: string;
1200
1455
  };
1201
1456
  /** Override which scheme variants to include. */
1202
1457
  modes?: GlazeOutputModes;
1203
1458
  /** Output color format. Default: 'oklch'. */
1204
1459
  format?: GlazeColorFormat;
1460
+ }
1461
+ /** Options for `theme.tasty()`. */
1462
+ interface GlazeTastyOptions extends GlazeTokenOptions {
1205
1463
  /**
1206
1464
  * Emit hue as a separate custom property, referenced via `var()`.
1207
- * Requires `format: 'oklch'` and every color to be pastel.
1465
+ * Requires `format: 'oklch'` (any other format throws) and every color to
1466
+ * be pastel.
1208
1467
  */
1209
1468
  splitHue?: boolean;
1210
1469
  /**
1211
1470
  * Base name for the theme-level hue var (`--{name}-hue`). Default: `'theme'`.
1212
- * Palette export auto-derives this from the theme name.
1471
+ * Must not equal the name of a color that sets its own hue (throws).
1213
1472
  */
1214
1473
  name?: string;
1215
1474
  }
1475
+ /** Options for `theme.tokens()` / `theme.json()` and their palette and token counterparts. */
1216
1476
  interface GlazeJsonOptions {
1217
1477
  /** Override which scheme variants to include. */
1218
1478
  modes?: GlazeOutputModes;
1219
1479
  /** Output color format. Default: 'oklch'. */
1220
1480
  format?: GlazeColorFormat;
1221
1481
  }
1482
+ /** Options for `theme.css()`. */
1222
1483
  interface GlazeCssOptions {
1223
1484
  /** Output color format. Default: 'oklch'. */
1224
1485
  format?: GlazeColorFormat;
@@ -1226,22 +1487,46 @@ interface GlazeCssOptions {
1226
1487
  suffix?: string;
1227
1488
  /**
1228
1489
  * Emit hue as a separate custom property, referenced via `var()`.
1229
- * Requires `format: 'oklch'` and every color to be pastel.
1490
+ * Requires `format: 'oklch'` (any other format throws) and every color to
1491
+ * be pastel.
1230
1492
  */
1231
1493
  splitHue?: boolean;
1232
1494
  /**
1233
1495
  * Base name for the theme-level hue var (`--{name}-hue`). Default: `'theme'`.
1234
- * Palette export auto-derives this from the theme name.
1496
+ * Must not equal the name of a color that sets its own hue (throws).
1235
1497
  */
1236
1498
  name?: string;
1499
+ /**
1500
+ * Add the HDR tier as `result.hdr` (see {@link GlazeCssResult.hdr}).
1501
+ * Default: the global `modes.hdr` (false). `css()` has no `modes` — it
1502
+ * always emits all four schemes — so this is its HDR switch.
1503
+ * @experimental No browser paints a CSS color past SDR white yet, so this
1504
+ * tier looks like SDR at best today, and its shape may change (for example
1505
+ * to CSS `hdr-color()`) once one does.
1506
+ */
1507
+ hdr?: boolean;
1237
1508
  }
1238
- /** CSS custom property declarations grouped by scheme variant. */
1239
- interface GlazeCssResult {
1509
+ /** CSS custom property declarations for each scheme variant. */
1510
+ interface GlazeCssSchemeBlocks {
1240
1511
  light: string;
1241
1512
  dark: string;
1242
1513
  lightContrast: string;
1243
1514
  darkContrast: string;
1244
1515
  }
1516
+ /** CSS custom property declarations grouped by scheme variant. */
1517
+ interface GlazeCssResult extends GlazeCssSchemeBlocks {
1518
+ /**
1519
+ * The HDR tier, present when HDR output is on — the `hdr` option, which
1520
+ * defaults to the global `modes.hdr`: one block per scheme,
1521
+ * each re-declaring every color that has an HDR value in any scheme — its
1522
+ * HDR value (extended `color(srgb R G B)`) where that scheme has one, and
1523
+ * the scheme's SDR declaration where it has none. The blocks are dense so
1524
+ * a light HDR value can never leak into dark: wire each one after the SDR
1525
+ * blocks, under the same selector plus `(dynamic-range: high)`. Every block
1526
+ * is an empty string when no color has an HDR value.
1527
+ */
1528
+ hdr?: GlazeCssSchemeBlocks;
1529
+ }
1245
1530
  /**
1246
1531
  * Color space used for DTCG `$value` color objects.
1247
1532
  * @see https://www.designtokens.org/
@@ -1271,14 +1556,52 @@ interface DtcgOklchColorValue {
1271
1556
  }
1272
1557
  /** A DTCG `$value` for a color token, in either supported color space. */
1273
1558
  type DtcgColorValue = DtcgSrgbColorValue | DtcgOklchColorValue;
1559
+ /**
1560
+ * The HDR value of a glow past SDR white, carried in a DTCG token's
1561
+ * `$extensions['me.tenphi.glaze'].hdr` (`$value` stays the SDR color, since
1562
+ * DTCG color components stop at 1). Maps onto native APIs: UIKit
1563
+ * `UIColor(red:green:blue:alpha:exposure:)` (AppKit: its `NSColor` twin) from
1564
+ * `base` and `exposure`, or Android
1565
+ * `Color.pack(r, g, b, 1f, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB))`
1566
+ * from `value`.
1567
+ */
1568
+ interface GlazeDtcgHdr {
1569
+ /** Gain over `base` in stops (`log2` of the linear factor), above 0. */
1570
+ exposure: number;
1571
+ /**
1572
+ * Luminance tone of the HDR value (e.g. `112`) — past 100 when the headroom
1573
+ * covers the step; a saturated base capped by `headroom` can land below 100,
1574
+ * though its brightest channel still exceeds 1.
1575
+ */
1576
+ tone: number;
1577
+ /** The opaque base (what SDR paints), as a DTCG sRGB color. */
1578
+ base: DtcgSrgbColorValue;
1579
+ /**
1580
+ * The HDR color, `base × 2^exposure` in linear light, as extended sRGB
1581
+ * components (the numbers of `glaze.formatHdr()`): its brightest channel
1582
+ * above 1 (the others may stay below).
1583
+ */
1584
+ value: {
1585
+ colorSpace: 'srgb';
1586
+ components: [number, number, number];
1587
+ };
1588
+ }
1589
+ /** The Glaze namespace of a DTCG token's `$extensions`. */
1590
+ interface GlazeDtcgExtensions {
1591
+ 'me.tenphi.glaze': {
1592
+ /** Present only with `modes.hdr`, on a glow variant that has an HDR value. */hdr: GlazeDtcgHdr;
1593
+ };
1594
+ }
1274
1595
  /**
1275
1596
  * A single W3C DTCG color token: `{ $type: 'color', $value }`.
1276
- * `$description` is optional and not populated by Glaze today.
1597
+ * `$description` is optional and not populated by Glaze today. `$extensions`
1598
+ * is set only with `modes.hdr`, on a glow variant with an HDR value.
1277
1599
  */
1278
1600
  interface DtcgColorToken {
1279
1601
  $type: 'color';
1280
1602
  $value: DtcgColorValue;
1281
1603
  $description?: string;
1604
+ $extensions?: GlazeDtcgExtensions;
1282
1605
  }
1283
1606
  /**
1284
1607
  * A W3C Design Tokens Format Module (2025.10) token tree for one scheme.
@@ -1412,6 +1735,18 @@ interface GlazeTailwindOptions {
1412
1735
  * `.dark.high-contrast`).
1413
1736
  */
1414
1737
  highContrastSelector?: string;
1738
+ /**
1739
+ * Selector wrapping the HDR overrides, emitted with `modes.hdr` after every
1740
+ * SDR block. Default: `'@media (dynamic-range: high)'`. Each HDR block is
1741
+ * dense (every color with an HDR value in any emitted scheme, SDR value
1742
+ * where the scheme has none) and is scoped by this selector alone (light),
1743
+ * combined with `darkSelector` (dark), with `highContrastSelector` (light
1744
+ * high contrast), or with both.
1745
+ * @experimental No browser paints a CSS color past SDR white yet, so this
1746
+ * tier looks like SDR at best today, and its shape may change (for example
1747
+ * to CSS `hdr-color()`) once one does.
1748
+ */
1749
+ hdrSelector?: string;
1415
1750
  }
1416
1751
  /** Options for `glaze.color().tailwind()`. `name` is required. */
1417
1752
  interface GlazeColorTailwindOptions extends GlazeTailwindOptions {
@@ -1434,7 +1769,10 @@ interface GlazePaletteOptions {
1434
1769
  */
1435
1770
  primary?: string;
1436
1771
  }
1437
- /** Options shared by palette `tokens()`, `tasty()`, and `css()` exports. */
1772
+ /**
1773
+ * Options shared by every palette export except `json()`: `tokens()`,
1774
+ * `tasty()`, `css()`, `dtcg()`, `dtcgResolver()`, and `tailwind()`.
1775
+ */
1438
1776
  interface GlazePaletteExportOptions {
1439
1777
  /**
1440
1778
  * Prefix mode. `true` uses `"<themeName>-"`, or provide a custom map.
@@ -1449,11 +1787,42 @@ interface GlazePaletteExportOptions {
1449
1787
  * When omitted, inherits the palette-level `primary`.
1450
1788
  */
1451
1789
  primary?: string | false;
1790
+ }
1791
+ /**
1792
+ * Options for `palette.tasty()`. There is no `name`: each theme's hue var is
1793
+ * named after the theme.
1794
+ */
1795
+ interface GlazePaletteTastyOptions extends GlazeTokenOptions, GlazePaletteExportOptions {
1796
+ /**
1797
+ * Emit hue as a separate custom property, referenced via `var()`.
1798
+ * Requires `format: 'oklch'` (any other format throws) and every color to
1799
+ * be pastel. The theme-level hue var is `--{themeName}-hue`.
1800
+ */
1801
+ splitHue?: boolean;
1802
+ }
1803
+ /**
1804
+ * Options for `palette.css()`. There is no `name`: each theme's hue var is
1805
+ * named after the theme.
1806
+ */
1807
+ interface GlazePaletteCssOptions extends GlazePaletteExportOptions {
1808
+ /** Output color format. Default: 'oklch'. */
1809
+ format?: GlazeColorFormat;
1810
+ /** Suffix appended to each CSS custom property name. Default: '-color'. */
1811
+ suffix?: string;
1452
1812
  /**
1453
1813
  * Emit hue as a separate custom property, referenced via `var()`.
1454
- * Requires `format: 'oklch'` and every color to be pastel.
1814
+ * Requires `format: 'oklch'` (any other format throws) and every color to
1815
+ * be pastel. The theme-level hue var is `--{themeName}-hue`.
1455
1816
  */
1456
1817
  splitHue?: boolean;
1818
+ /**
1819
+ * Add the HDR tier as `result.hdr` (see {@link GlazeCssResult.hdr}).
1820
+ * Default: the global `modes.hdr` (false).
1821
+ * @experimental No browser paints a CSS color past SDR white yet, so this
1822
+ * tier looks like SDR at best today, and its shape may change (for example
1823
+ * to CSS `hdr-color()`) once one does.
1824
+ */
1825
+ hdr?: boolean;
1457
1826
  }
1458
1827
  interface GlazePalette {
1459
1828
  /** Theme names in insertion order. */
@@ -1492,13 +1861,14 @@ interface GlazePalette {
1492
1861
  * Prefix defaults to `true`. Inherits the palette-level `primary`.
1493
1862
  * @see https://tasty.style/docs
1494
1863
  */
1495
- tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
1496
- /** Export all themes as plain JSON grouped by theme name. */
1497
- json(options?: GlazeJsonOptions & {
1498
- prefix?: boolean | Record<string, string>;
1499
- }): Record<string, Record<string, Record<string, string>>>;
1864
+ tasty(options?: GlazePaletteTastyOptions): Record<string, Record<string, string>>;
1865
+ /**
1866
+ * Export all themes as plain JSON grouped by theme name. No prefix, primary
1867
+ * alias, or collision handling: each theme keeps its own key.
1868
+ */
1869
+ json(options?: GlazeJsonOptions): Record<string, Record<string, Record<string, string>>>;
1500
1870
  /** Export all themes as CSS custom property declarations. */
1501
- css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
1871
+ css(options?: GlazePaletteCssOptions): GlazeCssResult;
1502
1872
  /**
1503
1873
  * Export all themes as W3C DTCG documents, one per scheme variant.
1504
1874
  * Prefix defaults to `true`. Inherits the palette-level `primary`.
@@ -1520,14 +1890,6 @@ interface GlazePalette {
1520
1890
  tailwind(options?: GlazeTailwindOptions & GlazePaletteExportOptions): string;
1521
1891
  }
1522
1892
  //#endregion
1523
- //#region src/serialize.d.ts
1524
- /** Type guard for theme authoring snapshots (prefers `kind`, falls back to shape). */
1525
- declare function isThemeExport(data: unknown): data is GlazeThemeExport;
1526
- /** Type guard for color-token authoring snapshots. */
1527
- declare function isColorTokenExport(data: unknown): data is GlazeColorTokenExport;
1528
- /** Type guard for palette authoring snapshots. */
1529
- declare function isPaletteExport(data: unknown): data is GlazePaletteExport;
1530
- //#endregion
1531
1893
  //#region src/glaze.d.ts
1532
1894
  type PaletteInput = Record<string, GlazeTheme>;
1533
1895
  /**
@@ -1553,9 +1915,13 @@ type PaletteInput = Record<string, GlazeTheme>;
1553
1915
  * const primary = glaze({ hue: 280, saturation: 80, darkHue: 268, darkSaturation: 65 });
1554
1916
  * // with config override:
1555
1917
  * const raw = glaze(280, 80, { lightTone: false });
1918
+ * const rawSeed = glaze({ hue: 280, saturation: 80 }, { lightTone: false });
1556
1919
  * ```
1557
1920
  */
1558
- declare function glaze(hueOrOptions: number | GlazeThemeSeed, saturation?: number, config?: GlazeConfigOverride): GlazeTheme;
1921
+ declare function glaze(hue: number, saturation?: number, config?: GlazeConfigOverride): GlazeTheme;
1922
+ declare function glaze(seed: GlazeThemeSeed, config?: GlazeConfigOverride): GlazeTheme;
1923
+ /** @deprecated Pass the config second: `glaze(seed, config)`. */
1924
+ declare function glaze(seed: GlazeThemeSeed, saturation: undefined, config?: GlazeConfigOverride): GlazeTheme;
1559
1925
  declare namespace glaze {
1560
1926
  var configure: (config: GlazeConfig) => void;
1561
1927
  var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => GlazePalette;
@@ -1563,18 +1929,28 @@ declare namespace glaze {
1563
1929
  var from: (data: GlazeThemeExport) => GlazeTheme;
1564
1930
  var color: (input: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?: GlazeConfigOverride) => GlazeColorToken;
1565
1931
  var shadow: (input: GlazeShadowInput) => ResolvedColorVariant;
1932
+ var glow: (input: GlazeGlowInput) => ResolvedColorVariant;
1566
1933
  var format: (variant: ResolvedColorVariant, colorFormat?: GlazeColorFormat, pastel?: boolean) => string;
1934
+ var formatHdr: (variant: ResolvedColorVariant, hdrFormat?: GlazeHdrFormat) => string | undefined;
1567
1935
  var fromHex: (hex: string) => GlazeTheme;
1568
1936
  var fromRgb: (r: number, g: number, b: number) => GlazeTheme;
1569
1937
  var colorFrom: (data: GlazeColorTokenExport) => GlazeColorToken;
1570
1938
  var paletteFrom: (data: GlazePaletteExport) => GlazePalette;
1571
- var isThemeExport: typeof isThemeExport;
1572
- var isColorTokenExport: typeof isColorTokenExport;
1573
- var isPaletteExport: typeof isPaletteExport;
1939
+ var isThemeExport: (value: unknown) => value is GlazeThemeExport;
1940
+ var isColorTokenExport: (value: unknown) => value is GlazeColorTokenExport;
1941
+ var isPaletteExport: (value: unknown) => value is GlazePaletteExport;
1574
1942
  var getConfig: () => GlazeConfigResolved;
1575
1943
  var resetConfig: () => void;
1576
1944
  }
1577
1945
  //#endregion
1946
+ //#region src/serialize.d.ts
1947
+ /** Type guard for theme authoring snapshots (prefers `kind`, falls back to shape). */
1948
+ declare function isThemeExport(data: unknown): data is GlazeThemeExport;
1949
+ /** Type guard for color-token authoring snapshots. */
1950
+ declare function isColorTokenExport(data: unknown): data is GlazeColorTokenExport;
1951
+ /** Type guard for palette authoring snapshots. */
1952
+ declare function isPaletteExport(data: unknown): data is GlazePaletteExport;
1953
+ //#endregion
1578
1954
  //#region src/channels.d.ts
1579
1955
  interface HueDeclaration {
1580
1956
  prop: string;
@@ -1583,7 +1959,7 @@ interface HueDeclaration {
1583
1959
  interface HuePlan {
1584
1960
  /** CSS `var()` reference spliced into `oklch(L C <hueVar>)`. */
1585
1961
  hueVar: string;
1586
- /** When true, emit a full inline color (shadow/mix/achromatic). */
1962
+ /** When true, emit a full inline color (shadow/glow/mix/achromatic). */
1587
1963
  inline: boolean;
1588
1964
  /** Scheme-independent `--*-hue` declarations for this color. */
1589
1965
  declarations: HueDeclaration[];
@@ -1619,12 +1995,14 @@ interface ChannelCtx {
1619
1995
  * emits raw CSS or non-Tasty token maps.
1620
1996
  */
1621
1997
  declare function assertNativeFormat(format: GlazeColorFormat | undefined, method: string): void;
1998
+ /** The modes `assertAllPastel` reads: which schemes are emitted. */
1999
+ type SchemeModes = Required<Pick<GlazeOutputModes, 'dark' | 'highContrast'>>;
1622
2000
  /**
1623
2001
  * Throw when `splitHue` is enabled but any exported color is not pastel.
1624
2002
  * Hue rotation is only clip-free when chroma is bounded by the hue-independent
1625
2003
  * safe chroma (`computeSafeChromaOKLCH`).
1626
2004
  */
1627
- declare function assertAllPastel(resolved: Map<string, ResolvedColor>, modes: Required<GlazeOutputModes>): void;
2005
+ declare function assertAllPastel(resolved: Map<string, ResolvedColor>, modes: SchemeModes): void;
1628
2006
  //#endregion
1629
2007
  //#region src/roles.d.ts
1630
2008
  /**
@@ -1720,7 +2098,11 @@ declare function variantToOkhsl(v: {
1720
2098
  *
1721
2099
  * Provides bidirectional OKHSL ↔ sRGB conversion, luminance computation
1722
2100
  * for both contrast metrics (WCAG 2 relative luminance and APCA screen
1723
- * luminance `Ys`), and multi-format output (okhsl, rgb, hsl, oklch).
2101
+ * luminance `Ys` — both the exact functions the contrast solver uses, and
2102
+ * both public), strict hex parsing (`parseHex` / `parseHexAlpha` check every
2103
+ * digit), and multi-format output (okhsl, rgb, hsl, oklch, plus the
2104
+ * unclamped `color(srgb …)` / `color(srgb-linear …)` writers for HDR glow
2105
+ * values, whose channels may exceed 1).
1724
2106
  */
1725
2107
  type Vec3 = [number, number, number];
1726
2108
  /**
@@ -1766,6 +2148,22 @@ declare function okhslToSrgb(h: number, s: number, l: number, pastel?: boolean):
1766
2148
  * This avoids over/under-estimating luminance for out-of-gamut OKHSL colors.
1767
2149
  */
1768
2150
  declare function gamutClampedLuminance(linearRgb: [number, number, number]): number;
2151
+ /**
2152
+ * Compute APCA screen luminance (`Ys`) from linear sRGB.
2153
+ *
2154
+ * APCA does not use the WCAG piecewise sRGB EOTF; it defines its own
2155
+ * luminance as `0.2126·R^2.4 + 0.7152·G^2.4 + 0.0722·B^2.4` over the
2156
+ * gamma-encoded (display) channels with a simple 2.4 exponent. The APCA
2157
+ * soft-clamp threshold in `apcaContrast` is calibrated against this basis,
2158
+ * so the solver must feed it `Ys`, not WCAG relative luminance. Channels
2159
+ * are gamut-clamped to [0, 1] first, matching `gamutClampedLuminance`.
2160
+ *
2161
+ * This is exactly the luminance Glaze's contrast solver (and its drift
2162
+ * check) feeds `apcaContrast`, so
2163
+ * `apcaContrast(apcaLuminanceFromLinearRgb(text), apcaLuminanceFromLinearRgb(bg))`
2164
+ * reproduces the solver's Lc for a resolved pair.
2165
+ */
2166
+ declare function apcaLuminanceFromLinearRgb(linearRgb: [number, number, number]): number;
1769
2167
  /**
1770
2168
  * Convert OKLab to OKHSL.
1771
2169
  * Input: [L, a, b] where L: 0–1, a/b: roughly -0.5 to 0.5.
@@ -1775,6 +2173,11 @@ declare const oklabToOkhsl: (lab: Vec3, pastel?: boolean) => Vec3;
1775
2173
  /**
1776
2174
  * Convert gamma-encoded sRGB (0–1 per channel) to OKHSL.
1777
2175
  * Returns [h, s, l] where h: 0–360, s: 0–1, l: 0–1.
2176
+ *
2177
+ * A gray reads with saturation 0 (its computed hue is kept). Its OKLab
2178
+ * residue would otherwise come out as a saturation that grows toward white
2179
+ * (`#fefefe` reads 1.6e-5, `rgb(254.999 254.999 254.999)` 1.6e-2), which a
2180
+ * color carries into every scheme and an OKHSL mix reads as a hue.
1778
2181
  */
1779
2182
  declare function srgbToOkhsl(rgb: [number, number, number], pastel?: boolean): [number, number, number];
1780
2183
  /**
@@ -1787,7 +2190,9 @@ declare function srgbToOkhsl(rgb: [number, number, number], pastel?: boolean): [
1787
2190
  declare function hslToSrgb(h: number, s: number, l: number): [number, number, number];
1788
2191
  /**
1789
2192
  * Parse a hex color string (#rgb or #rrggbb) to sRGB [r, g, b] in 0–1 range.
1790
- * Returns null if the string is not a valid hex color.
2193
+ * The leading `#` is optional. Returns null if the string is not a valid hex
2194
+ * color: a wrong length, any character outside `0-9a-f` (case-insensitive),
2195
+ * or a form with alpha.
1791
2196
  *
1792
2197
  * For 8-digit hex (`#rrggbbaa`) and 4-digit hex (`#rgba`) with alpha,
1793
2198
  * use {@link parseHexAlpha}.
@@ -1796,7 +2201,12 @@ declare function parseHex(hex: string): [number, number, number] | null;
1796
2201
  /**
1797
2202
  * Parse a hex color string (#rgb, #rrggbb, #rgba, or #rrggbbaa) to
1798
2203
  * sRGB [r, g, b] in 0–1 range plus an optional alpha (0–1).
1799
- * Returns null if the string is not a valid hex color.
2204
+ * The leading `#` is optional. Returns null if the string is not a valid hex
2205
+ * color: a wrong length or any character outside `0-9a-f`
2206
+ * (case-insensitive).
2207
+ *
2208
+ * Every digit is checked up front: `parseInt` alone stops at the first bad
2209
+ * character, so `'#1z2z3z'` would otherwise read as `#010203`.
1800
2210
  */
1801
2211
  declare function parseHexAlpha(hex: string): {
1802
2212
  rgb: [number, number, number];
@@ -1831,6 +2241,25 @@ declare function formatHsl(h: number, s: number, l: number, pastel?: boolean): s
1831
2241
  * h: 0–360, s: 0–1, l: 0–1 (factor scale, as returned by every converter).
1832
2242
  */
1833
2243
  declare function formatOklch(h: number, s: number, l: number, pastel?: boolean): string;
2244
+ /**
2245
+ * Format linear sRGB channels as a CSS `color(srgb-linear R G B)` string with
2246
+ * 4 decimals. Unlike the other writers it takes linear light, not OKHSL, and
2247
+ * does not clamp: a channel may exceed 1, which is how an HDR glow value
2248
+ * written with `glaze.formatHdr(v, 'srgb-linear')` goes past SDR white — `1`
2249
+ * is SDR white, `2` one stop above it (the default extended form is
2250
+ * `formatSrgb`). Opaque only; HDR values carry no alpha.
2251
+ */
2252
+ declare function formatSrgbLinear(rgb: [number, number, number]): string;
2253
+ /**
2254
+ * Format extended sRGB channels — gamma-encoded, with the transfer function
2255
+ * continued past 1 (`sRGBLinearToGamma` does) — as a CSS `color(srgb R G B)`
2256
+ * string with 4 decimals. Like `formatSrgbLinear` it takes the channels of
2257
+ * its own space and does not clamp, so an HDR glow value
2258
+ * (`glaze.formatHdr()`) can pass SDR white: `1` is SDR white, about `1.3533`
2259
+ * one stop above it. CSS reads it as the same color as the matching
2260
+ * `color(srgb-linear …)`. Opaque only; HDR values carry no alpha.
2261
+ */
2262
+ declare function formatSrgb(rgb: [number, number, number]): string;
1834
2263
  /**
1835
2264
  * Convert gamma-encoded sRGB channels (0–1) to a 6-digit lowercase hex
1836
2265
  * string (`#rrggbb`). Channels are clamped to [0,1] and rounded to 8-bit.
@@ -1844,5 +2273,21 @@ declare function srgbToHex(rgb: [number, number, number]): `#${string}`;
1844
2273
  */
1845
2274
  declare function okhslToOklch(h: number, s: number, l: number, pastel?: boolean): [number, number, number];
1846
2275
  //#endregion
1847
- export { APCA_HC_ENHANCEMENT, APCA_MAX_LC, APCA_PRESETS, type AdaptationMode, type ApcaPreset, type ChannelCtx, type ColorDef, type ColorMap, type ContrastPreset, type ContrastSpec, type DtcgColorSpace, type DtcgColorToken, type DtcgColorValue, type DtcgDocument, type DtcgOklchColorValue, type DtcgResolverModifier, type DtcgResolverRef, type DtcgResolverSet, type DtcgSrgbColorValue, type DtcgTokenTree, type ExtremeValue, type FindToneForContrastOptions, type FindToneForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, GLAZE_EXPORT_VERSION, type GlazeColorCssOptions, type GlazeColorDtcgResolverOptions, type GlazeColorDtcgResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorInputExport, type GlazeColorOverrides, type GlazeColorOverridesExport, type GlazeColorTailwindOptions, type GlazeColorToken, type GlazeColorTokenExport, type GlazeColorValue, type GlazeConfig, type GlazeConfigOverride, type GlazeConfigResolved, type GlazeCssOptions, type GlazeCssResult, type GlazeDtcgOptions, type GlazeDtcgResolverContextNames, type GlazeDtcgResolverDocument, type GlazeDtcgResolverOptions, type GlazeDtcgResult, type GlazeExportKind, type GlazeExportVersion, type GlazeExtendOptions, type GlazeFromInput, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExport, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTailwindOptions, type GlazeTheme, type GlazeThemeExport, type GlazeThemeSeed, type GlazeTokenOptions, type HCPair, type HexColor, type HueDeclaration, type HuePlan, type MinContrast, type MixColorDef, type OkhslColor, type OkhstColor, type OklchColor, type Polarity, REF_EPS, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ResolvedContrast, type RgbColor, type Role, type RoleInput, type ShadowColorDef, type ShadowTuning, type ToneValue, type ToneWindow, apcaContrast, assertAllPastel, assertNativeFormat, contrastRatioFromLuminance, cuspLightness, findToneForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOkhst, formatOklch, formatRgb, fromTone, gamutClampedLuminance, glaze, hslToSrgb, inferRoleFromName, isColorTokenExport, isPaletteExport, isThemeExport, normalizeRole, okhslToLinearSrgb, okhslToOkhst, okhslToOklab, okhslToOklch, okhslToSrgb, okhstToOkhsl, oklabToOkhsl, oppositeRole, parseHex, parseHexAlpha, relativeLuminanceFromLinearRgb, resolveApcaTarget, resolveContrastForLevel, resolveContrastForMode, resolveMinContrast, roleToPolarity, srgbToHex, srgbToOkhsl, toTone, toneFromY, variantToOkhsl, yFromTone };
2276
+ //#region src/lighting.d.ts
2277
+ /**
2278
+ * Linear sRGB of a resolved HDR value: the base's channels times
2279
+ * `2^exposure`, unclamped (the brightest channel can reach `2^headroom`).
2280
+ * The base is non-pastel OKHSL, so no `pastel` flag applies.
2281
+ */
2282
+ declare function hdrToLinearSrgb(hdr: ResolvedHdr): [number, number, number];
2283
+ /**
2284
+ * Extended sRGB of a resolved HDR value: `hdrToLinearSrgb` through the sRGB
2285
+ * transfer function, continued past 1 the way CSS and the platform
2286
+ * extended-sRGB spaces continue it, unclamped. These are the channels of
2287
+ * `color(srgb R G B)` (`glaze.formatHdr()`), and what a WebGPU `'srgb'`
2288
+ * canvas, `CGColorSpace.extendedSRGB`, and Android's `EXTENDED_SRGB` take.
2289
+ */
2290
+ declare function hdrToSrgb(hdr: ResolvedHdr): [number, number, number];
2291
+ //#endregion
2292
+ export { APCA_HC_ENHANCEMENT, APCA_MAX_LC, APCA_PRESETS, type AdaptationMode, type ApcaPreset, type ChannelCtx, type ColorDef, type ColorMap, type ContrastPreset, type ContrastSpec, type DtcgColorSpace, type DtcgColorToken, type DtcgColorValue, type DtcgDocument, type DtcgOklchColorValue, type DtcgResolverModifier, type DtcgResolverRef, type DtcgResolverSet, type DtcgSrgbColorValue, type DtcgTokenTree, type ExtremeValue, type FindToneForContrastOptions, type FindToneForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, GLAZE_EXPORT_VERSION, type GlazeColorCssOptions, type GlazeColorDtcgResolverOptions, type GlazeColorDtcgResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorInputExport, type GlazeColorOverrides, type GlazeColorOverridesExport, type GlazeColorTailwindOptions, type GlazeColorToken, type GlazeColorTokenExport, type GlazeColorValue, type GlazeConfig, type GlazeConfigOverride, type GlazeConfigResolved, type GlazeCssOptions, type GlazeCssResult, type GlazeCssSchemeBlocks, type GlazeDtcgExtensions, type GlazeDtcgHdr, type GlazeDtcgOptions, type GlazeDtcgResolverContextNames, type GlazeDtcgResolverDocument, type GlazeDtcgResolverOptions, type GlazeDtcgResult, type GlazeExportKind, type GlazeExportVersion, type GlazeExtendOptions, type GlazeFromInput, type GlazeGlowInput, type GlazeHdrFormat, type GlazeJsonOptions, type GlazeLightingInput, type GlazeOutputModes, type GlazePalette, type GlazePaletteCssOptions, type GlazePaletteExport, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazePaletteTastyOptions, type GlazeShadowInput, type GlazeTailwindOptions, type GlazeTastyOptions, type GlazeTheme, type GlazeThemeExport, type GlazeThemeSeed, type GlazeTokenOptions, type GlowColorDef, type GlowTuning, type HCPair, type HexColor, type HueDeclaration, type HuePlan, type LightingTuning, type MinContrast, type MixColorDef, type OkhslColor, type OkhstColor, type OklchColor, type Polarity, REF_EPS, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ResolvedContrast, type ResolvedHdr, type RgbColor, type Role, type RoleInput, type ShadowColorDef, type ShadowTuning, type ToneValue, type ToneWindow, apcaContrast, apcaLuminanceFromLinearRgb, assertAllPastel, assertNativeFormat, contrastRatioFromLuminance, cuspLightness, findToneForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOkhst, formatOklch, formatRgb, formatSrgb, formatSrgbLinear, fromTone, gamutClampedLuminance, glaze, hdrToLinearSrgb, hdrToSrgb, hslToSrgb, inferRoleFromName, isColorTokenExport, isPaletteExport, isThemeExport, normalizeRole, okhslToLinearSrgb, okhslToOkhst, okhslToOklab, okhslToOklch, okhslToSrgb, okhstToOkhsl, oklabToOkhsl, oppositeRole, parseHex, parseHexAlpha, relativeLuminanceFromLinearRgb, resolveApcaTarget, resolveContrastForLevel, resolveContrastForMode, resolveMinContrast, roleToPolarity, srgbToHex, srgbToOkhsl, toTone, toneFromY, variantToOkhsl, yFromTone };
1848
2293
  //# sourceMappingURL=index.d.mts.map