vireglass 2.3.1 → 3.0.1

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.
Files changed (58) hide show
  1. package/README.md +37 -6
  2. package/dist/{adapters-BOPIRMnL.d.cts → adapters--bXcGvhW.d.cts} +2 -2
  3. package/dist/{adapters-B_amRBqc.d.ts → adapters-BlMhc6pI.d.ts} +2 -2
  4. package/dist/{chunk-MMPK6DCK.js → chunk-CPSIY2DZ.js} +58 -8
  5. package/dist/chunk-CPSIY2DZ.js.map +1 -0
  6. package/dist/{chunk-UDPJLNFW.js → chunk-RWUR3OV6.js} +4 -4
  7. package/dist/{chunk-UDPJLNFW.js.map → chunk-RWUR3OV6.js.map} +1 -1
  8. package/dist/{chunk-CTTZNZFV.js → chunk-VLDD655U.js} +3 -3
  9. package/dist/{chunk-CTTZNZFV.js.map → chunk-VLDD655U.js.map} +1 -1
  10. package/dist/{chunk-V47YU75P.js → chunk-YAN2OK4H.js} +31 -38
  11. package/dist/chunk-YAN2OK4H.js.map +1 -0
  12. package/dist/{chunk-SLRPHDV7.js → chunk-Z4FKYY47.js} +3 -3
  13. package/dist/{chunk-SLRPHDV7.js.map → chunk-Z4FKYY47.js.map} +1 -1
  14. package/dist/dom.cjs +185 -58
  15. package/dist/dom.cjs.map +1 -1
  16. package/dist/dom.d.cts +73 -26
  17. package/dist/dom.d.ts +73 -26
  18. package/dist/dom.js +121 -57
  19. package/dist/dom.js.map +1 -1
  20. package/dist/{geometry-RhKd7CM5.d.cts → geometry-ip9WSlZv.d.cts} +1 -1
  21. package/dist/{geometry-GvXtt-_S.d.ts → geometry-pabkYV7w.d.ts} +1 -1
  22. package/dist/{group-model-z4N27qsC.d.ts → group-model-CQiI5cCe.d.ts} +1 -1
  23. package/dist/{group-model-DwtixGhG.d.cts → group-model-DX2_W9J_.d.cts} +1 -1
  24. package/dist/index.cjs +92 -40
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +6 -6
  27. package/dist/index.d.ts +6 -6
  28. package/dist/index.js +5 -5
  29. package/dist/law.cjs +56 -6
  30. package/dist/law.cjs.map +1 -1
  31. package/dist/law.d.cts +54 -4
  32. package/dist/law.d.ts +54 -4
  33. package/dist/law.js +1 -1
  34. package/dist/{material-CnUmdKg1.d.ts → material-D9m1EN47.d.cts} +9 -6
  35. package/dist/{material-CnUmdKg1.d.cts → material-D9m1EN47.d.ts} +9 -6
  36. package/dist/react.d.cts +1 -1
  37. package/dist/react.d.ts +1 -1
  38. package/dist/reference.d.cts +2 -2
  39. package/dist/reference.d.ts +2 -2
  40. package/dist/reference.js +2 -2
  41. package/dist/web/index.cjs +91 -39
  42. package/dist/web/index.cjs.map +1 -1
  43. package/dist/web/index.d.cts +3 -3
  44. package/dist/web/index.d.ts +3 -3
  45. package/dist/web/index.js +4 -4
  46. package/docs/dom.md +49 -3
  47. package/docs/law.md +1 -1
  48. package/package.json +1 -1
  49. package/src/dom/body.ts +93 -39
  50. package/src/dom/index.ts +50 -21
  51. package/src/dom/probe.ts +1 -1
  52. package/src/dom/rim.ts +69 -32
  53. package/src/dom/style-hold.ts +8 -0
  54. package/src/law.ts +54 -4
  55. package/src/lens-shader.ts +26 -33
  56. package/src/material.ts +10 -7
  57. package/dist/chunk-MMPK6DCK.js.map +0 -1
  58. package/dist/chunk-V47YU75P.js.map +0 -1
package/dist/dom.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { B as BackdropSample } from './adaptation-BSbbdExK.cjs';
2
- import { V as VireGlassGeometry } from './geometry-RhKd7CM5.cjs';
3
- import { V as VireGlassOptics, a as VireGlassMaterial } from './material-CnUmdKg1.cjs';
4
- import { T as TouchWarp, M as MorphShape, V as VireGlassAccessibility, S as ScrollEdgeStyle, G as GroupPlane } from './group-model-DwtixGhG.cjs';
5
- import { V as VireGlassAccent } from './adapters-BOPIRMnL.cjs';
2
+ import { V as VireGlassGeometry } from './geometry-ip9WSlZv.cjs';
3
+ import { V as VireGlassOptics, a as VireGlassMaterial } from './material-D9m1EN47.cjs';
4
+ import { T as TouchWarp, M as MorphShape, V as VireGlassAccessibility, S as ScrollEdgeStyle, G as GroupPlane } from './group-model-DX2_W9J_.cjs';
5
+ import { V as VireGlassAccent } from './adapters--bXcGvhW.cjs';
6
6
 
7
7
  /** Any `backdrop-filter` at all (e.g. `blur()`) — the fallback path's own requirement. */
8
8
  declare function supportsBackdropFilter(): boolean;
@@ -32,7 +32,9 @@ declare function parseColor(value: string): RgbColor | null;
32
32
  * formula here would mean the ink-polarity decision quietly drifts between renderers on the same
33
33
  * page. `samples` are 0..255 per channel, matching what `parseColor` returns.
34
34
  */
35
- declare function statsFromSamples(samples: readonly RgbColor[]): BackdropSample;
35
+ declare function statsFromSamples(samples: readonly (Omit<RgbColor, 'a'> & {
36
+ a?: number;
37
+ })[]): BackdropSample;
36
38
  /**
37
39
  * Composites a stack of backgrounds front to back, the way the compositor does.
38
40
  *
@@ -100,13 +102,26 @@ declare function lightConicAngle(light: readonly [number, number]): number;
100
102
  * the light. Both arcs come out of this one expression — that is why they are opposed. */
101
103
  declare function rimLobe(deltaDeg: number, specular: number): number;
102
104
  type RimAmbient = readonly [number, number, number];
105
+ /** Lightness of an ambient colour, the weights the lens uses. */
106
+ declare function ambientLuma(ambient: RimAmbient): number;
107
+ /** How strongly the line is drawn over a surround of this lightness (§2, §6). */
108
+ declare function rimStrength(luma: number): number;
103
109
  /**
104
- * The gradient for the hairline. Colour comes from the environment — "over a yellow flower the rim
105
- * is yellow, over sky it is blue" (§2) — lifted toward white where the key light lands. Away from
106
- * both arcs only the dark edge remains.
110
+ * The line's opacity where the rim's normal sits `deltaDeg` from the light: a floor all the way
111
+ * round and the key-light lobe on top of it, all of it scaled by the medium's reflectance up to
112
+ * the reference material's.
113
+ */
114
+ declare function rimLineAlpha(deltaDeg: number, optics: VireGlassOptics, luma: number): number;
115
+ /**
116
+ * The gradient for the hairline: a light line round the whole contour, brighter toward the key
117
+ * light, drawn over the dark edge. Its colour comes from the environment — "over a yellow flower
118
+ * the rim is yellow, over sky it is blue" (§2) — lifted toward white, and its strength follows how
119
+ * light the environment is.
107
120
  *
108
121
  * The opposing arc carries an iridescent fringe (§2), so `iridescence` pulls its channels apart
109
122
  * rather than lifting them together.
123
+ *
124
+ * Two layers, the line first: `--vireglass-rim` is a background list and paints as one.
110
125
  */
111
126
  declare function rimGradientCss(optics: VireGlassOptics, ambient: RimAmbient, light: readonly [number, number], appear?: number): string;
112
127
  declare const RIM_WIDTH_PX: 1;
@@ -119,7 +134,7 @@ declare const RIM_WIDTH_PX: 1;
119
134
  * everything around it. It has to hold at every angle, including the one facing away from the key
120
135
  * light where the ordinary rim falls back to a dim dark line.
121
136
  */
122
- declare function contrastRimCss(bodyLuma: number, rimLuma: number): string;
137
+ declare function contrastRimCss(bodyLuma: number, rimLuma: number, appear?: number): string;
123
138
 
124
139
  declare function shadowAlphaFrom(sample: {
125
140
  busy: number;
@@ -151,6 +166,9 @@ type GlassBody = {
151
166
  density: number;
152
167
  /** Lightness the body tints toward. */
153
168
  tintLuma: number;
169
+ /** The part of the density the ink's legibility asked for, and the pole it asked toward. */
170
+ need: number;
171
+ pole: number;
154
172
  };
155
173
  /**
156
174
  * `ink` is POLARITY, 1 light and 0 dark, matching the shader's uniform. The requirements are
@@ -160,23 +178,37 @@ type GlassBody = {
160
178
  declare function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink: number): GlassBody;
161
179
  /**
162
180
  * PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly
163
- * disappears — right for a piece of background, wrong for a control. It is a MINIMUM, not an
164
- * addition, so a body that already stands apart is left alone.
181
+ * disappears — right for a piece of background, wrong for a control. It is a MINIMUM on the
182
+ * density, toward light whatever the ink, and it does not read the backdrop: the lift it gives is
183
+ * `presence` times the room left under the light pole, so it fades out as the room does and has no
184
+ * step anywhere on the scale.
185
+ */
186
+ declare function withPresence(body: GlassBody, optics: VireGlassOptics, _sample?: BodyBackdrop): GlassBody;
187
+ type BodyLayer = {
188
+ /** Straight (not premultiplied) colour, 0…1 per channel. */
189
+ r: number;
190
+ g: number;
191
+ b: number;
192
+ alpha: number;
193
+ };
194
+ /**
195
+ * The body as ONE translucent layer over the backdrop, which is the form the DOM can draw it in.
196
+ *
197
+ * The lens does not paint a body, it transforms what it refracts, in a chain that stays affine in
198
+ * the backdrop: a mix toward the tint at `density`, the matte lift, the medium's pull toward its
199
+ * own lightness, the ambient spill and the concentration of light (§3, `MEDIUM`). Composing it
200
+ * gives `out = A * backdrop + B` per channel, and a layer of colour `B / (1 - A)` at opacity
201
+ * `1 - A` over the backdrop is that, except where the colour clamps to 0..1: over a saturated dark
202
+ * backdrop (dark blue) a channel is off by up to 0.024.
165
203
  *
166
- * The direction is the body's own. The previous version decided "lighter over dark, darker over
167
- * light" from the backdrop alone, and then, when the body disagreed, clamped `tintLuma` to the
168
- * backdrop's mean — the one value that separates from nothing. Light ink over a dark backdrop puts
169
- * the body at 0.07 against a backdrop of 0.12: already separating, downward, and the clamp pulled
170
- * it back onto the backdrop. Measured on the default material at presence 0.08: exactly 0.0000 at
171
- * backdrops of 0.12, 0.20 and 0.35.
204
+ * This is what lifts the body over a dark backdrop. The tint alone, under light ink, is darker
205
+ * than the dark it sits on; the medium's pull, the matte lift and the concentration are what make
206
+ * it read lighter, as in the reference (M 2:29, A 2:17).
172
207
  *
173
- * What the demand is DIVIDED by is deliberately the distance to the tint's pole rather than to the
174
- * body's own tint. Dividing by the latter is arithmetically tighter and asks for far more density
175
- * wherever the two are close — enough to drive it to the ceiling over a dark backdrop and stop the
176
- * glass being a window at all, which check:optics says plainly. Presence is a floor on visibility,
177
- * not a licence to go opaque.
208
+ * `appear` multiplies the layers exactly where the lens's `u_appear` does, so `optics` is the
209
+ * element's optics BEFORE `applyAppear`: scaling both would count it twice.
178
210
  */
179
- declare function withPresence(body: GlassBody, optics: VireGlassOptics, sample: BodyBackdrop): GlassBody;
211
+ declare function bodyLayer(optics: VireGlassOptics, sample: BodyBackdrop, ink: number, ambient: readonly [number, number, number], appear?: number): BodyLayer;
180
212
 
181
213
  declare function systemAccessibility(): VireGlassAccessibility;
182
214
  /** Fires whenever any of the three changes. The material has to follow a setting turned on while
@@ -320,9 +352,19 @@ type AttachGlassOptions = {
320
352
  } | null) => void;
321
353
  /** Pointer response (§5). On by default. */
322
354
  interactive?: boolean;
323
- /** Overrides the probe entirely — images and video are invisible to it, and the host app
324
- * already knows its own cover-art accent. */
355
+ /**
356
+ * Overrides the probe entirely. The probe reads declared backgrounds, so images, video and
357
+ * canvases are invisible to it; a host that knows its backdrop (a cover's accent, a gradient)
358
+ * states it here, and changes it later with `setSample`. `statsFromSamples` builds one from
359
+ * a handful of colours.
360
+ */
325
361
  sample?: BackdropSample;
362
+ /**
363
+ * Whether `attachGlass` paints the body as the element's `background-color`. On by default;
364
+ * turn it off if the host owns that property — `--vireglass-body-color` is always emitted
365
+ * either way and carries the same colour.
366
+ */
367
+ body?: boolean;
326
368
  };
327
369
  /**
328
370
  * Shapes this element flows into (docs/reference.md §5): merging with a neighbour, or splitting
@@ -363,8 +405,13 @@ type GlassHandle = {
363
405
  strength: number;
364
406
  } | null): void;
365
407
  setMorph(morph: GlassMorph | null): void;
408
+ /**
409
+ * Replaces the backdrop the glass adapts to, without re-attaching, and repaints. The same
410
+ * object as `sample` in the options; `null` goes back to probing declared backgrounds.
411
+ */
412
+ setSample(sample: BackdropSample | null): void;
366
413
  destroy(): void;
367
414
  };
368
415
  declare function attachGlass(el: HTMLElement, opts?: AttachGlassOptions): GlassHandle;
369
416
 
370
- export { type AttachGlassOptions, type BodyBackdrop, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, attachGlass, attachScrollEdge, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLobe, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
417
+ export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
package/dist/dom.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { B as BackdropSample } from './adaptation-BSbbdExK.js';
2
- import { V as VireGlassGeometry } from './geometry-GvXtt-_S.js';
3
- import { V as VireGlassOptics, a as VireGlassMaterial } from './material-CnUmdKg1.js';
4
- import { T as TouchWarp, M as MorphShape, V as VireGlassAccessibility, S as ScrollEdgeStyle, G as GroupPlane } from './group-model-z4N27qsC.js';
5
- import { V as VireGlassAccent } from './adapters-B_amRBqc.js';
2
+ import { V as VireGlassGeometry } from './geometry-pabkYV7w.js';
3
+ import { V as VireGlassOptics, a as VireGlassMaterial } from './material-D9m1EN47.js';
4
+ import { T as TouchWarp, M as MorphShape, V as VireGlassAccessibility, S as ScrollEdgeStyle, G as GroupPlane } from './group-model-CQiI5cCe.js';
5
+ import { V as VireGlassAccent } from './adapters-BlMhc6pI.js';
6
6
 
7
7
  /** Any `backdrop-filter` at all (e.g. `blur()`) — the fallback path's own requirement. */
8
8
  declare function supportsBackdropFilter(): boolean;
@@ -32,7 +32,9 @@ declare function parseColor(value: string): RgbColor | null;
32
32
  * formula here would mean the ink-polarity decision quietly drifts between renderers on the same
33
33
  * page. `samples` are 0..255 per channel, matching what `parseColor` returns.
34
34
  */
35
- declare function statsFromSamples(samples: readonly RgbColor[]): BackdropSample;
35
+ declare function statsFromSamples(samples: readonly (Omit<RgbColor, 'a'> & {
36
+ a?: number;
37
+ })[]): BackdropSample;
36
38
  /**
37
39
  * Composites a stack of backgrounds front to back, the way the compositor does.
38
40
  *
@@ -100,13 +102,26 @@ declare function lightConicAngle(light: readonly [number, number]): number;
100
102
  * the light. Both arcs come out of this one expression — that is why they are opposed. */
101
103
  declare function rimLobe(deltaDeg: number, specular: number): number;
102
104
  type RimAmbient = readonly [number, number, number];
105
+ /** Lightness of an ambient colour, the weights the lens uses. */
106
+ declare function ambientLuma(ambient: RimAmbient): number;
107
+ /** How strongly the line is drawn over a surround of this lightness (§2, §6). */
108
+ declare function rimStrength(luma: number): number;
103
109
  /**
104
- * The gradient for the hairline. Colour comes from the environment — "over a yellow flower the rim
105
- * is yellow, over sky it is blue" (§2) — lifted toward white where the key light lands. Away from
106
- * both arcs only the dark edge remains.
110
+ * The line's opacity where the rim's normal sits `deltaDeg` from the light: a floor all the way
111
+ * round and the key-light lobe on top of it, all of it scaled by the medium's reflectance up to
112
+ * the reference material's.
113
+ */
114
+ declare function rimLineAlpha(deltaDeg: number, optics: VireGlassOptics, luma: number): number;
115
+ /**
116
+ * The gradient for the hairline: a light line round the whole contour, brighter toward the key
117
+ * light, drawn over the dark edge. Its colour comes from the environment — "over a yellow flower
118
+ * the rim is yellow, over sky it is blue" (§2) — lifted toward white, and its strength follows how
119
+ * light the environment is.
107
120
  *
108
121
  * The opposing arc carries an iridescent fringe (§2), so `iridescence` pulls its channels apart
109
122
  * rather than lifting them together.
123
+ *
124
+ * Two layers, the line first: `--vireglass-rim` is a background list and paints as one.
110
125
  */
111
126
  declare function rimGradientCss(optics: VireGlassOptics, ambient: RimAmbient, light: readonly [number, number], appear?: number): string;
112
127
  declare const RIM_WIDTH_PX: 1;
@@ -119,7 +134,7 @@ declare const RIM_WIDTH_PX: 1;
119
134
  * everything around it. It has to hold at every angle, including the one facing away from the key
120
135
  * light where the ordinary rim falls back to a dim dark line.
121
136
  */
122
- declare function contrastRimCss(bodyLuma: number, rimLuma: number): string;
137
+ declare function contrastRimCss(bodyLuma: number, rimLuma: number, appear?: number): string;
123
138
 
124
139
  declare function shadowAlphaFrom(sample: {
125
140
  busy: number;
@@ -151,6 +166,9 @@ type GlassBody = {
151
166
  density: number;
152
167
  /** Lightness the body tints toward. */
153
168
  tintLuma: number;
169
+ /** The part of the density the ink's legibility asked for, and the pole it asked toward. */
170
+ need: number;
171
+ pole: number;
154
172
  };
155
173
  /**
156
174
  * `ink` is POLARITY, 1 light and 0 dark, matching the shader's uniform. The requirements are
@@ -160,23 +178,37 @@ type GlassBody = {
160
178
  declare function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink: number): GlassBody;
161
179
  /**
162
180
  * PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly
163
- * disappears — right for a piece of background, wrong for a control. It is a MINIMUM, not an
164
- * addition, so a body that already stands apart is left alone.
181
+ * disappears — right for a piece of background, wrong for a control. It is a MINIMUM on the
182
+ * density, toward light whatever the ink, and it does not read the backdrop: the lift it gives is
183
+ * `presence` times the room left under the light pole, so it fades out as the room does and has no
184
+ * step anywhere on the scale.
185
+ */
186
+ declare function withPresence(body: GlassBody, optics: VireGlassOptics, _sample?: BodyBackdrop): GlassBody;
187
+ type BodyLayer = {
188
+ /** Straight (not premultiplied) colour, 0…1 per channel. */
189
+ r: number;
190
+ g: number;
191
+ b: number;
192
+ alpha: number;
193
+ };
194
+ /**
195
+ * The body as ONE translucent layer over the backdrop, which is the form the DOM can draw it in.
196
+ *
197
+ * The lens does not paint a body, it transforms what it refracts, in a chain that stays affine in
198
+ * the backdrop: a mix toward the tint at `density`, the matte lift, the medium's pull toward its
199
+ * own lightness, the ambient spill and the concentration of light (§3, `MEDIUM`). Composing it
200
+ * gives `out = A * backdrop + B` per channel, and a layer of colour `B / (1 - A)` at opacity
201
+ * `1 - A` over the backdrop is that, except where the colour clamps to 0..1: over a saturated dark
202
+ * backdrop (dark blue) a channel is off by up to 0.024.
165
203
  *
166
- * The direction is the body's own. The previous version decided "lighter over dark, darker over
167
- * light" from the backdrop alone, and then, when the body disagreed, clamped `tintLuma` to the
168
- * backdrop's mean — the one value that separates from nothing. Light ink over a dark backdrop puts
169
- * the body at 0.07 against a backdrop of 0.12: already separating, downward, and the clamp pulled
170
- * it back onto the backdrop. Measured on the default material at presence 0.08: exactly 0.0000 at
171
- * backdrops of 0.12, 0.20 and 0.35.
204
+ * This is what lifts the body over a dark backdrop. The tint alone, under light ink, is darker
205
+ * than the dark it sits on; the medium's pull, the matte lift and the concentration are what make
206
+ * it read lighter, as in the reference (M 2:29, A 2:17).
172
207
  *
173
- * What the demand is DIVIDED by is deliberately the distance to the tint's pole rather than to the
174
- * body's own tint. Dividing by the latter is arithmetically tighter and asks for far more density
175
- * wherever the two are close — enough to drive it to the ceiling over a dark backdrop and stop the
176
- * glass being a window at all, which check:optics says plainly. Presence is a floor on visibility,
177
- * not a licence to go opaque.
208
+ * `appear` multiplies the layers exactly where the lens's `u_appear` does, so `optics` is the
209
+ * element's optics BEFORE `applyAppear`: scaling both would count it twice.
178
210
  */
179
- declare function withPresence(body: GlassBody, optics: VireGlassOptics, sample: BodyBackdrop): GlassBody;
211
+ declare function bodyLayer(optics: VireGlassOptics, sample: BodyBackdrop, ink: number, ambient: readonly [number, number, number], appear?: number): BodyLayer;
180
212
 
181
213
  declare function systemAccessibility(): VireGlassAccessibility;
182
214
  /** Fires whenever any of the three changes. The material has to follow a setting turned on while
@@ -320,9 +352,19 @@ type AttachGlassOptions = {
320
352
  } | null) => void;
321
353
  /** Pointer response (§5). On by default. */
322
354
  interactive?: boolean;
323
- /** Overrides the probe entirely — images and video are invisible to it, and the host app
324
- * already knows its own cover-art accent. */
355
+ /**
356
+ * Overrides the probe entirely. The probe reads declared backgrounds, so images, video and
357
+ * canvases are invisible to it; a host that knows its backdrop (a cover's accent, a gradient)
358
+ * states it here, and changes it later with `setSample`. `statsFromSamples` builds one from
359
+ * a handful of colours.
360
+ */
325
361
  sample?: BackdropSample;
362
+ /**
363
+ * Whether `attachGlass` paints the body as the element's `background-color`. On by default;
364
+ * turn it off if the host owns that property — `--vireglass-body-color` is always emitted
365
+ * either way and carries the same colour.
366
+ */
367
+ body?: boolean;
326
368
  };
327
369
  /**
328
370
  * Shapes this element flows into (docs/reference.md §5): merging with a neighbour, or splitting
@@ -363,8 +405,13 @@ type GlassHandle = {
363
405
  strength: number;
364
406
  } | null): void;
365
407
  setMorph(morph: GlassMorph | null): void;
408
+ /**
409
+ * Replaces the backdrop the glass adapts to, without re-attaching, and repaints. The same
410
+ * object as `sample` in the options; `null` goes back to probing declared backgrounds.
411
+ */
412
+ setSample(sample: BackdropSample | null): void;
366
413
  destroy(): void;
367
414
  };
368
415
  declare function attachGlass(el: HTMLElement, opts?: AttachGlassOptions): GlassHandle;
369
416
 
370
- export { type AttachGlassOptions, type BodyBackdrop, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, attachGlass, attachScrollEdge, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLobe, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
417
+ export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };