vireglass 3.2.0 → 3.2.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.
- package/dist/dom.cjs +28 -12
- package/dist/dom.cjs.map +1 -1
- package/dist/dom.js +29 -13
- package/dist/dom.js.map +1 -1
- package/package.json +1 -1
- package/src/dom/index.ts +1 -1
- package/src/dom/spectral-map.ts +36 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vireglass",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "A physically-derived liquid glass material for interfaces. One material model, three render targets: WebGL2, live DOM, and Android AGSL.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Danil Kotlaev",
|
package/src/dom/index.ts
CHANGED
|
@@ -642,7 +642,7 @@ export function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): Gla
|
|
|
642
642
|
// it on every scroll would re-run a per-pixel loop and a PNG encode for a picture that did
|
|
643
643
|
// not change; the refraction itself updates in the compositor with no JS at all.
|
|
644
644
|
const full = settledOptics();
|
|
645
|
-
const key = `m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${full.refraction}:${full.refractionScale}:${full.bevelDp}:${full.blur}`;
|
|
645
|
+
const key = `m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${full.refraction}:${full.refractionScale}:${full.bevelDp}:${full.blur}:${full.thicknessDp}:${full.film}:${full.iridescence}:${full.diffraction}`;
|
|
646
646
|
if (interim && filterEl) {
|
|
647
647
|
// The filter keeps its map; feImage stretches it over the live box.
|
|
648
648
|
} else if (isEmpty(geometry)) {
|
package/src/dom/spectral-map.ts
CHANGED
|
@@ -32,6 +32,25 @@ function mapDensity(bevel: number, dpr: number): number {
|
|
|
32
32
|
return Math.min(dpr, BEVEL_SAMPLES / bevel);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/** Intervals of the hue table along the depth, read with linear interpolation. */
|
|
36
|
+
const DEPTH_STEPS = 2048;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `spectralHue` is a function of the depth alone for one element, so it is tabled along the depth.
|
|
40
|
+
* The nodes sit at `(k / DEPTH_STEPS)²` of the bevel: the rim's slope turns fastest at the silhouette.
|
|
41
|
+
*/
|
|
42
|
+
function hueAlongDepth(bevel: number, rim: number, thick: number, optics: VireGlassOptics): Float64Array {
|
|
43
|
+
const table = new Float64Array((DEPTH_STEPS + 1) * 3);
|
|
44
|
+
for (let k = 0; k <= DEPTH_STEPS; k += 1) {
|
|
45
|
+
const s = k / DEPTH_STEPS;
|
|
46
|
+
const [r, g, b] = spectralHue(s * s * bevel, bevel, rim, thick, optics);
|
|
47
|
+
table[k * 3] = r;
|
|
48
|
+
table[k * 3 + 1] = g;
|
|
49
|
+
table[k * 3 + 2] = b;
|
|
50
|
+
}
|
|
51
|
+
return table;
|
|
52
|
+
}
|
|
53
|
+
|
|
35
54
|
export function renderSpectralPixels(
|
|
36
55
|
optics: VireGlassOptics,
|
|
37
56
|
geometry: VireGlassGeometry,
|
|
@@ -48,26 +67,31 @@ export function renderSpectralPixels(
|
|
|
48
67
|
const halfW = geometry.width / 2;
|
|
49
68
|
const halfH = geometry.height / 2;
|
|
50
69
|
const neutral = Math.round((1 / HEADROOM) * 255);
|
|
70
|
+
const table = hueAlongDepth(bevel, rim, thick, optics);
|
|
71
|
+
const toByte = 255 / HEADROOM;
|
|
72
|
+
// Past the bevel the glass is plain: a neutral multiplier, not a missing one.
|
|
73
|
+
new Uint32Array(data.buffer).fill(new Uint32Array(new Uint8ClampedArray([neutral, neutral, neutral, 255]).buffer)[0]!);
|
|
74
|
+
const corner = Math.max(geometry.cornerRadius, bevel);
|
|
51
75
|
|
|
52
76
|
for (let py = 0; py < height; py += 1) {
|
|
53
77
|
const y = (py + 0.5) / density - halfH;
|
|
78
|
+
const ay = Math.abs(y);
|
|
79
|
+
// Where |x| is within this, the rounded rect's distance field puts the point at least a bevel deep.
|
|
80
|
+
const plain = Math.max(ay <= halfH - bevel ? halfW - corner : -1, ay <= halfH - corner ? halfW - bevel : -1);
|
|
54
81
|
for (let px = 0; px < width; px += 1) {
|
|
55
82
|
const x = (px + 0.5) / density - halfW;
|
|
83
|
+
if (Math.abs(x) <= plain) continue;
|
|
56
84
|
const i = (py * width + px) * 4;
|
|
57
85
|
const sd = sdfRoundedRect(x, y, geometry.width, geometry.height, geometry.cornerRadius);
|
|
58
86
|
const e = Math.max(-sd, 0);
|
|
59
|
-
if (e >= bevel)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const [r, g, b] = spectralHue(e, bevel, rim, thick, optics);
|
|
68
|
-
data[i] = Math.round((r / HEADROOM) * 255);
|
|
69
|
-
data[i + 1] = Math.round((g / HEADROOM) * 255);
|
|
70
|
-
data[i + 2] = Math.round((b / HEADROOM) * 255);
|
|
87
|
+
if (e >= bevel) continue;
|
|
88
|
+
const u = Math.sqrt(e / bevel) * DEPTH_STEPS;
|
|
89
|
+
const k = Math.min(Math.floor(u), DEPTH_STEPS - 1);
|
|
90
|
+
const f = u - k;
|
|
91
|
+
const at = k * 3;
|
|
92
|
+
data[i] = Math.round((table[at] + (table[at + 3] - table[at]) * f) * toByte);
|
|
93
|
+
data[i + 1] = Math.round((table[at + 1] + (table[at + 4] - table[at + 1]) * f) * toByte);
|
|
94
|
+
data[i + 2] = Math.round((table[at + 2] + (table[at + 5] - table[at + 2]) * f) * toByte);
|
|
71
95
|
data[i + 3] = 255;
|
|
72
96
|
}
|
|
73
97
|
}
|