layershift 0.1.1 → 0.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.
@@ -1,4 +1,4 @@
1
- class V {
1
+ class st {
2
2
  worker;
3
3
  currentBuffer;
4
4
  pendingTimeSec = null;
@@ -14,28 +14,28 @@ class V {
14
14
  * After this call, the original depthData.frames arrays are neutered
15
15
  * and should not be accessed.
16
16
  */
17
- static async create(t, e, r) {
18
- const i = new Worker(
17
+ static async create(t, e, i) {
18
+ const r = new Worker(
19
19
  new URL(
20
20
  /* @vite-ignore */
21
21
  "/assets/depth-worker-CMcEa805.js",
22
22
  import.meta.url
23
23
  ),
24
24
  { type: "module" }
25
- ), a = e * r, l = new V(i, a), n = t.frames.map((c) => {
26
- const h = new Uint8Array(c.length);
27
- return h.set(c), h.buffer;
25
+ ), o = e * i, s = new st(r, o), a = t.frames.map((h) => {
26
+ const l = new Uint8Array(h.length);
27
+ return l.set(h), l.buffer;
28
28
  });
29
- return await new Promise((c, h) => {
30
- const d = setTimeout(() => h(new Error("Worker init timeout")), 1e4);
31
- i.onmessage = (p) => {
32
- p.data.type === "ready" && (clearTimeout(d), c());
33
- }, i.onerror = (p) => {
34
- clearTimeout(d), h(p);
35
- }, i.postMessage(
29
+ return await new Promise((h, l) => {
30
+ const u = setTimeout(() => l(new Error("Worker init timeout")), 1e4);
31
+ r.onmessage = (f) => {
32
+ f.data.type === "ready" && (clearTimeout(u), h());
33
+ }, r.onerror = (f) => {
34
+ clearTimeout(u), l(f);
35
+ }, r.postMessage(
36
36
  {
37
37
  type: "init",
38
- frames: n,
38
+ frames: a,
39
39
  meta: {
40
40
  frameCount: t.meta.frameCount,
41
41
  fps: t.meta.fps,
@@ -43,17 +43,17 @@ class V {
43
43
  height: t.meta.height
44
44
  },
45
45
  targetWidth: e,
46
- targetHeight: r
46
+ targetHeight: i
47
47
  },
48
- n
48
+ a
49
49
  // Transfer list
50
50
  );
51
- }), i.onmessage = (c) => {
52
- if (c.data.type === "result" && (l.currentBuffer = c.data.data, l.workerBusy = !1, l.pendingTimeSec !== null)) {
53
- const h = l.pendingTimeSec;
54
- l.pendingTimeSec = null, l.requestSample(h);
51
+ }), r.onmessage = (h) => {
52
+ if (h.data.type === "result" && (s.currentBuffer = h.data.data, s.workerBusy = !1, s.pendingTimeSec !== null)) {
53
+ const l = s.pendingTimeSec;
54
+ s.pendingTimeSec = null, s.requestSample(l);
55
55
  }
56
- }, l;
56
+ }, s;
57
57
  }
58
58
  /**
59
59
  * Get the current depth frame — always synchronous, zero main-thread work.
@@ -82,11 +82,11 @@ class V {
82
82
  this.disposed = !0, this.worker.terminate();
83
83
  }
84
84
  }
85
- class I {
86
- constructor(t, e, r) {
87
- this.depthData = t, this.targetWidth = e, this.targetHeight = r;
88
- const i = t.meta.width * t.meta.height, a = e * r;
89
- this.interpolatedDepth = new Float32Array(i), this.bilateralOutput = new Float32Array(i), this.resizedDepth = new Float32Array(a), this.uint8Output = new Uint8Array(a);
85
+ class bt {
86
+ constructor(t, e, i) {
87
+ this.depthData = t, this.targetWidth = e, this.targetHeight = i;
88
+ const r = t.meta.width * t.meta.height, o = e * i;
89
+ this.interpolatedDepth = new Float32Array(r), this.bilateralOutput = new Float32Array(r), this.resizedDepth = new Float32Array(o), this.uint8Output = new Uint8Array(o);
90
90
  }
91
91
  interpolatedDepth;
92
92
  resizedDepth;
@@ -100,21 +100,21 @@ class I {
100
100
  lastNextFrameIndex = -1;
101
101
  lastLerpFactor = -1;
102
102
  sample(t) {
103
- const e = L(t * this.depthData.meta.fps, 0, this.depthData.meta.frameCount - 1), r = Math.floor(e), i = Math.min(r + 1, this.depthData.meta.frameCount - 1), a = e - r, l = r !== this.lastFrameIndex || i !== this.lastNextFrameIndex, n = Math.abs(a - this.lastLerpFactor) > 1e-3;
104
- if (!l && !n)
103
+ const e = Z(t * this.depthData.meta.fps, 0, this.depthData.meta.frameCount - 1), i = Math.floor(e), r = Math.min(i + 1, this.depthData.meta.frameCount - 1), o = e - i, s = i !== this.lastFrameIndex || r !== this.lastNextFrameIndex, a = Math.abs(o - this.lastLerpFactor) > 1e-3;
104
+ if (!s && !a)
105
105
  return this.uint8Output;
106
- this.lastFrameIndex = r, this.lastNextFrameIndex = i, this.lastLerpFactor = a;
107
- const c = 1 - a, h = this.depthData.frames[r], d = this.depthData.frames[i];
108
- for (let u = 0; u < this.interpolatedDepth.length; u += 1)
109
- this.interpolatedDepth[u] = (h[u] * c + d[u] * a) / 255;
110
- G(
106
+ this.lastFrameIndex = i, this.lastNextFrameIndex = r, this.lastLerpFactor = o;
107
+ const h = 1 - o, l = this.depthData.frames[i], u = this.depthData.frames[r];
108
+ for (let d = 0; d < this.interpolatedDepth.length; d += 1)
109
+ this.interpolatedDepth[d] = (l[d] * h + u[d] * o) / 255;
110
+ Ot(
111
111
  this.interpolatedDepth,
112
112
  this.depthData.meta.width,
113
113
  this.depthData.meta.height,
114
114
  this.bilateralOutput
115
115
  );
116
- const p = this.targetWidth !== this.depthData.meta.width || this.targetHeight !== this.depthData.meta.height;
117
- p && N(
116
+ const f = this.targetWidth !== this.depthData.meta.width || this.targetHeight !== this.depthData.meta.height;
117
+ f && Vt(
118
118
  this.bilateralOutput,
119
119
  this.depthData.meta.width,
120
120
  this.depthData.meta.height,
@@ -122,25 +122,25 @@ class I {
122
122
  this.targetHeight,
123
123
  this.resizedDepth
124
124
  );
125
- const s = p ? this.resizedDepth : this.bilateralOutput;
126
- for (let u = 0; u < this.uint8Output.length; u += 1)
127
- this.uint8Output[u] = s[u] * 255 + 0.5 | 0;
125
+ const c = f ? this.resizedDepth : this.bilateralOutput;
126
+ for (let d = 0; d < this.uint8Output.length; d += 1)
127
+ this.uint8Output[d] = c[d] * 255 + 0.5 | 0;
128
128
  return this.uint8Output;
129
129
  }
130
130
  }
131
- async function H(o, t, e) {
132
- const [r, i] = await Promise.all([
133
- z(t),
134
- k(o)
131
+ async function At(n, t, e) {
132
+ const [i, r] = await Promise.all([
133
+ Ct(t),
134
+ Mt(n)
135
135
  ]);
136
- return X(i, r);
136
+ return _t(r, i);
137
137
  }
138
- async function z(o) {
139
- const t = await fetch(o);
138
+ async function Ct(n) {
139
+ const t = await fetch(n);
140
140
  if (!t.ok)
141
141
  throw new Error(`Failed to fetch depth metadata (${t.status} ${t.statusText}).`);
142
142
  const e = await t.json();
143
- return B(e), {
143
+ return It(e), {
144
144
  frameCount: e.frameCount,
145
145
  fps: e.fps,
146
146
  width: e.width,
@@ -148,87 +148,87 @@ async function z(o) {
148
148
  sourceFps: e.sourceFps
149
149
  };
150
150
  }
151
- async function k(o, t) {
152
- const e = await fetch(o);
151
+ async function Mt(n, t) {
152
+ const e = await fetch(n);
153
153
  if (!e.ok)
154
154
  throw new Error(`Failed to fetch depth data (${e.status} ${e.statusText}).`);
155
155
  e.headers.get("content-length");
156
- const r = e.body;
157
- if (!r)
156
+ const i = e.body;
157
+ if (!i)
158
158
  return new Uint8Array(await e.arrayBuffer());
159
- const i = [];
160
- let a = 0;
161
- const l = r.getReader();
159
+ const r = [];
160
+ let o = 0;
161
+ const s = i.getReader();
162
162
  for (; ; ) {
163
- const { done: h, value: d } = await l.read();
164
- if (h)
163
+ const { done: l, value: u } = await s.read();
164
+ if (l)
165
165
  break;
166
- d && (i.push(d), a += d.byteLength);
166
+ u && (r.push(u), o += u.byteLength);
167
167
  }
168
- const n = new Uint8Array(a);
169
- let c = 0;
170
- for (const h of i)
171
- n.set(h, c), c += h.byteLength;
172
- return n;
168
+ const a = new Uint8Array(o);
169
+ let h = 0;
170
+ for (const l of r)
171
+ a.set(l, h), h += l.byteLength;
172
+ return a;
173
173
  }
174
- function X(o, t) {
175
- if (o.byteLength < 4)
174
+ function _t(n, t) {
175
+ if (n.byteLength < 4)
176
176
  throw new Error("Depth data binary is missing the frame-count header.");
177
- const r = new DataView(o.buffer, o.byteOffset, o.byteLength).getUint32(0, !0), i = t.width * t.height, a = 4 + r * i;
178
- if (o.byteLength !== a)
177
+ const i = new DataView(n.buffer, n.byteOffset, n.byteLength).getUint32(0, !0), r = t.width * t.height, o = 4 + i * r;
178
+ if (n.byteLength !== o)
179
179
  throw new Error(
180
- `Depth data byte length mismatch. Expected ${a} bytes, received ${o.byteLength}.`
180
+ `Depth data byte length mismatch. Expected ${o} bytes, received ${n.byteLength}.`
181
181
  );
182
- if (r !== t.frameCount)
182
+ if (i !== t.frameCount)
183
183
  throw new Error(
184
- `Depth frame count mismatch between metadata (${t.frameCount}) and binary header (${r}).`
184
+ `Depth frame count mismatch between metadata (${t.frameCount}) and binary header (${i}).`
185
185
  );
186
- const l = o.subarray(4), n = new Array(r);
187
- for (let c = 0; c < r; c += 1) {
188
- const h = c * i;
189
- n[c] = l.subarray(h, h + i);
186
+ const s = n.subarray(4), a = new Array(i);
187
+ for (let h = 0; h < i; h += 1) {
188
+ const l = h * r;
189
+ a[h] = s.subarray(l, l + r);
190
190
  }
191
- return { meta: t, frames: n };
191
+ return { meta: t, frames: a };
192
192
  }
193
- function B(o) {
194
- if (!o || typeof o.frameCount != "number" || typeof o.fps != "number" || typeof o.width != "number" || typeof o.height != "number" || typeof o.sourceFps != "number")
193
+ function It(n) {
194
+ if (!n || typeof n.frameCount != "number" || typeof n.fps != "number" || typeof n.width != "number" || typeof n.height != "number" || typeof n.sourceFps != "number")
195
195
  throw new Error("Depth metadata is malformed.");
196
- if (!Number.isFinite(o.frameCount) || !Number.isFinite(o.fps) || !Number.isFinite(o.width) || !Number.isFinite(o.height) || !Number.isFinite(o.sourceFps) || o.frameCount <= 0 || o.fps <= 0 || o.width <= 0 || o.height <= 0 || o.sourceFps <= 0)
196
+ if (!Number.isFinite(n.frameCount) || !Number.isFinite(n.fps) || !Number.isFinite(n.width) || !Number.isFinite(n.height) || !Number.isFinite(n.sourceFps) || n.frameCount <= 0 || n.fps <= 0 || n.width <= 0 || n.height <= 0 || n.sourceFps <= 0)
197
197
  throw new Error("Depth metadata contains invalid numeric values.");
198
198
  }
199
- function N(o, t, e, r, i, a) {
200
- const l = t / r, n = e / i;
201
- for (let c = 0; c < i; c += 1) {
202
- const h = (c + 0.5) * n - 0.5, d = L(Math.floor(h), 0, e - 1), p = L(d + 1, 0, e - 1), s = h - d;
203
- for (let u = 0; u < r; u += 1) {
204
- const m = (u + 0.5) * l - 0.5, v = L(Math.floor(m), 0, t - 1), x = L(v + 1, 0, t - 1), b = m - v, T = o[d * t + v], y = o[d * t + x], R = o[p * t + v], f = o[p * t + x], w = T + (y - T) * b, U = R + (f - R) * b;
205
- a[c * r + u] = w + (U - w) * s;
199
+ function Vt(n, t, e, i, r, o) {
200
+ const s = t / i, a = e / r;
201
+ for (let h = 0; h < r; h += 1) {
202
+ const l = (h + 0.5) * a - 0.5, u = Z(Math.floor(l), 0, e - 1), f = Z(u + 1, 0, e - 1), c = l - u;
203
+ for (let d = 0; d < i; d += 1) {
204
+ const m = (d + 0.5) * s - 0.5, g = Z(Math.floor(m), 0, t - 1), U = Z(g + 1, 0, t - 1), b = m - g, E = n[u * t + g], p = n[u * t + U], v = n[f * t + g], T = n[f * t + U], x = E + (p - E) * b, y = v + (T - v) * b;
205
+ o[h * i + d] = x + (y - x) * c;
206
206
  }
207
207
  }
208
208
  }
209
- function G(o, t, e, r) {
210
- for (let l = 0; l < e; l += 1)
211
- for (let n = 0; n < t; n += 1) {
212
- const c = l * t + n, h = o[c];
213
- let d = 1, p = h;
214
- for (let s = -2; s <= 2; s += 1) {
215
- const u = l + s;
216
- if (!(u < 0 || u >= e))
209
+ function Ot(n, t, e, i) {
210
+ for (let s = 0; s < e; s += 1)
211
+ for (let a = 0; a < t; a += 1) {
212
+ const h = s * t + a, l = n[h];
213
+ let u = 1, f = l;
214
+ for (let c = -2; c <= 2; c += 1) {
215
+ const d = s + c;
216
+ if (!(d < 0 || d >= e))
217
217
  for (let m = -2; m <= 2; m += 1) {
218
- if (m === 0 && s === 0) continue;
219
- const v = n + m;
220
- if (v < 0 || v >= t) continue;
221
- const x = o[u * t + v], b = m * m + s * s, T = x - h, y = Math.exp(-b / 2.25 - T * T / 0.01);
222
- d += y, p += x * y;
218
+ if (m === 0 && c === 0) continue;
219
+ const g = a + m;
220
+ if (g < 0 || g >= t) continue;
221
+ const U = n[d * t + g], b = m * m + c * c, E = U - l, p = Math.exp(-b / 2.25 - E * E / 0.01);
222
+ u += p, f += U * p;
223
223
  }
224
224
  }
225
- r[c] = p / d;
225
+ i[h] = f / u;
226
226
  }
227
227
  }
228
- function L(o, t, e) {
229
- return Math.min(e, Math.max(t, o));
228
+ function Z(n, t, e) {
229
+ return Math.min(e, Math.max(t, n));
230
230
  }
231
- const W = {
231
+ const kt = {
232
232
  parallaxStrength: 0.05,
233
233
  contrastLow: 0.05,
234
234
  contrastHigh: 0.95,
@@ -238,123 +238,123 @@ const W = {
238
238
  pomSteps: 16,
239
239
  overscanPadding: 0.08
240
240
  };
241
- function q(o, t, e) {
242
- const r = new Float32Array(256);
243
- if (o.length === 0 || t <= 0 || e <= 0)
244
- return _(r);
245
- const i = $(o.length), a = t * e;
246
- let l = 0;
247
- const n = new Uint32Array(256);
248
- for (const f of i) {
249
- const w = o[f], U = Math.min(w.length, a);
250
- for (let M = 0; M < U; M += 1)
251
- n[w[M]] += 1;
252
- l += U;
253
- }
254
- if (l === 0)
255
- return _(r);
256
- const c = 1 / l;
257
- for (let f = 0; f < 256; f += 1)
258
- r[f] = n[f] * c;
259
- const h = new Float32Array(256);
260
- h[0] = r[0];
261
- for (let f = 1; f < 256; f += 1)
262
- h[f] = h[f - 1] + r[f];
263
- const d = S(h, 0.05), p = S(h, 0.25), s = S(h, 0.5), u = S(h, 0.75), m = S(h, 0.95);
264
- let v = 0;
265
- for (let f = 0; f < 256; f += 1)
266
- v += f / 255 * r[f];
267
- let x = 0;
268
- for (let f = 0; f < 256; f += 1) {
269
- const w = f / 255 - v;
270
- x += r[f] * w * w;
271
- }
272
- const b = Math.sqrt(x), T = m - d, y = u - p, R = j(r);
241
+ function Ht(n, t, e) {
242
+ const i = new Float32Array(256);
243
+ if (n.length === 0 || t <= 0 || e <= 0)
244
+ return pt(i);
245
+ const r = Xt(n.length), o = t * e;
246
+ let s = 0;
247
+ const a = new Uint32Array(256);
248
+ for (const T of r) {
249
+ const x = n[T], y = Math.min(x.length, o);
250
+ for (let S = 0; S < y; S += 1)
251
+ a[x[S]] += 1;
252
+ s += y;
253
+ }
254
+ if (s === 0)
255
+ return pt(i);
256
+ const h = 1 / s;
257
+ for (let T = 0; T < 256; T += 1)
258
+ i[T] = a[T] * h;
259
+ const l = new Float32Array(256);
260
+ l[0] = i[0];
261
+ for (let T = 1; T < 256; T += 1)
262
+ l[T] = l[T - 1] + i[T];
263
+ const u = Y(l, 0.05), f = Y(l, 0.25), c = Y(l, 0.5), d = Y(l, 0.75), m = Y(l, 0.95);
264
+ let g = 0;
265
+ for (let T = 0; T < 256; T += 1)
266
+ g += T / 255 * i[T];
267
+ let U = 0;
268
+ for (let T = 0; T < 256; T += 1) {
269
+ const x = T / 255 - g;
270
+ U += i[T] * x * x;
271
+ }
272
+ const b = Math.sqrt(U), E = m - u, p = d - f, v = Nt(i);
273
273
  return {
274
- mean: v,
274
+ mean: g,
275
275
  stdDev: b,
276
- p5: d,
277
- p25: p,
278
- median: s,
279
- p75: u,
276
+ p5: u,
277
+ p25: f,
278
+ median: c,
279
+ p75: d,
280
280
  p95: m,
281
- effectiveRange: T,
282
- iqr: y,
283
- bimodality: R,
284
- histogram: r
281
+ effectiveRange: E,
282
+ iqr: p,
283
+ bimodality: v,
284
+ histogram: i
285
285
  };
286
286
  }
287
- function Y(o) {
288
- if (o.effectiveRange < 0.05 || o.stdDev < 0.02)
289
- return { ...W };
290
- const t = o.effectiveRange - 0.5, e = o.bimodality - 0.4, r = g(
287
+ function Bt(n) {
288
+ if (n.effectiveRange < 0.05 || n.stdDev < 0.02)
289
+ return { ...kt };
290
+ const t = n.effectiveRange - 0.5, e = n.bimodality - 0.4, i = O(
291
291
  0.05 - t * 0.03 + e * 0.01,
292
292
  0.035,
293
293
  0.065
294
- ), i = g(o.p5 - 0.03, 0, 0.25), a = g(o.p95 + 0.03, 0.75, 1), l = g((r - 0.03) / 0.05, 0, 1), n = g(0.6 - l * 0.25, 0.35, 0.6), c = g(0.6 - t * 0.2, 0.5, 0.7), h = g(0.4 + t * 0.2, 0.25, 0.5), d = 16, p = g(r + 0.03, 0.06, 0.1);
294
+ ), r = O(n.p5 - 0.03, 0, 0.25), o = O(n.p95 + 0.03, 0.75, 1), s = O((i - 0.03) / 0.05, 0, 1), a = O(0.6 - s * 0.25, 0.35, 0.6), h = O(0.6 - t * 0.2, 0.5, 0.7), l = O(0.4 + t * 0.2, 0.25, 0.5), u = 16, f = O(i + 0.03, 0.06, 0.1);
295
295
  return {
296
- parallaxStrength: r,
297
- contrastLow: i,
298
- contrastHigh: a,
299
- verticalReduction: n,
300
- dofStart: c,
301
- dofStrength: h,
302
- pomSteps: d,
303
- overscanPadding: p
296
+ parallaxStrength: i,
297
+ contrastLow: r,
298
+ contrastHigh: o,
299
+ verticalReduction: a,
300
+ dofStart: h,
301
+ dofStrength: l,
302
+ pomSteps: u,
303
+ overscanPadding: f
304
304
  };
305
305
  }
306
- function $(o) {
307
- if (o <= 0) return [];
308
- if (o === 1) return [0];
309
- const t = o - 1, e = [
306
+ function Xt(n) {
307
+ if (n <= 0) return [];
308
+ if (n === 1) return [0];
309
+ const t = n - 1, e = [
310
310
  0,
311
- Math.floor(o / 4),
312
- Math.floor(o / 2),
313
- Math.floor(3 * o / 4),
311
+ Math.floor(n / 4),
312
+ Math.floor(n / 2),
313
+ Math.floor(3 * n / 4),
314
314
  t
315
- ], r = /* @__PURE__ */ new Set(), i = [];
316
- for (const a of e)
317
- r.has(a) || (r.add(a), i.push(a));
318
- return i;
315
+ ], i = /* @__PURE__ */ new Set(), r = [];
316
+ for (const o of e)
317
+ i.has(o) || (i.add(o), r.push(o));
318
+ return r;
319
319
  }
320
- function S(o, t) {
320
+ function Y(n, t) {
321
321
  for (let e = 0; e < 256; e += 1)
322
- if (o[e] >= t)
322
+ if (n[e] >= t)
323
323
  return e / 255;
324
324
  return 1;
325
325
  }
326
- function j(o) {
326
+ function Nt(n) {
327
327
  const t = new Float32Array(256);
328
- for (let s = 0; s < 256; s += 1) {
329
- let u = 0, m = 0;
330
- for (let v = s - 2; v <= s + 2; v += 1)
331
- v >= 0 && v < 256 && (u += o[v], m += 1);
332
- t[s] = u / m;
328
+ for (let c = 0; c < 256; c += 1) {
329
+ let d = 0, m = 0;
330
+ for (let g = c - 2; g <= c + 2; g += 1)
331
+ g >= 0 && g < 256 && (d += n[g], m += 1);
332
+ t[c] = d / m;
333
333
  }
334
334
  let e = 0;
335
- for (let s = 0; s < 256; s += 1)
336
- e += t[s];
335
+ for (let c = 0; c < 256; c += 1)
336
+ e += t[c];
337
337
  e /= 256;
338
- const r = e * 2, i = 25, a = [];
339
- for (let s = 1; s < 255; s += 1)
340
- t[s] > t[s - 1] && t[s] > t[s + 1] && t[s] >= r && a.push({ bin: s, height: t[s] });
341
- if (t[0] > t[1] && t[0] >= r && a.push({ bin: 0, height: t[0] }), t[255] > t[254] && t[255] >= r && a.push({ bin: 255, height: t[255] }), a.sort((s, u) => u.height - s.height), a.length < 2) return 0;
342
- const l = a[0];
343
- let n = null;
344
- for (let s = 1; s < a.length; s += 1)
345
- if (Math.abs(a[s].bin - l.bin) >= i) {
346
- n = a[s];
338
+ const i = e * 2, r = 25, o = [];
339
+ for (let c = 1; c < 255; c += 1)
340
+ t[c] > t[c - 1] && t[c] > t[c + 1] && t[c] >= i && o.push({ bin: c, height: t[c] });
341
+ if (t[0] > t[1] && t[0] >= i && o.push({ bin: 0, height: t[0] }), t[255] > t[254] && t[255] >= i && o.push({ bin: 255, height: t[255] }), o.sort((c, d) => d.height - c.height), o.length < 2) return 0;
342
+ const s = o[0];
343
+ let a = null;
344
+ for (let c = 1; c < o.length; c += 1)
345
+ if (Math.abs(o[c].bin - s.bin) >= r) {
346
+ a = o[c];
347
347
  break;
348
348
  }
349
- if (!n) return 0;
350
- const c = Math.min(l.bin, n.bin), h = Math.max(l.bin, n.bin);
351
- let d = 1 / 0;
352
- for (let s = c; s <= h; s += 1)
353
- t[s] < d && (d = t[s]);
354
- const p = Math.min(l.height, n.height);
355
- return p <= 0 ? 0 : g(1 - d / p, 0, 1);
356
- }
357
- function _(o) {
349
+ if (!a) return 0;
350
+ const h = Math.min(s.bin, a.bin), l = Math.max(s.bin, a.bin);
351
+ let u = 1 / 0;
352
+ for (let c = h; c <= l; c += 1)
353
+ t[c] < u && (u = t[c]);
354
+ const f = Math.min(s.height, a.height);
355
+ return f <= 0 ? 0 : O(1 - u / f, 0, 1);
356
+ }
357
+ function pt(n) {
358
358
  return {
359
359
  mean: 0,
360
360
  stdDev: 0,
@@ -366,13 +366,13 @@ function _(o) {
366
366
  effectiveRange: 0,
367
367
  iqr: 0,
368
368
  bimodality: 0,
369
- histogram: o
369
+ histogram: n
370
370
  };
371
371
  }
372
- function g(o, t, e) {
373
- return Math.min(e, Math.max(t, o));
372
+ function O(n, t, e) {
373
+ return Math.min(e, Math.max(t, n));
374
374
  }
375
- const K = (
375
+ const zt = (
376
376
  /* glsl */
377
377
  `#version 300 es
378
378
  in vec2 aPosition;
@@ -396,7 +396,7 @@ const K = (
396
396
  gl_Position = vec4(aPosition, 0.0, 1.0);
397
397
  }
398
398
  `
399
- ), Z = (
399
+ ), Wt = (
400
400
  /* glsl */
401
401
  `#version 300 es
402
402
  precision highp float;
@@ -567,52 +567,52 @@ const K = (
567
567
  fragColor = color;
568
568
  }
569
569
  `
570
- ), D = {
570
+ ), q = {
571
571
  contrastLow: 0.05,
572
572
  contrastHigh: 0.95,
573
573
  verticalReduction: 0.5,
574
574
  dofStart: 0.6,
575
575
  dofStrength: 0.4
576
576
  };
577
- function O(o, t, e) {
578
- const r = o.createShader(t);
579
- if (!r) throw new Error("Failed to create shader.");
580
- if (o.shaderSource(r, e), o.compileShader(r), !o.getShaderParameter(r, o.COMPILE_STATUS)) {
581
- const i = o.getShaderInfoLog(r) ?? "";
582
- throw o.deleteShader(r), new Error(`Shader compilation failed:
583
- ${i}`);
577
+ function gt(n, t, e) {
578
+ const i = n.createShader(t);
579
+ if (!i) throw new Error("Failed to create shader.");
580
+ if (n.shaderSource(i, e), n.compileShader(i), !n.getShaderParameter(i, n.COMPILE_STATUS)) {
581
+ const r = n.getShaderInfoLog(i) ?? "";
582
+ throw n.deleteShader(i), new Error(`Shader compilation failed:
583
+ ${r}`);
584
584
  }
585
- return r;
585
+ return i;
586
586
  }
587
- function J(o, t, e) {
588
- const r = o.createProgram();
589
- if (!r) throw new Error("Failed to create program.");
590
- if (o.attachShader(r, t), o.attachShader(r, e), o.linkProgram(r), !o.getProgramParameter(r, o.LINK_STATUS)) {
591
- const i = o.getProgramInfoLog(r) ?? "";
592
- throw o.deleteProgram(r), new Error(`Program linking failed:
593
- ${i}`);
587
+ function Gt(n, t, e) {
588
+ const i = n.createProgram();
589
+ if (!i) throw new Error("Failed to create program.");
590
+ if (n.attachShader(i, t), n.attachShader(i, e), n.linkProgram(i), !n.getProgramParameter(i, n.LINK_STATUS)) {
591
+ const r = n.getProgramInfoLog(i) ?? "";
592
+ throw n.deleteProgram(i), new Error(`Program linking failed:
593
+ ${r}`);
594
594
  }
595
- return o.detachShader(r, t), o.detachShader(r, e), o.deleteShader(t), o.deleteShader(e), r;
595
+ return n.detachShader(i, t), n.detachShader(i, e), n.deleteShader(t), n.deleteShader(e), i;
596
596
  }
597
- function Q(o, t) {
597
+ function jt(n, t) {
598
598
  return {
599
- uImage: o.getUniformLocation(t, "uImage"),
600
- uDepth: o.getUniformLocation(t, "uDepth"),
601
- uOffset: o.getUniformLocation(t, "uOffset"),
602
- uStrength: o.getUniformLocation(t, "uStrength"),
603
- uPomEnabled: o.getUniformLocation(t, "uPomEnabled"),
604
- uPomSteps: o.getUniformLocation(t, "uPomSteps"),
605
- uContrastLow: o.getUniformLocation(t, "uContrastLow"),
606
- uContrastHigh: o.getUniformLocation(t, "uContrastHigh"),
607
- uVerticalReduction: o.getUniformLocation(t, "uVerticalReduction"),
608
- uDofStart: o.getUniformLocation(t, "uDofStart"),
609
- uDofStrength: o.getUniformLocation(t, "uDofStrength"),
610
- uImageTexelSize: o.getUniformLocation(t, "uImageTexelSize"),
611
- uUvOffset: o.getUniformLocation(t, "uUvOffset"),
612
- uUvScale: o.getUniformLocation(t, "uUvScale")
599
+ uImage: n.getUniformLocation(t, "uImage"),
600
+ uDepth: n.getUniformLocation(t, "uDepth"),
601
+ uOffset: n.getUniformLocation(t, "uOffset"),
602
+ uStrength: n.getUniformLocation(t, "uStrength"),
603
+ uPomEnabled: n.getUniformLocation(t, "uPomEnabled"),
604
+ uPomSteps: n.getUniformLocation(t, "uPomSteps"),
605
+ uContrastLow: n.getUniformLocation(t, "uContrastLow"),
606
+ uContrastHigh: n.getUniformLocation(t, "uContrastHigh"),
607
+ uVerticalReduction: n.getUniformLocation(t, "uVerticalReduction"),
608
+ uDofStart: n.getUniformLocation(t, "uDofStart"),
609
+ uDofStrength: n.getUniformLocation(t, "uDofStrength"),
610
+ uImageTexelSize: n.getUniformLocation(t, "uImageTexelSize"),
611
+ uUvOffset: n.getUniformLocation(t, "uUvOffset"),
612
+ uUvScale: n.getUniformLocation(t, "uUvScale")
613
613
  };
614
614
  }
615
- class A {
615
+ class $ {
616
616
  /** Debounce delay for resize events to avoid layout thrashing. */
617
617
  static RESIZE_DEBOUNCE_MS = 100;
618
618
  /** Compile-time upper bound for the POM for-loop in GLSL. */
@@ -667,20 +667,20 @@ class A {
667
667
  pomEnabled: e.pomEnabled,
668
668
  pomSteps: e.pomSteps,
669
669
  overscanPadding: e.overscanPadding,
670
- contrastLow: e.contrastLow ?? D.contrastLow,
671
- contrastHigh: e.contrastHigh ?? D.contrastHigh,
672
- verticalReduction: e.verticalReduction ?? D.verticalReduction,
673
- dofStart: e.dofStart ?? D.dofStart,
674
- dofStrength: e.dofStrength ?? D.dofStrength
670
+ contrastLow: e.contrastLow ?? q.contrastLow,
671
+ contrastHigh: e.contrastHigh ?? q.contrastHigh,
672
+ verticalReduction: e.verticalReduction ?? q.verticalReduction,
673
+ dofStart: e.dofStart ?? q.dofStart,
674
+ dofStrength: e.dofStrength ?? q.dofStrength
675
675
  }, this.canvas = document.createElement("canvas");
676
- const r = this.canvas.getContext("webgl2", {
676
+ const i = this.canvas.getContext("webgl2", {
677
677
  antialias: !1,
678
678
  alpha: !1,
679
679
  desynchronized: !0,
680
680
  powerPreference: "high-performance"
681
681
  });
682
- if (!r) throw new Error("WebGL 2 is not supported.");
683
- this.gl = r, "drawingBufferColorSpace" in r && (r.drawingBufferColorSpace = "srgb"), r.clearColor(0, 0, 0, 1), r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL, !0), this.container.appendChild(this.canvas), this.initGPUResources(), this.setupResizeHandling(), this.canvas.addEventListener("webglcontextlost", this.handleContextLost), this.canvas.addEventListener("webglcontextrestored", this.handleContextRestored);
682
+ if (!i) throw new Error("WebGL 2 is not supported.");
683
+ this.gl = i, "drawingBufferColorSpace" in i && (i.drawingBufferColorSpace = "srgb"), i.clearColor(0, 0, 0, 1), i.pixelStorei(i.UNPACK_FLIP_Y_WEBGL, !0), this.container.appendChild(this.canvas), this.initGPUResources(), this.setupResizeHandling(), this.canvas.addEventListener("webglcontextlost", this.handleContextLost), this.canvas.addEventListener("webglcontextrestored", this.handleContextRestored);
684
684
  }
685
685
  /**
686
686
  * Set up the scene: create video texture, depth texture, and set
@@ -693,9 +693,9 @@ class A {
693
693
  * @param depthWidth - Width of the precomputed depth map (e.g. 512).
694
694
  * @param depthHeight - Height of the precomputed depth map (e.g. 512).
695
695
  */
696
- initialize(t, e, r) {
697
- const i = this.gl;
698
- i && (this.disposeTextures(), this.videoAspect = t.videoWidth / t.videoHeight, this.depthWidth = e, this.depthHeight = r, this.videoTexture = i.createTexture(), i.activeTexture(i.TEXTURE0), i.bindTexture(i.TEXTURE_2D, this.videoTexture), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), this.depthTexture = i.createTexture(), i.activeTexture(i.TEXTURE1), i.bindTexture(i.TEXTURE_2D, this.depthTexture), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.texStorage2D(i.TEXTURE_2D, 1, i.R8, e, r), this.program && this.uniforms && (i.useProgram(this.program), i.uniform1i(this.uniforms.uImage, 0), i.uniform1i(this.uniforms.uDepth, 1), i.uniform1f(this.uniforms.uStrength, this.config.parallaxStrength), i.uniform1i(this.uniforms.uPomEnabled, this.config.pomEnabled ? 1 : 0), i.uniform1i(this.uniforms.uPomSteps, this.config.pomSteps), i.uniform1f(this.uniforms.uContrastLow, this.config.contrastLow), i.uniform1f(this.uniforms.uContrastHigh, this.config.contrastHigh), i.uniform1f(this.uniforms.uVerticalReduction, this.config.verticalReduction), i.uniform1f(this.uniforms.uDofStart, this.config.dofStart), i.uniform1f(this.uniforms.uDofStrength, this.config.dofStrength), i.uniform2f(this.uniforms.uImageTexelSize, 1 / t.videoWidth, 1 / t.videoHeight)), this.recalculateViewportLayout());
696
+ initialize(t, e, i) {
697
+ const r = this.gl;
698
+ r && (this.disposeTextures(), this.videoAspect = t.videoWidth / t.videoHeight, this.depthWidth = e, this.depthHeight = i, this.videoTexture = r.createTexture(), r.activeTexture(r.TEXTURE0), r.bindTexture(r.TEXTURE_2D, this.videoTexture), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_MIN_FILTER, r.LINEAR), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_MAG_FILTER, r.LINEAR), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_WRAP_S, r.CLAMP_TO_EDGE), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_WRAP_T, r.CLAMP_TO_EDGE), this.depthTexture = r.createTexture(), r.activeTexture(r.TEXTURE1), r.bindTexture(r.TEXTURE_2D, this.depthTexture), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_MIN_FILTER, r.LINEAR), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_MAG_FILTER, r.LINEAR), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_WRAP_S, r.CLAMP_TO_EDGE), r.texParameteri(r.TEXTURE_2D, r.TEXTURE_WRAP_T, r.CLAMP_TO_EDGE), r.texStorage2D(r.TEXTURE_2D, 1, r.R8, e, i), this.program && this.uniforms && (r.useProgram(this.program), r.uniform1i(this.uniforms.uImage, 0), r.uniform1i(this.uniforms.uDepth, 1), r.uniform1f(this.uniforms.uStrength, this.config.parallaxStrength), r.uniform1i(this.uniforms.uPomEnabled, this.config.pomEnabled ? 1 : 0), r.uniform1i(this.uniforms.uPomSteps, this.config.pomSteps), r.uniform1f(this.uniforms.uContrastLow, this.config.contrastLow), r.uniform1f(this.uniforms.uContrastHigh, this.config.contrastHigh), r.uniform1f(this.uniforms.uVerticalReduction, this.config.verticalReduction), r.uniform1f(this.uniforms.uDofStart, this.config.dofStart), r.uniform1f(this.uniforms.uDofStrength, this.config.dofStrength), r.uniform2f(this.uniforms.uImageTexelSize, 1 / t.videoWidth, 1 / t.videoHeight)), this.recalculateViewportLayout());
699
699
  }
700
700
  /**
701
701
  * Begin the render loop.
@@ -707,8 +707,8 @@ class A {
707
707
  * When RVFC is not available, falls back to a single RAF loop that
708
708
  * does everything (the pre-RVFC behavior).
709
709
  */
710
- start(t, e, r, i) {
711
- this.stop(), this.playbackVideo = t, this.readDepth = e, this.readInput = r, this.onVideoFrame = i ?? null, this.rvfcSupported = A.isRVFCSupported(), this.rvfcSupported && (this.rvfcHandle = t.requestVideoFrameCallback(this.videoFrameLoop)), this.animationFrameHandle = window.requestAnimationFrame(this.renderLoop);
710
+ start(t, e, i, r) {
711
+ this.stop(), this.playbackVideo = t, this.readDepth = e, this.readInput = i, this.onVideoFrame = r ?? null, this.rvfcSupported = $.isRVFCSupported(), this.rvfcSupported && (this.rvfcHandle = t.requestVideoFrameCallback(this.videoFrameLoop)), this.animationFrameHandle = window.requestAnimationFrame(this.renderLoop);
712
712
  }
713
713
  /** Stop both render loops and release callbacks. */
714
714
  stop() {
@@ -725,13 +725,13 @@ class A {
725
725
  initGPUResources() {
726
726
  const t = this.gl;
727
727
  if (!t) return;
728
- const e = Z.replace(
728
+ const e = Wt.replace(
729
729
  "#version 300 es",
730
730
  `#version 300 es
731
- #define MAX_POM_STEPS ${A.MAX_POM_STEPS}`
732
- ), r = O(t, t.VERTEX_SHADER, K), i = O(t, t.FRAGMENT_SHADER, e);
733
- this.program = J(t, r, i), this.uniforms = Q(t, this.program);
734
- const a = new Float32Array([
731
+ #define MAX_POM_STEPS ${$.MAX_POM_STEPS}`
732
+ ), i = gt(t, t.VERTEX_SHADER, zt), r = gt(t, t.FRAGMENT_SHADER, e);
733
+ this.program = Gt(t, i, r), this.uniforms = jt(t, this.program);
734
+ const o = new Float32Array([
735
735
  -1,
736
736
  -1,
737
737
  // bottom-left
@@ -746,10 +746,10 @@ class A {
746
746
  // top-right
747
747
  ]);
748
748
  this.vao = t.createVertexArray(), t.bindVertexArray(this.vao);
749
- const l = t.createBuffer();
750
- t.bindBuffer(t.ARRAY_BUFFER, l), t.bufferData(t.ARRAY_BUFFER, a, t.STATIC_DRAW);
751
- const n = t.getAttribLocation(this.program, "aPosition");
752
- t.enableVertexAttribArray(n), t.vertexAttribPointer(n, 2, t.FLOAT, !1, 0, 0), t.bindVertexArray(null), t.disable(t.DEPTH_TEST);
749
+ const s = t.createBuffer();
750
+ t.bindBuffer(t.ARRAY_BUFFER, s), t.bufferData(t.ARRAY_BUFFER, o, t.STATIC_DRAW);
751
+ const a = t.getAttribLocation(this.program, "aPosition");
752
+ t.enableVertexAttribArray(a), t.vertexAttribPointer(a, 2, t.FLOAT, !1, 0, 0), t.bindVertexArray(null), t.disable(t.DEPTH_TEST);
753
753
  }
754
754
  // -----------------------------------------------------------------------
755
755
  // RVFC feature detection
@@ -768,11 +768,11 @@ class A {
768
768
  * when the video frame actually changes (~24-30fps, not 60-120fps).
769
769
  */
770
770
  videoFrameLoop = (t, e) => {
771
- const r = this.playbackVideo;
772
- if (!r) return;
773
- this.rvfcHandle = r.requestVideoFrameCallback(this.videoFrameLoop);
774
- const i = e.mediaTime ?? r.currentTime;
775
- this.updateDepthTexture(i), this.onVideoFrame && this.onVideoFrame(i, e.presentedFrames ?? 0);
771
+ const i = this.playbackVideo;
772
+ if (!i) return;
773
+ this.rvfcHandle = i.requestVideoFrameCallback(this.videoFrameLoop);
774
+ const r = e.mediaTime ?? i.currentTime;
775
+ this.updateDepthTexture(r), this.onVideoFrame && this.onVideoFrame(r, e.presentedFrames ?? 0);
776
776
  };
777
777
  // -----------------------------------------------------------------------
778
778
  // Render loop (RAF) — input + render at display refresh rate
@@ -793,8 +793,8 @@ class A {
793
793
  const t = this.gl, e = this.playbackVideo;
794
794
  if (!(!t || !this.program || !this.uniforms || !this.vao) && !(!e || e.readyState < HTMLMediaElement.HAVE_CURRENT_DATA)) {
795
795
  if (t.useProgram(this.program), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, this.videoTexture), t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, t.RGBA, t.UNSIGNED_BYTE, e), this.rvfcSupported || this.updateDepthTexture(e.currentTime), this.readInput) {
796
- const r = this.readInput();
797
- t.uniform2f(this.uniforms.uOffset, -r.x, r.y);
796
+ const i = this.readInput();
797
+ t.uniform2f(this.uniforms.uOffset, -i.x, i.y);
798
798
  }
799
799
  t.bindVertexArray(this.vao), t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
800
800
  }
@@ -803,7 +803,7 @@ class A {
803
803
  updateDepthTexture(t) {
804
804
  const e = this.gl;
805
805
  if (!e || !this.readDepth || !this.depthTexture) return;
806
- const r = this.readDepth(t);
806
+ const i = this.readDepth(t);
807
807
  e.activeTexture(e.TEXTURE1), e.bindTexture(e.TEXTURE_2D, this.depthTexture), e.texSubImage2D(
808
808
  e.TEXTURE_2D,
809
809
  0,
@@ -813,7 +813,7 @@ class A {
813
813
  this.depthHeight,
814
814
  e.RED,
815
815
  e.UNSIGNED_BYTE,
816
- r
816
+ i
817
817
  );
818
818
  }
819
819
  // -----------------------------------------------------------------------
@@ -832,7 +832,7 @@ class A {
832
832
  scheduleResizeRecalculate = () => {
833
833
  this.resizeTimer !== null && window.clearTimeout(this.resizeTimer), this.resizeTimer = window.setTimeout(() => {
834
834
  this.resizeTimer = null, this.recalculateViewportLayout();
835
- }, A.RESIZE_DEBOUNCE_MS);
835
+ }, $.RESIZE_DEBOUNCE_MS);
836
836
  };
837
837
  /**
838
838
  * Recalculate the WebGL canvas size and UV transform to match the
@@ -844,13 +844,13 @@ class A {
844
844
  recalculateViewportLayout() {
845
845
  const t = this.gl;
846
846
  if (!t) return;
847
- const { width: e, height: r } = this.getViewportSize(), i = Math.min(window.devicePixelRatio, 2), a = Math.round(e * i), l = Math.round(r * i);
848
- (this.canvas.width !== a || this.canvas.height !== l) && (this.canvas.width = a, this.canvas.height = l, t.viewport(0, 0, a, l));
849
- const n = e / r, c = this.config.parallaxStrength + this.config.overscanPadding;
850
- let h = 1, d = 1;
851
- n > this.videoAspect ? d = this.videoAspect / n : h = n / this.videoAspect;
852
- const p = 1 + c * 2;
853
- h /= p, d /= p, this.uvOffset = [(1 - h) / 2, (1 - d) / 2], this.uvScale = [h, d], this.program && this.uniforms && (t.useProgram(this.program), t.uniform2f(this.uniforms.uUvOffset, this.uvOffset[0], this.uvOffset[1]), t.uniform2f(this.uniforms.uUvScale, this.uvScale[0], this.uvScale[1]));
847
+ const { width: e, height: i } = this.getViewportSize(), r = Math.min(window.devicePixelRatio, 2), o = Math.round(e * r), s = Math.round(i * r);
848
+ (this.canvas.width !== o || this.canvas.height !== s) && (this.canvas.width = o, this.canvas.height = s, t.viewport(0, 0, o, s));
849
+ const a = e / i, h = this.config.parallaxStrength + this.config.overscanPadding;
850
+ let l = 1, u = 1;
851
+ a > this.videoAspect ? u = this.videoAspect / a : l = a / this.videoAspect;
852
+ const f = 1 + h * 2;
853
+ l /= f, u /= f, this.uvOffset = [(1 - l) / 2, (1 - u) / 2], this.uvScale = [l, u], this.program && this.uniforms && (t.useProgram(this.program), t.uniform2f(this.uniforms.uUvOffset, this.uvOffset[0], this.uvOffset[1]), t.uniform2f(this.uniforms.uUvScale, this.uvScale[0], this.uvScale[1]));
854
854
  }
855
855
  /** Read the container's pixel dimensions, with a minimum of 1x1. */
856
856
  getViewportSize() {
@@ -881,7 +881,7 @@ class A {
881
881
  t && (this.program && (t.deleteProgram(this.program), this.program = null), this.vao && (t.deleteVertexArray(this.vao), this.vao = null), this.uniforms = null);
882
882
  }
883
883
  }
884
- const E = {
884
+ const B = {
885
885
  parallaxX: 0.4,
886
886
  parallaxY: 1,
887
887
  parallaxMax: 30,
@@ -890,9 +890,9 @@ const E = {
890
890
  loop: !0,
891
891
  muted: !0
892
892
  };
893
- class tt {
894
- constructor(t, e = 0.08, r = 0.06) {
895
- this.host = t, this.lerpFactor = e, this.motionLerpFactor = r, this.host.addEventListener("mousemove", this.handleMouseMove), this.host.addEventListener("mouseleave", this.resetPointerTarget), this.host.addEventListener("touchstart", this.handleFirstTouch, { once: !0 });
893
+ let Yt = class yt {
894
+ constructor(t, e = 0.08, i = 0.06) {
895
+ this.host = t, this.lerpFactor = e, this.motionLerpFactor = i, this.host.addEventListener("mousemove", this.handleMouseMove), this.host.addEventListener("mouseleave", this.resetPointerTarget), this.host.addEventListener("touchstart", this.handleTouchStart, { passive: !0 }), this.host.addEventListener("touchmove", this.handleTouchMove, { passive: !0 }), this.host.addEventListener("touchend", this.handleTouchEnd, { passive: !0 }), this.host.addEventListener("touchcancel", this.handleTouchEnd, { passive: !0 });
896
896
  }
897
897
  pointerTarget = { x: 0, y: 0 };
898
898
  motionTarget = { x: 0, y: 0 };
@@ -900,24 +900,42 @@ class tt {
900
900
  usingMotionInput = !1;
901
901
  motionListenerAttached = !1;
902
902
  motionRequested = !1;
903
+ touchActive = !1;
904
+ touchAnchorX = 0;
905
+ touchAnchorY = 0;
903
906
  lerpFactor;
904
907
  motionLerpFactor;
908
+ /** Pixels of finger drag to reach full parallax offset (-1 or 1). */
909
+ static TOUCH_DRAG_RANGE = 100;
905
910
  update() {
906
- const t = this.usingMotionInput ? this.motionTarget : this.pointerTarget, e = this.usingMotionInput ? this.motionLerpFactor : this.lerpFactor;
907
- return this.smoothedOutput.x = P(this.smoothedOutput.x, t.x, e), this.smoothedOutput.y = P(this.smoothedOutput.y, t.y, e), this.smoothedOutput;
911
+ const t = this.touchActive ? this.pointerTarget : this.usingMotionInput ? this.motionTarget : this.pointerTarget, e = this.usingMotionInput && !this.touchActive ? this.motionLerpFactor : this.lerpFactor;
912
+ return this.smoothedOutput.x = it(this.smoothedOutput.x, t.x, e), this.smoothedOutput.y = it(this.smoothedOutput.y, t.y, e), this.smoothedOutput;
908
913
  }
909
914
  dispose() {
910
- this.host.removeEventListener("mousemove", this.handleMouseMove), this.host.removeEventListener("mouseleave", this.resetPointerTarget), this.host.removeEventListener("touchstart", this.handleFirstTouch), this.motionListenerAttached && (window.removeEventListener("deviceorientation", this.handleDeviceOrientation), this.motionListenerAttached = !1);
915
+ this.host.removeEventListener("mousemove", this.handleMouseMove), this.host.removeEventListener("mouseleave", this.resetPointerTarget), this.host.removeEventListener("touchstart", this.handleTouchStart), this.host.removeEventListener("touchmove", this.handleTouchMove), this.host.removeEventListener("touchend", this.handleTouchEnd), this.host.removeEventListener("touchcancel", this.handleTouchEnd), this.motionListenerAttached && (window.removeEventListener("deviceorientation", this.handleDeviceOrientation), this.motionListenerAttached = !1);
911
916
  }
912
917
  handleMouseMove = (t) => {
913
- const e = this.host.getBoundingClientRect(), r = (t.clientX - e.left) / e.width * 2 - 1, i = (t.clientY - e.top) / e.height * 2 - 1;
914
- this.pointerTarget.x = F(r, -1, 1), this.pointerTarget.y = F(i, -1, 1);
918
+ const e = this.host.getBoundingClientRect(), i = (t.clientX - e.left) / e.width * 2 - 1, r = (t.clientY - e.top) / e.height * 2 - 1;
919
+ this.pointerTarget.x = z(i, -1, 1), this.pointerTarget.y = z(r, -1, 1);
915
920
  };
916
921
  resetPointerTarget = () => {
917
922
  this.pointerTarget.x = 0, this.pointerTarget.y = 0;
918
923
  };
919
- handleFirstTouch = async () => {
920
- if (this.motionRequested || (this.motionRequested = !0, typeof DeviceOrientationEvent > "u")) return;
924
+ handleTouchStart = (t) => {
925
+ const e = t.touches[0];
926
+ e && (this.touchActive = !0, this.touchAnchorX = e.clientX, this.touchAnchorY = e.clientY, this.pointerTarget.x = 0, this.pointerTarget.y = 0, this.motionRequested || (this.motionRequested = !0, this.requestMotionPermission()));
927
+ };
928
+ handleTouchMove = (t) => {
929
+ const e = t.touches[0];
930
+ if (!e) return;
931
+ const i = e.clientX - this.touchAnchorX, r = e.clientY - this.touchAnchorY, o = yt.TOUCH_DRAG_RANGE;
932
+ this.pointerTarget.x = z(i / o, -1, 1), this.pointerTarget.y = z(r / o, -1, 1);
933
+ };
934
+ handleTouchEnd = () => {
935
+ this.touchActive = !1, this.pointerTarget.x = 0, this.pointerTarget.y = 0;
936
+ };
937
+ async requestMotionPermission() {
938
+ if (typeof DeviceOrientationEvent > "u") return;
921
939
  const t = DeviceOrientationEvent;
922
940
  if (typeof t.requestPermission == "function")
923
941
  try {
@@ -926,13 +944,13 @@ class tt {
926
944
  return;
927
945
  }
928
946
  this.motionListenerAttached || (window.addEventListener("deviceorientation", this.handleDeviceOrientation), this.motionListenerAttached = !0), this.usingMotionInput = !0;
929
- };
947
+ }
930
948
  handleDeviceOrientation = (t) => {
931
- const e = F((t.gamma ?? 0) / 45, -1, 1), r = F((t.beta ?? 0) / 45, -1, 1);
932
- this.motionTarget.x = P(this.motionTarget.x, e, this.motionLerpFactor), this.motionTarget.y = P(this.motionTarget.y, r, this.motionLerpFactor);
949
+ const e = z((t.gamma ?? 0) / 45, -1, 1), i = z((t.beta ?? 0) / 45, -1, 1);
950
+ this.motionTarget.x = it(this.motionTarget.x, e, this.motionLerpFactor), this.motionTarget.y = it(this.motionTarget.y, i, this.motionLerpFactor);
933
951
  };
934
- }
935
- class C extends HTMLElement {
952
+ };
953
+ class ht extends HTMLElement {
936
954
  static TAG_NAME = "layershift-parallax";
937
955
  static get observedAttributes() {
938
956
  return [
@@ -963,36 +981,36 @@ class C extends HTMLElement {
963
981
  }
964
982
  // --- Attribute helpers ---
965
983
  getAttrFloat(t, e) {
966
- const r = this.getAttribute(t);
967
- if (r === null) return e;
968
- const i = parseFloat(r);
969
- return Number.isFinite(i) ? i : e;
984
+ const i = this.getAttribute(t);
985
+ if (i === null) return e;
986
+ const r = parseFloat(i);
987
+ return Number.isFinite(r) ? r : e;
970
988
  }
971
989
  getAttrBool(t, e) {
972
990
  if (!this.hasAttribute(t)) return e;
973
- const r = this.getAttribute(t);
974
- return !(r === "false" || r === "0");
991
+ const i = this.getAttribute(t);
992
+ return !(i === "false" || i === "0");
975
993
  }
976
994
  get parallaxX() {
977
- return this.getAttrFloat("parallax-x", E.parallaxX);
995
+ return this.getAttrFloat("parallax-x", B.parallaxX);
978
996
  }
979
997
  get parallaxY() {
980
- return this.getAttrFloat("parallax-y", E.parallaxY);
998
+ return this.getAttrFloat("parallax-y", B.parallaxY);
981
999
  }
982
1000
  get parallaxMax() {
983
- return this.getAttrFloat("parallax-max", E.parallaxMax);
1001
+ return this.getAttrFloat("parallax-max", B.parallaxMax);
984
1002
  }
985
1003
  get overscan() {
986
- return this.getAttrFloat("overscan", E.overscan);
1004
+ return this.getAttrFloat("overscan", B.overscan);
987
1005
  }
988
1006
  get shouldAutoplay() {
989
- return this.getAttrBool("autoplay", E.autoplay);
1007
+ return this.getAttrBool("autoplay", B.autoplay);
990
1008
  }
991
1009
  get shouldLoop() {
992
- return this.getAttrBool("loop", E.loop);
1010
+ return this.getAttrBool("loop", B.loop);
993
1011
  }
994
1012
  get shouldMute() {
995
- return this.getAttrBool("muted", E.muted);
1013
+ return this.getAttrBool("muted", B.muted);
996
1014
  }
997
1015
  // --- Event dispatching ---
998
1016
  /**
@@ -1035,7 +1053,7 @@ class C extends HTMLElement {
1035
1053
  disconnectedCallback() {
1036
1054
  this.dispose();
1037
1055
  }
1038
- attributeChangedCallback(t, e, r) {
1056
+ attributeChangedCallback(t, e, i) {
1039
1057
  ["src", "depth-src", "depth-meta"].includes(t) && (this.initialized ? (this.dispose(), this.setupShadowDOM(), this.init()) : this.isConnected && this.getAttribute("src") && this.getAttribute("depth-src") && this.getAttribute("depth-meta") && this.init());
1040
1058
  }
1041
1059
  // --- Shadow DOM setup ---
@@ -1066,114 +1084,114 @@ class C extends HTMLElement {
1066
1084
  }
1067
1085
  // --- Initialization ---
1068
1086
  async init() {
1069
- const t = this.getAttribute("src"), e = this.getAttribute("depth-src"), r = this.getAttribute("depth-meta");
1070
- if (!t || !e || !r) {
1071
- const i = "src, depth-src, and depth-meta attributes are required.";
1072
- console.warn(`<layershift-parallax>: ${i}`), this.emit("layershift-parallax:error", { message: i });
1087
+ const t = this.getAttribute("src"), e = this.getAttribute("depth-src"), i = this.getAttribute("depth-meta");
1088
+ if (!t || !e || !i) {
1089
+ const r = "src, depth-src, and depth-meta attributes are required.";
1090
+ console.warn(`<layershift-parallax>: ${r}`), this.emit("layershift-parallax:error", { message: r });
1073
1091
  return;
1074
1092
  }
1075
1093
  if (this.container) {
1076
1094
  this.abortController = new AbortController();
1077
1095
  try {
1078
- const [i, a] = await Promise.all([
1096
+ const [r, o] = await Promise.all([
1079
1097
  this.createVideoElement(t),
1080
- H(e, r)
1098
+ At(e, i)
1081
1099
  ]);
1082
1100
  if (this.abortController.signal.aborted) {
1083
- i.remove();
1101
+ r.remove();
1084
1102
  return;
1085
1103
  }
1086
- this.video = i, this.loopCount = 0, this.attachVideoEventListeners(i);
1087
- const l = q(
1088
- a.frames,
1089
- a.meta.width,
1090
- a.meta.height
1091
- ), n = Y(l), c = this.hasAttribute("parallax-max") ? this.parallaxMax / Math.max(i.videoWidth, 1) : n.parallaxStrength, h = this.hasAttribute("overscan") ? this.overscan : n.overscanPadding;
1092
- let d;
1104
+ this.video = r, this.loopCount = 0, this.attachVideoEventListeners(r);
1105
+ const s = Ht(
1106
+ o.frames,
1107
+ o.meta.width,
1108
+ o.meta.height
1109
+ ), a = Bt(s), h = this.hasAttribute("parallax-max") ? this.parallaxMax / Math.max(r.videoWidth, 1) : a.parallaxStrength, l = this.hasAttribute("overscan") ? this.overscan : a.overscanPadding;
1110
+ let u;
1093
1111
  try {
1094
- const u = await V.create(
1095
- a,
1096
- a.meta.width,
1097
- a.meta.height
1112
+ const d = await st.create(
1113
+ o,
1114
+ o.meta.width,
1115
+ o.meta.height
1098
1116
  );
1099
- this.depthWorker = u, d = (m) => u.sample(m);
1117
+ this.depthWorker = d, u = (m) => d.sample(m);
1100
1118
  } catch {
1101
- const u = new I(
1102
- a,
1103
- a.meta.width,
1104
- a.meta.height
1119
+ const d = new bt(
1120
+ o,
1121
+ o.meta.width,
1122
+ o.meta.height
1105
1123
  );
1106
- d = (m) => u.sample(m);
1124
+ u = (m) => d.sample(m);
1107
1125
  }
1108
1126
  if (this.abortController.signal.aborted) {
1109
- i.remove(), this.depthWorker?.dispose(), this.depthWorker = null;
1127
+ r.remove(), this.depthWorker?.dispose(), this.depthWorker = null;
1110
1128
  return;
1111
1129
  }
1112
- this.renderer = new A(this.container, {
1113
- parallaxStrength: c,
1130
+ this.renderer = new $(this.container, {
1131
+ parallaxStrength: h,
1114
1132
  pomEnabled: !0,
1115
- pomSteps: n.pomSteps,
1116
- overscanPadding: h,
1117
- contrastLow: n.contrastLow,
1118
- contrastHigh: n.contrastHigh,
1119
- verticalReduction: n.verticalReduction,
1120
- dofStart: n.dofStart,
1121
- dofStrength: n.dofStrength
1122
- }), this.renderer.initialize(i, a.meta.width, a.meta.height), this.inputHandler = new tt(this);
1123
- const p = this.parallaxX, s = this.parallaxY;
1133
+ pomSteps: a.pomSteps,
1134
+ overscanPadding: l,
1135
+ contrastLow: a.contrastLow,
1136
+ contrastHigh: a.contrastHigh,
1137
+ verticalReduction: a.verticalReduction,
1138
+ dofStart: a.dofStart,
1139
+ dofStrength: a.dofStrength
1140
+ }), this.renderer.initialize(r, o.meta.width, o.meta.height), this.inputHandler = new Yt(this);
1141
+ const f = this.parallaxX, c = this.parallaxY;
1124
1142
  if (this.renderer.start(
1125
- i,
1126
- d,
1143
+ r,
1144
+ u,
1127
1145
  () => {
1128
- const u = this.inputHandler.update();
1146
+ const d = this.inputHandler.update();
1129
1147
  return {
1130
- x: u.x * p,
1131
- y: u.y * s
1148
+ x: d.x * f,
1149
+ y: d.y * c
1132
1150
  };
1133
1151
  },
1134
1152
  // RVFC callback: dispatch 'frame' event on each new video frame
1135
- (u, m) => {
1153
+ (d, m) => {
1136
1154
  this.emit("layershift-parallax:frame", {
1137
- currentTime: u,
1155
+ currentTime: d,
1138
1156
  frameNumber: m
1139
1157
  });
1140
1158
  }
1141
1159
  ), this.shouldAutoplay) {
1142
- i.currentTime = 0;
1160
+ r.currentTime = 0;
1143
1161
  try {
1144
- await i.play();
1162
+ await r.play();
1145
1163
  } catch {
1146
1164
  }
1147
1165
  }
1148
1166
  this.initialized = !0, this.emit("layershift-parallax:ready", {
1149
- videoWidth: i.videoWidth,
1150
- videoHeight: i.videoHeight,
1151
- duration: i.duration,
1152
- depthProfile: l,
1153
- derivedParams: n
1167
+ videoWidth: r.videoWidth,
1168
+ videoHeight: r.videoHeight,
1169
+ duration: r.duration,
1170
+ depthProfile: s,
1171
+ derivedParams: a
1154
1172
  });
1155
- } catch (i) {
1156
- const a = i instanceof Error ? i.message : "Failed to initialize.";
1157
- console.error("<layershift-parallax>: Failed to initialize.", i), this.emit("layershift-parallax:error", { message: a });
1173
+ } catch (r) {
1174
+ const o = r instanceof Error ? r.message : "Failed to initialize.";
1175
+ console.error("<layershift-parallax>: Failed to initialize.", r), this.emit("layershift-parallax:error", { message: o });
1158
1176
  }
1159
1177
  }
1160
1178
  }
1161
1179
  // --- Video element ---
1162
1180
  async createVideoElement(t) {
1163
1181
  const e = document.createElement("video");
1164
- return e.crossOrigin = "anonymous", e.setAttribute("crossorigin", "anonymous"), e.playsInline = !0, e.setAttribute("playsinline", ""), e.setAttribute("webkit-playsinline", "true"), e.muted = this.shouldMute, e.defaultMuted = this.shouldMute, this.shouldMute && e.setAttribute("muted", ""), e.loop = this.shouldLoop, e.preload = "auto", e.style.display = "none", e.src = t, this.shadow.appendChild(e), await new Promise((r, i) => {
1182
+ return e.crossOrigin = "anonymous", e.setAttribute("crossorigin", "anonymous"), e.playsInline = !0, e.setAttribute("playsinline", ""), e.setAttribute("webkit-playsinline", "true"), e.muted = this.shouldMute, e.defaultMuted = this.shouldMute, this.shouldMute && e.setAttribute("muted", ""), e.loop = this.shouldLoop, e.preload = "auto", e.style.display = "none", e.src = t, this.shadow.appendChild(e), await new Promise((i, r) => {
1165
1183
  if (e.readyState >= HTMLMediaElement.HAVE_METADATA) {
1166
- r();
1184
+ i();
1167
1185
  return;
1168
1186
  }
1169
- const a = () => {
1170
- n(), r();
1171
- }, l = () => {
1172
- n(), i(new Error("Failed to load video metadata."));
1173
- }, n = () => {
1174
- e.removeEventListener("loadedmetadata", a), e.removeEventListener("error", l);
1187
+ const o = () => {
1188
+ a(), i();
1189
+ }, s = () => {
1190
+ a(), r(new Error("Failed to load video metadata."));
1191
+ }, a = () => {
1192
+ e.removeEventListener("loadedmetadata", o), e.removeEventListener("error", s);
1175
1193
  };
1176
- e.addEventListener("loadedmetadata", a), e.addEventListener("error", l), e.load();
1194
+ e.addEventListener("loadedmetadata", o), e.addEventListener("error", s), e.load();
1177
1195
  }), e;
1178
1196
  }
1179
1197
  // --- Cleanup ---
@@ -1181,13 +1199,2252 @@ class C extends HTMLElement {
1181
1199
  this.abortController?.abort(), this.abortController = null, this.renderer?.dispose(), this.renderer = null, this.inputHandler?.dispose(), this.inputHandler = null, this.depthWorker?.dispose(), this.depthWorker = null, this.video && (this.video.pause(), this.video.removeAttribute("src"), this.video.load(), this.video.remove(), this.video = null), this.initialized = !1, this.loopCount = 0, this.container = null;
1182
1200
  }
1183
1201
  }
1184
- function F(o, t, e) {
1185
- return Math.min(e, Math.max(t, o));
1202
+ function z(n, t, e) {
1203
+ return Math.min(e, Math.max(t, n));
1204
+ }
1205
+ function it(n, t, e) {
1206
+ return n + (t - n) * e;
1186
1207
  }
1187
- function P(o, t, e) {
1188
- return o + (t - o) * e;
1208
+ const qt = (
1209
+ /* glsl */
1210
+ `#version 300 es
1211
+ in vec2 aPosition;
1212
+ uniform vec2 uMeshScale;
1213
+ void main() {
1214
+ gl_Position = vec4(aPosition * uMeshScale, 0.0, 1.0);
1215
+ }
1216
+ `
1217
+ ), Zt = (
1218
+ /* glsl */
1219
+ `#version 300 es
1220
+ precision lowp float;
1221
+ out vec4 fragColor;
1222
+ void main() { fragColor = vec4(0.0); }
1223
+ `
1224
+ ), $t = (
1225
+ /* glsl */
1226
+ `#version 300 es
1227
+ in vec2 aPosition;
1228
+ uniform vec2 uMeshScale;
1229
+ void main() {
1230
+ gl_Position = vec4(aPosition * uMeshScale, 0.0, 1.0);
1231
+ }
1232
+ `
1233
+ ), Jt = (
1234
+ /* glsl */
1235
+ `#version 300 es
1236
+ precision lowp float;
1237
+ out vec4 fragColor;
1238
+ void main() { fragColor = vec4(1.0); }
1239
+ `
1240
+ ), Kt = (
1241
+ /* glsl */
1242
+ `#version 300 es
1243
+ in vec2 aPosition;
1244
+ out vec2 vUv;
1245
+ void main() {
1246
+ vUv = aPosition * 0.5 + 0.5;
1247
+ gl_Position = vec4(aPosition, 0.0, 1.0);
1248
+ }
1249
+ `
1250
+ ), Qt = (
1251
+ /* glsl */
1252
+ `#version 300 es
1253
+ precision highp float;
1254
+ uniform sampler2D uMask;
1255
+ uniform vec2 uTexelSize;
1256
+ in vec2 vUv;
1257
+ out vec2 fragSeed;
1258
+
1259
+ void main() {
1260
+ float center = texture(uMask, vUv).r;
1261
+ float left = texture(uMask, vUv + vec2(-uTexelSize.x, 0.0)).r;
1262
+ float right = texture(uMask, vUv + vec2( uTexelSize.x, 0.0)).r;
1263
+ float up = texture(uMask, vUv + vec2(0.0, uTexelSize.y)).r;
1264
+ float down = texture(uMask, vUv + vec2(0.0, -uTexelSize.y)).r;
1265
+
1266
+ bool isEdge = (step(0.5, center) != step(0.5, left)) ||
1267
+ (step(0.5, center) != step(0.5, right)) ||
1268
+ (step(0.5, center) != step(0.5, up)) ||
1269
+ (step(0.5, center) != step(0.5, down));
1270
+
1271
+ if (isEdge) {
1272
+ fragSeed = vUv;
1273
+ } else {
1274
+ fragSeed = vec2(-1.0);
1275
+ }
1276
+ }
1277
+ `
1278
+ ), te = (
1279
+ /* glsl */
1280
+ `#version 300 es
1281
+ in vec2 aPosition;
1282
+ out vec2 vUv;
1283
+ void main() {
1284
+ vUv = aPosition * 0.5 + 0.5;
1285
+ gl_Position = vec4(aPosition, 0.0, 1.0);
1286
+ }
1287
+ `
1288
+ ), ee = (
1289
+ /* glsl */
1290
+ `#version 300 es
1291
+ precision highp float;
1292
+ uniform sampler2D uSeedTex;
1293
+ uniform float uStepSize;
1294
+ in vec2 vUv;
1295
+ out vec2 fragSeed;
1296
+
1297
+ void main() {
1298
+ vec2 bestSeed = texture(uSeedTex, vUv).rg;
1299
+ float bestDist = (bestSeed.x < 0.0) ? 1.0e10 : distance(vUv, bestSeed);
1300
+
1301
+ for (int dy = -1; dy <= 1; dy++) {
1302
+ for (int dx = -1; dx <= 1; dx++) {
1303
+ if (dx == 0 && dy == 0) continue;
1304
+ vec2 offset = vec2(float(dx), float(dy)) * uStepSize;
1305
+ vec2 sampleUv = vUv + offset;
1306
+ if (sampleUv.x < 0.0 || sampleUv.x > 1.0 || sampleUv.y < 0.0 || sampleUv.y > 1.0) continue;
1307
+ vec2 neighborSeed = texture(uSeedTex, sampleUv).rg;
1308
+ if (neighborSeed.x < 0.0) continue;
1309
+ float d = distance(vUv, neighborSeed);
1310
+ if (d < bestDist) {
1311
+ bestDist = d;
1312
+ bestSeed = neighborSeed;
1313
+ }
1314
+ }
1315
+ }
1316
+
1317
+ fragSeed = bestSeed;
1318
+ }
1319
+ `
1320
+ ), ie = (
1321
+ /* glsl */
1322
+ `#version 300 es
1323
+ in vec2 aPosition;
1324
+ out vec2 vUv;
1325
+ void main() {
1326
+ vUv = aPosition * 0.5 + 0.5;
1327
+ gl_Position = vec4(aPosition, 0.0, 1.0);
1328
+ }
1329
+ `
1330
+ ), re = (
1331
+ /* glsl */
1332
+ `#version 300 es
1333
+ precision highp float;
1334
+ uniform sampler2D uSeedTex;
1335
+ uniform sampler2D uMask;
1336
+ uniform float uBevelWidth;
1337
+ in vec2 vUv;
1338
+ out vec4 fragDist;
1339
+
1340
+ void main() {
1341
+ float mask = texture(uMask, vUv).r;
1342
+ if (mask < 0.5) {
1343
+ fragDist = vec4(0.0);
1344
+ return;
1345
+ }
1346
+
1347
+ vec2 seed = texture(uSeedTex, vUv).rg;
1348
+ if (seed.x < 0.0) {
1349
+ fragDist = vec4(1.0);
1350
+ return;
1351
+ }
1352
+
1353
+ float d = distance(vUv, seed);
1354
+ float normalized = clamp(d / max(uBevelWidth, 0.001), 0.0, 1.0);
1355
+ fragDist = vec4(normalized, 0.0, 0.0, 1.0);
1356
+ }
1357
+ `
1358
+ ), oe = (
1359
+ /* glsl */
1360
+ `#version 300 es
1361
+ in vec2 aPosition;
1362
+ uniform vec2 uUvOffset;
1363
+ uniform vec2 uUvScale;
1364
+ out vec2 vUv;
1365
+ out vec2 vScreenUv;
1366
+ void main() {
1367
+ vec2 baseUv = aPosition * 0.5 + 0.5;
1368
+ vUv = baseUv * uUvScale + uUvOffset;
1369
+ vScreenUv = baseUv;
1370
+ gl_Position = vec4(aPosition, 0.0, 1.0);
1371
+ }
1372
+ `
1373
+ ), ne = (
1374
+ /* glsl */
1375
+ `#version 300 es
1376
+ precision highp float;
1377
+
1378
+ #define MAX_POM_STEPS 32
1379
+
1380
+ uniform sampler2D uImage;
1381
+ uniform sampler2D uDepth;
1382
+ uniform vec2 uOffset;
1383
+ uniform float uStrength;
1384
+ uniform int uPomSteps;
1385
+
1386
+ // Lens transform: remap depth curve for exaggerated/compressed depth feel
1387
+ uniform float uDepthPower; // >1 = telephoto, <1 = wide-angle
1388
+ uniform float uDepthScale; // multiplier on depth range
1389
+ uniform float uDepthBias; // shift depth origin
1390
+
1391
+ // Depth-adaptive contrast
1392
+ uniform float uContrastLow;
1393
+ uniform float uContrastHigh;
1394
+ uniform float uVerticalReduction;
1395
+
1396
+ // DOF
1397
+ uniform float uDofStart;
1398
+ uniform float uDofStrength;
1399
+ uniform vec2 uImageTexelSize;
1400
+
1401
+ // Interior mood
1402
+ uniform float uFogDensity; // volumetric fog bias (0 = none, 0.3 = subtle)
1403
+ uniform vec3 uFogColor; // fog tint color
1404
+ uniform float uColorShift; // warm/cool grading shift
1405
+ uniform float uBrightnessBias; // overall brightness adjustment
1406
+
1407
+ in vec2 vUv;
1408
+ in vec2 vScreenUv;
1409
+
1410
+ layout(location = 0) out vec4 fragColor;
1411
+ layout(location = 1) out vec4 fragDepth;
1412
+
1413
+ // Apply lens transform to raw depth
1414
+ float lensDepth(float raw) {
1415
+ float d = smoothstep(uContrastLow, uContrastHigh, raw);
1416
+ d = pow(d, uDepthPower) * uDepthScale + uDepthBias;
1417
+ return clamp(d, 0.0, 1.0);
1418
+ }
1419
+
1420
+ float edgeFade(vec2 uv) {
1421
+ float margin = uStrength * 1.5;
1422
+ float fadeX = smoothstep(0.0, margin, uv.x) * smoothstep(0.0, margin, 1.0 - uv.x);
1423
+ float fadeY = smoothstep(0.0, margin, uv.y) * smoothstep(0.0, margin, 1.0 - uv.y);
1424
+ return fadeX * fadeY;
1425
+ }
1426
+
1427
+ // POM ray-march with lens-transformed depth
1428
+ vec2 pomDisplace(vec2 uv, out float hitDepth) {
1429
+ float layerD = 1.0 / float(uPomSteps);
1430
+ vec2 scaledOffset = uOffset;
1431
+ scaledOffset.y *= uVerticalReduction;
1432
+ vec2 deltaUV = scaledOffset * uStrength / float(uPomSteps);
1433
+ float currentLayerDepth = 0.0;
1434
+ vec2 currentUV = uv;
1435
+ float fade = edgeFade(uv);
1436
+
1437
+ for (int i = 0; i < MAX_POM_STEPS; i++) {
1438
+ if (i >= uPomSteps) break;
1439
+ float raw = texture(uDepth, currentUV).r;
1440
+ float depthAtUV = 1.0 - lensDepth(raw);
1441
+ if (currentLayerDepth > depthAtUV) {
1442
+ vec2 prevUV = currentUV - deltaUV;
1443
+ float prevLayerD = currentLayerDepth - layerD;
1444
+ float prevRaw = texture(uDepth, prevUV).r;
1445
+ float prevDepthAtUV = 1.0 - lensDepth(prevRaw);
1446
+ float afterD = depthAtUV - currentLayerDepth;
1447
+ float beforeD = prevDepthAtUV - prevLayerD;
1448
+ float t = afterD / (afterD - beforeD);
1449
+ vec2 hitUV = mix(currentUV, prevUV, t);
1450
+ hitDepth = mix(depthAtUV, prevDepthAtUV, t);
1451
+ return mix(uv, hitUV, fade);
1452
+ }
1453
+ currentUV += deltaUV;
1454
+ currentLayerDepth += layerD;
1455
+ }
1456
+ hitDepth = 1.0 - lensDepth(texture(uDepth, currentUV).r);
1457
+ return mix(uv, currentUV, fade);
1458
+ }
1459
+
1460
+ void main() {
1461
+ float hitDepth;
1462
+ vec2 displaced = pomDisplace(vUv, hitDepth);
1463
+ displaced = clamp(displaced, vec2(0.0), vec2(1.0));
1464
+
1465
+ vec4 color = texture(uImage, displaced);
1466
+
1467
+ // DOF: blur far objects
1468
+ float rawDepthAtHit = texture(uDepth, displaced).r;
1469
+ float lensD = lensDepth(rawDepthAtHit);
1470
+ float dof = smoothstep(uDofStart, 1.0, lensD) * uDofStrength;
1471
+ if (dof > 0.01) {
1472
+ vec2 ts = uImageTexelSize;
1473
+ vec4 blurred = (
1474
+ texture(uImage, displaced + vec2( ts.x, 0.0)) +
1475
+ texture(uImage, displaced + vec2(-ts.x, 0.0)) +
1476
+ texture(uImage, displaced + vec2( 0.0, ts.y)) +
1477
+ texture(uImage, displaced + vec2( 0.0, -ts.y)) +
1478
+ texture(uImage, displaced + vec2( ts.x, ts.y)) +
1479
+ texture(uImage, displaced + vec2(-ts.x, -ts.y)) +
1480
+ texture(uImage, displaced + vec2( ts.x, -ts.y)) +
1481
+ texture(uImage, displaced + vec2(-ts.x, ts.y))
1482
+ ) * 0.125;
1483
+ color = mix(color, blurred, dof);
1484
+ }
1485
+
1486
+ // Volumetric fog bias: far objects fade into fog color
1487
+ float fogFactor = smoothstep(0.3, 1.0, lensD) * uFogDensity;
1488
+ color.rgb = mix(color.rgb, uFogColor, fogFactor);
1489
+
1490
+ // Color grading shift: warm near, cool far (or vice versa)
1491
+ float gradeAmount = (lensD - 0.5) * uColorShift;
1492
+ color.r += gradeAmount * 0.08;
1493
+ color.b -= gradeAmount * 0.08;
1494
+
1495
+ // Brightness bias
1496
+ color.rgb *= (1.0 + uBrightnessBias);
1497
+
1498
+ // Subtle vignette inside portal
1499
+ float dist = length(vScreenUv - 0.5) * 1.4;
1500
+ color.rgb *= 1.0 - pow(dist, 3.0) * 0.3;
1501
+
1502
+ fragColor = color;
1503
+ // Write lens-transformed depth to second attachment for boundary effects
1504
+ fragDepth = vec4(lensD, 0.0, 0.0, 1.0);
1505
+ }
1506
+ `
1507
+ ), se = (
1508
+ /* glsl */
1509
+ `#version 300 es
1510
+ in vec2 aPosition;
1511
+ out vec2 vUv;
1512
+ void main() {
1513
+ vUv = aPosition * 0.5 + 0.5;
1514
+ gl_Position = vec4(aPosition, 0.0, 1.0);
1515
+ }
1516
+ `
1517
+ ), ae = (
1518
+ /* glsl */
1519
+ `#version 300 es
1520
+ precision highp float;
1521
+ uniform sampler2D uInteriorColor;
1522
+ uniform sampler2D uDistField;
1523
+ uniform float uEdgeOcclusionWidth; // how far edge darkening extends
1524
+ uniform float uEdgeOcclusionStrength; // how strong (0=none, 1=full black)
1525
+
1526
+ in vec2 vUv;
1527
+ out vec4 fragColor;
1528
+
1529
+ // sRGB ↔ linear conversions for correct lighting math
1530
+ vec3 toLinear(vec3 s) {
1531
+ return mix(s / 12.92, pow((s + 0.055) / 1.055, vec3(2.4)), step(0.04045, s));
1532
+ }
1533
+ vec3 toSRGB(vec3 l) {
1534
+ return mix(l * 12.92, 1.055 * pow(l, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, l));
1535
+ }
1536
+
1537
+ void main() {
1538
+ vec4 color = texture(uInteriorColor, vUv);
1539
+ float dist = texture(uDistField, vUv).r; // 0=edge, 1=deep interior
1540
+
1541
+ // Emissive passthrough: preserve original video luminance.
1542
+ // Only apply a subtle edge occlusion ramp to sell chamfer→interior depth.
1543
+ vec3 linear = toLinear(color.rgb);
1544
+ float occ = smoothstep(0.0, uEdgeOcclusionWidth, dist);
1545
+ linear *= mix(1.0 - uEdgeOcclusionStrength, 1.0, occ);
1546
+
1547
+ fragColor = vec4(toSRGB(linear), color.a);
1548
+ }
1549
+ `
1550
+ ), he = (
1551
+ /* glsl */
1552
+ `#version 300 es
1553
+ in vec2 aPosition;
1554
+ in vec2 aNormal;
1555
+ uniform float uRimWidth;
1556
+ uniform vec2 uMeshScale;
1557
+ out vec2 vNormal;
1558
+ out vec2 vEdgeUv; // screen-space UV for sampling FBO textures
1559
+ out float vEdgeDist; // 0 at edge, 1 at outer extent
1560
+
1561
+ void main() {
1562
+ vec2 scaledPos = aPosition * uMeshScale;
1563
+ vec2 scaledNormal = normalize(aNormal * uMeshScale);
1564
+ vec2 pos = scaledPos + scaledNormal * uRimWidth;
1565
+
1566
+ // Pass screen-space UV of this fragment for FBO sampling
1567
+ vEdgeUv = pos * 0.5 + 0.5;
1568
+ vNormal = scaledNormal;
1569
+
1570
+ // Distance from the actual edge (0) to the outer rim extent (1)
1571
+ vEdgeDist = length(pos - scaledPos) / max(uRimWidth, 0.001);
1572
+
1573
+ gl_Position = vec4(pos, 0.0, 1.0);
1574
+ }
1575
+ `
1576
+ ), le = (
1577
+ /* glsl */
1578
+ `#version 300 es
1579
+ precision highp float;
1580
+
1581
+ uniform sampler2D uInteriorColor;
1582
+ uniform sampler2D uInteriorDepth;
1583
+ uniform sampler2D uDistField;
1584
+ uniform float uRimIntensity;
1585
+ uniform vec3 uRimColor;
1586
+ uniform float uRefractionStrength;
1587
+ uniform float uChromaticStrength;
1588
+ uniform float uOcclusionIntensity;
1589
+ uniform vec2 uTexelSize; // 1.0 / viewport resolution
1590
+
1591
+ // Volumetric edge wall
1592
+ uniform float uEdgeThickness;
1593
+ uniform float uEdgeSpecular;
1594
+ uniform vec3 uEdgeColor;
1595
+ uniform vec2 uLightDir;
1596
+ uniform float uBevelIntensity;
1597
+
1598
+ in vec2 vNormal;
1599
+ in vec2 vEdgeUv;
1600
+ in float vEdgeDist;
1601
+ out vec4 fragColor;
1602
+
1603
+ void main() {
1604
+ // Clamp UV to valid range for texture sampling
1605
+ vec2 sampleUv = clamp(vEdgeUv, vec2(0.001), vec2(0.999));
1606
+
1607
+ // Sample interior depth at this boundary location
1608
+ float interiorDepth = texture(uInteriorDepth, sampleUv).r;
1609
+
1610
+ // === DEPTH-REACTIVE RIM (structural seam) ===
1611
+ float depthReactivity = 1.0 - interiorDepth; // 1=near, 0=far
1612
+ float rimProfile = 1.0 - smoothstep(0.0, 1.0, vEdgeDist);
1613
+ rimProfile = pow(rimProfile, 1.5); // sharper falloff = more structural
1614
+
1615
+ float depthPressure = mix(0.2, 1.0, depthReactivity * depthReactivity);
1616
+ float rim = rimProfile * depthPressure * uRimIntensity;
1617
+
1618
+ vec3 rimCol = uRimColor;
1619
+ rimCol.r += depthReactivity * 0.15;
1620
+ rimCol.g += depthReactivity * 0.05;
1621
+
1622
+ // === REFRACTION DISTORTION ===
1623
+ vec2 ts = uTexelSize * 3.0;
1624
+ float dLeft = texture(uInteriorDepth, sampleUv + vec2(-ts.x, 0.0)).r;
1625
+ float dRight = texture(uInteriorDepth, sampleUv + vec2( ts.x, 0.0)).r;
1626
+ float dUp = texture(uInteriorDepth, sampleUv + vec2(0.0, ts.y)).r;
1627
+ float dDown = texture(uInteriorDepth, sampleUv + vec2(0.0, -ts.y)).r;
1628
+ vec2 depthGradient = vec2(dRight - dLeft, dUp - dDown);
1629
+ vec2 refractUv = sampleUv + depthGradient * uRefractionStrength * rimProfile;
1630
+ refractUv = clamp(refractUv, vec2(0.001), vec2(0.999));
1631
+
1632
+ vec4 refractedColor = texture(uInteriorColor, refractUv);
1633
+
1634
+ // === CHROMATIC FRINGE ===
1635
+ float chromaticAmount = uChromaticStrength * depthReactivity * rimProfile;
1636
+ vec2 chromaticDir = vNormal * chromaticAmount;
1637
+ float cr = texture(uInteriorColor, refractUv + chromaticDir).r;
1638
+ float cg = refractedColor.g;
1639
+ float cb = texture(uInteriorColor, refractUv - chromaticDir).b;
1640
+ vec3 chromaticColor = vec3(cr, cg, cb);
1641
+
1642
+ // === OCCLUSION CONTACT SHADOW ===
1643
+ float occlusionAmount = smoothstep(0.4, 0.0, interiorDepth) * uOcclusionIntensity * rimProfile;
1644
+
1645
+ // === VOLUMETRIC EDGE WALL ===
1646
+ // Sample distance field to get the inner-side distance at this boundary location
1647
+ float edgeDist = texture(uDistField, sampleUv).r;
1648
+ float wallZone = smoothstep(uEdgeThickness, 0.0, edgeDist) * rimProfile;
1649
+
1650
+ // Wall lighting from distance field gradient
1651
+ vec2 dtx = vec2(1.0) / vec2(textureSize(uDistField, 0));
1652
+ float wdL = texture(uDistField, sampleUv + vec2(-dtx.x, 0.0)).r;
1653
+ float wdR = texture(uDistField, sampleUv + vec2( dtx.x, 0.0)).r;
1654
+ float wdU = texture(uDistField, sampleUv + vec2(0.0, dtx.y)).r;
1655
+ float wdD = texture(uDistField, sampleUv + vec2(0.0, -dtx.y)).r;
1656
+ vec2 wallNormal = vec2(wdR - wdL, wdU - wdD);
1657
+ float wnLen = length(wallNormal);
1658
+ if (wnLen > 0.001) wallNormal /= wnLen;
1659
+
1660
+ float wallSpec = pow(max(dot(wallNormal, uLightDir), 0.0), 16.0) * uEdgeSpecular;
1661
+ vec3 wallColor = mix(refractedColor.rgb * 0.4, uEdgeColor, 0.3);
1662
+ wallColor += vec3(wallSpec);
1663
+
1664
+ // === COMPOSITE ===
1665
+ vec3 color = mix(refractedColor.rgb, chromaticColor, min(chromaticAmount * 10.0, 1.0));
1666
+ color *= (1.0 - occlusionAmount * 0.4);
1667
+
1668
+ // Blend in volumetric wall
1669
+ color = mix(color, wallColor, wallZone * uBevelIntensity);
1670
+
1671
+ // Add rim energy on top
1672
+ color += rimCol * rim;
1673
+
1674
+ // Alpha: rim edge fades out
1675
+ float alpha = rimProfile * max(rim, occlusionAmount + chromaticAmount * 5.0 + wallZone * 0.5);
1676
+ alpha = clamp(alpha, 0.0, 1.0);
1677
+
1678
+ fragColor = vec4(color * alpha, alpha);
1679
+ }
1680
+ `
1681
+ ), ce = (
1682
+ /* glsl */
1683
+ `#version 300 es
1684
+ in vec2 aPosition;
1685
+ in vec3 aNormal3;
1686
+ in float aLerpT; // 0 = inner (at silhouette), 1 = outer edge
1687
+ uniform vec2 uMeshScale;
1688
+ out vec3 vNormal;
1689
+ out vec2 vScreenUv;
1690
+ out float vLerpT;
1691
+
1692
+ void main() {
1693
+ vec2 sp = aPosition * uMeshScale;
1694
+ vNormal = aNormal3;
1695
+ vScreenUv = sp * 0.5 + 0.5;
1696
+ vLerpT = aLerpT;
1697
+ gl_Position = vec4(sp, 0.0, 1.0);
1698
+ }
1699
+ `
1700
+ ), ue = (
1701
+ /* glsl */
1702
+ `#version 300 es
1703
+ precision highp float;
1704
+ uniform vec3 uLightDir3;
1705
+ uniform vec3 uChamferColor;
1706
+ uniform float uChamferAmbient;
1707
+ uniform float uChamferSpecular;
1708
+ uniform float uChamferShininess;
1709
+ uniform sampler2D uInteriorColor;
1710
+ uniform vec2 uTexelSize; // 1 / viewport resolution
1711
+
1712
+ in vec3 vNormal;
1713
+ in vec2 vScreenUv;
1714
+ in float vLerpT;
1715
+ out vec4 fragColor;
1716
+
1717
+ vec3 toLinear(vec3 s) {
1718
+ return mix(s / 12.92, pow((s + 0.055) / 1.055, vec3(2.4)), step(0.04045, s));
1719
+ }
1720
+ vec3 toSRGB(vec3 l) {
1721
+ return mix(l * 12.92, 1.055 * pow(l, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, l));
1722
+ }
1723
+
1724
+ // Approximate gaussian blur via 13-tap poisson disc, radius scaled by vLerpT.
1725
+ vec3 blurSample(vec2 center, float radius) {
1726
+ // Poisson disc offsets (normalized to unit circle)
1727
+ const vec2 offsets[12] = vec2[12](
1728
+ vec2(-0.326, -0.406), vec2(-0.840, -0.074), vec2(-0.696, 0.457),
1729
+ vec2(-0.203, 0.621), vec2( 0.962, -0.195), vec2( 0.473, -0.480),
1730
+ vec2( 0.519, 0.767), vec2( 0.185, -0.893), vec2( 0.507, 0.064),
1731
+ vec2(-0.321, -0.860), vec2(-0.791, 0.557), vec2( 0.330, 0.418)
1732
+ );
1733
+ vec3 sum = texture(uInteriorColor, center).rgb;
1734
+ for (int i = 0; i < 12; i++) {
1735
+ vec2 uv = center + offsets[i] * radius;
1736
+ uv = clamp(uv, vec2(0.001), vec2(0.999));
1737
+ sum += texture(uInteriorColor, uv).rgb;
1738
+ }
1739
+ return sum / 13.0;
1740
+ }
1741
+
1742
+ void main() {
1743
+ vec3 N = normalize(vNormal);
1744
+ vec3 L = normalize(uLightDir3);
1745
+ vec3 V = vec3(0.0, 0.0, -1.0); // orthographic view direction
1746
+
1747
+ // Blinn-Phong lighting in linear space
1748
+ float diff = max(dot(N, L), 0.0);
1749
+ vec3 H = normalize(L + V);
1750
+ float spec = pow(max(dot(N, H), 0.0), uChamferShininess) * uChamferSpecular;
1751
+
1752
+ // Sample interior video with progressive blur (sharper at inner edge)
1753
+ vec2 uv = clamp(vScreenUv, vec2(0.001), vec2(0.999));
1754
+ float blurRadius = vLerpT * 12.0 * length(uTexelSize);
1755
+ vec3 videoSample = blurRadius > 0.0001
1756
+ ? blurSample(uv, blurRadius)
1757
+ : texture(uInteriorColor, uv).rgb;
1758
+
1759
+ // Base color: video tinted through chamfer color (like frosted glass)
1760
+ vec3 video = toLinear(videoSample);
1761
+ vec3 tint = toLinear(uChamferColor);
1762
+ // Blend: mostly video near inner edge, more tinted at outer edge
1763
+ vec3 base = mix(video, video * tint * 3.0, vLerpT * 0.5);
1764
+
1765
+ // Apply Blinn-Phong
1766
+ vec3 lit = base * (uChamferAmbient + (1.0 - uChamferAmbient) * diff) + vec3(spec);
1767
+ fragColor = vec4(toSRGB(lit), 1.0);
1768
+ }
1769
+ `
1770
+ );
1771
+ function L(n, t, e) {
1772
+ const i = n.createShader(t);
1773
+ if (!i) throw new Error("Failed to create shader.");
1774
+ if (n.shaderSource(i, e), n.compileShader(i), !n.getShaderParameter(i, n.COMPILE_STATUS)) {
1775
+ const r = n.getShaderInfoLog(i) ?? "";
1776
+ throw n.deleteShader(i), new Error(`Shader compilation failed:
1777
+ ${r}`);
1778
+ }
1779
+ return i;
1780
+ }
1781
+ function V(n, t, e) {
1782
+ const i = n.createProgram();
1783
+ if (!i) throw new Error("Failed to create program.");
1784
+ if (n.attachShader(i, t), n.attachShader(i, e), n.linkProgram(i), !n.getProgramParameter(i, n.LINK_STATUS)) {
1785
+ const r = n.getProgramInfoLog(i) ?? "";
1786
+ throw n.deleteProgram(i), new Error(`Program linking failed:
1787
+ ${r}`);
1788
+ }
1789
+ return n.detachShader(i, t), n.detachShader(i, e), n.deleteShader(t), n.deleteShader(e), i;
1790
+ }
1791
+ function fe(n) {
1792
+ const t = [];
1793
+ let e = 0;
1794
+ for (let i = 0; i < n.length - 2; i += 2) {
1795
+ const r = n[i], o = n[i + 1], s = n[i + 2], a = n[i + 3], h = s - r, l = a - o, u = Math.sqrt(h * h + l * l);
1796
+ if (u < 1e-6) continue;
1797
+ const f = -l / u, c = h / u;
1798
+ t.push(
1799
+ r,
1800
+ o,
1801
+ f,
1802
+ c,
1803
+ r,
1804
+ o,
1805
+ -f,
1806
+ -c,
1807
+ s,
1808
+ a,
1809
+ f,
1810
+ c,
1811
+ s,
1812
+ a,
1813
+ f,
1814
+ c,
1815
+ r,
1816
+ o,
1817
+ -f,
1818
+ -c,
1819
+ s,
1820
+ a,
1821
+ -f,
1822
+ -c
1823
+ ), e += 6;
1824
+ }
1825
+ return {
1826
+ vertices: new Float32Array(t),
1827
+ count: e
1828
+ };
1829
+ }
1830
+ function de(n, t, e, i, r) {
1831
+ if (i <= 0)
1832
+ return { vertices: new Float32Array(0), count: 0 };
1833
+ const o = r * Math.PI / 180, s = -Math.cos(o), a = Math.sin(o), h = [];
1834
+ let l = 0;
1835
+ for (let u = 0; u < t.length; u++) {
1836
+ const f = t[u], m = ((u + 1 < t.length ? t[u + 1] : n.length) - f) / 2;
1837
+ if (m < 3) continue;
1838
+ const g = m - 1;
1839
+ let U = 0;
1840
+ for (let x = 0; x < g; x++) {
1841
+ const y = f + x * 2, S = n[y], F = n[y + 1], P = n[y + 2], _ = n[y + 3];
1842
+ U += S * _ - P * F;
1843
+ }
1844
+ const b = U >= 0 ? 1 : -1, E = [], p = [];
1845
+ for (let x = 0; x < g; x++) {
1846
+ const y = f + x * 2, S = n[y + 2] - n[y], F = n[y + 3] - n[y + 1], P = Math.sqrt(S * S + F * F);
1847
+ P < 1e-8 ? (E.push(x > 0 ? E[x - 1] : 0), p.push(x > 0 ? p[x - 1] : 0)) : (E.push(-F / P * b), p.push(S / P * b));
1848
+ }
1849
+ const v = [], T = [];
1850
+ for (let x = 0; x < g; x++) {
1851
+ const y = (x - 1 + g) % g;
1852
+ let S = E[y] + E[x], F = p[y] + p[x];
1853
+ const P = Math.sqrt(S * S + F * F);
1854
+ P > 1e-8 ? (S /= P, F /= P) : (S = E[x], F = p[x]), v.push(S), T.push(F);
1855
+ }
1856
+ for (let x = 0; x < g; x++) {
1857
+ const y = x, S = (x + 1) % g, F = f + x * 2, P = f + (x + 1) % g * 2, _ = n[F], k = n[F + 1], D = n[P], R = n[P + 1], C = v[y] * a, M = T[y] * a, H = s, I = v[S] * a, N = T[S] * a, j = s, et = _ + v[y] * i, mt = k + T[y] * i, wt = D + v[S] * i, Lt = R + T[S] * i;
1858
+ h.push(_, k, C, M, H, 0), h.push(et, mt, C, M, H, 1), h.push(D, R, I, N, j, 0), h.push(D, R, I, N, j, 0), h.push(et, mt, C, M, H, 1), h.push(wt, Lt, I, N, j, 1), l += 6;
1859
+ }
1860
+ }
1861
+ return {
1862
+ vertices: new Float32Array(h),
1863
+ count: l
1864
+ };
1865
+ }
1866
+ class ft {
1867
+ static RESIZE_DEBOUNCE_MS = 100;
1868
+ canvas;
1869
+ gl = null;
1870
+ container;
1871
+ // Shader programs
1872
+ stencilProgram = null;
1873
+ maskProgram = null;
1874
+ jfaSeedProgram = null;
1875
+ jfaFloodProgram = null;
1876
+ jfaDistProgram = null;
1877
+ interiorProgram = null;
1878
+ compositeProgram = null;
1879
+ boundaryProgram = null;
1880
+ chamferProgram = null;
1881
+ // Uniform locations (stored as Record for flexibility)
1882
+ stencilUniforms = {};
1883
+ maskUniforms = {};
1884
+ jfaSeedUniforms = {};
1885
+ jfaFloodUniforms = {};
1886
+ jfaDistUniforms = {};
1887
+ interiorUniforms = {};
1888
+ compositeUniforms = {};
1889
+ boundaryUniforms = {};
1890
+ chamferUniforms = {};
1891
+ // Geometry
1892
+ quadVao = null;
1893
+ stencilVao = null;
1894
+ stencilIndexCount = 0;
1895
+ maskVao = null;
1896
+ boundaryVao = null;
1897
+ boundaryVertexCount = 0;
1898
+ chamferVao = null;
1899
+ chamferVertexCount = 0;
1900
+ // Source textures
1901
+ videoTexture = null;
1902
+ depthTexture = null;
1903
+ // Interior FBO (units 2, 3)
1904
+ interiorFbo = null;
1905
+ interiorColorTex = null;
1906
+ interiorDepthTex = null;
1907
+ fboWidth = 0;
1908
+ fboHeight = 0;
1909
+ // JFA distance field system (unit 4 for final distance)
1910
+ maskFbo = null;
1911
+ maskTex = null;
1912
+ jfaPingFbo = null;
1913
+ jfaPingTex = null;
1914
+ jfaPongFbo = null;
1915
+ jfaPongTex = null;
1916
+ distFbo = null;
1917
+ distTex = null;
1918
+ jfaWidth = 0;
1919
+ jfaHeight = 0;
1920
+ distFieldDirty = !0;
1921
+ // Dimensions
1922
+ depthWidth = 0;
1923
+ depthHeight = 0;
1924
+ videoAspect = 16 / 9;
1925
+ meshAspect = 1;
1926
+ meshScaleX = 0.65;
1927
+ meshScaleY = 0.65;
1928
+ // Callbacks
1929
+ readDepth = null;
1930
+ readInput = null;
1931
+ playbackVideo = null;
1932
+ onVideoFrame = null;
1933
+ // Animation
1934
+ animationFrameHandle = 0;
1935
+ rvfcHandle = 0;
1936
+ rvfcSupported = !1;
1937
+ resizeObserver = null;
1938
+ resizeTimer = null;
1939
+ // UV transform
1940
+ uvOffset = [0, 0];
1941
+ uvScale = [1, 1];
1942
+ // Precomputed light direction (2D for bevel, 3D for chamfer)
1943
+ lightDirX = -0.707;
1944
+ lightDirY = 0.707;
1945
+ lightDir3 = [-0.5, 0.7, -0.3];
1946
+ config;
1947
+ constructor(t, e) {
1948
+ this.container = t, this.config = { ...e };
1949
+ const i = this.config.bevelLightAngle * Math.PI / 180;
1950
+ this.lightDirX = Math.cos(i), this.lightDirY = Math.sin(i);
1951
+ const r = this.config.lightDirection, o = Math.sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
1952
+ o > 1e-6 && (this.lightDir3 = [r[0] / o, r[1] / o, r[2] / o]), this.canvas = document.createElement("canvas");
1953
+ const s = this.canvas.getContext("webgl2", {
1954
+ antialias: !0,
1955
+ alpha: !0,
1956
+ premultipliedAlpha: !0,
1957
+ stencil: !0,
1958
+ desynchronized: !0,
1959
+ powerPreference: "high-performance"
1960
+ });
1961
+ if (!s) throw new Error("WebGL 2 is not supported.");
1962
+ this.gl = s, "drawingBufferColorSpace" in s && (s.drawingBufferColorSpace = "srgb"), s.clearColor(0, 0, 0, 0), s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL, !0), this.container.appendChild(this.canvas), this.initGPUResources(), this.setupResizeHandling(), this.canvas.addEventListener("webglcontextlost", this.handleContextLost), this.canvas.addEventListener("webglcontextrestored", this.handleContextRestored);
1963
+ }
1964
+ initialize(t, e, i, r) {
1965
+ const o = this.gl;
1966
+ o && (this.disposeTextures(), this.disposeFBO(), this.disposeJFA(), this.disposeStencilGeometry(), this.disposeBoundaryGeometry(), this.disposeChamferGeometry(), this.videoAspect = t.videoWidth / t.videoHeight, this.meshAspect = r.aspect, this.depthWidth = e, this.depthHeight = i, this.videoTexture = o.createTexture(), o.activeTexture(o.TEXTURE0), o.bindTexture(o.TEXTURE_2D, this.videoTexture), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MIN_FILTER, o.LINEAR), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MAG_FILTER, o.LINEAR), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_WRAP_S, o.CLAMP_TO_EDGE), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_WRAP_T, o.CLAMP_TO_EDGE), this.depthTexture = o.createTexture(), o.activeTexture(o.TEXTURE1), o.bindTexture(o.TEXTURE_2D, this.depthTexture), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MIN_FILTER, o.LINEAR), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_MAG_FILTER, o.LINEAR), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_WRAP_S, o.CLAMP_TO_EDGE), o.texParameteri(o.TEXTURE_2D, o.TEXTURE_WRAP_T, o.CLAMP_TO_EDGE), o.texStorage2D(o.TEXTURE_2D, 1, o.R8, e, i), this.uploadStencilMesh(r), this.uploadMaskMesh(r), this.uploadBoundaryMesh(r), this.uploadChamferMesh(r), this.interiorProgram && (o.useProgram(this.interiorProgram), o.uniform1i(this.interiorUniforms.uImage, 0), o.uniform1i(this.interiorUniforms.uDepth, 1), o.uniform1f(this.interiorUniforms.uStrength, this.config.parallaxStrength), o.uniform1i(this.interiorUniforms.uPomSteps, this.config.pomSteps), o.uniform1f(this.interiorUniforms.uDepthPower, this.config.depthPower), o.uniform1f(this.interiorUniforms.uDepthScale, this.config.depthScale), o.uniform1f(this.interiorUniforms.uDepthBias, this.config.depthBias), o.uniform1f(this.interiorUniforms.uContrastLow, this.config.contrastLow), o.uniform1f(this.interiorUniforms.uContrastHigh, this.config.contrastHigh), o.uniform1f(this.interiorUniforms.uVerticalReduction, this.config.verticalReduction), o.uniform1f(this.interiorUniforms.uDofStart, this.config.dofStart), o.uniform1f(this.interiorUniforms.uDofStrength, this.config.dofStrength), o.uniform2f(this.interiorUniforms.uImageTexelSize, 1 / t.videoWidth, 1 / t.videoHeight), o.uniform1f(this.interiorUniforms.uFogDensity, this.config.fogDensity), o.uniform3f(this.interiorUniforms.uFogColor, ...this.config.fogColor), o.uniform1f(this.interiorUniforms.uColorShift, this.config.colorShift), o.uniform1f(this.interiorUniforms.uBrightnessBias, this.config.brightnessBias)), this.compositeProgram && (o.useProgram(this.compositeProgram), o.uniform1i(this.compositeUniforms.uInteriorColor, 2), o.uniform1i(this.compositeUniforms.uDistField, 4), o.uniform1f(this.compositeUniforms.uEdgeOcclusionWidth, this.config.edgeOcclusionWidth), o.uniform1f(this.compositeUniforms.uEdgeOcclusionStrength, this.config.edgeOcclusionStrength)), this.chamferProgram && (o.useProgram(this.chamferProgram), o.uniform3f(this.chamferUniforms.uLightDir3, ...this.lightDir3), o.uniform3f(this.chamferUniforms.uChamferColor, ...this.config.chamferColor), o.uniform1f(this.chamferUniforms.uChamferAmbient, this.config.chamferAmbient), o.uniform1f(this.chamferUniforms.uChamferSpecular, this.config.chamferSpecular), o.uniform1f(this.chamferUniforms.uChamferShininess, this.config.chamferShininess), o.uniform1i(this.chamferUniforms.uInteriorColor, 2)), this.boundaryProgram && (o.useProgram(this.boundaryProgram), o.uniform1i(this.boundaryUniforms.uInteriorColor, 2), o.uniform1i(this.boundaryUniforms.uInteriorDepth, 3), o.uniform1i(this.boundaryUniforms.uDistField, 4), o.uniform1f(this.boundaryUniforms.uRimIntensity, this.config.rimLightIntensity), o.uniform3f(this.boundaryUniforms.uRimColor, ...this.config.rimLightColor), o.uniform1f(this.boundaryUniforms.uRefractionStrength, this.config.refractionStrength), o.uniform1f(this.boundaryUniforms.uChromaticStrength, this.config.chromaticStrength), o.uniform1f(this.boundaryUniforms.uOcclusionIntensity, this.config.occlusionIntensity), o.uniform1f(this.boundaryUniforms.uEdgeThickness, this.config.edgeThickness), o.uniform1f(this.boundaryUniforms.uEdgeSpecular, this.config.edgeSpecular), o.uniform3f(this.boundaryUniforms.uEdgeColor, ...this.config.edgeColor), o.uniform2f(this.boundaryUniforms.uLightDir, this.lightDirX, this.lightDirY), o.uniform1f(this.boundaryUniforms.uBevelIntensity, this.config.bevelIntensity)), this.recalculateViewportLayout());
1967
+ }
1968
+ // -----------------------------------------------------------------------
1969
+ // Geometry upload
1970
+ // -----------------------------------------------------------------------
1971
+ uploadStencilMesh(t) {
1972
+ const e = this.gl;
1973
+ if (!e || !this.stencilProgram) return;
1974
+ this.stencilVao = e.createVertexArray(), e.bindVertexArray(this.stencilVao);
1975
+ const i = e.createBuffer();
1976
+ e.bindBuffer(e.ARRAY_BUFFER, i), e.bufferData(e.ARRAY_BUFFER, t.vertices, e.STATIC_DRAW);
1977
+ const r = e.getAttribLocation(this.stencilProgram, "aPosition");
1978
+ e.enableVertexAttribArray(r), e.vertexAttribPointer(r, 2, e.FLOAT, !1, 0, 0);
1979
+ const o = e.createBuffer();
1980
+ e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, o), e.bufferData(e.ELEMENT_ARRAY_BUFFER, t.indices, e.STATIC_DRAW), this.stencilIndexCount = t.indices.length, e.bindVertexArray(null);
1981
+ }
1982
+ uploadMaskMesh(t) {
1983
+ const e = this.gl;
1984
+ if (!e || !this.maskProgram) return;
1985
+ this.maskVao = e.createVertexArray(), e.bindVertexArray(this.maskVao);
1986
+ const i = e.createBuffer();
1987
+ e.bindBuffer(e.ARRAY_BUFFER, i), e.bufferData(e.ARRAY_BUFFER, t.vertices, e.STATIC_DRAW);
1988
+ const r = e.getAttribLocation(this.maskProgram, "aPosition");
1989
+ e.enableVertexAttribArray(r), e.vertexAttribPointer(r, 2, e.FLOAT, !1, 0, 0);
1990
+ const o = e.createBuffer();
1991
+ e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, o), e.bufferData(e.ELEMENT_ARRAY_BUFFER, t.indices, e.STATIC_DRAW), e.bindVertexArray(null);
1992
+ }
1993
+ uploadBoundaryMesh(t) {
1994
+ const e = this.gl;
1995
+ if (!e || !this.boundaryProgram) return;
1996
+ const i = fe(t.edgeVertices);
1997
+ if (i.count === 0) return;
1998
+ this.boundaryVao = e.createVertexArray(), e.bindVertexArray(this.boundaryVao);
1999
+ const r = e.createBuffer();
2000
+ e.bindBuffer(e.ARRAY_BUFFER, r), e.bufferData(e.ARRAY_BUFFER, i.vertices, e.STATIC_DRAW);
2001
+ const o = 16, s = e.getAttribLocation(this.boundaryProgram, "aPosition");
2002
+ e.enableVertexAttribArray(s), e.vertexAttribPointer(s, 2, e.FLOAT, !1, o, 0);
2003
+ const a = e.getAttribLocation(this.boundaryProgram, "aNormal");
2004
+ a >= 0 && (e.enableVertexAttribArray(a), e.vertexAttribPointer(a, 2, e.FLOAT, !1, o, 8)), this.boundaryVertexCount = i.count, e.bindVertexArray(null);
2005
+ }
2006
+ uploadChamferMesh(t) {
2007
+ const e = this.gl;
2008
+ if (!e || !this.chamferProgram || this.config.chamferWidth <= 0) return;
2009
+ const i = de(
2010
+ t.edgeVertices,
2011
+ t.contourOffsets,
2012
+ t.contourIsHole,
2013
+ this.config.chamferWidth,
2014
+ this.config.chamferAngle
2015
+ );
2016
+ if (i.count === 0) return;
2017
+ this.chamferVao = e.createVertexArray(), e.bindVertexArray(this.chamferVao);
2018
+ const r = e.createBuffer();
2019
+ e.bindBuffer(e.ARRAY_BUFFER, r), e.bufferData(e.ARRAY_BUFFER, i.vertices, e.STATIC_DRAW);
2020
+ const o = 24, s = e.getAttribLocation(this.chamferProgram, "aPosition");
2021
+ e.enableVertexAttribArray(s), e.vertexAttribPointer(s, 2, e.FLOAT, !1, o, 0);
2022
+ const a = e.getAttribLocation(this.chamferProgram, "aNormal3");
2023
+ a >= 0 && (e.enableVertexAttribArray(a), e.vertexAttribPointer(a, 3, e.FLOAT, !1, o, 8));
2024
+ const h = e.getAttribLocation(this.chamferProgram, "aLerpT");
2025
+ h >= 0 && (e.enableVertexAttribArray(h), e.vertexAttribPointer(h, 1, e.FLOAT, !1, o, 20)), this.chamferVertexCount = i.count, e.bindVertexArray(null);
2026
+ }
2027
+ disposeChamferGeometry() {
2028
+ const t = this.gl;
2029
+ t && (this.chamferVao && (t.deleteVertexArray(this.chamferVao), this.chamferVao = null), this.chamferVertexCount = 0);
2030
+ }
2031
+ // -----------------------------------------------------------------------
2032
+ // FBO management
2033
+ // -----------------------------------------------------------------------
2034
+ createFBO(t, e) {
2035
+ const i = this.gl;
2036
+ if (!i) return;
2037
+ this.disposeFBO(), this.fboWidth = t, this.fboHeight = e, this.interiorFbo = i.createFramebuffer(), i.bindFramebuffer(i.FRAMEBUFFER, this.interiorFbo), this.interiorColorTex = i.createTexture(), i.activeTexture(i.TEXTURE2), i.bindTexture(i.TEXTURE_2D, this.interiorColorTex), i.texStorage2D(i.TEXTURE_2D, 1, i.RGBA8, t, e), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.framebufferTexture2D(i.FRAMEBUFFER, i.COLOR_ATTACHMENT0, i.TEXTURE_2D, this.interiorColorTex, 0), this.interiorDepthTex = i.createTexture(), i.activeTexture(i.TEXTURE3), i.bindTexture(i.TEXTURE_2D, this.interiorDepthTex), i.texStorage2D(i.TEXTURE_2D, 1, i.RGBA8, t, e), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.framebufferTexture2D(i.FRAMEBUFFER, i.COLOR_ATTACHMENT1, i.TEXTURE_2D, this.interiorDepthTex, 0), i.drawBuffers([i.COLOR_ATTACHMENT0, i.COLOR_ATTACHMENT1]);
2038
+ const r = i.checkFramebufferStatus(i.FRAMEBUFFER);
2039
+ r !== i.FRAMEBUFFER_COMPLETE && console.error("Interior FBO incomplete:", r), i.bindFramebuffer(i.FRAMEBUFFER, null);
2040
+ }
2041
+ // -----------------------------------------------------------------------
2042
+ // JFA Distance Field
2043
+ // -----------------------------------------------------------------------
2044
+ createJFAResources(t, e) {
2045
+ const i = this.gl;
2046
+ if (!i) return;
2047
+ this.disposeJFA();
2048
+ const r = Math.max(1, Math.round(t / 2)), o = Math.max(1, Math.round(e / 2));
2049
+ this.jfaWidth = r, this.jfaHeight = o;
2050
+ const s = (a, h, l, u) => {
2051
+ const f = i.createFramebuffer();
2052
+ return i.bindFramebuffer(i.FRAMEBUFFER, f), i.bindTexture(i.TEXTURE_2D, a), i.texStorage2D(i.TEXTURE_2D, 1, h, l, u), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MIN_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_MAG_FILTER, i.LINEAR), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_S, i.CLAMP_TO_EDGE), i.texParameteri(i.TEXTURE_2D, i.TEXTURE_WRAP_T, i.CLAMP_TO_EDGE), i.framebufferTexture2D(i.FRAMEBUFFER, i.COLOR_ATTACHMENT0, i.TEXTURE_2D, a, 0), i.bindFramebuffer(i.FRAMEBUFFER, null), f;
2053
+ };
2054
+ this.maskTex = i.createTexture(), this.maskFbo = s(this.maskTex, i.R8, r, o), this.jfaPingTex = i.createTexture(), this.jfaPingFbo = s(this.jfaPingTex, i.RG16F, r, o), this.jfaPongTex = i.createTexture(), this.jfaPongFbo = s(this.jfaPongTex, i.RG16F, r, o), this.distTex = i.createTexture(), this.distFbo = s(this.distTex, i.RGBA8, r, o), this.distFieldDirty = !0;
2055
+ }
2056
+ computeDistanceField() {
2057
+ const t = this.gl;
2058
+ if (!t || !this.maskFbo || !this.maskVao || !this.quadVao || !this.jfaPingFbo || !this.jfaPongFbo || !this.distFbo) return;
2059
+ const e = this.jfaWidth, i = this.jfaHeight;
2060
+ if (e === 0 || i === 0) return;
2061
+ t.viewport(0, 0, e, i), t.disable(t.STENCIL_TEST), t.disable(t.BLEND), t.bindFramebuffer(t.FRAMEBUFFER, this.maskFbo), t.clearColor(0, 0, 0, 1), t.clear(t.COLOR_BUFFER_BIT), t.useProgram(this.maskProgram), t.uniform2f(this.maskUniforms.uMeshScale, this.meshScaleX, this.meshScaleY), t.bindVertexArray(this.maskVao), t.drawElements(t.TRIANGLES, this.stencilIndexCount, t.UNSIGNED_SHORT, 0), t.bindFramebuffer(t.FRAMEBUFFER, this.jfaPingFbo), t.clearColor(-1, -1, 0, 0), t.clear(t.COLOR_BUFFER_BIT), t.useProgram(this.jfaSeedProgram), t.activeTexture(t.TEXTURE5), t.bindTexture(t.TEXTURE_2D, this.maskTex), t.uniform1i(this.jfaSeedUniforms.uMask, 5), t.uniform2f(this.jfaSeedUniforms.uTexelSize, 1 / e, 1 / i), t.bindVertexArray(this.quadVao), t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
2062
+ const r = Math.max(e, i), o = [];
2063
+ let s = Math.ceil(r / 2);
2064
+ for (; s >= 1; )
2065
+ o.push(s), s = Math.floor(s / 2);
2066
+ t.useProgram(this.jfaFloodProgram);
2067
+ let a = this.jfaPingTex, h = this.jfaPongFbo, l = this.jfaPongTex;
2068
+ for (let f = 0; f < o.length; f++) {
2069
+ const c = o[f] / Math.max(e, i);
2070
+ t.bindFramebuffer(t.FRAMEBUFFER, h), t.activeTexture(t.TEXTURE5), t.bindTexture(t.TEXTURE_2D, a), t.uniform1i(this.jfaFloodUniforms.uSeedTex, 5), t.uniform1f(this.jfaFloodUniforms.uStepSize, c), t.bindVertexArray(this.quadVao), t.drawArrays(t.TRIANGLE_STRIP, 0, 4);
2071
+ const d = a, m = h;
2072
+ a = l, h = m === this.jfaPongFbo ? this.jfaPingFbo : this.jfaPongFbo, l = d;
2073
+ }
2074
+ t.bindFramebuffer(t.FRAMEBUFFER, this.distFbo), t.clearColor(0, 0, 0, 1), t.clear(t.COLOR_BUFFER_BIT), t.useProgram(this.jfaDistProgram), t.activeTexture(t.TEXTURE5), t.bindTexture(t.TEXTURE_2D, a), t.uniform1i(this.jfaDistUniforms.uSeedTex, 5), t.activeTexture(t.TEXTURE6), t.bindTexture(t.TEXTURE_2D, this.maskTex), t.uniform1i(this.jfaDistUniforms.uMask, 6);
2075
+ const u = Math.max(this.config.bevelWidth, this.config.edgeOcclusionWidth);
2076
+ t.uniform1f(this.jfaDistUniforms.uBevelWidth, u), t.bindVertexArray(this.quadVao), t.drawArrays(t.TRIANGLE_STRIP, 0, 4), t.activeTexture(t.TEXTURE4), t.bindTexture(t.TEXTURE_2D, this.distTex), t.bindFramebuffer(t.FRAMEBUFFER, null), this.distFieldDirty = !1;
2077
+ }
2078
+ // -----------------------------------------------------------------------
2079
+ // Render loop control
2080
+ // -----------------------------------------------------------------------
2081
+ start(t, e, i, r) {
2082
+ this.stop(), this.playbackVideo = t, this.readDepth = e, this.readInput = i, this.onVideoFrame = r ?? null, this.rvfcSupported = "requestVideoFrameCallback" in HTMLVideoElement.prototype, this.rvfcSupported && (this.rvfcHandle = t.requestVideoFrameCallback(this.videoFrameLoop)), this.animationFrameHandle = window.requestAnimationFrame(this.renderLoop);
2083
+ }
2084
+ stop() {
2085
+ this.animationFrameHandle && (window.cancelAnimationFrame(this.animationFrameHandle), this.animationFrameHandle = 0), this.rvfcHandle && this.playbackVideo && (this.playbackVideo.cancelVideoFrameCallback(this.rvfcHandle), this.rvfcHandle = 0), this.playbackVideo = null, this.readDepth = null, this.readInput = null, this.onVideoFrame = null, this.rvfcSupported = !1;
2086
+ }
2087
+ dispose() {
2088
+ this.stop(), this.disposeTextures(), this.disposeFBO(), this.disposeJFA(), this.disposeStencilGeometry(), this.disposeBoundaryGeometry(), this.disposeChamferGeometry(), this.disposeGPUResources(), this.canvas.removeEventListener("webglcontextlost", this.handleContextLost), this.canvas.removeEventListener("webglcontextrestored", this.handleContextRestored), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), window.removeEventListener("resize", this.scheduleResizeRecalculate), this.resizeTimer !== null && (window.clearTimeout(this.resizeTimer), this.resizeTimer = null);
2089
+ }
2090
+ // -----------------------------------------------------------------------
2091
+ // GPU resource initialization
2092
+ // -----------------------------------------------------------------------
2093
+ initGPUResources() {
2094
+ const t = this.gl;
2095
+ if (!t) return;
2096
+ this.stencilProgram = V(
2097
+ t,
2098
+ L(t, t.VERTEX_SHADER, qt),
2099
+ L(t, t.FRAGMENT_SHADER, Zt)
2100
+ ), this.stencilUniforms = {
2101
+ uMeshScale: t.getUniformLocation(this.stencilProgram, "uMeshScale")
2102
+ }, this.maskProgram = V(
2103
+ t,
2104
+ L(t, t.VERTEX_SHADER, $t),
2105
+ L(t, t.FRAGMENT_SHADER, Jt)
2106
+ ), this.maskUniforms = {
2107
+ uMeshScale: t.getUniformLocation(this.maskProgram, "uMeshScale")
2108
+ }, this.jfaSeedProgram = V(
2109
+ t,
2110
+ L(t, t.VERTEX_SHADER, Kt),
2111
+ L(t, t.FRAGMENT_SHADER, Qt)
2112
+ ), this.jfaSeedUniforms = this.getUniforms(this.jfaSeedProgram, ["uMask", "uTexelSize"]), this.jfaFloodProgram = V(
2113
+ t,
2114
+ L(t, t.VERTEX_SHADER, te),
2115
+ L(t, t.FRAGMENT_SHADER, ee)
2116
+ ), this.jfaFloodUniforms = this.getUniforms(this.jfaFloodProgram, ["uSeedTex", "uStepSize"]), this.jfaDistProgram = V(
2117
+ t,
2118
+ L(t, t.VERTEX_SHADER, ie),
2119
+ L(t, t.FRAGMENT_SHADER, re)
2120
+ ), this.jfaDistUniforms = this.getUniforms(this.jfaDistProgram, ["uSeedTex", "uMask", "uBevelWidth"]), this.interiorProgram = V(
2121
+ t,
2122
+ L(t, t.VERTEX_SHADER, oe),
2123
+ L(t, t.FRAGMENT_SHADER, ne)
2124
+ ), this.interiorUniforms = this.getUniforms(this.interiorProgram, [
2125
+ "uImage",
2126
+ "uDepth",
2127
+ "uOffset",
2128
+ "uStrength",
2129
+ "uPomSteps",
2130
+ "uDepthPower",
2131
+ "uDepthScale",
2132
+ "uDepthBias",
2133
+ "uContrastLow",
2134
+ "uContrastHigh",
2135
+ "uVerticalReduction",
2136
+ "uDofStart",
2137
+ "uDofStrength",
2138
+ "uImageTexelSize",
2139
+ "uFogDensity",
2140
+ "uFogColor",
2141
+ "uColorShift",
2142
+ "uBrightnessBias",
2143
+ "uUvOffset",
2144
+ "uUvScale"
2145
+ ]), this.compositeProgram = V(
2146
+ t,
2147
+ L(t, t.VERTEX_SHADER, se),
2148
+ L(t, t.FRAGMENT_SHADER, ae)
2149
+ ), this.compositeUniforms = this.getUniforms(this.compositeProgram, [
2150
+ "uInteriorColor",
2151
+ "uDistField",
2152
+ "uEdgeOcclusionWidth",
2153
+ "uEdgeOcclusionStrength"
2154
+ ]), this.boundaryProgram = V(
2155
+ t,
2156
+ L(t, t.VERTEX_SHADER, he),
2157
+ L(t, t.FRAGMENT_SHADER, le)
2158
+ ), this.boundaryUniforms = this.getUniforms(this.boundaryProgram, [
2159
+ "uInteriorColor",
2160
+ "uInteriorDepth",
2161
+ "uDistField",
2162
+ "uRimIntensity",
2163
+ "uRimColor",
2164
+ "uRimWidth",
2165
+ "uMeshScale",
2166
+ "uRefractionStrength",
2167
+ "uChromaticStrength",
2168
+ "uOcclusionIntensity",
2169
+ "uTexelSize",
2170
+ "uEdgeThickness",
2171
+ "uEdgeSpecular",
2172
+ "uEdgeColor",
2173
+ "uLightDir",
2174
+ "uBevelIntensity"
2175
+ ]), this.chamferProgram = V(
2176
+ t,
2177
+ L(t, t.VERTEX_SHADER, ce),
2178
+ L(t, t.FRAGMENT_SHADER, ue)
2179
+ ), this.chamferUniforms = this.getUniforms(this.chamferProgram, [
2180
+ "uMeshScale",
2181
+ "uLightDir3",
2182
+ "uChamferColor",
2183
+ "uChamferAmbient",
2184
+ "uChamferSpecular",
2185
+ "uChamferShininess",
2186
+ "uInteriorColor",
2187
+ "uTexelSize"
2188
+ ]);
2189
+ const e = new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]);
2190
+ this.quadVao = t.createVertexArray(), t.bindVertexArray(this.quadVao);
2191
+ const i = t.createBuffer();
2192
+ t.bindBuffer(t.ARRAY_BUFFER, i), t.bufferData(t.ARRAY_BUFFER, e, t.STATIC_DRAW);
2193
+ const r = t.getAttribLocation(this.interiorProgram, "aPosition");
2194
+ t.enableVertexAttribArray(r), t.vertexAttribPointer(r, 2, t.FLOAT, !1, 0, 0), t.bindVertexArray(null), t.disable(t.DEPTH_TEST);
2195
+ }
2196
+ getUniforms(t, e) {
2197
+ const i = this.gl, r = {};
2198
+ for (const o of e)
2199
+ r[o] = i.getUniformLocation(t, o);
2200
+ return r;
2201
+ }
2202
+ // -----------------------------------------------------------------------
2203
+ // RVFC loop
2204
+ // -----------------------------------------------------------------------
2205
+ videoFrameLoop = (t, e) => {
2206
+ const i = this.playbackVideo;
2207
+ if (!i) return;
2208
+ this.rvfcHandle = i.requestVideoFrameCallback(this.videoFrameLoop);
2209
+ const r = e.mediaTime ?? i.currentTime;
2210
+ this.updateDepthTexture(r), this.onVideoFrame && this.onVideoFrame(r, e.presentedFrames ?? 0);
2211
+ };
2212
+ // -----------------------------------------------------------------------
2213
+ // Main render loop
2214
+ // -----------------------------------------------------------------------
2215
+ renderLoop = () => {
2216
+ this.animationFrameHandle = window.requestAnimationFrame(this.renderLoop);
2217
+ const t = this.gl, e = this.playbackVideo;
2218
+ if (!t || !this.interiorProgram || !this.quadVao || !e || e.readyState < HTMLMediaElement.HAVE_CURRENT_DATA || !this.interiorFbo || !this.interiorColorTex || !this.interiorDepthTex) return;
2219
+ this.distFieldDirty && this.maskVao && this.distFbo && (this.computeDistanceField(), t.viewport(0, 0, this.canvas.width, this.canvas.height)), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, this.videoTexture), t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, t.RGBA, t.UNSIGNED_BYTE, e), this.rvfcSupported || this.updateDepthTexture(e.currentTime);
2220
+ let i = 0, r = 0;
2221
+ if (this.readInput) {
2222
+ const o = this.readInput();
2223
+ i = -o.x, r = o.y;
2224
+ }
2225
+ t.bindFramebuffer(t.FRAMEBUFFER, this.interiorFbo), t.viewport(0, 0, this.fboWidth, this.fboHeight), t.clearColor(0, 0, 0, 1), t.clear(t.COLOR_BUFFER_BIT), t.useProgram(this.interiorProgram), t.uniform2f(this.interiorUniforms.uOffset, i, r), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, this.videoTexture), t.activeTexture(t.TEXTURE1), t.bindTexture(t.TEXTURE_2D, this.depthTexture), t.bindVertexArray(this.quadVao), t.drawArrays(t.TRIANGLE_STRIP, 0, 4), t.bindFramebuffer(t.FRAMEBUFFER, null), t.clearColor(0, 0, 0, 0), t.viewport(0, 0, this.canvas.width, this.canvas.height), t.clear(t.COLOR_BUFFER_BIT | t.STENCIL_BUFFER_BIT), this.stencilVao && this.stencilProgram && this.stencilIndexCount > 0 && (t.enable(t.STENCIL_TEST), t.stencilFunc(t.ALWAYS, 1, 255), t.stencilOp(t.KEEP, t.KEEP, t.REPLACE), t.stencilMask(255), t.colorMask(!1, !1, !1, !1), t.useProgram(this.stencilProgram), t.bindVertexArray(this.stencilVao), t.drawElements(t.TRIANGLES, this.stencilIndexCount, t.UNSIGNED_SHORT, 0), t.colorMask(!0, !0, !0, !0)), t.stencilFunc(t.EQUAL, 1, 255), t.stencilMask(0), t.activeTexture(t.TEXTURE2), t.bindTexture(t.TEXTURE_2D, this.interiorColorTex), t.activeTexture(t.TEXTURE3), t.bindTexture(t.TEXTURE_2D, this.interiorDepthTex), t.activeTexture(t.TEXTURE4), t.bindTexture(t.TEXTURE_2D, this.distTex), t.useProgram(this.compositeProgram), t.bindVertexArray(this.quadVao), t.drawArrays(t.TRIANGLE_STRIP, 0, 4), t.disable(t.STENCIL_TEST), this.chamferVao && this.chamferProgram && this.chamferVertexCount > 0 && (t.useProgram(this.chamferProgram), t.uniform2f(this.chamferUniforms.uMeshScale, this.meshScaleX, this.meshScaleY), t.uniform2f(this.chamferUniforms.uTexelSize, 1 / this.canvas.width, 1 / this.canvas.height), t.bindVertexArray(this.chamferVao), t.drawArrays(t.TRIANGLES, 0, this.chamferVertexCount)), this.boundaryVao && this.boundaryProgram && this.boundaryVertexCount > 0 && this.config.rimLightIntensity > 0 && (t.enable(t.BLEND), t.blendFunc(t.SRC_ALPHA, t.ONE_MINUS_SRC_ALPHA), t.useProgram(this.boundaryProgram), t.bindVertexArray(this.boundaryVao), t.drawArrays(t.TRIANGLES, 0, this.boundaryVertexCount), t.disable(t.BLEND));
2226
+ };
2227
+ updateDepthTexture(t) {
2228
+ const e = this.gl;
2229
+ if (!e || !this.readDepth || !this.depthTexture) return;
2230
+ const i = this.readDepth(t);
2231
+ e.activeTexture(e.TEXTURE1), e.bindTexture(e.TEXTURE_2D, this.depthTexture), e.texSubImage2D(
2232
+ e.TEXTURE_2D,
2233
+ 0,
2234
+ 0,
2235
+ 0,
2236
+ this.depthWidth,
2237
+ this.depthHeight,
2238
+ e.RED,
2239
+ e.UNSIGNED_BYTE,
2240
+ i
2241
+ );
2242
+ }
2243
+ // -----------------------------------------------------------------------
2244
+ // Resize handling
2245
+ // -----------------------------------------------------------------------
2246
+ setupResizeHandling() {
2247
+ typeof ResizeObserver < "u" && (this.resizeObserver = new ResizeObserver(() => {
2248
+ this.scheduleResizeRecalculate();
2249
+ }), this.resizeObserver.observe(this.container)), window.addEventListener("resize", this.scheduleResizeRecalculate), this.recalculateViewportLayout();
2250
+ }
2251
+ scheduleResizeRecalculate = () => {
2252
+ this.resizeTimer !== null && window.clearTimeout(this.resizeTimer), this.resizeTimer = window.setTimeout(() => {
2253
+ this.resizeTimer = null, this.recalculateViewportLayout();
2254
+ }, ft.RESIZE_DEBOUNCE_MS);
2255
+ };
2256
+ recalculateViewportLayout() {
2257
+ const t = this.gl;
2258
+ if (!t) return;
2259
+ const { width: e, height: i } = this.getViewportSize(), r = Math.min(window.devicePixelRatio, 2), o = Math.round(e * r), s = Math.round(i * r);
2260
+ (this.canvas.width !== o || this.canvas.height !== s) && (this.canvas.width = o, this.canvas.height = s, t.viewport(0, 0, o, s)), (this.fboWidth !== o || this.fboHeight !== s) && this.createFBO(o, s);
2261
+ const a = Math.max(1, Math.round(o / 2)), h = Math.max(1, Math.round(s / 2));
2262
+ (this.jfaWidth !== a || this.jfaHeight !== h) && this.createJFAResources(o, s);
2263
+ const l = e / i, u = this.config.parallaxStrength + this.config.overscanPadding;
2264
+ let f = 1, c = 1;
2265
+ l > this.videoAspect ? c = this.videoAspect / l : f = l / this.videoAspect;
2266
+ const d = 1 + u * 2;
2267
+ f /= d, c /= d, this.uvOffset = [(1 - f) / 2, (1 - c) / 2], this.uvScale = [f, c], this.interiorProgram && (t.useProgram(this.interiorProgram), t.uniform2f(this.interiorUniforms.uUvOffset, this.uvOffset[0], this.uvOffset[1]), t.uniform2f(this.interiorUniforms.uUvScale, this.uvScale[0], this.uvScale[1]));
2268
+ const m = 0.65;
2269
+ this.meshScaleX = m, this.meshScaleY = m, l > this.meshAspect ? this.meshScaleX = m * (this.meshAspect / l) : this.meshScaleY = m * (l / this.meshAspect), this.stencilProgram && (t.useProgram(this.stencilProgram), t.uniform2f(this.stencilUniforms.uMeshScale, this.meshScaleX, this.meshScaleY)), this.boundaryProgram && (t.useProgram(this.boundaryProgram), t.uniform2f(this.boundaryUniforms.uMeshScale, this.meshScaleX, this.meshScaleY), t.uniform1f(this.boundaryUniforms.uRimWidth, this.config.rimLightWidth), t.uniform2f(this.boundaryUniforms.uTexelSize, 1 / o, 1 / s)), this.chamferProgram && (t.useProgram(this.chamferProgram), t.uniform2f(this.chamferUniforms.uMeshScale, this.meshScaleX, this.meshScaleY)), this.distFieldDirty = !0;
2270
+ }
2271
+ getViewportSize() {
2272
+ const t = Math.max(1, Math.round(this.container.clientWidth || window.innerWidth)), e = Math.max(1, Math.round(this.container.clientHeight || window.innerHeight));
2273
+ return { width: t, height: e };
2274
+ }
2275
+ // -----------------------------------------------------------------------
2276
+ // Context loss
2277
+ // -----------------------------------------------------------------------
2278
+ handleContextLost = (t) => {
2279
+ t.preventDefault(), this.animationFrameHandle && (window.cancelAnimationFrame(this.animationFrameHandle), this.animationFrameHandle = 0);
2280
+ };
2281
+ handleContextRestored = () => {
2282
+ const t = this.canvas.getContext("webgl2", {
2283
+ alpha: !0,
2284
+ premultipliedAlpha: !0,
2285
+ stencil: !0
2286
+ });
2287
+ t && (this.gl = t, t.clearColor(0, 0, 0, 0), t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL, !0), this.initGPUResources(), this.playbackVideo && (this.animationFrameHandle = window.requestAnimationFrame(this.renderLoop)));
2288
+ };
2289
+ // -----------------------------------------------------------------------
2290
+ // Cleanup
2291
+ // -----------------------------------------------------------------------
2292
+ disposeTextures() {
2293
+ const t = this.gl;
2294
+ t && (this.videoTexture && (t.deleteTexture(this.videoTexture), this.videoTexture = null), this.depthTexture && (t.deleteTexture(this.depthTexture), this.depthTexture = null));
2295
+ }
2296
+ disposeFBO() {
2297
+ const t = this.gl;
2298
+ t && (this.interiorColorTex && (t.deleteTexture(this.interiorColorTex), this.interiorColorTex = null), this.interiorDepthTex && (t.deleteTexture(this.interiorDepthTex), this.interiorDepthTex = null), this.interiorFbo && (t.deleteFramebuffer(this.interiorFbo), this.interiorFbo = null), this.fboWidth = 0, this.fboHeight = 0);
2299
+ }
2300
+ disposeJFA() {
2301
+ const t = this.gl;
2302
+ t && (this.maskTex && (t.deleteTexture(this.maskTex), this.maskTex = null), this.maskFbo && (t.deleteFramebuffer(this.maskFbo), this.maskFbo = null), this.jfaPingTex && (t.deleteTexture(this.jfaPingTex), this.jfaPingTex = null), this.jfaPingFbo && (t.deleteFramebuffer(this.jfaPingFbo), this.jfaPingFbo = null), this.jfaPongTex && (t.deleteTexture(this.jfaPongTex), this.jfaPongTex = null), this.jfaPongFbo && (t.deleteFramebuffer(this.jfaPongFbo), this.jfaPongFbo = null), this.distTex && (t.deleteTexture(this.distTex), this.distTex = null), this.distFbo && (t.deleteFramebuffer(this.distFbo), this.distFbo = null), this.jfaWidth = 0, this.jfaHeight = 0, this.distFieldDirty = !0);
2303
+ }
2304
+ disposeStencilGeometry() {
2305
+ const t = this.gl;
2306
+ t && (this.stencilVao && (t.deleteVertexArray(this.stencilVao), this.stencilVao = null), this.maskVao && (t.deleteVertexArray(this.maskVao), this.maskVao = null), this.stencilIndexCount = 0);
2307
+ }
2308
+ disposeBoundaryGeometry() {
2309
+ const t = this.gl;
2310
+ t && (this.boundaryVao && (t.deleteVertexArray(this.boundaryVao), this.boundaryVao = null), this.boundaryVertexCount = 0);
2311
+ }
2312
+ disposeGPUResources() {
2313
+ const t = this.gl;
2314
+ t && (this.stencilProgram && (t.deleteProgram(this.stencilProgram), this.stencilProgram = null), this.maskProgram && (t.deleteProgram(this.maskProgram), this.maskProgram = null), this.jfaSeedProgram && (t.deleteProgram(this.jfaSeedProgram), this.jfaSeedProgram = null), this.jfaFloodProgram && (t.deleteProgram(this.jfaFloodProgram), this.jfaFloodProgram = null), this.jfaDistProgram && (t.deleteProgram(this.jfaDistProgram), this.jfaDistProgram = null), this.interiorProgram && (t.deleteProgram(this.interiorProgram), this.interiorProgram = null), this.compositeProgram && (t.deleteProgram(this.compositeProgram), this.compositeProgram = null), this.boundaryProgram && (t.deleteProgram(this.boundaryProgram), this.boundaryProgram = null), this.chamferProgram && (t.deleteProgram(this.chamferProgram), this.chamferProgram = null), this.quadVao && (t.deleteVertexArray(this.quadVao), this.quadVao = null), this.stencilUniforms = {}, this.maskUniforms = {}, this.jfaSeedUniforms = {}, this.jfaFloodUniforms = {}, this.jfaDistUniforms = {}, this.interiorUniforms = {}, this.compositeUniforms = {}, this.boundaryUniforms = {}, this.chamferUniforms = {});
2315
+ }
2316
+ }
2317
+ async function me(n) {
2318
+ const t = await fetch(n);
2319
+ if (!t.ok)
2320
+ throw new Error(`Failed to fetch SVG: ${t.status} ${t.statusText}`);
2321
+ const e = await t.text();
2322
+ return pe(e);
2323
+ }
2324
+ function pe(n) {
2325
+ const i = new DOMParser().parseFromString(n, "image/svg+xml").querySelector("svg");
2326
+ if (!i)
2327
+ throw new Error("No <svg> element found in document.");
2328
+ const r = ge(i);
2329
+ if (r.length === 0)
2330
+ throw new Error("No path data found in SVG.");
2331
+ let o = 1 / 0, s = 1 / 0, a = -1 / 0, h = -1 / 0;
2332
+ for (const D of r)
2333
+ for (let R = 0; R < D.length; R += 2)
2334
+ o = Math.min(o, D[R]), a = Math.max(a, D[R]), s = Math.min(s, D[R + 1]), h = Math.max(h, D[R + 1]);
2335
+ const l = a - o, u = h - s, f = (o + a) / 2, c = (s + h) / 2, d = 2 / Math.max(l, u), m = l / u, g = r.map((D) => {
2336
+ const R = [];
2337
+ for (let C = 0; C < D.length; C += 2)
2338
+ R.push((D[C] - f) * d), R.push(-((D[C + 1] - c) * d));
2339
+ return R;
2340
+ }), U = Se(g), b = [], E = [];
2341
+ for (const D of U) {
2342
+ const { flatCoords: R, holeIndices: C } = ye(D), M = Re(R, C), H = b.length / 2;
2343
+ for (const I of M)
2344
+ E.push(I + H);
2345
+ for (const I of R)
2346
+ b.push(I);
2347
+ }
2348
+ const p = b, v = E, T = [], x = [], y = [], S = St(g);
2349
+ for (let D = 0; D < g.length; D++) {
2350
+ const R = g[D];
2351
+ x.push(T.length), y.push(S[D]);
2352
+ for (let C = 0; C < R.length; C++)
2353
+ T.push(R[C]);
2354
+ R.length >= 2 && T.push(R[0], R[1]);
2355
+ }
2356
+ let F = 1 / 0, P = 1 / 0, _ = -1 / 0, k = -1 / 0;
2357
+ for (let D = 0; D < p.length; D += 2)
2358
+ F = Math.min(F, p[D]), _ = Math.max(_, p[D]), P = Math.min(P, p[D + 1]), k = Math.max(k, p[D + 1]);
2359
+ return {
2360
+ vertices: new Float32Array(p),
2361
+ indices: new Uint16Array(v),
2362
+ edgeVertices: new Float32Array(T),
2363
+ contourOffsets: x,
2364
+ contourIsHole: y,
2365
+ bounds: { minX: F, maxX: _, minY: P, maxY: k },
2366
+ aspect: m
2367
+ };
2368
+ }
2369
+ function ge(n) {
2370
+ const t = [];
2371
+ return n.querySelectorAll("path").forEach((h) => {
2372
+ const l = h.getAttribute("d");
2373
+ if (!l) return;
2374
+ const u = Te(l);
2375
+ t.push(...u);
2376
+ }), n.querySelectorAll("polygon").forEach((h) => {
2377
+ const l = h.getAttribute("points");
2378
+ if (!l) return;
2379
+ const u = vt(l);
2380
+ u.length >= 6 && t.push(u);
2381
+ }), n.querySelectorAll("polyline").forEach((h) => {
2382
+ const l = h.getAttribute("points");
2383
+ if (!l) return;
2384
+ const u = vt(l);
2385
+ u.length >= 6 && t.push(u);
2386
+ }), n.querySelectorAll("rect").forEach((h) => {
2387
+ const l = parseFloat(h.getAttribute("x") || "0"), u = parseFloat(h.getAttribute("y") || "0"), f = parseFloat(h.getAttribute("width") || "0"), c = parseFloat(h.getAttribute("height") || "0");
2388
+ f > 0 && c > 0 && t.push([l, u, l + f, u, l + f, u + c, l, u + c]);
2389
+ }), n.querySelectorAll("circle").forEach((h) => {
2390
+ const l = parseFloat(h.getAttribute("cx") || "0"), u = parseFloat(h.getAttribute("cy") || "0"), f = parseFloat(h.getAttribute("r") || "0");
2391
+ f > 0 && t.push(ve(l, u, f));
2392
+ }), n.querySelectorAll("ellipse").forEach((h) => {
2393
+ const l = parseFloat(h.getAttribute("cx") || "0"), u = parseFloat(h.getAttribute("cy") || "0"), f = parseFloat(h.getAttribute("rx") || "0"), c = parseFloat(h.getAttribute("ry") || "0");
2394
+ f > 0 && c > 0 && t.push(xe(l, u, f, c));
2395
+ }), t;
2396
+ }
2397
+ function vt(n) {
2398
+ const t = [], e = n.trim().split(/[\s,]+/);
2399
+ for (let i = 0; i < e.length - 1; i += 2) {
2400
+ const r = parseFloat(e[i]), o = parseFloat(e[i + 1]);
2401
+ Number.isFinite(r) && Number.isFinite(o) && t.push(r, o);
2402
+ }
2403
+ return t;
2404
+ }
2405
+ function ve(n, t, e, i = 64) {
2406
+ const r = [];
2407
+ for (let o = 0; o < i; o++) {
2408
+ const s = 2 * Math.PI * o / i;
2409
+ r.push(n + e * Math.cos(s), t + e * Math.sin(s));
2410
+ }
2411
+ return r;
2412
+ }
2413
+ function xe(n, t, e, i, r = 64) {
2414
+ const o = [];
2415
+ for (let s = 0; s < r; s++) {
2416
+ const a = 2 * Math.PI * s / r;
2417
+ o.push(n + e * Math.cos(a), t + i * Math.sin(a));
2418
+ }
2419
+ return o;
2420
+ }
2421
+ function Te(n) {
2422
+ const t = [];
2423
+ let e = [], i = 0, r = 0, o = 0, s = 0, a = 0, h = 0, l = "";
2424
+ const u = Ee(n);
2425
+ let f = 0;
2426
+ function c() {
2427
+ return f >= u.length ? 0 : parseFloat(u[f++]);
2428
+ }
2429
+ for (; f < u.length; ) {
2430
+ const d = u[f];
2431
+ let m;
2432
+ /^[a-zA-Z]$/.test(d) ? (m = d, f++) : m = l === "M" ? "L" : l === "m" ? "l" : l;
2433
+ const g = m === m.toLowerCase();
2434
+ switch (m.toUpperCase()) {
2435
+ case "M": {
2436
+ e.length > 0 && t.push(e), e = [];
2437
+ const b = c() + (g ? i : 0), E = c() + (g ? r : 0);
2438
+ i = b, r = E, o = b, s = E, e.push(i, r), a = i, h = r;
2439
+ break;
2440
+ }
2441
+ case "L": {
2442
+ i = c() + (g ? i : 0), r = c() + (g ? r : 0), e.push(i, r), a = i, h = r;
2443
+ break;
2444
+ }
2445
+ case "H": {
2446
+ i = c() + (g ? i : 0), e.push(i, r), a = i, h = r;
2447
+ break;
2448
+ }
2449
+ case "V": {
2450
+ r = c() + (g ? r : 0), e.push(i, r), a = i, h = r;
2451
+ break;
2452
+ }
2453
+ case "C": {
2454
+ const b = c() + (g ? i : 0), E = c() + (g ? r : 0), p = c() + (g ? i : 0), v = c() + (g ? r : 0), T = c() + (g ? i : 0), x = c() + (g ? r : 0);
2455
+ J(e, i, r, b, E, p, v, T, x), i = T, r = x, a = p, h = v;
2456
+ break;
2457
+ }
2458
+ case "S": {
2459
+ const b = 2 * i - a, E = 2 * r - h, p = c() + (g ? i : 0), v = c() + (g ? r : 0), T = c() + (g ? i : 0), x = c() + (g ? r : 0);
2460
+ J(e, i, r, b, E, p, v, T, x), i = T, r = x, a = p, h = v;
2461
+ break;
2462
+ }
2463
+ case "Q": {
2464
+ const b = c() + (g ? i : 0), E = c() + (g ? r : 0), p = c() + (g ? i : 0), v = c() + (g ? r : 0);
2465
+ xt(e, i, r, b, E, p, v), i = p, r = v, a = b, h = E;
2466
+ break;
2467
+ }
2468
+ case "T": {
2469
+ const b = 2 * i - a, E = 2 * r - h, p = c() + (g ? i : 0), v = c() + (g ? r : 0);
2470
+ xt(e, i, r, b, E, p, v), i = p, r = v, a = b, h = E;
2471
+ break;
2472
+ }
2473
+ case "A": {
2474
+ const b = c(), E = c(), p = c(), v = c(), T = c(), x = c() + (g ? i : 0), y = c() + (g ? r : 0);
2475
+ Ae(e, i, r, b, E, p, !!v, !!T, x, y), i = x, r = y, a = i, h = r;
2476
+ break;
2477
+ }
2478
+ case "Z": {
2479
+ i = o, r = s, e.length > 0 && t.push(e), e = [], a = i, h = r;
2480
+ break;
2481
+ }
2482
+ default:
2483
+ f++;
2484
+ break;
2485
+ }
2486
+ l = m;
2487
+ }
2488
+ return e.length >= 6 && t.push(e), t;
2489
+ }
2490
+ function Ee(n) {
2491
+ const t = [], e = /([a-zA-Z])|([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)/g;
2492
+ let i;
2493
+ for (; (i = e.exec(n)) !== null; )
2494
+ t.push(i[0]);
2495
+ return t;
2496
+ }
2497
+ const be = 0.5;
2498
+ function J(n, t, e, i, r, o, s, a, h, l = 0) {
2499
+ if (l > 12) {
2500
+ n.push(a, h);
2501
+ return;
2502
+ }
2503
+ const u = a - t, f = h - e, c = Math.sqrt(u * u + f * f);
2504
+ if (c < 1e-6) {
2505
+ n.push(a, h);
2506
+ return;
2507
+ }
2508
+ const d = Math.abs((i - a) * f - (r - h) * u) / c, m = Math.abs((o - a) * f - (s - h) * u) / c;
2509
+ if (d + m < be) {
2510
+ n.push(a, h);
2511
+ return;
2512
+ }
2513
+ const g = (t + i) / 2, U = (e + r) / 2, b = (i + o) / 2, E = (r + s) / 2, p = (o + a) / 2, v = (s + h) / 2, T = (g + b) / 2, x = (U + E) / 2, y = (b + p) / 2, S = (E + v) / 2, F = (T + y) / 2, P = (x + S) / 2;
2514
+ J(n, t, e, g, U, T, x, F, P, l + 1), J(n, F, P, y, S, p, v, a, h, l + 1);
2515
+ }
2516
+ function xt(n, t, e, i, r, o, s) {
2517
+ const a = t + 0.6666666666666666 * (i - t), h = e + 2 / 3 * (r - e), l = o + 2 / 3 * (i - o), u = s + 2 / 3 * (r - s);
2518
+ J(n, t, e, a, h, l, u, o, s);
2519
+ }
2520
+ function Ae(n, t, e, i, r, o, s, a, h, l) {
2521
+ if (i === 0 || r === 0) {
2522
+ n.push(h, l);
2523
+ return;
2524
+ }
2525
+ let u = Math.abs(i), f = Math.abs(r);
2526
+ const c = o * Math.PI / 180, d = Math.cos(c), m = Math.sin(c), g = (t - h) / 2, U = (e - l) / 2, b = d * g + m * U, E = -m * g + d * U;
2527
+ let p = b * b / (u * u) + E * E / (f * f);
2528
+ if (p > 1) {
2529
+ const M = Math.sqrt(p);
2530
+ u *= M, f *= M, p = 1;
2531
+ }
2532
+ const v = u * u, T = f * f, x = b * b, y = E * E;
2533
+ let S = Math.max(0, (v * T - v * y - T * x) / (v * y + T * x));
2534
+ S = Math.sqrt(S), s === a && (S = -S);
2535
+ const F = S * (u * E) / f, P = S * -(f * b) / u, _ = d * F - m * P + (t + h) / 2, k = m * F + d * P + (e + l) / 2, D = Tt(1, 0, (b - F) / u, (E - P) / f);
2536
+ let R = Tt(
2537
+ (b - F) / u,
2538
+ (E - P) / f,
2539
+ (-b - F) / u,
2540
+ (-E - P) / f
2541
+ );
2542
+ !a && R > 0 && (R -= 2 * Math.PI), a && R < 0 && (R += 2 * Math.PI);
2543
+ const C = Math.max(4, Math.ceil(Math.abs(R) / (Math.PI / 16)));
2544
+ for (let M = 1; M <= C; M++) {
2545
+ const H = D + M / C * R, I = Math.cos(H), N = Math.sin(H), j = d * u * I - m * f * N + _, et = m * u * I + d * f * N + k;
2546
+ n.push(j, et);
2547
+ }
2548
+ }
2549
+ function Tt(n, t, e, i) {
2550
+ const r = n * i - t * e < 0 ? -1 : 1, o = n * e + t * i, s = Math.sqrt(n * n + t * t), a = Math.sqrt(e * e + i * i), h = o / (s * a);
2551
+ return r * Math.acos(Math.max(-1, Math.min(1, h)));
2552
+ }
2553
+ function ye(n) {
2554
+ const t = [], e = [];
2555
+ for (let i = 0; i < n.length; i++) {
2556
+ i > 0 && e.push(t.length / 2);
2557
+ for (const r of n[i])
2558
+ t.push(r);
2559
+ }
2560
+ return { flatCoords: t, holeIndices: e };
2561
+ }
2562
+ function St(n) {
2563
+ const t = n.length, e = n.map((r) => Math.abs(Rt(r))), i = new Array(t).fill(!1);
2564
+ for (let r = 0; r < t; r++) {
2565
+ let o = 0;
2566
+ const s = n[r][0], a = n[r][1];
2567
+ for (let h = 0; h < t; h++)
2568
+ r !== h && e[h] > e[r] && Dt(s, a, n[h]) && o++;
2569
+ i[r] = o % 2 === 1;
2570
+ }
2571
+ return i;
2572
+ }
2573
+ function Se(n) {
2574
+ if (n.length <= 1)
2575
+ return [n];
2576
+ const t = St(n), e = n.map((s, a) => {
2577
+ const h = Rt(s);
2578
+ return { index: a, contour: s, area: h, isOuter: !t[a] };
2579
+ }), i = e.filter((s) => s.isOuter), r = e.filter((s) => !s.isOuter);
2580
+ if (i.length === 0)
2581
+ return n.map((s) => [s]);
2582
+ const o = i.map((s) => ({
2583
+ outer: s.contour,
2584
+ holes: []
2585
+ }));
2586
+ for (const s of r) {
2587
+ const a = s.contour[0], h = s.contour[1];
2588
+ let l = -1, u = 1 / 0;
2589
+ for (let f = 0; f < i.length; f++)
2590
+ if (Dt(a, h, i[f].contour)) {
2591
+ const c = Math.abs(i[f].area);
2592
+ c < u && (u = c, l = f);
2593
+ }
2594
+ l >= 0 ? o[l].holes.push(s.contour) : o.push({ outer: s.contour, holes: [] });
2595
+ }
2596
+ return o.map((s) => [s.outer, ...s.holes]);
2597
+ }
2598
+ function Rt(n) {
2599
+ let t = 0;
2600
+ const e = n.length;
2601
+ for (let i = 0; i < e; i += 2) {
2602
+ const r = n[i], o = n[i + 1], s = n[(i + 2) % e], a = n[(i + 3) % e];
2603
+ t += r * a - s * o;
2604
+ }
2605
+ return t / 2;
2606
+ }
2607
+ function Dt(n, t, e) {
2608
+ let i = !1;
2609
+ const r = e.length;
2610
+ for (let o = 0, s = r - 2; o < r; s = o, o += 2) {
2611
+ const a = e[o], h = e[o + 1], l = e[s], u = e[s + 1];
2612
+ h > t != u > t && n < (l - a) * (t - h) / (u - h) + a && (i = !i);
2613
+ }
2614
+ return i;
2615
+ }
2616
+ function Re(n, t, e = 2) {
2617
+ const i = t && t.length > 0, r = i ? t[0] * e : n.length;
2618
+ let o = Ft(n, 0, r, e, !0);
2619
+ const s = [];
2620
+ if (!o || o.next === o.prev) return s;
2621
+ i && (o = we(n, t, o, e));
2622
+ let a = 1 / 0, h = 1 / 0, l = -1 / 0, u = -1 / 0, f = 0;
2623
+ if (n.length > 80 * e) {
2624
+ for (let c = 0; c < r; c += e) {
2625
+ const d = n[c], m = n[c + 1];
2626
+ d < a && (a = d), m < h && (h = m), d > l && (l = d), m > u && (u = m);
2627
+ }
2628
+ f = Math.max(l - a, u - h), f = f !== 0 ? 32767 / f : 0;
2629
+ }
2630
+ return K(o, s, e, a, h, f, 0), s;
2631
+ }
2632
+ function Ft(n, t, e, i, r) {
2633
+ let o = null;
2634
+ if (r === Be(n, t, e, i) > 0)
2635
+ for (let s = t; s < e; s += i)
2636
+ o = Et(s, n[s], n[s + 1], o);
2637
+ else
2638
+ for (let s = e - i; s >= t; s -= i)
2639
+ o = Et(s, n[s], n[s + 1], o);
2640
+ return o && at(o, o.next) && (tt(o), o = o.next), o ? (o.next.prev = o, o.prev.next = o, o.next) : null;
2641
+ }
2642
+ function X(n, t) {
2643
+ t || (t = n);
2644
+ let e = n, i;
2645
+ do
2646
+ if (i = !1, !e.steiner && (at(e, e.next) || w(e.prev, e, e.next) === 0)) {
2647
+ if (tt(e), e = t = e.prev, e === e.next) break;
2648
+ i = !0;
2649
+ } else
2650
+ e = e.next;
2651
+ while (i || e !== t);
2652
+ return t;
2653
+ }
2654
+ function K(n, t, e, i, r, o, s) {
2655
+ if (!n) return;
2656
+ !s && o && _e(n, i, r, o);
2657
+ let a = n, h, l;
2658
+ for (; n.prev !== n.next; ) {
2659
+ if (h = n.prev, l = n.next, o ? Fe(n, i, r, o) : De(n)) {
2660
+ t.push(h.i / e, n.i / e, l.i / e), tt(n), n = l.next, a = l.next;
2661
+ continue;
2662
+ }
2663
+ if (n = l, n === a) {
2664
+ s ? s === 1 ? (n = Ue(X(n), t, e), K(n, t, e, i, r, o, 2)) : s === 2 && Pe(n, t, e, i, r, o) : K(X(n), t, e, i, r, o, 1);
2665
+ break;
2666
+ }
2667
+ }
2668
+ }
2669
+ function De(n) {
2670
+ const t = n.prev, e = n, i = n.next;
2671
+ if (w(t, e, i) >= 0) return !1;
2672
+ const r = t.x, o = e.x, s = i.x, a = t.y, h = e.y, l = i.y, u = r < o ? r < s ? r : s : o < s ? o : s, f = a < h ? a < l ? a : l : h < l ? h : l, c = r > o ? r > s ? r : s : o > s ? o : s, d = a > h ? a > l ? a : l : h > l ? h : l;
2673
+ let m = i.next;
2674
+ for (; m !== t; ) {
2675
+ if (m.x >= u && m.x <= c && m.y >= f && m.y <= d && G(r, a, o, h, s, l, m.x, m.y) && w(m.prev, m, m.next) >= 0)
2676
+ return !1;
2677
+ m = m.next;
2678
+ }
2679
+ return !0;
2680
+ }
2681
+ function Fe(n, t, e, i) {
2682
+ const r = n.prev, o = n, s = n.next;
2683
+ if (w(r, o, s) >= 0) return !1;
2684
+ const a = r.x, h = o.x, l = s.x, u = r.y, f = o.y, c = s.y, d = a < h ? a < l ? a : l : h < l ? h : l, m = u < f ? u < c ? u : c : f < c ? f : c, g = a > h ? a > l ? a : l : h > l ? h : l, U = u > f ? u > c ? u : c : f > c ? f : c, b = ct(d, m, t, e, i), E = ct(g, U, t, e, i);
2685
+ let p = n.prevZ, v = n.nextZ;
2686
+ for (; p && p.z >= b && v && v.z <= E; ) {
2687
+ if (p.x >= d && p.x <= g && p.y >= m && p.y <= U && p !== r && p !== s && G(a, u, h, f, l, c, p.x, p.y) && w(p.prev, p, p.next) >= 0 || (p = p.prevZ, v.x >= d && v.x <= g && v.y >= m && v.y <= U && v !== r && v !== s && G(a, u, h, f, l, c, v.x, v.y) && w(v.prev, v, v.next) >= 0)) return !1;
2688
+ v = v.nextZ;
2689
+ }
2690
+ for (; p && p.z >= b; ) {
2691
+ if (p.x >= d && p.x <= g && p.y >= m && p.y <= U && p !== r && p !== s && G(a, u, h, f, l, c, p.x, p.y) && w(p.prev, p, p.next) >= 0) return !1;
2692
+ p = p.prevZ;
2693
+ }
2694
+ for (; v && v.z <= E; ) {
2695
+ if (v.x >= d && v.x <= g && v.y >= m && v.y <= U && v !== r && v !== s && G(a, u, h, f, l, c, v.x, v.y) && w(v.prev, v, v.next) >= 0) return !1;
2696
+ v = v.nextZ;
2697
+ }
2698
+ return !0;
2699
+ }
2700
+ function Ue(n, t, e) {
2701
+ let i = n;
2702
+ do {
2703
+ const r = i.prev, o = i.next.next;
2704
+ !at(r, o) && Ut(r, i, i.next, o) && Q(r, o) && Q(o, r) && (t.push(r.i / e, i.i / e, o.i / e), tt(i), tt(i.next), i = n = o), i = i.next;
2705
+ } while (i !== n);
2706
+ return X(i);
2707
+ }
2708
+ function Pe(n, t, e, i, r, o) {
2709
+ let s = n;
2710
+ do {
2711
+ let a = s.next.next;
2712
+ for (; a !== s.prev; ) {
2713
+ if (s.i !== a.i && Oe(s, a)) {
2714
+ let h = Pt(s, a);
2715
+ s = X(s, s.next), h = X(h, h.next), K(s, t, e, i, r, o, 0), K(h, t, e, i, r, o, 0);
2716
+ return;
2717
+ }
2718
+ a = a.next;
2719
+ }
2720
+ s = s.next;
2721
+ } while (s !== n);
2722
+ }
2723
+ function we(n, t, e, i) {
2724
+ const r = [];
2725
+ for (let o = 0; o < t.length; o++) {
2726
+ const s = t[o] * i, a = o < t.length - 1 ? t[o + 1] * i : n.length, h = Ft(n, s, a, i, !1);
2727
+ h && (h === h.next && (h.steiner = !0), r.push(Ve(h)));
2728
+ }
2729
+ r.sort((o, s) => o.x - s.x);
2730
+ for (const o of r)
2731
+ e = Le(o, e);
2732
+ return e;
2733
+ }
2734
+ function Le(n, t) {
2735
+ const e = Ce(n, t);
2736
+ if (!e) return t;
2737
+ const i = Pt(e, n);
2738
+ return X(i, i.next), X(e, e.next);
2739
+ }
2740
+ function Ce(n, t) {
2741
+ let e = t;
2742
+ const i = n.x, r = n.y;
2743
+ let o = -1 / 0, s = null;
2744
+ do {
2745
+ if (r <= e.y && r >= e.next.y && e.next.y !== e.y) {
2746
+ const f = e.x + (r - e.y) / (e.next.y - e.y) * (e.next.x - e.x);
2747
+ if (f <= i && f > o && (o = f, s = e.x < e.next.x ? e : e.next, f === i))
2748
+ return s;
2749
+ }
2750
+ e = e.next;
2751
+ } while (e !== t);
2752
+ if (!s) return null;
2753
+ const a = s, h = s.x, l = s.y;
2754
+ let u = 1 / 0;
2755
+ e = s;
2756
+ do {
2757
+ if (i >= e.x && e.x >= h && i !== e.x && G(r < l ? i : o, r, h, l, r < l ? o : i, r, e.x, e.y)) {
2758
+ const f = Math.abs(r - e.y) / (i - e.x);
2759
+ Q(e, n) && (f < u || f === u && (e.x > s.x || Me(s, e))) && (s = e, u = f);
2760
+ }
2761
+ e = e.next;
2762
+ } while (e !== a);
2763
+ return s;
2764
+ }
2765
+ function Me(n, t) {
2766
+ return w(n.prev, n, t.prev) < 0 && w(t.next, n, n.next) < 0;
2767
+ }
2768
+ function _e(n, t, e, i) {
2769
+ let r = n;
2770
+ do
2771
+ r.z === 0 && (r.z = ct(r.x, r.y, t, e, i)), r.prevZ = r.prev, r.nextZ = r.next, r = r.next;
2772
+ while (r !== n);
2773
+ r.prevZ.nextZ = null, r.prevZ = null, Ie(r);
2774
+ }
2775
+ function Ie(n) {
2776
+ let t = 1, e;
2777
+ do {
2778
+ let i = n;
2779
+ n = null;
2780
+ let r = null;
2781
+ for (e = 0; i; ) {
2782
+ e++;
2783
+ let o = i, s = 0;
2784
+ for (let h = 0; h < t && (s++, o = o.nextZ, !!o); h++)
2785
+ ;
2786
+ let a = t;
2787
+ for (; s > 0 || a > 0 && o; ) {
2788
+ let h;
2789
+ s !== 0 && (a === 0 || !o || i.z <= o.z) ? (h = i, i = i.nextZ, s--) : (h = o, o = o.nextZ, a--), r ? r.nextZ = h : n = h, h.prevZ = r, r = h;
2790
+ }
2791
+ i = o;
2792
+ }
2793
+ r.nextZ = null, t *= 2;
2794
+ } while (e > 1);
2795
+ return n;
2796
+ }
2797
+ function ct(n, t, e, i, r) {
2798
+ let o = (n - e) * r | 0, s = (t - i) * r | 0;
2799
+ return o = (o | o << 8) & 16711935, o = (o | o << 4) & 252645135, o = (o | o << 2) & 858993459, o = (o | o << 1) & 1431655765, s = (s | s << 8) & 16711935, s = (s | s << 4) & 252645135, s = (s | s << 2) & 858993459, s = (s | s << 1) & 1431655765, o | s << 1;
2800
+ }
2801
+ function Ve(n) {
2802
+ let t = n, e = n;
2803
+ do
2804
+ (t.x < e.x || t.x === e.x && t.y < e.y) && (e = t), t = t.next;
2805
+ while (t !== n);
2806
+ return e;
2807
+ }
2808
+ function G(n, t, e, i, r, o, s, a) {
2809
+ return (r - s) * (t - a) - (n - s) * (o - a) >= 0 && (n - s) * (i - a) - (e - s) * (t - a) >= 0 && (e - s) * (o - a) - (r - s) * (i - a) >= 0;
2810
+ }
2811
+ function Oe(n, t) {
2812
+ return n.next.i !== t.i && n.prev.i !== t.i && !ke(n, t) && (Q(n, t) && Q(t, n) && He(n, t) && (w(n.prev, n, t.prev) !== 0 || w(n, t.prev, t) !== 0) || at(n, t) && w(n.prev, n, n.next) > 0 && w(t.prev, t, t.next) > 0);
2813
+ }
2814
+ function w(n, t, e) {
2815
+ return (t.y - n.y) * (e.x - t.x) - (t.x - n.x) * (e.y - t.y);
2816
+ }
2817
+ function at(n, t) {
2818
+ return n.x === t.x && n.y === t.y;
2819
+ }
2820
+ function Ut(n, t, e, i) {
2821
+ const r = ot(w(n, t, e)), o = ot(w(n, t, i)), s = ot(w(e, i, n)), a = ot(w(e, i, t));
2822
+ return !!(r !== o && s !== a || r === 0 && rt(n, e, t) || o === 0 && rt(n, i, t) || s === 0 && rt(e, n, i) || a === 0 && rt(e, t, i));
2823
+ }
2824
+ function rt(n, t, e) {
2825
+ return t.x <= Math.max(n.x, e.x) && t.x >= Math.min(n.x, e.x) && t.y <= Math.max(n.y, e.y) && t.y >= Math.min(n.y, e.y);
2826
+ }
2827
+ function ot(n) {
2828
+ return n > 0 ? 1 : n < 0 ? -1 : 0;
2829
+ }
2830
+ function ke(n, t) {
2831
+ let e = n;
2832
+ do {
2833
+ if (e.i !== n.i && e.next.i !== n.i && e.i !== t.i && e.next.i !== t.i && Ut(e, e.next, n, t)) return !0;
2834
+ e = e.next;
2835
+ } while (e !== n);
2836
+ return !1;
2837
+ }
2838
+ function Q(n, t) {
2839
+ return w(n.prev, n, n.next) < 0 ? w(n, t, n.next) >= 0 && w(n, n.prev, t) >= 0 : w(n, t, n.prev) < 0 || w(n, n.next, t) < 0;
2840
+ }
2841
+ function He(n, t) {
2842
+ let e = n, i = !1;
2843
+ const r = (n.x + t.x) / 2, o = (n.y + t.y) / 2;
2844
+ do
2845
+ e.y > o != e.next.y > o && e.next.y !== e.y && r < (e.next.x - e.x) * (o - e.y) / (e.next.y - e.y) + e.x && (i = !i), e = e.next;
2846
+ while (e !== n);
2847
+ return i;
2848
+ }
2849
+ function Pt(n, t) {
2850
+ const e = ut(n.i, n.x, n.y), i = ut(t.i, t.x, t.y), r = n.next, o = t.prev;
2851
+ return n.next = t, t.prev = n, e.next = r, r.prev = e, i.next = e, e.prev = i, o.next = i, i.prev = o, i;
2852
+ }
2853
+ function Et(n, t, e, i) {
2854
+ const r = ut(n, t, e);
2855
+ return i ? (r.next = i.next, r.prev = i, i.next.prev = r, i.next = r) : (r.prev = r, r.next = r), r;
2856
+ }
2857
+ function tt(n) {
2858
+ n.next.prev = n.prev, n.prev.next = n.next, n.prevZ && (n.prevZ.nextZ = n.nextZ), n.nextZ && (n.nextZ.prevZ = n.prevZ);
2859
+ }
2860
+ function ut(n, t, e) {
2861
+ return {
2862
+ i: n,
2863
+ x: t,
2864
+ y: e,
2865
+ prev: null,
2866
+ next: null,
2867
+ z: 0,
2868
+ prevZ: null,
2869
+ nextZ: null,
2870
+ steiner: !1
2871
+ };
2872
+ }
2873
+ function Be(n, t, e, i) {
2874
+ let r = 0;
2875
+ for (let o = t, s = e - i; o < e; o += i)
2876
+ r += (n[s] - n[o]) * (n[o + 1] + n[s + 1]), s = o;
2877
+ return r;
2878
+ }
2879
+ const A = {
2880
+ parallaxX: 0.4,
2881
+ parallaxY: 0.8,
2882
+ parallaxMax: 30,
2883
+ overscan: 0.06,
2884
+ pomSteps: 16,
2885
+ // Boundary effects
2886
+ rimIntensity: 0.6,
2887
+ rimColor: "#ffffff",
2888
+ rimWidth: 0.025,
2889
+ refractionStrength: 0.015,
2890
+ chromaticStrength: 8e-3,
2891
+ occlusionIntensity: 0.4,
2892
+ // Lens transform
2893
+ depthPower: 0.7,
2894
+ // < 1 = wide-angle, exaggerated foreground
2895
+ depthScale: 1.2,
2896
+ // expand depth range beyond 1.0
2897
+ depthBias: -0.05,
2898
+ // slight bias toward near
2899
+ // Interior mood
2900
+ fogDensity: 0.15,
2901
+ fogColor: "#1a1a2e",
2902
+ colorShift: 0.6,
2903
+ brightnessBias: 0.05,
2904
+ // Depth-adaptive
2905
+ contrastLow: 0.02,
2906
+ contrastHigh: 0.98,
2907
+ verticalReduction: 0.5,
2908
+ dofStart: 0.5,
2909
+ dofStrength: 0.5,
2910
+ // Bevel / dimensional typography
2911
+ bevelIntensity: 0.5,
2912
+ bevelWidth: 0.04,
2913
+ bevelDarkening: 0.2,
2914
+ bevelDesaturation: 0.12,
2915
+ bevelLightAngle: 135,
2916
+ // Volumetric edge wall
2917
+ edgeThickness: 0.01,
2918
+ edgeSpecular: 0.35,
2919
+ edgeColor: "#a0a0a0",
2920
+ // Chamfer geometry
2921
+ chamferWidth: 0.025,
2922
+ chamferAngle: 45,
2923
+ chamferColor: "#262630",
2924
+ chamferAmbient: 0.12,
2925
+ chamferSpecular: 0.3,
2926
+ chamferShininess: 24,
2927
+ // Edge occlusion (emissive interior)
2928
+ edgeOcclusionWidth: 0.03,
2929
+ edgeOcclusionStrength: 0.2,
2930
+ lightDirection: "-0.5,0.7,-0.3",
2931
+ autoplay: !0,
2932
+ loop: !0,
2933
+ muted: !0
2934
+ };
2935
+ class dt {
2936
+ constructor(t, e = 0.08, i = 0.06) {
2937
+ this.host = t, this.lerpFactor = e, this.motionLerpFactor = i, this.host.addEventListener("mousemove", this.handleMouseMove), this.host.addEventListener("mouseleave", this.resetPointerTarget), this.host.addEventListener("touchstart", this.handleTouchStart, { passive: !0 }), this.host.addEventListener("touchmove", this.handleTouchMove, { passive: !0 }), this.host.addEventListener("touchend", this.handleTouchEnd, { passive: !0 }), this.host.addEventListener("touchcancel", this.handleTouchEnd, { passive: !0 });
2938
+ }
2939
+ pointerTarget = { x: 0, y: 0 };
2940
+ motionTarget = { x: 0, y: 0 };
2941
+ smoothedOutput = { x: 0, y: 0 };
2942
+ usingMotionInput = !1;
2943
+ motionListenerAttached = !1;
2944
+ motionRequested = !1;
2945
+ touchActive = !1;
2946
+ touchAnchorX = 0;
2947
+ touchAnchorY = 0;
2948
+ lerpFactor;
2949
+ motionLerpFactor;
2950
+ static TOUCH_DRAG_RANGE = 100;
2951
+ update() {
2952
+ const t = this.touchActive ? this.pointerTarget : this.usingMotionInput ? this.motionTarget : this.pointerTarget, e = this.usingMotionInput && !this.touchActive ? this.motionLerpFactor : this.lerpFactor;
2953
+ return this.smoothedOutput.x = nt(this.smoothedOutput.x, t.x, e), this.smoothedOutput.y = nt(this.smoothedOutput.y, t.y, e), this.smoothedOutput;
2954
+ }
2955
+ dispose() {
2956
+ this.host.removeEventListener("mousemove", this.handleMouseMove), this.host.removeEventListener("mouseleave", this.resetPointerTarget), this.host.removeEventListener("touchstart", this.handleTouchStart), this.host.removeEventListener("touchmove", this.handleTouchMove), this.host.removeEventListener("touchend", this.handleTouchEnd), this.host.removeEventListener("touchcancel", this.handleTouchEnd), this.motionListenerAttached && (window.removeEventListener("deviceorientation", this.handleDeviceOrientation), this.motionListenerAttached = !1);
2957
+ }
2958
+ handleMouseMove = (t) => {
2959
+ const e = this.host.getBoundingClientRect(), i = (t.clientX - e.left) / e.width * 2 - 1, r = (t.clientY - e.top) / e.height * 2 - 1;
2960
+ this.pointerTarget.x = W(i, -1, 1), this.pointerTarget.y = W(r, -1, 1);
2961
+ };
2962
+ resetPointerTarget = () => {
2963
+ this.pointerTarget.x = 0, this.pointerTarget.y = 0;
2964
+ };
2965
+ handleTouchStart = (t) => {
2966
+ const e = t.touches[0];
2967
+ e && (this.touchActive = !0, this.touchAnchorX = e.clientX, this.touchAnchorY = e.clientY, this.pointerTarget.x = 0, this.pointerTarget.y = 0, this.motionRequested || (this.motionRequested = !0, this.requestMotionPermission()));
2968
+ };
2969
+ handleTouchMove = (t) => {
2970
+ const e = t.touches[0];
2971
+ if (!e) return;
2972
+ const i = e.clientX - this.touchAnchorX, r = e.clientY - this.touchAnchorY, o = dt.TOUCH_DRAG_RANGE;
2973
+ this.pointerTarget.x = W(i / o, -1, 1), this.pointerTarget.y = W(r / o, -1, 1);
2974
+ };
2975
+ handleTouchEnd = () => {
2976
+ this.touchActive = !1, this.pointerTarget.x = 0, this.pointerTarget.y = 0;
2977
+ };
2978
+ async requestMotionPermission() {
2979
+ if (typeof DeviceOrientationEvent > "u") return;
2980
+ const t = DeviceOrientationEvent;
2981
+ if (typeof t.requestPermission == "function")
2982
+ try {
2983
+ if (await t.requestPermission() !== "granted") return;
2984
+ } catch {
2985
+ return;
2986
+ }
2987
+ this.motionListenerAttached || (window.addEventListener("deviceorientation", this.handleDeviceOrientation), this.motionListenerAttached = !0), this.usingMotionInput = !0;
2988
+ }
2989
+ handleDeviceOrientation = (t) => {
2990
+ const e = W((t.gamma ?? 0) / 45, -1, 1), i = W((t.beta ?? 0) / 45, -1, 1);
2991
+ this.motionTarget.x = nt(this.motionTarget.x, e, this.motionLerpFactor), this.motionTarget.y = nt(this.motionTarget.y, i, this.motionLerpFactor);
2992
+ };
2993
+ }
2994
+ class lt extends HTMLElement {
2995
+ static TAG_NAME = "layershift-portal";
2996
+ static get observedAttributes() {
2997
+ return [
2998
+ "src",
2999
+ "depth-src",
3000
+ "depth-meta",
3001
+ "logo-src",
3002
+ "parallax-x",
3003
+ "parallax-y",
3004
+ "parallax-max",
3005
+ "overscan",
3006
+ "pom-steps",
3007
+ "rim-intensity",
3008
+ "rim-color",
3009
+ "rim-width",
3010
+ "refraction-strength",
3011
+ "chromatic-strength",
3012
+ "occlusion-intensity",
3013
+ "depth-power",
3014
+ "depth-scale",
3015
+ "depth-bias",
3016
+ "fog-density",
3017
+ "fog-color",
3018
+ "color-shift",
3019
+ "brightness-bias",
3020
+ "contrast-low",
3021
+ "contrast-high",
3022
+ "vertical-reduction",
3023
+ "dof-start",
3024
+ "dof-strength",
3025
+ "bevel-intensity",
3026
+ "bevel-width",
3027
+ "bevel-darkening",
3028
+ "bevel-desaturation",
3029
+ "bevel-light-angle",
3030
+ "edge-thickness",
3031
+ "edge-specular",
3032
+ "edge-color",
3033
+ "chamfer-width",
3034
+ "chamfer-angle",
3035
+ "chamfer-color",
3036
+ "chamfer-ambient",
3037
+ "chamfer-specular",
3038
+ "chamfer-shininess",
3039
+ "edge-occlusion-width",
3040
+ "edge-occlusion-strength",
3041
+ "light-direction",
3042
+ "autoplay",
3043
+ "loop",
3044
+ "muted"
3045
+ ];
3046
+ }
3047
+ shadow;
3048
+ container = null;
3049
+ renderer = null;
3050
+ inputHandler = null;
3051
+ depthWorker = null;
3052
+ video = null;
3053
+ mesh = null;
3054
+ initialized = !1;
3055
+ abortController = null;
3056
+ loopCount = 0;
3057
+ constructor() {
3058
+ super(), this.shadow = this.attachShadow({ mode: "open" });
3059
+ }
3060
+ // --- Attribute helpers ---
3061
+ getAttrFloat(t, e) {
3062
+ const i = this.getAttribute(t);
3063
+ if (i === null) return e;
3064
+ const r = parseFloat(i);
3065
+ return Number.isFinite(r) ? r : e;
3066
+ }
3067
+ getAttrBool(t, e) {
3068
+ if (!this.hasAttribute(t)) return e;
3069
+ const i = this.getAttribute(t);
3070
+ return !(i === "false" || i === "0");
3071
+ }
3072
+ getAttrColor(t, e) {
3073
+ const i = this.getAttribute(t) ?? e;
3074
+ return Xe(i);
3075
+ }
3076
+ getAttrVec3(t, e) {
3077
+ const r = (this.getAttribute(t) ?? e).split(",").map((s) => parseFloat(s.trim()));
3078
+ if (r.length >= 3 && r.every(Number.isFinite))
3079
+ return [r[0], r[1], r[2]];
3080
+ const o = e.split(",").map((s) => parseFloat(s.trim()));
3081
+ return [o[0], o[1], o[2]];
3082
+ }
3083
+ get parallaxX() {
3084
+ return this.getAttrFloat("parallax-x", A.parallaxX);
3085
+ }
3086
+ get parallaxY() {
3087
+ return this.getAttrFloat("parallax-y", A.parallaxY);
3088
+ }
3089
+ get parallaxMax() {
3090
+ return this.getAttrFloat("parallax-max", A.parallaxMax);
3091
+ }
3092
+ get overscan() {
3093
+ return this.getAttrFloat("overscan", A.overscan);
3094
+ }
3095
+ get pomSteps() {
3096
+ return this.getAttrFloat("pom-steps", A.pomSteps);
3097
+ }
3098
+ // Boundary
3099
+ get rimIntensity() {
3100
+ return this.getAttrFloat("rim-intensity", A.rimIntensity);
3101
+ }
3102
+ get rimWidth() {
3103
+ return this.getAttrFloat("rim-width", A.rimWidth);
3104
+ }
3105
+ get rimColor() {
3106
+ return this.getAttrColor("rim-color", A.rimColor);
3107
+ }
3108
+ get refractionStrength() {
3109
+ return this.getAttrFloat("refraction-strength", A.refractionStrength);
3110
+ }
3111
+ get chromaticStrength() {
3112
+ return this.getAttrFloat("chromatic-strength", A.chromaticStrength);
3113
+ }
3114
+ get occlusionIntensity() {
3115
+ return this.getAttrFloat("occlusion-intensity", A.occlusionIntensity);
3116
+ }
3117
+ // Lens transform
3118
+ get depthPower() {
3119
+ return this.getAttrFloat("depth-power", A.depthPower);
3120
+ }
3121
+ get depthScale() {
3122
+ return this.getAttrFloat("depth-scale", A.depthScale);
3123
+ }
3124
+ get depthBias() {
3125
+ return this.getAttrFloat("depth-bias", A.depthBias);
3126
+ }
3127
+ // Interior mood
3128
+ get fogDensity() {
3129
+ return this.getAttrFloat("fog-density", A.fogDensity);
3130
+ }
3131
+ get fogColor() {
3132
+ return this.getAttrColor("fog-color", A.fogColor);
3133
+ }
3134
+ get colorShift() {
3135
+ return this.getAttrFloat("color-shift", A.colorShift);
3136
+ }
3137
+ get brightnessBias() {
3138
+ return this.getAttrFloat("brightness-bias", A.brightnessBias);
3139
+ }
3140
+ // Depth-adaptive
3141
+ get contrastLow() {
3142
+ return this.getAttrFloat("contrast-low", A.contrastLow);
3143
+ }
3144
+ get contrastHigh() {
3145
+ return this.getAttrFloat("contrast-high", A.contrastHigh);
3146
+ }
3147
+ get verticalReduction() {
3148
+ return this.getAttrFloat("vertical-reduction", A.verticalReduction);
3149
+ }
3150
+ get dofStart() {
3151
+ return this.getAttrFloat("dof-start", A.dofStart);
3152
+ }
3153
+ get dofStrength() {
3154
+ return this.getAttrFloat("dof-strength", A.dofStrength);
3155
+ }
3156
+ // Bevel / dimensional typography
3157
+ get bevelIntensity() {
3158
+ return this.getAttrFloat("bevel-intensity", A.bevelIntensity);
3159
+ }
3160
+ get bevelWidth() {
3161
+ return this.getAttrFloat("bevel-width", A.bevelWidth);
3162
+ }
3163
+ get bevelDarkening() {
3164
+ return this.getAttrFloat("bevel-darkening", A.bevelDarkening);
3165
+ }
3166
+ get bevelDesaturation() {
3167
+ return this.getAttrFloat("bevel-desaturation", A.bevelDesaturation);
3168
+ }
3169
+ get bevelLightAngle() {
3170
+ return this.getAttrFloat("bevel-light-angle", A.bevelLightAngle);
3171
+ }
3172
+ // Volumetric edge wall
3173
+ get edgeThickness() {
3174
+ return this.getAttrFloat("edge-thickness", A.edgeThickness);
3175
+ }
3176
+ get edgeSpecular() {
3177
+ return this.getAttrFloat("edge-specular", A.edgeSpecular);
3178
+ }
3179
+ get edgeColor() {
3180
+ return this.getAttrColor("edge-color", A.edgeColor);
3181
+ }
3182
+ // Chamfer geometry
3183
+ get chamferWidth() {
3184
+ return this.getAttrFloat("chamfer-width", A.chamferWidth);
3185
+ }
3186
+ get chamferAngle() {
3187
+ return this.getAttrFloat("chamfer-angle", A.chamferAngle);
3188
+ }
3189
+ get chamferColor() {
3190
+ return this.getAttrColor("chamfer-color", A.chamferColor);
3191
+ }
3192
+ get chamferAmbient() {
3193
+ return this.getAttrFloat("chamfer-ambient", A.chamferAmbient);
3194
+ }
3195
+ get chamferSpecular() {
3196
+ return this.getAttrFloat("chamfer-specular", A.chamferSpecular);
3197
+ }
3198
+ get chamferShininess() {
3199
+ return this.getAttrFloat("chamfer-shininess", A.chamferShininess);
3200
+ }
3201
+ // Edge occlusion
3202
+ get edgeOcclusionWidth() {
3203
+ return this.getAttrFloat("edge-occlusion-width", A.edgeOcclusionWidth);
3204
+ }
3205
+ get edgeOcclusionStrength() {
3206
+ return this.getAttrFloat("edge-occlusion-strength", A.edgeOcclusionStrength);
3207
+ }
3208
+ get lightDirection3() {
3209
+ return this.getAttrVec3("light-direction", A.lightDirection);
3210
+ }
3211
+ get shouldAutoplay() {
3212
+ return this.getAttrBool("autoplay", A.autoplay);
3213
+ }
3214
+ get shouldLoop() {
3215
+ return this.getAttrBool("loop", A.loop);
3216
+ }
3217
+ get shouldMute() {
3218
+ return this.getAttrBool("muted", A.muted);
3219
+ }
3220
+ // --- Event dispatching ---
3221
+ emit(t, e) {
3222
+ this.dispatchEvent(
3223
+ new CustomEvent(t, {
3224
+ detail: e,
3225
+ bubbles: !0,
3226
+ composed: !0
3227
+ })
3228
+ );
3229
+ }
3230
+ attachVideoEventListeners(t) {
3231
+ t.addEventListener("play", () => {
3232
+ this.emit("layershift-portal:play", {
3233
+ currentTime: t.currentTime
3234
+ });
3235
+ }), t.addEventListener("pause", () => {
3236
+ this.emit("layershift-portal:pause", {
3237
+ currentTime: t.currentTime
3238
+ });
3239
+ }), t.addEventListener("ended", () => {
3240
+ t.loop && (this.loopCount += 1, this.emit("layershift-portal:loop", {
3241
+ loopCount: this.loopCount
3242
+ }));
3243
+ });
3244
+ }
3245
+ // --- Lifecycle ---
3246
+ connectedCallback() {
3247
+ this.setupShadowDOM(), this.init();
3248
+ }
3249
+ disconnectedCallback() {
3250
+ this.dispose();
3251
+ }
3252
+ attributeChangedCallback(t, e, i) {
3253
+ ["src", "depth-src", "depth-meta", "logo-src"].includes(t) && (this.initialized ? (this.dispose(), this.setupShadowDOM(), this.init()) : this.isConnected && this.getAttribute("src") && this.getAttribute("depth-src") && this.getAttribute("depth-meta") && this.getAttribute("logo-src") && this.init());
3254
+ }
3255
+ // --- Shadow DOM ---
3256
+ setupShadowDOM() {
3257
+ this.shadow.innerHTML = "";
3258
+ const t = document.createElement("style");
3259
+ t.textContent = `
3260
+ :host {
3261
+ display: block;
3262
+ width: 100%;
3263
+ height: 100%;
3264
+ position: relative;
3265
+ overflow: hidden;
3266
+ background: transparent;
3267
+ }
3268
+ .container {
3269
+ width: 100%;
3270
+ height: 100%;
3271
+ position: absolute;
3272
+ inset: 0;
3273
+ }
3274
+ canvas {
3275
+ display: block;
3276
+ width: 100%;
3277
+ height: 100%;
3278
+ }
3279
+ `, this.shadow.appendChild(t), this.container = document.createElement("div"), this.container.className = "container", this.shadow.appendChild(this.container);
3280
+ }
3281
+ // --- Initialization ---
3282
+ async init() {
3283
+ const t = this.getAttribute("src"), e = this.getAttribute("depth-src"), i = this.getAttribute("depth-meta"), r = this.getAttribute("logo-src");
3284
+ if (!t || !e || !i || !r) {
3285
+ const o = "src, depth-src, depth-meta, and logo-src attributes are required.";
3286
+ console.warn(`<layershift-portal>: ${o}`), this.emit("layershift-portal:error", { message: o });
3287
+ return;
3288
+ }
3289
+ if (this.container) {
3290
+ this.abortController = new AbortController();
3291
+ try {
3292
+ const [o, s, a] = await Promise.all([
3293
+ this.createVideoElement(t),
3294
+ At(e, i),
3295
+ me(r)
3296
+ ]);
3297
+ if (this.abortController.signal.aborted) {
3298
+ o.remove();
3299
+ return;
3300
+ }
3301
+ this.video = o, this.mesh = a, this.loopCount = 0, this.attachVideoEventListeners(o);
3302
+ const h = this.parallaxMax / Math.max(o.videoWidth, 1);
3303
+ let l;
3304
+ try {
3305
+ const d = await st.create(
3306
+ s,
3307
+ s.meta.width,
3308
+ s.meta.height
3309
+ );
3310
+ this.depthWorker = d, l = (m) => d.sample(m);
3311
+ } catch {
3312
+ const d = new bt(
3313
+ s,
3314
+ s.meta.width,
3315
+ s.meta.height
3316
+ );
3317
+ l = (m) => d.sample(m);
3318
+ }
3319
+ if (this.abortController.signal.aborted) {
3320
+ o.remove(), this.depthWorker?.dispose(), this.depthWorker = null;
3321
+ return;
3322
+ }
3323
+ const u = {
3324
+ parallaxStrength: h,
3325
+ overscanPadding: this.overscan,
3326
+ pomSteps: this.pomSteps,
3327
+ // Boundary
3328
+ rimLightIntensity: this.rimIntensity,
3329
+ rimLightColor: this.rimColor,
3330
+ rimLightWidth: this.rimWidth,
3331
+ refractionStrength: this.refractionStrength,
3332
+ chromaticStrength: this.chromaticStrength,
3333
+ occlusionIntensity: this.occlusionIntensity,
3334
+ // Lens transform
3335
+ depthPower: this.depthPower,
3336
+ depthScale: this.depthScale,
3337
+ depthBias: this.depthBias,
3338
+ // Interior mood
3339
+ fogDensity: this.fogDensity,
3340
+ fogColor: this.fogColor,
3341
+ colorShift: this.colorShift,
3342
+ brightnessBias: this.brightnessBias,
3343
+ // Depth-adaptive
3344
+ contrastLow: this.contrastLow,
3345
+ contrastHigh: this.contrastHigh,
3346
+ verticalReduction: this.verticalReduction,
3347
+ dofStart: this.dofStart,
3348
+ dofStrength: this.dofStrength,
3349
+ // Bevel / dimensional typography
3350
+ bevelIntensity: this.bevelIntensity,
3351
+ bevelWidth: this.bevelWidth,
3352
+ bevelDarkening: this.bevelDarkening,
3353
+ bevelDesaturation: this.bevelDesaturation,
3354
+ bevelLightAngle: this.bevelLightAngle,
3355
+ // Volumetric edge wall
3356
+ edgeThickness: this.edgeThickness,
3357
+ edgeSpecular: this.edgeSpecular,
3358
+ edgeColor: this.edgeColor,
3359
+ // Chamfer geometry
3360
+ chamferWidth: this.chamferWidth,
3361
+ chamferAngle: this.chamferAngle,
3362
+ chamferColor: this.chamferColor,
3363
+ chamferAmbient: this.chamferAmbient,
3364
+ chamferSpecular: this.chamferSpecular,
3365
+ chamferShininess: this.chamferShininess,
3366
+ // Edge occlusion
3367
+ edgeOcclusionWidth: this.edgeOcclusionWidth,
3368
+ edgeOcclusionStrength: this.edgeOcclusionStrength,
3369
+ lightDirection: this.lightDirection3
3370
+ };
3371
+ this.renderer = new ft(this.container, u), this.renderer.initialize(o, s.meta.width, s.meta.height, a), this.inputHandler = new dt(this);
3372
+ const f = this.parallaxX, c = this.parallaxY;
3373
+ if (this.renderer.start(
3374
+ o,
3375
+ l,
3376
+ () => {
3377
+ const d = this.inputHandler.update();
3378
+ return { x: d.x * f, y: d.y * c };
3379
+ },
3380
+ (d, m) => {
3381
+ this.emit("layershift-portal:frame", {
3382
+ currentTime: d,
3383
+ frameNumber: m
3384
+ });
3385
+ }
3386
+ ), this.shouldAutoplay) {
3387
+ o.currentTime = 0;
3388
+ try {
3389
+ await o.play();
3390
+ } catch {
3391
+ }
3392
+ }
3393
+ this.initialized = !0, this.emit("layershift-portal:ready", {
3394
+ videoWidth: o.videoWidth,
3395
+ videoHeight: o.videoHeight,
3396
+ duration: o.duration
3397
+ });
3398
+ } catch (o) {
3399
+ const s = o instanceof Error ? o.message : "Failed to initialize.";
3400
+ console.error("<layershift-portal>: Failed to initialize.", o), this.emit("layershift-portal:error", { message: s });
3401
+ }
3402
+ }
3403
+ }
3404
+ // --- Video element ---
3405
+ async createVideoElement(t) {
3406
+ const e = document.createElement("video");
3407
+ return e.crossOrigin = "anonymous", e.setAttribute("crossorigin", "anonymous"), e.playsInline = !0, e.setAttribute("playsinline", ""), e.setAttribute("webkit-playsinline", "true"), e.muted = this.shouldMute, e.defaultMuted = this.shouldMute, this.shouldMute && e.setAttribute("muted", ""), e.loop = this.shouldLoop, e.preload = "auto", e.style.display = "none", e.src = t, this.shadow.appendChild(e), await new Promise((i, r) => {
3408
+ if (e.readyState >= HTMLMediaElement.HAVE_METADATA) {
3409
+ i();
3410
+ return;
3411
+ }
3412
+ const o = () => {
3413
+ a(), i();
3414
+ }, s = () => {
3415
+ a(), r(new Error("Failed to load video metadata."));
3416
+ }, a = () => {
3417
+ e.removeEventListener("loadedmetadata", o), e.removeEventListener("error", s);
3418
+ };
3419
+ e.addEventListener("loadedmetadata", o), e.addEventListener("error", s), e.load();
3420
+ }), e;
3421
+ }
3422
+ // --- Cleanup ---
3423
+ dispose() {
3424
+ this.abortController?.abort(), this.abortController = null, this.renderer?.dispose(), this.renderer = null, this.inputHandler?.dispose(), this.inputHandler = null, this.depthWorker?.dispose(), this.depthWorker = null, this.video && (this.video.pause(), this.video.removeAttribute("src"), this.video.load(), this.video.remove(), this.video = null), this.mesh = null, this.initialized = !1, this.loopCount = 0, this.container = null;
3425
+ }
3426
+ }
3427
+ function W(n, t, e) {
3428
+ return Math.min(e, Math.max(t, n));
3429
+ }
3430
+ function nt(n, t, e) {
3431
+ return n + (t - n) * e;
3432
+ }
3433
+ function Xe(n) {
3434
+ const t = n.replace("#", "");
3435
+ if (t.length === 3) {
3436
+ const e = parseInt(t[0] + t[0], 16) / 255, i = parseInt(t[1] + t[1], 16) / 255, r = parseInt(t[2] + t[2], 16) / 255;
3437
+ return [e, i, r];
3438
+ }
3439
+ if (t.length === 6) {
3440
+ const e = parseInt(t.substring(0, 2), 16) / 255, i = parseInt(t.substring(2, 4), 16) / 255, r = parseInt(t.substring(4, 6), 16) / 255;
3441
+ return [e, i, r];
3442
+ }
3443
+ return [0, 0, 0];
1189
3444
  }
1190
- customElements.get(C.TAG_NAME) || customElements.define(C.TAG_NAME, C);
3445
+ customElements.get(ht.TAG_NAME) || customElements.define(ht.TAG_NAME, ht);
3446
+ customElements.get(lt.TAG_NAME) || customElements.define(lt.TAG_NAME, lt);
1191
3447
  export {
1192
- C as LayershiftElement
3448
+ ht as LayershiftElement,
3449
+ lt as LayershiftPortalElement
1193
3450
  };