vireglass 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/{chunk-JF3FK254.js → chunk-2XJJO7SC.js} +4 -4
- package/dist/{chunk-JF3FK254.js.map → chunk-2XJJO7SC.js.map} +1 -1
- package/dist/{chunk-3PGYF2NK.js → chunk-CTTZNZFV.js} +3 -3
- package/dist/{chunk-3PGYF2NK.js.map → chunk-CTTZNZFV.js.map} +1 -1
- package/dist/{chunk-IQOBZGCF.js → chunk-H5QTBF67.js} +30 -32
- package/dist/chunk-H5QTBF67.js.map +1 -0
- package/dist/{chunk-TTOKBARR.js → chunk-MMPK6DCK.js} +10 -3
- package/dist/chunk-MMPK6DCK.js.map +1 -0
- package/dist/{chunk-P2ZOODXD.js → chunk-SLRPHDV7.js} +3 -3
- package/dist/{chunk-P2ZOODXD.js.map → chunk-SLRPHDV7.js.map} +1 -1
- package/dist/dom.cjs +79 -52
- package/dist/dom.cjs.map +1 -1
- package/dist/dom.d.cts +27 -4
- package/dist/dom.d.ts +27 -4
- package/dist/dom.js +48 -26
- package/dist/dom.js.map +1 -1
- package/dist/{group-model-8u4GKrUu.d.cts → group-model-DwtixGhG.d.cts} +15 -6
- package/dist/{group-model-vYSmEVia.d.ts → group-model-z4N27qsC.d.ts} +15 -6
- package/dist/index.cjs +28 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/law.cjs +8 -1
- package/dist/law.cjs.map +1 -1
- package/dist/law.d.cts +7 -0
- package/dist/law.d.ts +7 -0
- package/dist/law.js +1 -1
- package/dist/reference.js +2 -2
- package/dist/web/index.cjs +1 -2
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.js +4 -4
- package/docs/law.md +2 -2
- package/package.json +11 -9
- package/src/dom/body.ts +24 -9
- package/src/dom/displacement.ts +7 -2
- package/src/dom/index.ts +52 -11
- package/src/dom/probe.ts +27 -3
- package/src/law.ts +7 -0
- package/src/sdf.ts +44 -36
- package/dist/chunk-IQOBZGCF.js.map +0 -1
- package/dist/chunk-TTOKBARR.js.map +0 -1
package/dist/dom.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { B as BackdropSample } from './adaptation-BSbbdExK.cjs';
|
|
2
2
|
import { V as VireGlassGeometry } from './geometry-RhKd7CM5.cjs';
|
|
3
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-
|
|
4
|
+
import { T as TouchWarp, M as MorphShape, V as VireGlassAccessibility, S as ScrollEdgeStyle, G as GroupPlane } from './group-model-DwtixGhG.cjs';
|
|
5
5
|
import { V as VireGlassAccent } from './adapters-DugC6Qri.cjs';
|
|
6
6
|
|
|
7
7
|
/** Any `backdrop-filter` at all (e.g. `blur()`) — the fallback path's own requirement. */
|
|
@@ -67,6 +67,9 @@ type DisplacementState = {
|
|
|
67
67
|
smoothing?: number;
|
|
68
68
|
morph?: MorphShape;
|
|
69
69
|
morph2?: MorphShape;
|
|
70
|
+
/** Any number of shapes flowing into this one. `morph`/`morph2` are the first two, kept so a
|
|
71
|
+
* caller that only ever had two does not have to change. */
|
|
72
|
+
morphs?: readonly MorphShape[];
|
|
70
73
|
};
|
|
71
74
|
/**
|
|
72
75
|
* The raw pixel buffer, with no canvas involved — the part actually worth unit-testing.
|
|
@@ -157,9 +160,21 @@ type GlassBody = {
|
|
|
157
160
|
declare function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink: number): GlassBody;
|
|
158
161
|
/**
|
|
159
162
|
* PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly
|
|
160
|
-
* disappears — right for a piece of background, wrong for a control.
|
|
161
|
-
*
|
|
162
|
-
*
|
|
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.
|
|
165
|
+
*
|
|
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.
|
|
172
|
+
*
|
|
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.
|
|
163
178
|
*/
|
|
164
179
|
declare function withPresence(body: GlassBody, optics: VireGlassOptics, sample: BodyBackdrop): GlassBody;
|
|
165
180
|
|
|
@@ -321,6 +336,14 @@ type GlassMorph = {
|
|
|
321
336
|
smoothing: number;
|
|
322
337
|
shape?: MorphShape;
|
|
323
338
|
shape2?: MorphShape;
|
|
339
|
+
/**
|
|
340
|
+
* Any number of shapes flowing into this one. Several independent elements becoming one whole is
|
|
341
|
+
* the behaviour; how many of them there are is the host's business, and it used to be the
|
|
342
|
+
* material's — the count lived in the field NAMES, so a fourth element had nowhere to go.
|
|
343
|
+
*
|
|
344
|
+
* `shape` and `shape2` still work and come first.
|
|
345
|
+
*/
|
|
346
|
+
shapes?: readonly MorphShape[];
|
|
324
347
|
};
|
|
325
348
|
type GlassHandle = {
|
|
326
349
|
update(): void;
|
package/dist/dom.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { B as BackdropSample } from './adaptation-BSbbdExK.js';
|
|
2
2
|
import { V as VireGlassGeometry } from './geometry-GvXtt-_S.js';
|
|
3
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-
|
|
4
|
+
import { T as TouchWarp, M as MorphShape, V as VireGlassAccessibility, S as ScrollEdgeStyle, G as GroupPlane } from './group-model-z4N27qsC.js';
|
|
5
5
|
import { V as VireGlassAccent } from './adapters-BfeAopGO.js';
|
|
6
6
|
|
|
7
7
|
/** Any `backdrop-filter` at all (e.g. `blur()`) — the fallback path's own requirement. */
|
|
@@ -67,6 +67,9 @@ type DisplacementState = {
|
|
|
67
67
|
smoothing?: number;
|
|
68
68
|
morph?: MorphShape;
|
|
69
69
|
morph2?: MorphShape;
|
|
70
|
+
/** Any number of shapes flowing into this one. `morph`/`morph2` are the first two, kept so a
|
|
71
|
+
* caller that only ever had two does not have to change. */
|
|
72
|
+
morphs?: readonly MorphShape[];
|
|
70
73
|
};
|
|
71
74
|
/**
|
|
72
75
|
* The raw pixel buffer, with no canvas involved — the part actually worth unit-testing.
|
|
@@ -157,9 +160,21 @@ type GlassBody = {
|
|
|
157
160
|
declare function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink: number): GlassBody;
|
|
158
161
|
/**
|
|
159
162
|
* PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly
|
|
160
|
-
* disappears — right for a piece of background, wrong for a control.
|
|
161
|
-
*
|
|
162
|
-
*
|
|
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.
|
|
165
|
+
*
|
|
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.
|
|
172
|
+
*
|
|
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.
|
|
163
178
|
*/
|
|
164
179
|
declare function withPresence(body: GlassBody, optics: VireGlassOptics, sample: BodyBackdrop): GlassBody;
|
|
165
180
|
|
|
@@ -321,6 +336,14 @@ type GlassMorph = {
|
|
|
321
336
|
smoothing: number;
|
|
322
337
|
shape?: MorphShape;
|
|
323
338
|
shape2?: MorphShape;
|
|
339
|
+
/**
|
|
340
|
+
* Any number of shapes flowing into this one. Several independent elements becoming one whole is
|
|
341
|
+
* the behaviour; how many of them there are is the host's business, and it used to be the
|
|
342
|
+
* material's — the count lived in the field NAMES, so a fourth element had nowhere to go.
|
|
343
|
+
*
|
|
344
|
+
* `shape` and `shape2` still work and come first.
|
|
345
|
+
*/
|
|
346
|
+
shapes?: readonly MorphShape[];
|
|
324
347
|
};
|
|
325
348
|
type GlassHandle = {
|
|
326
349
|
update(): void;
|
package/dist/dom.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { shadowTint, NO_ACCESSIBILITY, createGroupState, createDeform, elasticAllowed, contrastRimLuma, concentricRadius, scrollEdgeStrength, scrollEdgeStyle, applyGlassScale, GLASS_SCALE_DEFAULT, applyAccessibility, applyAppear, accentTone, accentAmount, raiseIntoGlass } from './chunk-
|
|
1
|
+
import { shadowTint, NO_ACCESSIBILITY, createGroupState, createDeform, elasticAllowed, contrastRimLuma, concentricRadius, scrollEdgeStrength, scrollEdgeStyle, applyGlassScale, GLASS_SCALE_DEFAULT, applyAccessibility, applyAppear, accentTone, accentAmount, raiseIntoGlass } from './chunk-CTTZNZFV.js';
|
|
2
2
|
import { ambientFrom, shouldInkBeLight, INK_LIGHT, INK_DARK } from './chunk-JNRZNMJJ.js';
|
|
3
|
-
import { touchWarp, sceneDistance, sceneGradient, sdfRoundedRect, VIREGLASS_MATERIAL, REST_LIGHT, resolveOptics, refractionStrength } from './chunk-
|
|
4
|
-
import { shadowOpacity, bevelDp, thicknessDp, rimDp, shadowOpacityFrom, shadowReachDp, halfMinDp, MAX_STRETCH, roundedRectGeometry } from './chunk-
|
|
5
|
-
import { LENS, BODY, RIM, TOUCH, SHADOW, SHADOW_GAP, SCROLL_EDGE, BEVEL, SPECTRAL, DISPERSION } from './chunk-
|
|
3
|
+
import { touchWarp, sceneDistance, sceneGradient, sdfRoundedRect, VIREGLASS_MATERIAL, REST_LIGHT, resolveOptics, refractionStrength } from './chunk-H5QTBF67.js';
|
|
4
|
+
import { shadowOpacity, bevelDp, thicknessDp, rimDp, shadowOpacityFrom, shadowReachDp, halfMinDp, MAX_STRETCH, roundedRectGeometry } from './chunk-SLRPHDV7.js';
|
|
5
|
+
import { LENS, BODY, RIM, TOUCH, SHADOW, SHADOW_GAP, SCROLL_EDGE, BEVEL, SPECTRAL, DISPERSION } from './chunk-MMPK6DCK.js';
|
|
6
6
|
|
|
7
7
|
// src/dom/displacement.ts
|
|
8
8
|
var SCALE_GAIN = 0.75;
|
|
@@ -29,6 +29,7 @@ function renderDisplacementPixels(optics, geometry, dpr, state = {}) {
|
|
|
29
29
|
const rawScale = optics.refraction * thicknessDp(geometry, optics) * SCALE_GAIN;
|
|
30
30
|
const scale = Math.min(rawScale, MAX_SCALE);
|
|
31
31
|
const smoothing = state.smoothing ?? 0;
|
|
32
|
+
const shapes = [state.morph, state.morph2, ...state.morphs ?? []];
|
|
32
33
|
const data = new Uint8ClampedArray(width * height * 4);
|
|
33
34
|
const halfW = geometry.width / 2;
|
|
34
35
|
const halfH = geometry.height / 2;
|
|
@@ -38,7 +39,7 @@ function renderDisplacementPixels(optics, geometry, dpr, state = {}) {
|
|
|
38
39
|
const x = (px + 0.5) / density - halfW;
|
|
39
40
|
const i = (py * width + px) * 4;
|
|
40
41
|
const [wx, wy] = state.touch ? touchWarp(x, y, state.touch) : [x, y];
|
|
41
|
-
const sd = sceneDistance(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing,
|
|
42
|
+
const sd = sceneDistance(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing, ...shapes);
|
|
42
43
|
const t = Math.min(Math.max((sd + bevel) / bevel, 0), 1);
|
|
43
44
|
if (t <= 0 || scale <= 0) {
|
|
44
45
|
data[i] = 128;
|
|
@@ -47,7 +48,7 @@ function renderDisplacementPixels(optics, geometry, dpr, state = {}) {
|
|
|
47
48
|
data[i + 3] = 255;
|
|
48
49
|
continue;
|
|
49
50
|
}
|
|
50
|
-
const [gx, gy] = sceneGradient(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing,
|
|
51
|
+
const [gx, gy] = sceneGradient(wx, wy, geometry.width, geometry.height, geometry.cornerRadius, smoothing, ...shapes);
|
|
51
52
|
const magnitude = bevelProfile(t) * (scale / 2);
|
|
52
53
|
const dx = -gx * magnitude;
|
|
53
54
|
const dy = -gy * magnitude;
|
|
@@ -310,10 +311,18 @@ function sampleColorAt(el, x, y) {
|
|
|
310
311
|
}
|
|
311
312
|
const composited = compositeLayers(layers);
|
|
312
313
|
if (composited) return composited;
|
|
313
|
-
|
|
314
|
-
if (!topmost) return null;
|
|
315
|
-
return parseColor(getComputedStyle(topmost).color);
|
|
314
|
+
return canvasColor(el);
|
|
316
315
|
}
|
|
316
|
+
function canvasColor(el) {
|
|
317
|
+
const doc = el.ownerDocument;
|
|
318
|
+
for (const node of [doc.documentElement, doc.body]) {
|
|
319
|
+
if (!node) continue;
|
|
320
|
+
const bg = parseColor(getComputedStyle(node).backgroundColor);
|
|
321
|
+
if (bg && bg.a > 1e-3) return bg.a >= 0.999 ? bg : compositeLayers([bg, WHITE]);
|
|
322
|
+
}
|
|
323
|
+
return WHITE;
|
|
324
|
+
}
|
|
325
|
+
var WHITE = { r: 255, g: 255, b: 255, a: 1 };
|
|
317
326
|
function probeBackdrop(el, opts = {}) {
|
|
318
327
|
const cols = opts.cols ?? GRID_COLS;
|
|
319
328
|
const rows = opts.rows ?? GRID_ROWS;
|
|
@@ -416,15 +425,17 @@ function resolveBody(optics, sample, ink) {
|
|
|
416
425
|
function withPresence(body, optics, sample) {
|
|
417
426
|
if (optics.presence <= 0) return body;
|
|
418
427
|
const mean = clamp(sample.luma, 0, 1);
|
|
419
|
-
const
|
|
420
|
-
const
|
|
421
|
-
const separation = Math.abs(
|
|
428
|
+
const above = Math.abs(body.tintLuma - mean) > 1e-4 ? body.tintLuma > mean : mean < 0.5;
|
|
429
|
+
const pole = above ? TINT_LIGHT : TINT_DARK;
|
|
430
|
+
const separation = Math.min(optics.presence, Math.abs(pole - mean));
|
|
422
431
|
const reached = Math.abs(body.tintLuma - mean) * body.density;
|
|
423
432
|
if (reached >= separation) return body;
|
|
424
|
-
const needed = separation / Math.max(Math.abs(
|
|
433
|
+
const needed = separation / Math.max(Math.abs(pole - mean), 1e-4);
|
|
425
434
|
return {
|
|
426
|
-
density: Math.max(body.density, Math.min(needed,
|
|
427
|
-
|
|
435
|
+
density: Math.max(body.density, Math.min(needed, BODY.presenceDemand)),
|
|
436
|
+
// Left where the tint law put it, unless it landed exactly on the backdrop — which is the
|
|
437
|
+
// case that used to be created here rather than avoided.
|
|
438
|
+
tintLuma: Math.abs(body.tintLuma - mean) > 1e-4 ? body.tintLuma : pole
|
|
428
439
|
};
|
|
429
440
|
}
|
|
430
441
|
|
|
@@ -659,15 +670,22 @@ function waveImpulse(g) {
|
|
|
659
670
|
return halfMinDp(g) * MAX_STRETCH * WAVE_OF_TRAVEL;
|
|
660
671
|
}
|
|
661
672
|
var STYLE_ATTR = "data-vireglass-styles";
|
|
662
|
-
function
|
|
663
|
-
|
|
673
|
+
function hostFor(el) {
|
|
674
|
+
const root = el.getRootNode();
|
|
675
|
+
return root instanceof ShadowRoot ? root : el.ownerDocument ?? document;
|
|
676
|
+
}
|
|
677
|
+
function styleParent(host) {
|
|
678
|
+
return host instanceof ShadowRoot ? host : host.head;
|
|
679
|
+
}
|
|
680
|
+
function ensureRimStyles(host) {
|
|
681
|
+
if (host.querySelector(`style[${STYLE_ATTR}]`)) return;
|
|
664
682
|
const style = document.createElement("style");
|
|
665
683
|
style.setAttribute(STYLE_ATTR, "");
|
|
666
684
|
style.textContent = `[${GLASS_ATTR}]::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;padding:var(--vireglass-rim-width,1px);background:var(--vireglass-rim,none);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude}[${GLASS_ATTR}]::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:var(--vireglass-glow,none);opacity:var(--vireglass-glow-opacity,0)}`;
|
|
667
|
-
|
|
685
|
+
styleParent(host).appendChild(style);
|
|
668
686
|
}
|
|
669
|
-
function getFilterHost() {
|
|
670
|
-
const existing =
|
|
687
|
+
function getFilterHost(host) {
|
|
688
|
+
const existing = host.querySelector(`svg[${FILTER_HOST_ATTR}]`);
|
|
671
689
|
if (existing) return existing;
|
|
672
690
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
673
691
|
svg.setAttribute(FILTER_HOST_ATTR, "");
|
|
@@ -677,7 +695,7 @@ function getFilterHost() {
|
|
|
677
695
|
svg.style.position = "absolute";
|
|
678
696
|
svg.style.pointerEvents = "none";
|
|
679
697
|
svg.appendChild(document.createElementNS(SVG_NS, "defs"));
|
|
680
|
-
|
|
698
|
+
(host instanceof ShadowRoot ? host : host.body).appendChild(svg);
|
|
681
699
|
return svg;
|
|
682
700
|
}
|
|
683
701
|
function buildFilterElement(id, mapUrl, optics, scale, spectral) {
|
|
@@ -715,6 +733,7 @@ function buildFilterElement(id, mapUrl, optics, scale, spectral) {
|
|
|
715
733
|
pass.setAttribute("xChannelSelector", "R");
|
|
716
734
|
pass.setAttribute("yChannelSelector", "G");
|
|
717
735
|
pass.setAttribute("result", `${name}raw`);
|
|
736
|
+
pass.setAttribute("data-vireglass-ratio", String(scale > 0 ? chScale / scale : 1));
|
|
718
737
|
const only = document.createElementNS(SVG_NS, "feColorMatrix");
|
|
719
738
|
only.setAttribute("in", `${name}raw`);
|
|
720
739
|
only.setAttribute("type", "matrix");
|
|
@@ -821,7 +840,8 @@ function attachGlass(el, opts = {}) {
|
|
|
821
840
|
apply();
|
|
822
841
|
});
|
|
823
842
|
warnIfNested(el);
|
|
824
|
-
|
|
843
|
+
const host = hostFor(el);
|
|
844
|
+
ensureRimStyles(host);
|
|
825
845
|
el.setAttribute(GLASS_ATTR, "");
|
|
826
846
|
const positionWasStatic = getComputedStyle(el).position === "static";
|
|
827
847
|
if (positionWasStatic) el.style.setProperty("position", "relative");
|
|
@@ -833,7 +853,7 @@ function attachGlass(el, opts = {}) {
|
|
|
833
853
|
}
|
|
834
854
|
function morphState() {
|
|
835
855
|
if (!morph) return {};
|
|
836
|
-
return { smoothing: morph.smoothing, morph: morph.shape, morph2: morph.shape2 };
|
|
856
|
+
return { smoothing: morph.smoothing, morph: morph.shape, morph2: morph.shape2, morphs: morph.shapes };
|
|
837
857
|
}
|
|
838
858
|
function morphKey() {
|
|
839
859
|
if (!morph) return "0";
|
|
@@ -849,7 +869,7 @@ function attachGlass(el, opts = {}) {
|
|
|
849
869
|
const key = `a${appear.toFixed(3)}|m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}:${opticsNow.blur}`;
|
|
850
870
|
if (key !== mapKey || !filterEl) {
|
|
851
871
|
const map = cached(`d|${key}`, () => buildDisplacementMap(opticsNow, geometry, devicePixelRatio(), morphState()));
|
|
852
|
-
const defs = getFilterHost().querySelector("defs");
|
|
872
|
+
const defs = getFilterHost(host).querySelector("defs");
|
|
853
873
|
const hue = hasSpectralEdge(opticsNow) ? cached(`h|${key}`, () => buildSpectralMap(opticsNow, geometry, devicePixelRatio())) : null;
|
|
854
874
|
const next = buildFilterElement(id, map.url, opticsNow, map.scale, hue);
|
|
855
875
|
if (filterEl?.parentNode) defs.replaceChild(next, filterEl);
|
|
@@ -915,9 +935,11 @@ function attachGlass(el, opts = {}) {
|
|
|
915
935
|
});
|
|
916
936
|
if (filterEl) {
|
|
917
937
|
const feImage = filterEl.querySelector("feImage");
|
|
918
|
-
const feDisplace = filterEl.querySelector("feDisplacementMap");
|
|
919
938
|
feImage?.setAttribute("href", map.url);
|
|
920
|
-
|
|
939
|
+
for (const pass of filterEl.querySelectorAll("feDisplacementMap")) {
|
|
940
|
+
const ratio = Number(pass.getAttribute("data-vireglass-ratio") ?? 1);
|
|
941
|
+
pass.setAttribute("scale", String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));
|
|
942
|
+
}
|
|
921
943
|
}
|
|
922
944
|
mapKey = "";
|
|
923
945
|
paintGlow(sampleOut.touchX, sampleOut.touchY, sampleOut.active * base.edgeLight, geometry);
|