@mirage-engine/core 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @mirage-engine/core
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 4b9e1b0: shader hooks pipeline
8
+ - Updated dependencies [4b9e1b0]
9
+ - @mirage-engine/painter@0.4.0
10
+
3
11
  ## 0.2.0
4
12
 
5
13
  ### Minor Changes
@@ -1,55 +1,55 @@
1
- var A = Object.defineProperty;
2
- var P = (i, e, t) => e in i ? A(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
3
- var h = (i, e, t) => (P(i, typeof e != "symbol" ? e + "" : e, t), t);
1
+ var k = Object.defineProperty;
2
+ var q = (s, e, t) => e in s ? k(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var h = (s, e, t) => (q(s, typeof e != "symbol" ? e + "" : e, t), t);
4
4
  import * as d from "three";
5
- const E = 0, O = 1, D = 2, k = 4, z = 8, N = 16, x = 1, R = 2, Z = 0, q = [
5
+ const S = 0, z = 1, L = 2, Y = 4, I = 8, _ = 16, x = 1, w = 2, ee = 0, W = [
6
6
  "include-tree",
7
7
  "exclude-tree",
8
8
  "include-self",
9
9
  "exclude-self",
10
10
  "end"
11
11
  ];
12
- function Y(i, e, t) {
12
+ function U(s, e, t) {
13
13
  const r = e.split(`
14
- `), s = [];
14
+ `), i = [];
15
15
  return r.forEach((a) => {
16
16
  const n = a.split(" ");
17
17
  let o = n[0];
18
18
  for (let l = 1; l < n.length; l++) {
19
19
  const c = n[l];
20
- i.measureText(o + " " + c).width < t ? o += " " + c : (s.push(o), o = c);
20
+ s.measureText(o + " " + c).width < t ? o += " " + c : (i.push(o), o = c);
21
21
  }
22
- s.push(o);
23
- }), s;
22
+ i.push(o);
23
+ }), i;
24
24
  }
25
- function I(i, e, t, r, s = 2) {
25
+ function N(s, e, t, r, i = 2) {
26
26
  const a = document.createElement("canvas"), n = a.getContext("2d");
27
27
  if (!n)
28
28
  throw new Error("[Mirage] Failed to create canvas context");
29
- const l = (window.devicePixelRatio || 1) * s;
29
+ const l = (window.devicePixelRatio || 1) * i;
30
30
  a.width = t * l, a.height = r * l, n.scale(l, l), n.font = e.font, n.fillStyle = e.color, n.textBaseline = "top", n.globalAlpha = 1;
31
- const c = Y(n, i, t), g = e.lineHeight;
32
- c.forEach((p, m) => {
33
- const T = m * g + 2;
31
+ const c = U(n, s, t), m = e.lineHeight;
32
+ c.forEach((g, p) => {
33
+ const y = p * m + 2;
34
34
  let v = 0;
35
- e.textAlign === "center" ? v = t / 2 : e.textAlign === "right" && (v = t), n.textAlign = e.textAlign, n.fillText(p, v, T);
35
+ e.textAlign === "center" ? v = t / 2 : e.textAlign === "right" && (v = t), n.textAlign = e.textAlign, n.fillText(g, v, y);
36
36
  });
37
- const u = new d.CanvasTexture(a);
38
- return u.colorSpace = d.SRGBColorSpace, u.minFilter = d.LinearFilter, u.magFilter = d.LinearFilter, u.needsUpdate = !0, u;
37
+ const f = new d.CanvasTexture(a);
38
+ return f.colorSpace = d.SRGBColorSpace, f.minFilter = d.LinearFilter, f.magFilter = d.LinearFilter, f.needsUpdate = !0, f;
39
39
  }
40
- function w(i) {
41
- return typeof i == "number" ? i : parseFloat(i) || 0;
40
+ function R(s) {
41
+ return typeof s == "number" ? s : parseFloat(s) || 0;
42
42
  }
43
- function _(i, e) {
44
- var o, l, c, g;
43
+ function X(s, e) {
44
+ var o, l, c, m;
45
45
  if (!e) {
46
- i.set(0, 0, 0, 0);
46
+ s.set(0, 0, 0, 0);
47
47
  return;
48
48
  }
49
- const t = e.split("/")[0].trim().split(/\s+/), r = w(t[0]), s = w((o = t[1]) != null ? o : t[0]), a = w((l = t[2]) != null ? l : t[0]), n = w((g = (c = t[3]) != null ? c : t[1]) != null ? g : t[0]);
50
- i.set(r, s, a, n);
49
+ const t = e.split("/")[0].trim().split(/\s+/), r = R(t[0]), i = R((o = t[1]) != null ? o : t[0]), a = R((l = t[2]) != null ? l : t[0]), n = R((m = (c = t[3]) != null ? c : t[1]) != null ? m : t[0]);
50
+ s.set(r, i, a, n);
51
51
  }
52
- const U = (
52
+ const H = (
53
53
  /* glsl */
54
54
  `
55
55
  varying vec2 vUv;
@@ -60,7 +60,7 @@ const U = (
60
60
  vScreenPos = gl_Position;
61
61
  }
62
62
  `
63
- ), W = (
63
+ ), $ = (
64
64
  /* glsl */
65
65
  `
66
66
 
@@ -130,19 +130,19 @@ const U = (
130
130
  }
131
131
  `
132
132
  );
133
- function S(i) {
134
- if (!i || i === "transparent")
133
+ function E(s) {
134
+ if (!s || s === "transparent")
135
135
  return { color: new d.Color(16777215), alpha: 0 };
136
- const e = i.match(
136
+ const e = s.match(
137
137
  /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
138
138
  );
139
139
  if (e) {
140
- const t = parseInt(e[1], 10), r = parseInt(e[2], 10), s = parseInt(e[3], 10), a = e[4] !== void 0 ? parseFloat(e[4]) : 1;
141
- return { color: new d.Color(`rgb(${t}, ${r}, ${s})`), alpha: a };
140
+ const t = parseInt(e[1], 10), r = parseInt(e[2], 10), i = parseInt(e[3], 10), a = e[4] !== void 0 ? parseFloat(e[4]) : 1;
141
+ return { color: new d.Color(`rgb(${t}, ${r}, ${i})`), alpha: a };
142
142
  }
143
- return { color: new d.Color(i), alpha: 1 };
143
+ return { color: new d.Color(s), alpha: 1 };
144
144
  }
145
- function H(i, e, t, r = null, s) {
145
+ function G(s, e, t, r = null, i) {
146
146
  var v;
147
147
  const a = r !== null, n = a ? (
148
148
  /* glsl */
@@ -155,52 +155,52 @@ function H(i, e, t, r = null, s) {
155
155
  `
156
156
  vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
157
157
  vec2 resultUv = screenUv;
158
- ${(s == null ? void 0 : s.uvModifier) || ""}
158
+ ${(i == null ? void 0 : i.uvModifier) || ""}
159
159
  `
160
160
  ) : "", l = a ? (
161
161
  /* glsl */
162
162
  `
163
163
  baseColor = texture2D(uTexture, resultUv);
164
164
  `
165
- ) : "", c = (s == null ? void 0 : s.colorModifier) || "", g = W.replace("#INJECT_DECLARATIONS", n).replace("#INJECT_UV_MODIFIER", o).replace("#INJECT_BASE_COLOR", l).replace("#INJECT_COLOR_MODIFIER", c), u = S(i.backgroundColor), p = S(i.borderColor), m = {
165
+ ) : "", c = (i == null ? void 0 : i.colorModifier) || "", m = $.replace("#INJECT_DECLARATIONS", n).replace("#INJECT_UV_MODIFIER", o).replace("#INJECT_BASE_COLOR", l).replace("#INJECT_COLOR_MODIFIER", c), f = E(s.backgroundColor), g = E(s.borderColor), p = {
166
166
  uSize: { value: new d.Vector2(e, t) },
167
167
  uBorderRadius: { value: new d.Vector4(0, 0, 0, 0) },
168
- uBorderWidth: { value: w(i.borderWidth) },
169
- uBgColor: { value: u.color },
170
- uBorderColor: { value: p.color },
171
- uOpacity: { value: (v = i.opacity) != null ? v : 1 },
172
- uBgOpacity: { value: u.alpha },
173
- uBorderOpacity: { value: p.alpha },
168
+ uBorderWidth: { value: R(s.borderWidth) },
169
+ uBgColor: { value: f.color },
170
+ uBorderColor: { value: g.color },
171
+ uOpacity: { value: (v = s.opacity) != null ? v : 1 },
172
+ uBgOpacity: { value: f.alpha },
173
+ uBorderOpacity: { value: g.alpha },
174
174
  uTexture: { value: null }
175
175
  };
176
- return _(m.uBorderRadius.value, i.borderRadius), a && (m.uTexture.value = r), new d.ShaderMaterial({
177
- uniforms: m,
178
- vertexShader: U,
179
- fragmentShader: g,
176
+ return X(p.uBorderRadius.value, s.borderRadius), a && (p.uTexture.value = r), new d.ShaderMaterial({
177
+ uniforms: p,
178
+ vertexShader: H,
179
+ fragmentShader: m,
180
180
  transparent: !0,
181
181
  side: d.FrontSide
182
182
  // for better performance
183
183
  });
184
184
  }
185
- function $(i, e, t, r, s) {
185
+ function J(s, e, t, r, i) {
186
186
  var o;
187
- const a = S(e.backgroundColor), n = S(e.borderColor);
188
- i.uniforms.uSize.value.set(t, r), _(i.uniforms.uBorderRadius.value, e.borderRadius), i.uniforms.uBorderWidth.value = w(e.borderWidth), i.uniforms.uBgColor.value.copy(a.color), i.uniforms.uBorderColor.value.copy(n.color), i.uniforms.uOpacity.value = (o = e.opacity) != null ? o : 1, i.uniforms.uBgOpacity.value = a.alpha, i.uniforms.uBorderOpacity.value = n.alpha, i.uniforms.uTexture && s !== void 0 && (i.uniforms.uTexture.value = s);
187
+ const a = E(e.backgroundColor), n = E(e.borderColor);
188
+ s.uniforms.uSize.value.set(t, r), X(s.uniforms.uBorderRadius.value, e.borderRadius), s.uniforms.uBorderWidth.value = R(e.borderWidth), s.uniforms.uBgColor.value.copy(a.color), s.uniforms.uBorderColor.value.copy(n.color), s.uniforms.uOpacity.value = (o = e.opacity) != null ? o : 1, s.uniforms.uBgOpacity.value = a.alpha, s.uniforms.uBorderOpacity.value = n.alpha, s.uniforms.uTexture && i !== void 0 && (s.uniforms.uTexture.value = i);
189
189
  }
190
- const F = {
191
- create(i, e, t, r, s, a = 2, n = null) {
192
- if (i === "BOX")
193
- return H(e, r, s, n);
194
- if (i === "TEXT") {
195
- const o = I(
190
+ const D = {
191
+ create(s, e, t, r, i, a = 2, n = null, o) {
192
+ if (s === "BOX")
193
+ return G(e, r, i, n, o);
194
+ if (s === "TEXT") {
195
+ const l = N(
196
196
  t || "",
197
197
  e,
198
198
  r,
199
- s,
199
+ i,
200
200
  a
201
201
  );
202
202
  return new d.MeshBasicMaterial({
203
- map: o,
203
+ map: l,
204
204
  transparent: !0,
205
205
  side: d.FrontSide,
206
206
  color: 16777215
@@ -208,22 +208,22 @@ const F = {
208
208
  }
209
209
  return new d.MeshBasicMaterial({ visible: !1 });
210
210
  },
211
- update(i, e, t, r, s, a, n = 2, o) {
211
+ update(s, e, t, r, i, a, n = 2, o) {
212
212
  if (e === "BOX")
213
- $(
214
- i,
215
- t,
213
+ J(
216
214
  s,
215
+ t,
216
+ i,
217
217
  a,
218
218
  o
219
219
  );
220
220
  else if (e === "TEXT") {
221
- const l = i;
221
+ const l = s;
222
222
  l.map && l.map.dispose();
223
- const c = I(
223
+ const c = N(
224
224
  r || "",
225
225
  t,
226
- s,
226
+ i,
227
227
  a,
228
228
  n
229
229
  );
@@ -231,7 +231,7 @@ const F = {
231
231
  }
232
232
  }
233
233
  };
234
- class G {
234
+ class V {
235
235
  constructor(e, t, r) {
236
236
  h(this, "canvas");
237
237
  h(this, "scene");
@@ -241,16 +241,17 @@ class G {
241
241
  h(this, "renderOrder", 0);
242
242
  h(this, "qualityFactor", 2);
243
243
  h(this, "mode", "overlay");
244
+ h(this, "clipArea", 1);
244
245
  h(this, "target");
245
246
  h(this, "mountContainer");
246
247
  h(this, "targetRect");
247
248
  h(this, "meshMap", /* @__PURE__ */ new Map());
248
- var n, o;
249
- this.target = e, this.mountContainer = r, this.mode = (n = t.mode) != null ? n : "overlay", this.canvas = document.createElement("canvas"), this.scene = new d.Scene(), this.targetRect = this.target.getBoundingClientRect();
250
- const s = this.targetRect.width, a = this.targetRect.height;
249
+ var n, o, l;
250
+ this.target = e, this.mountContainer = r, this.mode = (n = t.mode) != null ? n : "overlay", this.clipArea = (o = t.travelerClipArea) != null ? o : 1, this.canvas = document.createElement("canvas"), this.scene = new d.Scene(), this.targetRect = this.target.getBoundingClientRect();
251
+ const i = this.targetRect.width, a = this.targetRect.height;
251
252
  this.camera = new d.OrthographicCamera(
252
- s / -2,
253
- s / 2,
253
+ i / -2,
254
+ i / 2,
254
255
  a / 2,
255
256
  a / -2,
256
257
  1,
@@ -261,7 +262,7 @@ class G {
261
262
  antialias: !0
262
263
  // [new]
263
264
  // premultipliedAlpha: true
264
- }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(s, a), this.applyTextQuality((o = t.quality) != null ? o : "medium");
265
+ }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(i, a), this.applyTextQuality((l = t.quality) != null ? l : "medium");
265
266
  }
266
267
  createRenderTarget() {
267
268
  this.renderTarget = new d.WebGLRenderTarget(
@@ -311,28 +312,29 @@ class G {
311
312
  ), this.camera.left = e / -2, this.camera.right = e / 2, this.camera.top = t / 2, this.camera.bottom = t / -2, this.camera.updateProjectionMatrix();
312
313
  }
313
314
  syncScene(e) {
314
- const t = this.target.getBoundingClientRect(), r = Math.abs(t.width - this.targetRect.width) > 0.1 || Math.abs(t.height - this.targetRect.height) > 0.1, s = this.mode === "overlay" && (Math.abs(t.top - this.targetRect.top) > 0.1 || Math.abs(t.left - this.targetRect.left) > 0.1);
315
- r ? (this.targetRect = t, this.setSize(this.targetRect.width, this.targetRect.height), this.updateCanvasLayout()) : s ? (this.targetRect = t, this.updateCanvasLayout()) : this.targetRect = t, this.renderOrder = 0;
315
+ const t = this.target.getBoundingClientRect(), r = Math.abs(t.width - this.targetRect.width) > 0.1 || Math.abs(t.height - this.targetRect.height) > 0.1, i = this.mode === "overlay" && (Math.abs(t.top - this.targetRect.top) > 0.1 || Math.abs(t.left - this.targetRect.left) > 0.1);
316
+ r ? (this.targetRect = t, this.setSize(this.targetRect.width, this.targetRect.height), this.updateCanvasLayout()) : i ? (this.targetRect = t, this.updateCanvasLayout()) : this.targetRect = t, this.renderOrder = 0;
316
317
  const a = /* @__PURE__ */ new Set();
317
318
  this.reconcileNode(e, a);
318
319
  for (const [n, o] of this.meshMap.entries())
319
320
  a.has(n) || (this.scene.remove(o), o.geometry.dispose(), o.material instanceof d.Material && o.material.dispose(), this.meshMap.delete(n));
320
321
  }
321
322
  reconcileNode(e, t) {
322
- var s;
323
+ var i;
323
324
  t.add(e.element);
324
325
  let r = this.meshMap.get(e.element);
325
326
  if (!r) {
326
327
  const a = new d.PlaneGeometry(1, 1);
327
328
  let n;
328
- n = F.create(
329
+ n = D.create(
329
330
  "BOX",
330
331
  e.styles,
331
332
  "",
332
333
  e.rect.width,
333
334
  e.rect.height,
334
335
  this.qualityFactor,
335
- e.isTraveler ? (s = this.renderTarget) == null ? void 0 : s.texture : void 0
336
+ e.isTraveler ? (i = this.renderTarget) == null ? void 0 : i.texture : void 0,
337
+ e.shaderHooks
336
338
  ), r = new d.Mesh(a, n), e.type === "TEXT" && (r.name = "BG_MESH"), this.scene.add(r), this.meshMap.set(e.element, r);
337
339
  }
338
340
  if (r.userData.domRect = e.rect, this.updateMeshProperties(r, e), this.updateMeshLayers(r, e), e.isTraveler && r.layers.enable(28), e.type === "BOX")
@@ -346,36 +348,36 @@ class G {
346
348
  let r = e.children.find(
347
349
  (c) => c.name === "TEXT_CHILD"
348
350
  );
349
- const s = JSON.stringify(t.textStyles), a = (o = r == null ? void 0 : r.userData) == null ? void 0 : o.styleHash;
350
- if (!r || t.dirtyMask & N || s !== a) {
351
+ const i = JSON.stringify(t.textStyles), a = (o = r == null ? void 0 : r.userData) == null ? void 0 : o.styleHash;
352
+ if (!r || t.dirtyMask & _ || i !== a) {
351
353
  r && ((l = r.material.map) == null || l.dispose(), r.geometry.dispose(), e.remove(r));
352
- const c = F.create(
354
+ const c = D.create(
353
355
  "TEXT",
354
356
  t.textStyles,
355
357
  t.textContent || "",
356
358
  t.rect.width,
357
359
  t.rect.height,
358
360
  this.qualityFactor
359
- ), g = new d.PlaneGeometry(1, 1);
360
- r = new d.Mesh(g, c), r.name = "TEXT_CHILD", r.userData = { styleHash: s }, this.updateMeshLayers(r, t), r.position.z = 5e-3, e.add(r);
361
+ ), m = new d.PlaneGeometry(1, 1);
362
+ r = new d.Mesh(m, c), r.name = "TEXT_CHILD", r.userData = { styleHash: i }, this.updateMeshLayers(r, t), r.position.z = 5e-3, e.add(r);
361
363
  }
362
364
  if (r) {
363
- const c = e.userData.domRect, g = c.x + c.width / 2, u = c.y + c.height / 2, p = t.rect.x + t.rect.width / 2, m = t.rect.y + t.rect.height / 2, T = p - g, v = -(m - u);
364
- r.position.set(T, v, 5e-3);
365
+ const c = e.userData.domRect, m = c.x + c.width / 2, f = c.y + c.height / 2, g = t.rect.x + t.rect.width / 2, p = t.rect.y + t.rect.height / 2, y = g - m, v = -(p - f);
366
+ r.position.set(y, v, 5e-3);
365
367
  }
366
368
  }
367
369
  updateMeshProperties(e, t) {
368
- var m;
369
- const { rect: r, styles: s } = t, a = this.renderer.getPixelRatio(), n = this.renderer.domElement.width / a, o = this.renderer.domElement.height / a;
370
+ var p;
371
+ const { rect: r, styles: i } = t, a = this.renderer.getPixelRatio(), n = this.renderer.domElement.width / a, o = this.renderer.domElement.height / a;
370
372
  e.scale.set(r.width, r.height, 1);
371
373
  const l = 1e-3;
372
374
  this.renderOrder++;
373
- const c = this.targetRect.left + window.scrollX, g = this.targetRect.top + window.scrollY, u = r.x - c, p = r.y - g;
375
+ const c = this.targetRect.left + window.scrollX, m = this.targetRect.top + window.scrollY, f = r.x - c, g = r.y - m;
374
376
  e.position.set(
375
- u - n / 2 + r.width / 2,
376
- -p + o / 2 - r.height / 2,
377
- s.zIndex + this.renderOrder * l
378
- ), F.update(
377
+ f - n / 2 + r.width / 2,
378
+ -g + o / 2 - r.height / 2,
379
+ i.zIndex + this.renderOrder * l
380
+ ), D.update(
379
381
  e.material,
380
382
  "BOX",
381
383
  t.styles,
@@ -383,12 +385,12 @@ class G {
383
385
  t.rect.width,
384
386
  t.rect.height,
385
387
  this.qualityFactor,
386
- t.isTraveler ? (m = this.renderTarget) == null ? void 0 : m.texture : void 0
388
+ t.isTraveler ? (p = this.renderTarget) == null ? void 0 : p.texture : void 0
387
389
  );
388
390
  }
389
391
  updateMeshLayers(e, t) {
390
392
  const r = (1 - (t.visibility & x)) * 30;
391
- e.layers.set(r), t.visibility === (x | R) && e.layers.enable(29);
393
+ e.layers.set(r), t.visibility === (x | w) && e.layers.enable(29);
392
394
  }
393
395
  captureRenderTarget() {
394
396
  const e = [];
@@ -398,11 +400,14 @@ class G {
398
400
  return;
399
401
  const t = new d.Color(), r = this.renderer.getClearAlpha();
400
402
  this.renderer.getClearColor(t), this.renderer.setClearColor(0, 0), this.renderer.setRenderTarget(this.renderTarget), this.renderer.clear(), this.renderer.autoClear = !1, this.renderer.setScissorTest(!0), this.camera.layers.set(29);
401
- const s = new d.Vector3(), a = this.targetRect.width, n = this.targetRect.height, o = this.renderer.getPixelRatio();
403
+ const i = new d.Vector3(), a = this.targetRect.width, n = this.targetRect.height, o = this.renderer.getPixelRatio();
402
404
  for (const l of e) {
403
- s.setFromMatrixPosition(l.matrixWorld), s.project(this.camera);
404
- const c = (s.x + 1) / 2 * a, g = (s.y + 1) / 2 * n, u = l.scale.x, p = l.scale.y, m = c - u / 2, T = g - p / 2, v = m * this.qualityFactor / o, B = T * this.qualityFactor / o, b = u * this.qualityFactor / o, f = p * this.qualityFactor / o;
405
- this.renderer.setScissor(v, B, b, f), this.renderer.render(this.scene, this.camera);
405
+ i.setFromMatrixPosition(l.matrixWorld), i.project(this.camera);
406
+ const c = (i.x + 1) / 2 * a, m = (i.y + 1) / 2 * n;
407
+ let f = 0, g = 1;
408
+ typeof this.clipArea == "number" ? g = this.clipArea : this.clipArea.endsWith("%") ? g = parseFloat(this.clipArea) / 100 : this.clipArea.endsWith("px") && (f = parseFloat(this.clipArea));
409
+ const p = l.scale.x * g + 0.5, y = l.scale.y * g + 0.5, v = c - p / 2, B = m - y / 2, M = (v * this.qualityFactor - f) / o, F = (B * this.qualityFactor - f) / o, b = (p * this.qualityFactor + f * 2) / o, u = (y * this.qualityFactor + f * 2) / o;
410
+ this.renderer.setScissor(M, F, b, u), this.renderer.render(this.scene, this.camera);
406
411
  }
407
412
  this.renderer.setScissorTest(!1), this.renderer.autoClear = !0, this.renderer.setRenderTarget(null), this.camera.layers.set(28), this.renderer.setClearColor(t, r);
408
413
  }
@@ -413,18 +418,18 @@ class G {
413
418
  showScissoredRenderTarget() {
414
419
  if (!this.renderTarget)
415
420
  return;
416
- const e = this.targetRect.width, t = this.targetRect.height, r = new d.PlaneGeometry(e, t), s = new d.MeshBasicMaterial({
421
+ const e = this.targetRect.width, t = this.targetRect.height, r = new d.PlaneGeometry(e, t), i = new d.MeshBasicMaterial({
417
422
  map: this.renderTarget.texture,
418
423
  side: d.DoubleSide,
419
424
  transparent: !0,
420
425
  opacity: 0.8
421
- }), a = new d.Mesh(r, s);
426
+ }), a = new d.Mesh(r, i);
422
427
  a.position.set(0, 0, 90), a.layers.set(28), this.scene.add(a);
423
428
  }
424
429
  }
425
- function J(i) {
430
+ function j(s) {
426
431
  const e = document.createRange();
427
- e.selectNodeContents(i);
432
+ e.selectNodeContents(s);
428
433
  const t = e.getBoundingClientRect();
429
434
  return {
430
435
  left: t.left,
@@ -433,126 +438,130 @@ function J(i) {
433
438
  height: t.height
434
439
  };
435
440
  }
436
- function V(i) {
437
- const e = parseFloat(i.fontSize);
438
- let t = parseFloat(i.lineHeight);
441
+ function Q(s) {
442
+ const e = parseFloat(s.fontSize);
443
+ let t = parseFloat(s.lineHeight);
439
444
  isNaN(t) && (t = e * 1.2);
440
- let r = parseFloat(i.letterSpacing);
445
+ let r = parseFloat(s.letterSpacing);
441
446
  return isNaN(r) && (r = 0), {
442
- font: `${i.fontStyle} ${i.fontWeight} ${i.fontSize} ${i.fontFamily}`,
443
- color: i.color,
444
- textAlign: i.textAlign || "start",
447
+ font: `${s.fontStyle} ${s.fontWeight} ${s.fontSize} ${s.fontFamily}`,
448
+ color: s.color,
449
+ textAlign: s.textAlign || "start",
445
450
  textBaseline: "alphabetic",
446
- direction: i.direction || "inherit",
451
+ direction: s.direction || "inherit",
447
452
  lineHeight: t,
448
453
  letterSpacing: r
449
454
  };
450
455
  }
451
- function X(i, e = O | D | k | N | z, t, r) {
452
- if (i.nodeType === Node.TEXT_NODE) {
453
- const f = i;
454
- if (!f.textContent || !f.textContent.trim())
456
+ function P(s, e = z | L | Y | _ | I, t, r) {
457
+ if (s.nodeType === Node.TEXT_NODE) {
458
+ const u = s;
459
+ if (!u.textContent || !u.textContent.trim())
455
460
  return null;
456
- const C = f.textContent.replace(/\s+/g, " ").trim();
461
+ const C = u.textContent.replace(/\s+/g, " ").trim();
457
462
  if (C.length === 0)
458
463
  return null;
459
- const y = J(f);
460
- if (y.width === 0 || y.height === 0)
464
+ const T = j(u);
465
+ if (T.width === 0 || T.height === 0)
461
466
  return null;
462
- const L = f.parentElement, M = L ? window.getComputedStyle(L) : null;
463
- return M ? {
467
+ const A = u.parentElement, O = A ? window.getComputedStyle(A) : null;
468
+ return O ? {
464
469
  id: Math.random().toString(36).substring(2, 9),
465
470
  type: "TEXT",
466
- element: f,
471
+ element: u,
467
472
  rect: {
468
- x: y.left + window.scrollX,
469
- y: y.top + window.scrollY,
470
- width: y.width,
471
- height: y.height
473
+ x: T.left + window.scrollX,
474
+ y: T.top + window.scrollY,
475
+ width: T.width,
476
+ height: T.height
472
477
  },
473
478
  styles: {
474
479
  backgroundColor: "transparent",
475
- opacity: parseFloat(M.opacity),
480
+ opacity: parseFloat(O.opacity),
476
481
  zIndex: 0,
477
482
  borderRadius: "0px",
478
483
  borderColor: "transparent",
479
484
  borderWidth: "0px"
480
485
  },
481
486
  textContent: C,
482
- textStyles: V(M),
487
+ textStyles: Q(O),
483
488
  dirtyMask: e,
484
489
  visibility: t,
485
490
  isTraveler: !1,
486
491
  children: []
487
492
  } : null;
488
493
  }
489
- const s = i, a = s.dataset.mirageFilter;
494
+ const i = s, a = i.dataset.mirageFilter;
490
495
  let n = t, o = t;
491
496
  if (a) {
492
- const f = new Set(a.split(/\s+/));
493
- for (const C of f)
494
- if (!q.includes(C))
497
+ const u = new Set(a.split(/\s+/));
498
+ for (const C of u)
499
+ if (!W.includes(C))
495
500
  throw new Error(
496
501
  `[MirageEngine] Invalid filter token: '${C}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`
497
502
  );
498
- if (f.has("end"))
503
+ if (u.has("end"))
499
504
  return null;
500
- if (f.has("include-tree") && f.has("exclude-tree"))
505
+ if (u.has("include-tree") && u.has("exclude-tree"))
501
506
  throw new Error(
502
507
  "[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element."
503
508
  );
504
- if (f.has("include-self") && f.has("exclude-self"))
509
+ if (u.has("include-self") && u.has("exclude-self"))
505
510
  throw new Error(
506
511
  "[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element."
507
512
  );
508
- f.has("include-tree") ? n = n | x : f.has("exclude-tree") && (n = n & ~x), o = n, f.has("include-self") ? o = o | x : f.has("exclude-self") && (o = o & ~x);
513
+ u.has("include-tree") ? n = n | x : u.has("exclude-tree") && (n = n & ~x), o = n, u.has("include-self") ? o = o | x : u.has("exclude-self") && (o = o & ~x);
509
514
  }
510
- o = o | t & R;
511
- const l = s.dataset.mirageTravel;
515
+ o = o | t & w;
516
+ const l = i.dataset.mirageTravel;
512
517
  let c = !1;
513
- l && new Set(l.split(/\s+/)).has("traveler") && (o = o & ~R, n = n & ~R, c = !0);
514
- const g = s.getBoundingClientRect(), u = window.getComputedStyle(s);
515
- if (g.width === 0 || g.height === 0 || u.display === "none")
518
+ l && new Set(l.split(/\s+/)).has("traveler") && (o = o & ~w, n = n & ~w, c = !0);
519
+ const m = i.dataset.mirageShader;
520
+ let f;
521
+ m && (f = JSON.parse(m));
522
+ const g = i.getBoundingClientRect(), p = window.getComputedStyle(i);
523
+ if (g.width === 0 || g.height === 0 || p.display === "none")
516
524
  return null;
517
- let p = s.getAttribute("data-mid");
518
- p || (p = Math.random().toString(36).substring(2, 11), s.setAttribute("data-mid", p));
519
- const m = parseInt(u.zIndex), T = {
520
- backgroundColor: u.backgroundColor,
521
- opacity: parseFloat(u.opacity),
522
- zIndex: isNaN(m) ? 0 : m,
523
- borderRadius: u.borderRadius,
524
- borderColor: u.borderColor,
525
- borderWidth: u.borderWidth
525
+ let y = i.getAttribute("data-mid");
526
+ y || (y = Math.random().toString(36).substring(2, 11), i.setAttribute("data-mid", y));
527
+ const v = parseInt(p.zIndex), B = {
528
+ backgroundColor: p.backgroundColor,
529
+ opacity: parseFloat(p.opacity),
530
+ zIndex: isNaN(v) ? 0 : v,
531
+ borderRadius: p.borderRadius,
532
+ borderColor: p.borderColor,
533
+ borderWidth: p.borderWidth
526
534
  };
527
- let v, B;
535
+ let M, F;
528
536
  const b = [];
529
- return Array.from(s.childNodes).forEach((f) => {
530
- const C = f.nodeType === Node.TEXT_NODE ? o : n, y = X(
531
- f,
537
+ return Array.from(i.childNodes).forEach((u) => {
538
+ const C = u.nodeType === Node.TEXT_NODE ? o : n, T = P(
539
+ u,
532
540
  e,
533
541
  C
534
542
  );
535
- y && b.push(y);
543
+ T && b.push(T);
536
544
  }), {
537
- id: p,
545
+ id: y,
538
546
  type: "BOX",
539
- element: s,
547
+ element: i,
540
548
  rect: {
541
549
  x: g.left + window.scrollX,
542
550
  y: g.top + window.scrollY,
543
551
  width: g.width,
544
552
  height: g.height
545
553
  },
546
- styles: T,
547
- textContent: v,
548
- textStyles: B,
554
+ styles: B,
555
+ textContent: M,
556
+ textStyles: F,
549
557
  dirtyMask: e,
550
558
  visibility: o,
551
559
  isTraveler: c,
552
- children: b
560
+ children: b,
561
+ shaderHooks: f
553
562
  };
554
563
  }
555
- class j {
564
+ class Z {
556
565
  constructor(e, t, r) {
557
566
  h(this, "target");
558
567
  h(this, "renderer");
@@ -561,14 +570,14 @@ class j {
561
570
  h(this, "isDomDirty", !1);
562
571
  h(this, "isRunning", !1);
563
572
  h(this, "isTravelEnabled", !1);
564
- h(this, "pendingMask", E);
573
+ h(this, "pendingMask", S);
565
574
  h(this, "mutationTimer", null);
566
575
  h(this, "cssTimer", null);
567
576
  h(this, "resizeConfig");
568
577
  h(this, "resizeTimer", null);
569
578
  h(this, "isResizing", !1);
570
579
  h(this, "onTransitionFinished", (e) => {
571
- this.target.contains(e.target) && this.mutationTimer === null && (this.cssTimer && clearTimeout(this.cssTimer), this.pendingMask |= O | D, this.cssTimer = window.setTimeout(() => {
580
+ this.target.contains(e.target) && this.mutationTimer === null && (this.cssTimer && clearTimeout(this.cssTimer), this.pendingMask |= z | L, this.cssTimer = window.setTimeout(() => {
572
581
  this.isDomDirty = !0, this.cssTimer = null;
573
582
  }, 50));
574
583
  });
@@ -586,18 +595,18 @@ class j {
586
595
  });
587
596
  var a, n;
588
597
  this.target = e, this.renderer = t, this.filter = r.filter;
589
- const s = (a = r.resizeDebounce) != null ? a : !0;
590
- s === !1 ? this.resizeConfig = { enabled: !1, delay: 0 } : s === !0 ? this.resizeConfig = { enabled: !0, delay: 150 } : this.resizeConfig = {
598
+ const i = (a = r.resizeDebounce) != null ? a : !0;
599
+ i === !1 ? this.resizeConfig = { enabled: !1, delay: 0 } : i === !0 ? this.resizeConfig = { enabled: !0, delay: 150 } : this.resizeConfig = {
591
600
  enabled: !0,
592
- delay: (n = s.delay) != null ? n : 150,
593
- onStart: s.onStart,
594
- onEnd: s.onEnd
601
+ delay: (n = i.delay) != null ? n : 150,
602
+ onStart: i.onStart,
603
+ onEnd: i.onEnd
595
604
  }, this.observer = new MutationObserver((o) => {
596
- let l = E;
605
+ let l = S;
597
606
  for (const c of o)
598
- c.type === "childList" ? l |= z : c.type === "attributes" && (c.attributeName === "style" || c.attributeName === "class") && (l |= O | D);
599
- if (l !== E) {
600
- if (this.pendingMask |= l, l & z) {
607
+ c.type === "childList" ? l |= I : c.type === "attributes" && (c.attributeName === "style" || c.attributeName === "class") && (l |= z | L);
608
+ if (l !== S) {
609
+ if (this.pendingMask |= l, l & I) {
601
610
  this.clearTimers(), console.log("Structural Change detected"), this.isDomDirty = !0;
602
611
  return;
603
612
  }
@@ -625,26 +634,26 @@ class j {
625
634
  this.isDomDirty = !1;
626
635
  const e = document.querySelector("[data-mirage-travel='traveler']") !== null;
627
636
  e && !this.isTravelEnabled && (this.isTravelEnabled = !0, this.renderer.createRenderTarget());
628
- const t = X(
637
+ const t = P(
629
638
  this.target,
630
639
  this.pendingMask,
631
- e ? x | R : x,
640
+ e ? x | w : x,
632
641
  this.filter
633
642
  );
634
- t && this.renderer.syncScene(t), this.pendingMask = E;
643
+ t && this.renderer.syncScene(t), this.pendingMask = S;
635
644
  }
636
645
  }
637
- class K {
646
+ class te {
638
647
  constructor(e, t) {
639
648
  h(this, "renderer");
640
649
  h(this, "syncer");
641
650
  h(this, "target");
642
- var s, a, n;
651
+ var i, a, n;
643
652
  this.target = e;
644
653
  let r;
645
- if (t.mode === "duplicate" ? r = (a = (s = t.container) != null ? s : this.target.parentElement) != null ? a : void 0 : r = (n = this.target.parentElement) != null ? n : void 0, !r)
654
+ if (t.mode === "duplicate" ? r = (a = (i = t.container) != null ? i : this.target.parentElement) != null ? a : void 0 : r = (n = this.target.parentElement) != null ? n : void 0, !r)
646
655
  throw new Error("[Mirage] Cannot find a container (parent or option).");
647
- this.renderer = new G(this.target, t, r), this.renderer.mount(), this.syncer = new j(this.target, this.renderer, t);
656
+ this.renderer = new V(this.target, t, r), this.renderer.mount(), this.syncer = new Z(this.target, this.renderer, t);
648
657
  }
649
658
  start() {
650
659
  this.syncer.start();
@@ -657,15 +666,15 @@ class K {
657
666
  }
658
667
  }
659
668
  export {
660
- q as ALLOWED_FILTERS,
661
- N as DIRTY_CONTENT,
662
- E as DIRTY_NONE,
663
- O as DIRTY_RECT,
664
- z as DIRTY_STRUCTURE,
665
- D as DIRTY_STYLE,
666
- k as DIRTY_ZINDEX,
667
- Z as EXCLUDED,
668
- K as Engine,
669
- R as SYSTEM_LAYER,
669
+ W as ALLOWED_FILTERS,
670
+ _ as DIRTY_CONTENT,
671
+ S as DIRTY_NONE,
672
+ z as DIRTY_RECT,
673
+ I as DIRTY_STRUCTURE,
674
+ L as DIRTY_STYLE,
675
+ Y as DIRTY_ZINDEX,
676
+ ee as EXCLUDED,
677
+ te as Engine,
678
+ w as SYSTEM_LAYER,
670
679
  x as USER_LAYER
671
680
  };
@@ -1,5 +1,5 @@
1
- (function(u,T){typeof exports=="object"&&typeof module!="undefined"?T(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],T):(u=typeof globalThis!="undefined"?globalThis:u||self,T(u.MirageEngine={},u.THREE))})(this,function(u,T){"use strict";var ee=Object.defineProperty;var te=(u,T,w)=>T in u?ee(u,T,{enumerable:!0,configurable:!0,writable:!0,value:w}):u[T]=w;var d=(u,T,w)=>(te(u,typeof T!="symbol"?T+"":T,w),w);function w(i){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(i){for(const t in i)if(t!=="default"){const r=Object.getOwnPropertyDescriptor(i,t);Object.defineProperty(e,t,r.get?r:{enumerable:!0,get:()=>i[t]})}}return e.default=i,Object.freeze(e)}const h=w(T),M=0,B=1,O=2,A=4,D=8,L=16,R=1,E=2,q=0,X=["include-tree","exclude-tree","include-self","exclude-self","end"];function W(i,e,t){const r=e.split(`
2
- `),s=[];return r.forEach(n=>{const a=n.split(" ");let o=a[0];for(let l=1;l<a.length;l++){const c=a[l];i.measureText(o+" "+c).width<t?o+=" "+c:(s.push(o),o=c)}s.push(o)}),s}function Y(i,e,t,r,s=2){const n=document.createElement("canvas"),a=n.getContext("2d");if(!a)throw new Error("[Mirage] Failed to create canvas context");const l=(window.devicePixelRatio||1)*s;n.width=t*l,n.height=r*l,a.scale(l,l),a.font=e.font,a.fillStyle=e.color,a.textBaseline="top",a.globalAlpha=1;const c=W(a,i,t),p=e.lineHeight;c.forEach((m,v)=>{const b=v*p+2;let y=0;e.textAlign==="center"?y=t/2:e.textAlign==="right"&&(y=t),a.textAlign=e.textAlign,a.fillText(m,y,b)});const f=new h.CanvasTexture(n);return f.colorSpace=h.SRGBColorSpace,f.minFilter=h.LinearFilter,f.magFilter=h.LinearFilter,f.needsUpdate=!0,f}function S(i){return typeof i=="number"?i:parseFloat(i)||0}function P(i,e){var o,l,c,p;if(!e){i.set(0,0,0,0);return}const t=e.split("/")[0].trim().split(/\s+/),r=S(t[0]),s=S((o=t[1])!=null?o:t[0]),n=S((l=t[2])!=null?l:t[0]),a=S((p=(c=t[3])!=null?c:t[1])!=null?p:t[0]);i.set(r,s,n,a)}const H=`
1
+ (function(u,T){typeof exports=="object"&&typeof module!="undefined"?T(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],T):(u=typeof globalThis!="undefined"?globalThis:u||self,T(u.MirageEngine={},u.THREE))})(this,function(u,T){"use strict";var re=Object.defineProperty;var ie=(u,T,w)=>T in u?re(u,T,{enumerable:!0,configurable:!0,writable:!0,value:w}):u[T]=w;var h=(u,T,w)=>(ie(u,typeof T!="symbol"?T+"":T,w),w);function w(s){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const t in s)if(t!=="default"){const r=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(e,t,r.get?r:{enumerable:!0,get:()=>s[t]})}}return e.default=s,Object.freeze(e)}const d=w(T),D=0,M=1,O=2,Y=4,B=8,L=16,C=1,E=2,H=0,P=["include-tree","exclude-tree","include-self","exclude-self","end"];function $(s,e,t){const r=e.split(`
2
+ `),i=[];return r.forEach(a=>{const n=a.split(" ");let o=n[0];for(let l=1;l<n.length;l++){const c=n[l];s.measureText(o+" "+c).width<t?o+=" "+c:(i.push(o),o=c)}i.push(o)}),i}function k(s,e,t,r,i=2){const a=document.createElement("canvas"),n=a.getContext("2d");if(!n)throw new Error("[Mirage] Failed to create canvas context");const l=(window.devicePixelRatio||1)*i;a.width=t*l,a.height=r*l,n.scale(l,l),n.font=e.font,n.fillStyle=e.color,n.textBaseline="top",n.globalAlpha=1;const c=$(n,s,t),v=e.lineHeight;c.forEach((m,g)=>{const R=g*v+2;let y=0;e.textAlign==="center"?y=t/2:e.textAlign==="right"&&(y=t),n.textAlign=e.textAlign,n.fillText(m,y,R)});const p=new d.CanvasTexture(a);return p.colorSpace=d.SRGBColorSpace,p.minFilter=d.LinearFilter,p.magFilter=d.LinearFilter,p.needsUpdate=!0,p}function S(s){return typeof s=="number"?s:parseFloat(s)||0}function U(s,e){var o,l,c,v;if(!e){s.set(0,0,0,0);return}const t=e.split("/")[0].trim().split(/\s+/),r=S(t[0]),i=S((o=t[1])!=null?o:t[0]),a=S((l=t[2])!=null?l:t[0]),n=S((v=(c=t[3])!=null?c:t[1])!=null?v:t[0]);s.set(r,i,a,n)}const G=`
3
3
  varying vec2 vUv;
4
4
  varying vec4 vScreenPos;
5
5
  void main() {
@@ -7,7 +7,7 @@
7
7
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
8
8
  vScreenPos = gl_Position;
9
9
  }
10
- `,$=`
10
+ `,J=`
11
11
 
12
12
  varying vec2 vUv;
13
13
 
@@ -73,13 +73,13 @@
73
73
 
74
74
  #include <colorspace_fragment>
75
75
  }
76
- `;function F(i){if(!i||i==="transparent")return{color:new h.Color(16777215),alpha:0};const e=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(e){const t=parseInt(e[1],10),r=parseInt(e[2],10),s=parseInt(e[3],10),n=e[4]!==void 0?parseFloat(e[4]):1;return{color:new h.Color(`rgb(${t}, ${r}, ${s})`),alpha:n}}return{color:new h.Color(i),alpha:1}}function G(i,e,t,r=null,s){var y;const n=r!==null,a=n?`
76
+ `;function F(s){if(!s||s==="transparent")return{color:new d.Color(16777215),alpha:0};const e=s.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(e){const t=parseInt(e[1],10),r=parseInt(e[2],10),i=parseInt(e[3],10),a=e[4]!==void 0?parseFloat(e[4]):1;return{color:new d.Color(`rgb(${t}, ${r}, ${i})`),alpha:a}}return{color:new d.Color(s),alpha:1}}function j(s,e,t,r=null,i){var y;const a=r!==null,n=a?`
77
77
  uniform sampler2D uTexture;
78
78
  varying vec4 vScreenPos;
79
- `:"",o=n?`
79
+ `:"",o=a?`
80
80
  vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
81
81
  vec2 resultUv = screenUv;
82
- ${(s==null?void 0:s.uvModifier)||""}
83
- `:"",l=n?`
82
+ ${(i==null?void 0:i.uvModifier)||""}
83
+ `:"",l=a?`
84
84
  baseColor = texture2D(uTexture, resultUv);
85
- `:"",c=(s==null?void 0:s.colorModifier)||"",p=$.replace("#INJECT_DECLARATIONS",a).replace("#INJECT_UV_MODIFIER",o).replace("#INJECT_BASE_COLOR",l).replace("#INJECT_COLOR_MODIFIER",c),f=F(i.backgroundColor),m=F(i.borderColor),v={uSize:{value:new h.Vector2(e,t)},uBorderRadius:{value:new h.Vector4(0,0,0,0)},uBorderWidth:{value:S(i.borderWidth)},uBgColor:{value:f.color},uBorderColor:{value:m.color},uOpacity:{value:(y=i.opacity)!=null?y:1},uBgOpacity:{value:f.alpha},uBorderOpacity:{value:m.alpha},uTexture:{value:null}};return P(v.uBorderRadius.value,i.borderRadius),n&&(v.uTexture.value=r),new h.ShaderMaterial({uniforms:v,vertexShader:H,fragmentShader:p,transparent:!0,side:h.FrontSide})}function j(i,e,t,r,s){var o;const n=F(e.backgroundColor),a=F(e.borderColor);i.uniforms.uSize.value.set(t,r),P(i.uniforms.uBorderRadius.value,e.borderRadius),i.uniforms.uBorderWidth.value=S(e.borderWidth),i.uniforms.uBgColor.value.copy(n.color),i.uniforms.uBorderColor.value.copy(a.color),i.uniforms.uOpacity.value=(o=e.opacity)!=null?o:1,i.uniforms.uBgOpacity.value=n.alpha,i.uniforms.uBorderOpacity.value=a.alpha,i.uniforms.uTexture&&s!==void 0&&(i.uniforms.uTexture.value=s)}const I={create(i,e,t,r,s,n=2,a=null){if(i==="BOX")return G(e,r,s,a);if(i==="TEXT"){const o=Y(t||"",e,r,s,n);return new h.MeshBasicMaterial({map:o,transparent:!0,side:h.FrontSide,color:16777215})}return new h.MeshBasicMaterial({visible:!1})},update(i,e,t,r,s,n,a=2,o){if(e==="BOX")j(i,t,s,n,o);else if(e==="TEXT"){const l=i;l.map&&l.map.dispose();const c=Y(r||"",t,s,n,a);l.map=c,l.needsUpdate=!0}}};class J{constructor(e,t,r){d(this,"canvas");d(this,"scene");d(this,"camera");d(this,"renderer");d(this,"renderTarget",null);d(this,"renderOrder",0);d(this,"qualityFactor",2);d(this,"mode","overlay");d(this,"target");d(this,"mountContainer");d(this,"targetRect");d(this,"meshMap",new Map);var a,o;this.target=e,this.mountContainer=r,this.mode=(a=t.mode)!=null?a:"overlay",this.canvas=document.createElement("canvas"),this.scene=new h.Scene,this.targetRect=this.target.getBoundingClientRect();const s=this.targetRect.width,n=this.targetRect.height;this.camera=new h.OrthographicCamera(s/-2,s/2,n/2,n/-2,1,1e3),this.camera.position.z=100,this.camera.layers.set(0),this.renderer=new h.WebGLRenderer({canvas:this.canvas,alpha:!0,antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(s,n),this.applyTextQuality((o=t.quality)!=null?o:"medium")}createRenderTarget(){this.renderTarget=new h.WebGLRenderTarget(this.targetRect.width*this.qualityFactor,this.targetRect.height*this.qualityFactor,{minFilter:h.LinearFilter,magFilter:h.LinearFilter,format:h.RGBAFormat,stencilBuffer:!1,depthBuffer:!0,samples:4})}applyTextQuality(e){if(typeof e=="number"){this.qualityFactor=Math.max(.1,e);return}switch(e){case"low":this.qualityFactor=1;break;case"high":this.qualityFactor=4;break;case"medium":default:this.qualityFactor=2;break}}mount(){this.mountContainer.prepend(this.canvas),this.canvas.style.pointerEvents=this.mode==="overlay"?"none":"auto",this.updateCanvasLayout()}updateCanvasLayout(){this.canvas.style.width=`${this.targetRect.width}px`,this.canvas.style.height=`${this.targetRect.height}px`,this.mode==="duplicate"?(this.canvas.style.position="",this.canvas.style.top="",this.canvas.style.left="",this.canvas.style.display="block"):(this.canvas.style.position="absolute",this.canvas.style.top=`${this.target.offsetTop}px`,this.canvas.style.left=`${this.target.offsetLeft}px`,this.canvas.style.display="block")}dispose(){this.renderer.dispose(),this.canvas.remove()}setSize(e,t){this.renderer.setSize(e,t),this.renderTarget&&this.renderTarget.setSize(e*this.qualityFactor,t*this.qualityFactor),this.camera.left=e/-2,this.camera.right=e/2,this.camera.top=t/2,this.camera.bottom=t/-2,this.camera.updateProjectionMatrix()}syncScene(e){const t=this.target.getBoundingClientRect(),r=Math.abs(t.width-this.targetRect.width)>.1||Math.abs(t.height-this.targetRect.height)>.1,s=this.mode==="overlay"&&(Math.abs(t.top-this.targetRect.top)>.1||Math.abs(t.left-this.targetRect.left)>.1);r?(this.targetRect=t,this.setSize(this.targetRect.width,this.targetRect.height),this.updateCanvasLayout()):s?(this.targetRect=t,this.updateCanvasLayout()):this.targetRect=t,this.renderOrder=0;const n=new Set;this.reconcileNode(e,n);for(const[a,o]of this.meshMap.entries())n.has(a)||(this.scene.remove(o),o.geometry.dispose(),o.material instanceof h.Material&&o.material.dispose(),this.meshMap.delete(a))}reconcileNode(e,t){var s;t.add(e.element);let r=this.meshMap.get(e.element);if(!r){const n=new h.PlaneGeometry(1,1);let a;a=I.create("BOX",e.styles,"",e.rect.width,e.rect.height,this.qualityFactor,e.isTraveler?(s=this.renderTarget)==null?void 0:s.texture:void 0),r=new h.Mesh(n,a),e.type==="TEXT"&&(r.name="BG_MESH"),this.scene.add(r),this.meshMap.set(e.element,r)}if(r.userData.domRect=e.rect,this.updateMeshProperties(r,e),this.updateMeshLayers(r,e),e.isTraveler&&r.layers.enable(28),e.type==="BOX")for(const n of e.children)this.reconcileNode(n,t);else e.type==="TEXT"&&this.reconcileTextChild(r,e)}reconcileTextChild(e,t){var o,l;let r=e.children.find(c=>c.name==="TEXT_CHILD");const s=JSON.stringify(t.textStyles),n=(o=r==null?void 0:r.userData)==null?void 0:o.styleHash;if(!r||t.dirtyMask&L||s!==n){r&&((l=r.material.map)==null||l.dispose(),r.geometry.dispose(),e.remove(r));const c=I.create("TEXT",t.textStyles,t.textContent||"",t.rect.width,t.rect.height,this.qualityFactor),p=new h.PlaneGeometry(1,1);r=new h.Mesh(p,c),r.name="TEXT_CHILD",r.userData={styleHash:s},this.updateMeshLayers(r,t),r.position.z=.005,e.add(r)}if(r){const c=e.userData.domRect,p=c.x+c.width/2,f=c.y+c.height/2,m=t.rect.x+t.rect.width/2,v=t.rect.y+t.rect.height/2,b=m-p,y=-(v-f);r.position.set(b,y,.005)}}updateMeshProperties(e,t){var v;const{rect:r,styles:s}=t,n=this.renderer.getPixelRatio(),a=this.renderer.domElement.width/n,o=this.renderer.domElement.height/n;e.scale.set(r.width,r.height,1);const l=.001;this.renderOrder++;const c=this.targetRect.left+window.scrollX,p=this.targetRect.top+window.scrollY,f=r.x-c,m=r.y-p;e.position.set(f-a/2+r.width/2,-m+o/2-r.height/2,s.zIndex+this.renderOrder*l),I.update(e.material,"BOX",t.styles,"",t.rect.width,t.rect.height,this.qualityFactor,t.isTraveler?(v=this.renderTarget)==null?void 0:v.texture:void 0)}updateMeshLayers(e,t){const r=(1-(t.visibility&R))*30;e.layers.set(r),t.visibility===(R|E)&&e.layers.enable(29)}captureRenderTarget(){const e=[];for(const l of this.meshMap.values())l.layers.mask&1<<28&&e.push(l);if(e.length===0)return;const t=new h.Color,r=this.renderer.getClearAlpha();this.renderer.getClearColor(t),this.renderer.setClearColor(0,0),this.renderer.setRenderTarget(this.renderTarget),this.renderer.clear(),this.renderer.autoClear=!1,this.renderer.setScissorTest(!0),this.camera.layers.set(29);const s=new h.Vector3,n=this.targetRect.width,a=this.targetRect.height,o=this.renderer.getPixelRatio();for(const l of e){s.setFromMatrixPosition(l.matrixWorld),s.project(this.camera);const c=(s.x+1)/2*n,p=(s.y+1)/2*a,f=l.scale.x,m=l.scale.y,v=c-f/2,b=p-m/2,y=v*this.qualityFactor/o,_=b*this.qualityFactor/o,z=f*this.qualityFactor/o,g=m*this.qualityFactor/o;this.renderer.setScissor(y,_,z,g),this.renderer.render(this.scene,this.camera)}this.renderer.setScissorTest(!1),this.renderer.autoClear=!0,this.renderer.setRenderTarget(null),this.camera.layers.set(28),this.renderer.setClearColor(t,r)}render(){this.renderTarget&&this.captureRenderTarget(),this.renderer.render(this.scene,this.camera)}showScissoredRenderTarget(){if(!this.renderTarget)return;const e=this.targetRect.width,t=this.targetRect.height,r=new h.PlaneGeometry(e,t),s=new h.MeshBasicMaterial({map:this.renderTarget.texture,side:h.DoubleSide,transparent:!0,opacity:.8}),n=new h.Mesh(r,s);n.position.set(0,0,90),n.layers.set(28),this.scene.add(n)}}function V(i){const e=document.createRange();e.selectNodeContents(i);const t=e.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function Z(i){const e=parseFloat(i.fontSize);let t=parseFloat(i.lineHeight);isNaN(t)&&(t=e*1.2);let r=parseFloat(i.letterSpacing);return isNaN(r)&&(r=0),{font:`${i.fontStyle} ${i.fontWeight} ${i.fontSize} ${i.fontFamily}`,color:i.color,textAlign:i.textAlign||"start",textBaseline:"alphabetic",direction:i.direction||"inherit",lineHeight:t,letterSpacing:r}}function U(i,e=B|O|A|L|D,t,r){if(i.nodeType===Node.TEXT_NODE){const g=i;if(!g.textContent||!g.textContent.trim())return null;const x=g.textContent.replace(/\s+/g," ").trim();if(x.length===0)return null;const C=V(g);if(C.width===0||C.height===0)return null;const k=g.parentElement,N=k?window.getComputedStyle(k):null;return N?{id:Math.random().toString(36).substring(2,9),type:"TEXT",element:g,rect:{x:C.left+window.scrollX,y:C.top+window.scrollY,width:C.width,height:C.height},styles:{backgroundColor:"transparent",opacity:parseFloat(N.opacity),zIndex:0,borderRadius:"0px",borderColor:"transparent",borderWidth:"0px"},textContent:x,textStyles:Z(N),dirtyMask:e,visibility:t,isTraveler:!1,children:[]}:null}const s=i,n=s.dataset.mirageFilter;let a=t,o=t;if(n){const g=new Set(n.split(/\s+/));for(const x of g)if(!X.includes(x))throw new Error(`[MirageEngine] Invalid filter token: '${x}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`);if(g.has("end"))return null;if(g.has("include-tree")&&g.has("exclude-tree"))throw new Error("[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element.");if(g.has("include-self")&&g.has("exclude-self"))throw new Error("[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element.");g.has("include-tree")?a=a|R:g.has("exclude-tree")&&(a=a&~R),o=a,g.has("include-self")?o=o|R:g.has("exclude-self")&&(o=o&~R)}o=o|t&E;const l=s.dataset.mirageTravel;let c=!1;l&&new Set(l.split(/\s+/)).has("traveler")&&(o=o&~E,a=a&~E,c=!0);const p=s.getBoundingClientRect(),f=window.getComputedStyle(s);if(p.width===0||p.height===0||f.display==="none")return null;let m=s.getAttribute("data-mid");m||(m=Math.random().toString(36).substring(2,11),s.setAttribute("data-mid",m));const v=parseInt(f.zIndex),b={backgroundColor:f.backgroundColor,opacity:parseFloat(f.opacity),zIndex:isNaN(v)?0:v,borderRadius:f.borderRadius,borderColor:f.borderColor,borderWidth:f.borderWidth};let y,_;const z=[];return Array.from(s.childNodes).forEach(g=>{const x=g.nodeType===Node.TEXT_NODE?o:a,C=U(g,e,x);C&&z.push(C)}),{id:m,type:"BOX",element:s,rect:{x:p.left+window.scrollX,y:p.top+window.scrollY,width:p.width,height:p.height},styles:b,textContent:y,textStyles:_,dirtyMask:e,visibility:o,isTraveler:c,children:z}}class Q{constructor(e,t,r){d(this,"target");d(this,"renderer");d(this,"filter");d(this,"observer");d(this,"isDomDirty",!1);d(this,"isRunning",!1);d(this,"isTravelEnabled",!1);d(this,"pendingMask",M);d(this,"mutationTimer",null);d(this,"cssTimer",null);d(this,"resizeConfig");d(this,"resizeTimer",null);d(this,"isResizing",!1);d(this,"onTransitionFinished",e=>{this.target.contains(e.target)&&this.mutationTimer===null&&(this.cssTimer&&clearTimeout(this.cssTimer),this.pendingMask|=B|O,this.cssTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.cssTimer=null},50))});d(this,"onWindowResize",()=>{if(!this.resizeConfig.enabled){this.isDomDirty=!0;return}this.isResizing||(this.isResizing=!0,this.resizeConfig.onStart&&this.resizeConfig.onStart()),this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.resizeConfig.onEnd&&this.resizeConfig.onEnd(),this.isResizing=!1,this.resizeTimer=null},this.resizeConfig.delay)});d(this,"renderLoop",()=>{this.isRunning&&(this.isDomDirty&&this.forceUpdateScene(),this.renderer.render(),requestAnimationFrame(this.renderLoop))});var n,a;this.target=e,this.renderer=t,this.filter=r.filter;const s=(n=r.resizeDebounce)!=null?n:!0;s===!1?this.resizeConfig={enabled:!1,delay:0}:s===!0?this.resizeConfig={enabled:!0,delay:150}:this.resizeConfig={enabled:!0,delay:(a=s.delay)!=null?a:150,onStart:s.onStart,onEnd:s.onEnd},this.observer=new MutationObserver(o=>{let l=M;for(const c of o)c.type==="childList"?l|=D:c.type==="attributes"&&(c.attributeName==="style"||c.attributeName==="class")&&(l|=B|O);if(l!==M){if(this.pendingMask|=l,l&D){this.clearTimers(),console.log("Structural Change detected"),this.isDomDirty=!0;return}this.mutationTimer&&clearTimeout(this.mutationTimer),this.mutationTimer=window.setTimeout(()=>{this.mutationTimer=null,this.isDomDirty=!0},200)}})}start(){this.isRunning||(this.isRunning=!0,this.observer.observe(this.target,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),this.target.addEventListener("transitionend",this.onTransitionFinished),this.target.addEventListener("animationend",this.onTransitionFinished),window.addEventListener("resize",this.onWindowResize),this.forceUpdateScene(),this.renderLoop())}stop(){this.isRunning=!1,this.observer.disconnect(),this.clearTimers(),this.target.removeEventListener("transitionend",this.onTransitionFinished),this.target.removeEventListener("animationend",this.onTransitionFinished),window.removeEventListener("resize",this.onWindowResize)}clearTimers(){this.mutationTimer&&(clearTimeout(this.mutationTimer),this.mutationTimer=null),this.cssTimer&&(clearTimeout(this.cssTimer),this.cssTimer=null)}forceUpdateScene(){this.isDomDirty=!1;const e=document.querySelector("[data-mirage-travel='traveler']")!==null;e&&!this.isTravelEnabled&&(this.isTravelEnabled=!0,this.renderer.createRenderTarget());const t=U(this.target,this.pendingMask,e?R|E:R,this.filter);t&&this.renderer.syncScene(t),this.pendingMask=M}}class K{constructor(e,t){d(this,"renderer");d(this,"syncer");d(this,"target");var s,n,a;this.target=e;let r;if(t.mode==="duplicate"?r=(n=(s=t.container)!=null?s:this.target.parentElement)!=null?n:void 0:r=(a=this.target.parentElement)!=null?a:void 0,!r)throw new Error("[Mirage] Cannot find a container (parent or option).");this.renderer=new J(this.target,t,r),this.renderer.mount(),this.syncer=new Q(this.target,this.renderer,t)}start(){this.syncer.start()}stop(){this.syncer.stop()}dispose(){this.syncer.stop(),this.renderer.dispose()}}u.ALLOWED_FILTERS=X,u.DIRTY_CONTENT=L,u.DIRTY_NONE=M,u.DIRTY_RECT=B,u.DIRTY_STRUCTURE=D,u.DIRTY_STYLE=O,u.DIRTY_ZINDEX=A,u.EXCLUDED=q,u.Engine=K,u.SYSTEM_LAYER=E,u.USER_LAYER=R,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
85
+ `:"",c=(i==null?void 0:i.colorModifier)||"",v=J.replace("#INJECT_DECLARATIONS",n).replace("#INJECT_UV_MODIFIER",o).replace("#INJECT_BASE_COLOR",l).replace("#INJECT_COLOR_MODIFIER",c),p=F(s.backgroundColor),m=F(s.borderColor),g={uSize:{value:new d.Vector2(e,t)},uBorderRadius:{value:new d.Vector4(0,0,0,0)},uBorderWidth:{value:S(s.borderWidth)},uBgColor:{value:p.color},uBorderColor:{value:m.color},uOpacity:{value:(y=s.opacity)!=null?y:1},uBgOpacity:{value:p.alpha},uBorderOpacity:{value:m.alpha},uTexture:{value:null}};return U(g.uBorderRadius.value,s.borderRadius),a&&(g.uTexture.value=r),new d.ShaderMaterial({uniforms:g,vertexShader:G,fragmentShader:v,transparent:!0,side:d.FrontSide})}function V(s,e,t,r,i){var o;const a=F(e.backgroundColor),n=F(e.borderColor);s.uniforms.uSize.value.set(t,r),U(s.uniforms.uBorderRadius.value,e.borderRadius),s.uniforms.uBorderWidth.value=S(e.borderWidth),s.uniforms.uBgColor.value.copy(a.color),s.uniforms.uBorderColor.value.copy(n.color),s.uniforms.uOpacity.value=(o=e.opacity)!=null?o:1,s.uniforms.uBgOpacity.value=a.alpha,s.uniforms.uBorderOpacity.value=n.alpha,s.uniforms.uTexture&&i!==void 0&&(s.uniforms.uTexture.value=i)}const I={create(s,e,t,r,i,a=2,n=null,o){if(s==="BOX")return j(e,r,i,n,o);if(s==="TEXT"){const l=k(t||"",e,r,i,a);return new d.MeshBasicMaterial({map:l,transparent:!0,side:d.FrontSide,color:16777215})}return new d.MeshBasicMaterial({visible:!1})},update(s,e,t,r,i,a,n=2,o){if(e==="BOX")V(s,t,i,a,o);else if(e==="TEXT"){const l=s;l.map&&l.map.dispose();const c=k(r||"",t,i,a,n);l.map=c,l.needsUpdate=!0}}};class Z{constructor(e,t,r){h(this,"canvas");h(this,"scene");h(this,"camera");h(this,"renderer");h(this,"renderTarget",null);h(this,"renderOrder",0);h(this,"qualityFactor",2);h(this,"mode","overlay");h(this,"clipArea",1);h(this,"target");h(this,"mountContainer");h(this,"targetRect");h(this,"meshMap",new Map);var n,o,l;this.target=e,this.mountContainer=r,this.mode=(n=t.mode)!=null?n:"overlay",this.clipArea=(o=t.travelerClipArea)!=null?o:1,this.canvas=document.createElement("canvas"),this.scene=new d.Scene,this.targetRect=this.target.getBoundingClientRect();const i=this.targetRect.width,a=this.targetRect.height;this.camera=new d.OrthographicCamera(i/-2,i/2,a/2,a/-2,1,1e3),this.camera.position.z=100,this.camera.layers.set(0),this.renderer=new d.WebGLRenderer({canvas:this.canvas,alpha:!0,antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(i,a),this.applyTextQuality((l=t.quality)!=null?l:"medium")}createRenderTarget(){this.renderTarget=new d.WebGLRenderTarget(this.targetRect.width*this.qualityFactor,this.targetRect.height*this.qualityFactor,{minFilter:d.LinearFilter,magFilter:d.LinearFilter,format:d.RGBAFormat,stencilBuffer:!1,depthBuffer:!0,samples:4})}applyTextQuality(e){if(typeof e=="number"){this.qualityFactor=Math.max(.1,e);return}switch(e){case"low":this.qualityFactor=1;break;case"high":this.qualityFactor=4;break;case"medium":default:this.qualityFactor=2;break}}mount(){this.mountContainer.prepend(this.canvas),this.canvas.style.pointerEvents=this.mode==="overlay"?"none":"auto",this.updateCanvasLayout()}updateCanvasLayout(){this.canvas.style.width=`${this.targetRect.width}px`,this.canvas.style.height=`${this.targetRect.height}px`,this.mode==="duplicate"?(this.canvas.style.position="",this.canvas.style.top="",this.canvas.style.left="",this.canvas.style.display="block"):(this.canvas.style.position="absolute",this.canvas.style.top=`${this.target.offsetTop}px`,this.canvas.style.left=`${this.target.offsetLeft}px`,this.canvas.style.display="block")}dispose(){this.renderer.dispose(),this.canvas.remove()}setSize(e,t){this.renderer.setSize(e,t),this.renderTarget&&this.renderTarget.setSize(e*this.qualityFactor,t*this.qualityFactor),this.camera.left=e/-2,this.camera.right=e/2,this.camera.top=t/2,this.camera.bottom=t/-2,this.camera.updateProjectionMatrix()}syncScene(e){const t=this.target.getBoundingClientRect(),r=Math.abs(t.width-this.targetRect.width)>.1||Math.abs(t.height-this.targetRect.height)>.1,i=this.mode==="overlay"&&(Math.abs(t.top-this.targetRect.top)>.1||Math.abs(t.left-this.targetRect.left)>.1);r?(this.targetRect=t,this.setSize(this.targetRect.width,this.targetRect.height),this.updateCanvasLayout()):i?(this.targetRect=t,this.updateCanvasLayout()):this.targetRect=t,this.renderOrder=0;const a=new Set;this.reconcileNode(e,a);for(const[n,o]of this.meshMap.entries())a.has(n)||(this.scene.remove(o),o.geometry.dispose(),o.material instanceof d.Material&&o.material.dispose(),this.meshMap.delete(n))}reconcileNode(e,t){var i;t.add(e.element);let r=this.meshMap.get(e.element);if(!r){const a=new d.PlaneGeometry(1,1);let n;n=I.create("BOX",e.styles,"",e.rect.width,e.rect.height,this.qualityFactor,e.isTraveler?(i=this.renderTarget)==null?void 0:i.texture:void 0,e.shaderHooks),r=new d.Mesh(a,n),e.type==="TEXT"&&(r.name="BG_MESH"),this.scene.add(r),this.meshMap.set(e.element,r)}if(r.userData.domRect=e.rect,this.updateMeshProperties(r,e),this.updateMeshLayers(r,e),e.isTraveler&&r.layers.enable(28),e.type==="BOX")for(const a of e.children)this.reconcileNode(a,t);else e.type==="TEXT"&&this.reconcileTextChild(r,e)}reconcileTextChild(e,t){var o,l;let r=e.children.find(c=>c.name==="TEXT_CHILD");const i=JSON.stringify(t.textStyles),a=(o=r==null?void 0:r.userData)==null?void 0:o.styleHash;if(!r||t.dirtyMask&L||i!==a){r&&((l=r.material.map)==null||l.dispose(),r.geometry.dispose(),e.remove(r));const c=I.create("TEXT",t.textStyles,t.textContent||"",t.rect.width,t.rect.height,this.qualityFactor),v=new d.PlaneGeometry(1,1);r=new d.Mesh(v,c),r.name="TEXT_CHILD",r.userData={styleHash:i},this.updateMeshLayers(r,t),r.position.z=.005,e.add(r)}if(r){const c=e.userData.domRect,v=c.x+c.width/2,p=c.y+c.height/2,m=t.rect.x+t.rect.width/2,g=t.rect.y+t.rect.height/2,R=m-v,y=-(g-p);r.position.set(R,y,.005)}}updateMeshProperties(e,t){var g;const{rect:r,styles:i}=t,a=this.renderer.getPixelRatio(),n=this.renderer.domElement.width/a,o=this.renderer.domElement.height/a;e.scale.set(r.width,r.height,1);const l=.001;this.renderOrder++;const c=this.targetRect.left+window.scrollX,v=this.targetRect.top+window.scrollY,p=r.x-c,m=r.y-v;e.position.set(p-n/2+r.width/2,-m+o/2-r.height/2,i.zIndex+this.renderOrder*l),I.update(e.material,"BOX",t.styles,"",t.rect.width,t.rect.height,this.qualityFactor,t.isTraveler?(g=this.renderTarget)==null?void 0:g.texture:void 0)}updateMeshLayers(e,t){const r=(1-(t.visibility&C))*30;e.layers.set(r),t.visibility===(C|E)&&e.layers.enable(29)}captureRenderTarget(){const e=[];for(const l of this.meshMap.values())l.layers.mask&1<<28&&e.push(l);if(e.length===0)return;const t=new d.Color,r=this.renderer.getClearAlpha();this.renderer.getClearColor(t),this.renderer.setClearColor(0,0),this.renderer.setRenderTarget(this.renderTarget),this.renderer.clear(),this.renderer.autoClear=!1,this.renderer.setScissorTest(!0),this.camera.layers.set(29);const i=new d.Vector3,a=this.targetRect.width,n=this.targetRect.height,o=this.renderer.getPixelRatio();for(const l of e){i.setFromMatrixPosition(l.matrixWorld),i.project(this.camera);const c=(i.x+1)/2*a,v=(i.y+1)/2*n;let p=0,m=1;typeof this.clipArea=="number"?m=this.clipArea:this.clipArea.endsWith("%")?m=parseFloat(this.clipArea)/100:this.clipArea.endsWith("px")&&(p=parseFloat(this.clipArea));const g=l.scale.x*m+.5,R=l.scale.y*m+.5,y=c-g/2,_=v-R/2,N=(y*this.qualityFactor-p)/o,A=(_*this.qualityFactor-p)/o,z=(g*this.qualityFactor+p*2)/o,f=(R*this.qualityFactor+p*2)/o;this.renderer.setScissor(N,A,z,f),this.renderer.render(this.scene,this.camera)}this.renderer.setScissorTest(!1),this.renderer.autoClear=!0,this.renderer.setRenderTarget(null),this.camera.layers.set(28),this.renderer.setClearColor(t,r)}render(){this.renderTarget&&this.captureRenderTarget(),this.renderer.render(this.scene,this.camera)}showScissoredRenderTarget(){if(!this.renderTarget)return;const e=this.targetRect.width,t=this.targetRect.height,r=new d.PlaneGeometry(e,t),i=new d.MeshBasicMaterial({map:this.renderTarget.texture,side:d.DoubleSide,transparent:!0,opacity:.8}),a=new d.Mesh(r,i);a.position.set(0,0,90),a.layers.set(28),this.scene.add(a)}}function Q(s){const e=document.createRange();e.selectNodeContents(s);const t=e.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function K(s){const e=parseFloat(s.fontSize);let t=parseFloat(s.lineHeight);isNaN(t)&&(t=e*1.2);let r=parseFloat(s.letterSpacing);return isNaN(r)&&(r=0),{font:`${s.fontStyle} ${s.fontWeight} ${s.fontSize} ${s.fontFamily}`,color:s.color,textAlign:s.textAlign||"start",textBaseline:"alphabetic",direction:s.direction||"inherit",lineHeight:t,letterSpacing:r}}function q(s,e=M|O|Y|L|B,t,r){if(s.nodeType===Node.TEXT_NODE){const f=s;if(!f.textContent||!f.textContent.trim())return null;const x=f.textContent.replace(/\s+/g," ").trim();if(x.length===0)return null;const b=Q(f);if(b.width===0||b.height===0)return null;const W=f.parentElement,X=W?window.getComputedStyle(W):null;return X?{id:Math.random().toString(36).substring(2,9),type:"TEXT",element:f,rect:{x:b.left+window.scrollX,y:b.top+window.scrollY,width:b.width,height:b.height},styles:{backgroundColor:"transparent",opacity:parseFloat(X.opacity),zIndex:0,borderRadius:"0px",borderColor:"transparent",borderWidth:"0px"},textContent:x,textStyles:K(X),dirtyMask:e,visibility:t,isTraveler:!1,children:[]}:null}const i=s,a=i.dataset.mirageFilter;let n=t,o=t;if(a){const f=new Set(a.split(/\s+/));for(const x of f)if(!P.includes(x))throw new Error(`[MirageEngine] Invalid filter token: '${x}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`);if(f.has("end"))return null;if(f.has("include-tree")&&f.has("exclude-tree"))throw new Error("[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element.");if(f.has("include-self")&&f.has("exclude-self"))throw new Error("[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element.");f.has("include-tree")?n=n|C:f.has("exclude-tree")&&(n=n&~C),o=n,f.has("include-self")?o=o|C:f.has("exclude-self")&&(o=o&~C)}o=o|t&E;const l=i.dataset.mirageTravel;let c=!1;l&&new Set(l.split(/\s+/)).has("traveler")&&(o=o&~E,n=n&~E,c=!0);const v=i.dataset.mirageShader;let p;v&&(p=JSON.parse(v));const m=i.getBoundingClientRect(),g=window.getComputedStyle(i);if(m.width===0||m.height===0||g.display==="none")return null;let R=i.getAttribute("data-mid");R||(R=Math.random().toString(36).substring(2,11),i.setAttribute("data-mid",R));const y=parseInt(g.zIndex),_={backgroundColor:g.backgroundColor,opacity:parseFloat(g.opacity),zIndex:isNaN(y)?0:y,borderRadius:g.borderRadius,borderColor:g.borderColor,borderWidth:g.borderWidth};let N,A;const z=[];return Array.from(i.childNodes).forEach(f=>{const x=f.nodeType===Node.TEXT_NODE?o:n,b=q(f,e,x);b&&z.push(b)}),{id:R,type:"BOX",element:i,rect:{x:m.left+window.scrollX,y:m.top+window.scrollY,width:m.width,height:m.height},styles:_,textContent:N,textStyles:A,dirtyMask:e,visibility:o,isTraveler:c,children:z,shaderHooks:p}}class ee{constructor(e,t,r){h(this,"target");h(this,"renderer");h(this,"filter");h(this,"observer");h(this,"isDomDirty",!1);h(this,"isRunning",!1);h(this,"isTravelEnabled",!1);h(this,"pendingMask",D);h(this,"mutationTimer",null);h(this,"cssTimer",null);h(this,"resizeConfig");h(this,"resizeTimer",null);h(this,"isResizing",!1);h(this,"onTransitionFinished",e=>{this.target.contains(e.target)&&this.mutationTimer===null&&(this.cssTimer&&clearTimeout(this.cssTimer),this.pendingMask|=M|O,this.cssTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.cssTimer=null},50))});h(this,"onWindowResize",()=>{if(!this.resizeConfig.enabled){this.isDomDirty=!0;return}this.isResizing||(this.isResizing=!0,this.resizeConfig.onStart&&this.resizeConfig.onStart()),this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.resizeConfig.onEnd&&this.resizeConfig.onEnd(),this.isResizing=!1,this.resizeTimer=null},this.resizeConfig.delay)});h(this,"renderLoop",()=>{this.isRunning&&(this.isDomDirty&&this.forceUpdateScene(),this.renderer.render(),requestAnimationFrame(this.renderLoop))});var a,n;this.target=e,this.renderer=t,this.filter=r.filter;const i=(a=r.resizeDebounce)!=null?a:!0;i===!1?this.resizeConfig={enabled:!1,delay:0}:i===!0?this.resizeConfig={enabled:!0,delay:150}:this.resizeConfig={enabled:!0,delay:(n=i.delay)!=null?n:150,onStart:i.onStart,onEnd:i.onEnd},this.observer=new MutationObserver(o=>{let l=D;for(const c of o)c.type==="childList"?l|=B:c.type==="attributes"&&(c.attributeName==="style"||c.attributeName==="class")&&(l|=M|O);if(l!==D){if(this.pendingMask|=l,l&B){this.clearTimers(),console.log("Structural Change detected"),this.isDomDirty=!0;return}this.mutationTimer&&clearTimeout(this.mutationTimer),this.mutationTimer=window.setTimeout(()=>{this.mutationTimer=null,this.isDomDirty=!0},200)}})}start(){this.isRunning||(this.isRunning=!0,this.observer.observe(this.target,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),this.target.addEventListener("transitionend",this.onTransitionFinished),this.target.addEventListener("animationend",this.onTransitionFinished),window.addEventListener("resize",this.onWindowResize),this.forceUpdateScene(),this.renderLoop())}stop(){this.isRunning=!1,this.observer.disconnect(),this.clearTimers(),this.target.removeEventListener("transitionend",this.onTransitionFinished),this.target.removeEventListener("animationend",this.onTransitionFinished),window.removeEventListener("resize",this.onWindowResize)}clearTimers(){this.mutationTimer&&(clearTimeout(this.mutationTimer),this.mutationTimer=null),this.cssTimer&&(clearTimeout(this.cssTimer),this.cssTimer=null)}forceUpdateScene(){this.isDomDirty=!1;const e=document.querySelector("[data-mirage-travel='traveler']")!==null;e&&!this.isTravelEnabled&&(this.isTravelEnabled=!0,this.renderer.createRenderTarget());const t=q(this.target,this.pendingMask,e?C|E:C,this.filter);t&&this.renderer.syncScene(t),this.pendingMask=D}}class te{constructor(e,t){h(this,"renderer");h(this,"syncer");h(this,"target");var i,a,n;this.target=e;let r;if(t.mode==="duplicate"?r=(a=(i=t.container)!=null?i:this.target.parentElement)!=null?a:void 0:r=(n=this.target.parentElement)!=null?n:void 0,!r)throw new Error("[Mirage] Cannot find a container (parent or option).");this.renderer=new Z(this.target,t,r),this.renderer.mount(),this.syncer=new ee(this.target,this.renderer,t)}start(){this.syncer.start()}stop(){this.syncer.stop()}dispose(){this.syncer.stop(),this.renderer.dispose()}}u.ALLOWED_FILTERS=P,u.DIRTY_CONTENT=L,u.DIRTY_NONE=D,u.DIRTY_RECT=M,u.DIRTY_STRUCTURE=B,u.DIRTY_STYLE=O,u.DIRTY_ZINDEX=Y,u.EXCLUDED=H,u.Engine=te,u.SYSTEM_LAYER=E,u.USER_LAYER=C,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
@@ -9,6 +9,7 @@ export declare class Renderer {
9
9
  private renderOrder;
10
10
  private qualityFactor;
11
11
  private mode;
12
+ private clipArea;
12
13
  private target;
13
14
  private mountContainer;
14
15
  private targetRect;
@@ -1,4 +1,4 @@
1
- import { TextStyles, BoxStyles } from '../../packages/painter/src/index.ts';
1
+ import { TextStyles, BoxStyles, ShaderHooks } from '../../packages/painter/src/index.ts';
2
2
  import { Visibility } from './flags';
3
3
 
4
4
  export type NodeType = "BOX" | "TEXT";
@@ -19,5 +19,6 @@ export interface SceneNode {
19
19
  dirtyMask: number;
20
20
  visibility: Visibility;
21
21
  isTraveler: boolean;
22
+ shaderHooks?: ShaderHooks;
22
23
  children: SceneNode[];
23
24
  }
@@ -1,5 +1,8 @@
1
1
  export type Quality = "low" | "medium" | "high" | number;
2
2
  export type MirageMode = "overlay" | "duplicate";
3
+ export type PxUnit = `${number}px`;
4
+ export type PercentUnit = `${number}%`;
5
+ export type travelerClipArea = PxUnit | PercentUnit | number;
3
6
  export interface FilterConfig {
4
7
  includeTree?: string[];
5
8
  excludeTree?: string[];
@@ -20,6 +23,7 @@ interface BaseConfig {
20
23
  };
21
24
  filter?: FilterConfig;
22
25
  resizeDebounce?: boolean | ResizeConfig;
26
+ travelerClipArea?: travelerClipArea;
23
27
  }
24
28
  export interface OverlayConfig extends BaseConfig {
25
29
  mode?: "overlay";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mirage-engine/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "main": "src/index.ts",
5
5
  "types": "src/index.ts",
6
6
  "peerDependencies": {
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@types/three": "^0.181.0",
16
- "@mirage-engine/painter": "0.3.0"
16
+ "@mirage-engine/painter": "0.4.0"
17
17
  },
18
18
  "private": false,
19
19
  "publishConfig": {
@@ -11,7 +11,7 @@ import {
11
11
  ALLOWED_FILTERS,
12
12
  } from "../types";
13
13
 
14
- import { BoxStyles, TextStyles } from "@mirage-engine/painter";
14
+ import { BoxStyles, TextStyles, ShaderHooks } from "@mirage-engine/painter";
15
15
  import { FilterConfig } from "../types/config";
16
16
 
17
17
  // Helper function: getTextNodeRect, isValidTextNode, isLeafTextElement, extractTextStyles
@@ -173,6 +173,14 @@ export function extractSceneGraph(
173
173
  }
174
174
  }
175
175
 
176
+ const shaderData = element.dataset.mirageShader;
177
+ let shaderHooks: ShaderHooks | undefined;
178
+ if (shaderData) {
179
+ shaderHooks = JSON.parse(shaderData) as ShaderHooks;
180
+ // [TODO] object 형태로 shader hooks 받기
181
+ // [TODO] 변수형태로 저장해서 return scene node에 넣어주기
182
+ }
183
+
176
184
  const rect = element.getBoundingClientRect();
177
185
  const computed = window.getComputedStyle(element);
178
186
 
@@ -181,6 +189,7 @@ export function extractSceneGraph(
181
189
  return null;
182
190
  }
183
191
 
192
+ // [TODO] dataset 방식으로 변경
184
193
  let id = element.getAttribute("data-mid");
185
194
  if (!id) {
186
195
  id = Math.random().toString(36).substring(2, 11);
@@ -232,5 +241,6 @@ export function extractSceneGraph(
232
241
  visibility: visibleFlag,
233
242
  isTraveler: isTraveler,
234
243
  children,
244
+ shaderHooks,
235
245
  };
236
246
  }
@@ -7,6 +7,7 @@ import {
7
7
  MirageMode,
8
8
  USER_LAYER,
9
9
  SYSTEM_LAYER,
10
+ travelerClipArea,
10
11
  } from "../types";
11
12
  import { Painter } from "@mirage-engine/painter";
12
13
 
@@ -19,6 +20,7 @@ export class Renderer {
19
20
  private renderOrder: number = 0;
20
21
  private qualityFactor: number = 2;
21
22
  private mode: MirageMode = "overlay";
23
+ private clipArea: travelerClipArea = 1;
22
24
 
23
25
  private target: HTMLElement;
24
26
  private mountContainer: HTMLElement;
@@ -35,7 +37,7 @@ export class Renderer {
35
37
  this.mountContainer = mountContainer;
36
38
 
37
39
  this.mode = config.mode ?? "overlay";
38
-
40
+ this.clipArea = config.travelerClipArea ?? 1;
39
41
  this.canvas = document.createElement("canvas");
40
42
  this.scene = new THREE.Scene();
41
43
 
@@ -210,6 +212,7 @@ export class Renderer {
210
212
  node.rect.height,
211
213
  this.qualityFactor,
212
214
  node.isTraveler ? this.renderTarget?.texture : undefined,
215
+ node.shaderHooks
213
216
  );
214
217
  mesh = new THREE.Mesh(geometry, material);
215
218
  if (node.type === "TEXT") mesh.name = "BG_MESH";
@@ -361,16 +364,27 @@ export class Renderer {
361
364
  const centerX = ((vector.x + 1) / 2) * canvasWidth;
362
365
  const centerY = ((vector.y + 1) / 2) * canvasHeight;
363
366
 
364
- const width = traveler.scale.x;
365
- const height = traveler.scale.y;
367
+ let clipDiff = 0;
368
+ let clipRadito = 1;
369
+ if (typeof this.clipArea === "number") {
370
+ clipRadito = this.clipArea;
371
+ } else if (this.clipArea.endsWith("%")) {
372
+ clipRadito = parseFloat(this.clipArea) / 100;
373
+ } else if (this.clipArea.endsWith("px")) {
374
+ clipDiff = parseFloat(this.clipArea);
375
+ }
376
+
377
+ const width = traveler.scale.x * clipRadito + 0.5;
378
+ const height = traveler.scale.y * clipRadito + 0.5;
366
379
 
367
380
  const localX = centerX - width / 2;
368
381
  const localY = centerY - height / 2;
369
382
 
370
- const scissorX = (localX * this.qualityFactor) / pixelRatio;
371
- const scissorY = (localY * this.qualityFactor) / pixelRatio;
372
- const scissorW = (width * this.qualityFactor) / pixelRatio;
373
- const scissorH = (height * this.qualityFactor) / pixelRatio;
383
+ const scissorX = (localX * this.qualityFactor - clipDiff) / pixelRatio;
384
+ const scissorY = (localY * this.qualityFactor - clipDiff) / pixelRatio;
385
+ const scissorW = (width * this.qualityFactor + clipDiff * 2) / pixelRatio;
386
+ const scissorH =
387
+ (height * this.qualityFactor + clipDiff * 2) / pixelRatio;
374
388
 
375
389
  this.renderer.setScissor(scissorX, scissorY, scissorW, scissorH);
376
390
  this.renderer.render(this.scene, this.camera);
@@ -1,4 +1,4 @@
1
- import { TextStyles, BoxStyles } from "@mirage-engine/painter";
1
+ import { TextStyles, BoxStyles, ShaderHooks } from "@mirage-engine/painter";
2
2
  import { Visibility } from "./flags";
3
3
 
4
4
  export type NodeType = "BOX" | "TEXT";
@@ -26,6 +26,7 @@ export interface SceneNode {
26
26
 
27
27
  visibility: Visibility;
28
28
  isTraveler: boolean;
29
+ shaderHooks?: ShaderHooks;
29
30
 
30
31
  children: SceneNode[];
31
32
  }
@@ -1,5 +1,8 @@
1
1
  export type Quality = "low" | "medium" | "high" | number;
2
2
  export type MirageMode = "overlay" | "duplicate";
3
+ export type PxUnit = `${number}px`;
4
+ export type PercentUnit = `${number}%`;
5
+ export type travelerClipArea = PxUnit | PercentUnit | number;
3
6
  export interface FilterConfig {
4
7
  includeTree?: string[];
5
8
  excludeTree?: string[];
@@ -22,6 +25,7 @@ interface BaseConfig {
22
25
  };
23
26
  filter?: FilterConfig;
24
27
  resizeDebounce?: boolean | ResizeConfig;
28
+ travelerClipArea? : travelerClipArea;
25
29
  }
26
30
 
27
31
  export interface OverlayConfig extends BaseConfig {