mirage-engine 0.2.13 → 0.2.15

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,175 +1,224 @@
1
- var B = Object.defineProperty;
2
- var z = (r, t, e) => t in r ? B(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
3
- var c = (r, t, e) => (z(r, typeof t != "symbol" ? t + "" : t, e), e);
4
- import * as h from "three";
5
- const v = 0, R = 1, b = 2, D = 4, C = 8, E = 16;
6
- function F(r, t, e) {
7
- const i = t.split(`
1
+ var k = Object.defineProperty;
2
+ var I = (r, e, t) => e in r ? k(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
+ var c = (r, e, t) => (I(r, typeof e != "symbol" ? e + "" : e, t), t);
4
+ import * as d from "three";
5
+ const T = 0, S = 1, B = 2, _ = 4, M = 8, z = 16, D = 0, F = 30, A = [
6
+ "include-tree",
7
+ "exclude-tree",
8
+ "include-self",
9
+ "exclude-self",
10
+ "end"
11
+ ];
12
+ function P(r, e, t) {
13
+ const i = e.split(`
8
14
  `), s = [];
9
15
  return i.forEach((n) => {
10
16
  const a = n.split(" ");
11
17
  let o = a[0];
12
- for (let l = 1; l < a.length; l++) {
13
- const d = a[l];
14
- r.measureText(o + " " + d).width < e ? o += " " + d : (s.push(o), o = d);
18
+ for (let h = 1; h < a.length; h++) {
19
+ const l = a[h];
20
+ r.measureText(o + " " + l).width < t ? o += " " + l : (s.push(o), o = l);
15
21
  }
16
22
  s.push(o);
17
23
  }), s;
18
24
  }
19
- function S(r, t, e, i, s = 2) {
25
+ function L(r, e, t, i, s = 2) {
20
26
  const n = document.createElement("canvas"), a = n.getContext("2d");
21
27
  if (!a)
22
28
  throw new Error("[Mirage] Failed to create canvas context");
23
- const l = (window.devicePixelRatio || 1) * s;
24
- n.width = e * l, n.height = i * l, a.scale(l, l), a.font = t.font, a.fillStyle = t.color, a.textBaseline = "top", a.globalAlpha = 1;
25
- const d = F(a, r, e), p = t.lineHeight;
26
- d.forEach((m, g) => {
27
- const y = g * p + 2;
28
- let f = 0;
29
- t.textAlign === "center" ? f = e / 2 : t.textAlign === "right" && (f = e), a.textAlign = t.textAlign, a.fillText(m, f, y);
29
+ const h = (window.devicePixelRatio || 1) * s;
30
+ n.width = t * h, n.height = i * h, a.scale(h, h), a.font = e.font, a.fillStyle = e.color, a.textBaseline = "top", a.globalAlpha = 1;
31
+ const l = P(a, r, t), p = e.lineHeight;
32
+ l.forEach((x, w) => {
33
+ const b = w * p + 2;
34
+ let y = 0;
35
+ e.textAlign === "center" ? y = t / 2 : e.textAlign === "right" && (y = t), a.textAlign = e.textAlign, a.fillText(x, y, b);
30
36
  });
31
- const u = new h.CanvasTexture(n);
32
- return u.colorSpace = h.SRGBColorSpace, u.minFilter = h.LinearFilter, u.magFilter = h.LinearFilter, u.needsUpdate = !0, u;
37
+ const f = new d.CanvasTexture(n);
38
+ return f.colorSpace = d.SRGBColorSpace, f.minFilter = d.LinearFilter, f.magFilter = d.LinearFilter, f.needsUpdate = !0, f;
33
39
  }
34
- function w(r) {
40
+ function v(r) {
35
41
  return typeof r == "number" ? r : parseFloat(r) || 0;
36
42
  }
37
- const O = `
43
+ function X(r, e) {
44
+ var o, h, l, p;
45
+ if (!e) {
46
+ r.set(0, 0, 0, 0);
47
+ return;
48
+ }
49
+ const t = e.split("/")[0].trim().split(/\s+/), i = v(t[0]), s = v((o = t[1]) != null ? o : t[0]), n = v((h = t[2]) != null ? h : t[0]), a = v((p = (l = t[3]) != null ? l : t[1]) != null ? p : t[0]);
50
+ r.set(i, s, n, a);
51
+ }
52
+ const W = (
53
+ /* glsl */
54
+ `
38
55
  varying vec2 vUv;
39
56
  void main() {
40
57
  vUv = uv;
41
58
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
42
59
  }
43
- `, A = `
60
+ `
61
+ ), Y = (
62
+ /* glsl */
63
+ `
64
+
44
65
  varying vec2 vUv;
45
66
 
46
67
  uniform vec2 uSize;
47
- uniform float uRadius;
68
+ uniform vec4 uRadius;
48
69
  uniform float uBorderWidth;
49
- uniform vec3 uColor;
70
+ uniform vec3 uBgColor;
50
71
  uniform vec3 uBorderColor;
51
72
  uniform float uOpacity;
52
73
  uniform float uBgOpacity;
74
+ uniform float uBorderOpacity;
53
75
 
54
- // SDF 박스 함수
76
+ // SDF box
55
77
  float sdRoundedBox(vec2 p, vec2 b, float r) {
56
78
  vec2 q = abs(p) - b + r;
79
+ // return length(max(q, 0.0)) - r;
57
80
  return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
58
81
  }
59
82
 
60
83
  void main() {
84
+ // uVu: (0.0, 0.0) ~ (1.0, 1.0) / center: (0.5, 0.5)
85
+ // p: (-1.0, -1.0) ~ (1.0, 1.0) / center: (0.0, 0.0)
61
86
  vec2 p = (vUv - 0.5) * uSize;
62
87
  vec2 halfSize = uSize * 0.5;
63
88
 
64
- float d = sdRoundedBox(p, halfSize, uRadius);
65
-
66
- float smoothEdge = 1.0;
89
+ // # border-radius
90
+ vec2 xRadii = mix(uRadius.xw, uRadius.yz, step(0.0, p.x));
91
+ float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
92
+ float d = sdRoundedBox(p, halfSize, r);
67
93
 
68
- float fillAlpha = 1.0 - smoothstep(-uBorderWidth - smoothEdge, -uBorderWidth, d);
69
-
70
- float borderAlpha = 0.0;
71
-
72
- if (uBorderWidth > 0.01) {
73
- borderAlpha = (1.0 - smoothstep(0.0, smoothEdge, d)) - fillAlpha;
74
- }
94
+ // 1px blur for anti-aliasing
95
+ float aa = 1.0;
75
96
 
76
- vec3 color = uColor;
77
- float totalAlpha = borderAlpha + fillAlpha;
78
-
79
- if (totalAlpha > 0.001) {
80
- color = mix(uColor, uBorderColor, borderAlpha / totalAlpha);
97
+ // x == 0~aa -> 1
98
+ // x < 0 -> 0
99
+ // x > aa -> 1
100
+ float bgMask = 1.0 - smoothstep(0.0, aa, d);
101
+
102
+ // v valley
103
+ // 10px -> 5
104
+ float halfBorder = uBorderWidth * 0.5;
105
+ // 10px :
106
+ // 0 -> 0
107
+ // -10 -> 0
108
+ // -5 -> -5
109
+ float borderD = abs(d + halfBorder) - halfBorder;
110
+ // ^ border 내부는 음수/외부는 양수
111
+
112
+ // [!] 내부가 음수인 곳에서 시작점이 0이면 내부는 안티 얼리어싱 되지 않음.
113
+ // 1에서 빼든 그대로든 상관없이 경계선 밖 1px
114
+
115
+ // 최종 alpha를 위해 border 부분에 해당하는 픽셀 만 1로 반환.
116
+ float borderAlpha = (1.0 - smoothstep(0.0, aa, borderD)) * uBorderOpacity;
117
+
118
+ if (uBorderWidth <= 0.01) {
119
+ borderAlpha = 0.0;
81
120
  }
82
-
83
- float shapeAlpha = borderAlpha + (fillAlpha * uBgOpacity);
84
- float finalOpacity = shapeAlpha * uOpacity;
85
-
121
+
122
+ float aFront = borderAlpha;
123
+ float aBack = uBgOpacity;
124
+ float aOut = aFront + aBack * (1.0 - aFront);
125
+
126
+ float safeAlpha = max(aOut, 0.0001);
127
+ vec3 cOut = (uBorderColor * aFront + uBgColor * aBack * (1.0 - aFront)) / safeAlpha;
128
+
129
+ float finalOpacity = aOut * bgMask * uOpacity;
130
+
86
131
  if (finalOpacity < 0.001) discard;
87
132
 
88
- gl_FragColor = vec4(color, finalOpacity);
133
+ gl_FragColor = vec4(cOut, finalOpacity);
134
+
135
+ #include <colorspace_fragment>
89
136
  }
90
- `;
91
- function x(r) {
137
+ `
138
+ );
139
+ function R(r) {
92
140
  if (!r || r === "transparent")
93
- return { color: new h.Color(16777215), alpha: 0 };
94
- const t = r.match(
141
+ return { color: new d.Color(16777215), alpha: 0 };
142
+ const e = r.match(
95
143
  /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
96
144
  );
97
- if (t) {
98
- const e = parseInt(t[1], 10), i = parseInt(t[2], 10), s = parseInt(t[3], 10), n = t[4] !== void 0 ? parseFloat(t[4]) : 1;
99
- return { color: new h.Color(`rgb(${e}, ${i}, ${s})`), alpha: n };
145
+ if (e) {
146
+ const t = parseInt(e[1], 10), i = parseInt(e[2], 10), s = parseInt(e[3], 10), n = e[4] !== void 0 ? parseFloat(e[4]) : 1;
147
+ return { color: new d.Color(`rgb(${t}, ${i}, ${s})`), alpha: n };
100
148
  }
101
- return { color: new h.Color(r), alpha: 1 };
149
+ return { color: new d.Color(r), alpha: 1 };
102
150
  }
103
- function I(r, t, e) {
151
+ function H(r, e, t) {
104
152
  var o;
105
- const i = x(r.backgroundColor), s = x(r.borderColor), n = {
106
- uSize: { value: new h.Vector2(t, e) },
107
- uRadius: { value: w(r.borderRadius) },
108
- uBorderWidth: { value: w(r.borderWidth) },
109
- uColor: { value: i.color },
153
+ const i = R(r.backgroundColor), s = R(r.borderColor), n = {
154
+ uSize: { value: new d.Vector2(e, t) },
155
+ uRadius: { value: new d.Vector4(0, 0, 0, 0) },
156
+ uBorderWidth: { value: v(r.borderWidth) },
157
+ uBgColor: { value: i.color },
110
158
  uBorderColor: { value: s.color },
111
159
  uOpacity: { value: (o = r.opacity) != null ? o : 1 },
112
- uBgOpacity: { value: i.alpha }
160
+ uBgOpacity: { value: i.alpha },
161
+ uBorderOpacity: { value: s.alpha }
113
162
  };
114
- return new h.ShaderMaterial({
163
+ return X(n.uRadius.value, r.borderRadius), new d.ShaderMaterial({
115
164
  uniforms: n,
116
- vertexShader: O,
117
- fragmentShader: A,
165
+ vertexShader: W,
166
+ fragmentShader: Y,
118
167
  transparent: !0,
119
- side: h.FrontSide
168
+ side: d.FrontSide
120
169
  // for better performance
121
170
  });
122
171
  }
123
- function L(r, t, e, i) {
172
+ function U(r, e, t, i) {
124
173
  var a;
125
- const s = x(t.backgroundColor), n = x(t.borderColor);
126
- r.uniforms.uSize.value.set(e, i), r.uniforms.uRadius.value = w(t.borderRadius), r.uniforms.uBorderWidth.value = w(t.borderWidth), r.uniforms.uColor.value.copy(s.color), r.uniforms.uBorderColor.value.copy(n.color), r.uniforms.uOpacity.value = (a = t.opacity) != null ? a : 1, r.uniforms.uBgOpacity.value = s.alpha;
174
+ const s = R(e.backgroundColor), n = R(e.borderColor);
175
+ r.uniforms.uSize.value.set(t, i), X(r.uniforms.uRadius.value, e.borderRadius), r.uniforms.uBorderWidth.value = v(e.borderWidth), r.uniforms.uBgColor.value.copy(s.color), r.uniforms.uBorderColor.value.copy(n.color), r.uniforms.uOpacity.value = (a = e.opacity) != null ? a : 1, r.uniforms.uBgOpacity.value = s.alpha, r.uniforms.uBorderOpacity.value = n.alpha;
127
176
  }
128
- const T = {
129
- create(r, t, e, i, s, n = 2) {
177
+ const E = {
178
+ create(r, e, t, i, s, n = 2) {
130
179
  if (r === "BOX")
131
- return I(t, i, s);
180
+ return H(e, i, s);
132
181
  if (r === "TEXT") {
133
- const a = S(
134
- e || "",
135
- t,
182
+ const a = L(
183
+ t || "",
184
+ e,
136
185
  i,
137
186
  s,
138
187
  n
139
188
  );
140
- return new h.MeshBasicMaterial({
189
+ return new d.MeshBasicMaterial({
141
190
  map: a,
142
191
  transparent: !0,
143
- side: h.FrontSide,
192
+ side: d.FrontSide,
144
193
  color: 16777215
145
194
  });
146
195
  }
147
- return new h.MeshBasicMaterial({ visible: !1 });
196
+ return new d.MeshBasicMaterial({ visible: !1 });
148
197
  },
149
- update(r, t, e, i, s, n, a = 2) {
150
- if (t === "BOX")
151
- L(
198
+ update(r, e, t, i, s, n, a = 2) {
199
+ if (e === "BOX")
200
+ U(
152
201
  r,
153
- e,
202
+ t,
154
203
  s,
155
204
  n
156
205
  );
157
- else if (t === "TEXT") {
206
+ else if (e === "TEXT") {
158
207
  const o = r;
159
208
  o.map && o.map.dispose();
160
- const l = S(
209
+ const h = L(
161
210
  i || "",
162
- e,
211
+ t,
163
212
  s,
164
213
  n,
165
214
  a
166
215
  );
167
- o.map = l, o.needsUpdate = !0;
216
+ o.map = h, o.needsUpdate = !0;
168
217
  }
169
218
  }
170
219
  };
171
- class X {
172
- constructor(t, e, i) {
220
+ class $ {
221
+ constructor(e, t, i) {
173
222
  c(this, "canvas");
174
223
  c(this, "scene");
175
224
  c(this, "camera");
@@ -177,33 +226,34 @@ class X {
177
226
  c(this, "renderOrder", 0);
178
227
  c(this, "textQualityFactor", 2);
179
228
  c(this, "mode", "overlay");
180
- c(this, "customZIndex", "9999");
181
229
  c(this, "target");
182
230
  c(this, "mountContainer");
183
231
  c(this, "targetRect");
184
232
  c(this, "meshMap", /* @__PURE__ */ new Map());
185
- var a, o, l;
186
- this.target = t, this.mountContainer = i, this.mode = (a = e.mode) != null ? a : "overlay", (o = e.style) != null && o.zIndex && (this.customZIndex = e.style.zIndex), this.canvas = document.createElement("canvas"), this.scene = new h.Scene(), this.targetRect = this.target.getBoundingClientRect();
233
+ var a, o;
234
+ this.target = e, this.mountContainer = i, this.mode = (a = t.mode) != null ? a : "overlay", this.canvas = document.createElement("canvas"), this.scene = new d.Scene(), this.targetRect = this.target.getBoundingClientRect();
187
235
  const s = this.targetRect.width, n = this.targetRect.height;
188
- this.camera = new h.OrthographicCamera(
236
+ this.camera = new d.OrthographicCamera(
189
237
  s / -2,
190
238
  s / 2,
191
239
  n / 2,
192
240
  n / -2,
193
241
  1,
194
242
  1e3
195
- ), this.camera.position.z = 100, this.renderer = new h.WebGLRenderer({
243
+ ), this.camera.position.z = 100, this.renderer = new d.WebGLRenderer({
196
244
  canvas: this.canvas,
197
245
  alpha: !0,
198
246
  antialias: !0
199
- }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(s, n), this.applyTextQuality((l = e.textQuality) != null ? l : "medium");
247
+ // [new]
248
+ // premultipliedAlpha: true
249
+ }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(s, n), this.applyTextQuality((o = t.textQuality) != null ? o : "medium");
200
250
  }
201
- applyTextQuality(t) {
202
- if (typeof t == "number") {
203
- this.textQualityFactor = Math.max(0.1, t);
251
+ applyTextQuality(e) {
252
+ if (typeof e == "number") {
253
+ this.textQualityFactor = Math.max(0.1, e);
204
254
  return;
205
255
  }
206
- switch (t) {
256
+ switch (e) {
207
257
  case "low":
208
258
  this.textQualityFactor = 1;
209
259
  break;
@@ -217,7 +267,7 @@ class X {
217
267
  }
218
268
  }
219
269
  mount() {
220
- this.mountContainer.appendChild(this.canvas), this.canvas.style.zIndex = this.customZIndex, this.canvas.style.pointerEvents = this.mode === "overlay" ? "none" : "auto", this.updateCanvasLayout();
270
+ this.mountContainer.prepend(this.canvas), this.canvas.style.pointerEvents = this.mode === "overlay" ? "none" : "auto", this.updateCanvasLayout();
221
271
  }
222
272
  updateCanvasLayout() {
223
273
  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");
@@ -225,97 +275,97 @@ class X {
225
275
  dispose() {
226
276
  this.renderer.dispose(), this.canvas.remove();
227
277
  }
228
- setSize(t, e) {
229
- this.renderer.setSize(t, e), this.camera.left = t / -2, this.camera.right = t / 2, this.camera.top = e / 2, this.camera.bottom = e / -2, this.camera.updateProjectionMatrix();
278
+ setSize(e, t) {
279
+ this.renderer.setSize(e, t), this.camera.left = e / -2, this.camera.right = e / 2, this.camera.top = t / 2, this.camera.bottom = t / -2, this.camera.updateProjectionMatrix();
230
280
  }
231
- syncScene(t) {
232
- const e = this.target.getBoundingClientRect(), i = Math.abs(e.width - this.targetRect.width) > 0.1 || Math.abs(e.height - this.targetRect.height) > 0.1, s = this.mode === "overlay" && (Math.abs(e.top - this.targetRect.top) > 0.1 || Math.abs(e.left - this.targetRect.left) > 0.1);
233
- i ? (this.targetRect = e, this.renderer.setSize(this.targetRect.width, this.targetRect.height), this.camera.left = this.targetRect.width / -2, this.camera.right = this.targetRect.width / 2, this.camera.top = this.targetRect.height / 2, this.camera.bottom = this.targetRect.height / -2, this.camera.updateProjectionMatrix(), this.updateCanvasLayout()) : s ? (this.targetRect = e, this.updateCanvasLayout()) : this.targetRect = e, this.renderOrder = 0;
281
+ syncScene(e) {
282
+ const t = this.target.getBoundingClientRect(), i = 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);
283
+ i ? (this.targetRect = t, this.renderer.setSize(this.targetRect.width, this.targetRect.height), this.camera.left = this.targetRect.width / -2, this.camera.right = this.targetRect.width / 2, this.camera.top = this.targetRect.height / 2, this.camera.bottom = this.targetRect.height / -2, this.camera.layers.set(0), this.camera.updateProjectionMatrix(), this.updateCanvasLayout()) : s ? (this.targetRect = t, this.updateCanvasLayout()) : this.targetRect = t, this.renderOrder = 0;
234
284
  const n = /* @__PURE__ */ new Set();
235
- this.reconcileNode(t, n);
285
+ this.reconcileNode(e, n);
236
286
  for (const [a, o] of this.meshMap.entries())
237
- n.has(a) || (this.scene.remove(o), o.geometry.dispose(), o.material instanceof h.Material && o.material.dispose(), this.meshMap.delete(a));
287
+ n.has(a) || (this.scene.remove(o), o.geometry.dispose(), o.material instanceof d.Material && o.material.dispose(), this.meshMap.delete(a));
238
288
  }
239
- reconcileNode(t, e) {
240
- e.add(t.element);
241
- let i = this.meshMap.get(t.element);
289
+ reconcileNode(e, t) {
290
+ t.add(e.element);
291
+ let i = this.meshMap.get(e.element);
242
292
  if (!i) {
243
- const s = new h.PlaneGeometry(1, 1), n = T.create(
293
+ const s = new d.PlaneGeometry(1, 1), n = E.create(
244
294
  "BOX",
245
- t.styles,
295
+ e.styles,
246
296
  "",
247
- t.rect.width,
248
- t.rect.height
297
+ e.rect.width,
298
+ e.rect.height
249
299
  );
250
- i = new h.Mesh(s, n), t.type === "TEXT" && (i.name = "BG_MESH"), this.scene.add(i), this.meshMap.set(t.element, i);
300
+ i = new d.Mesh(s, n), i.layers.set(e.visibility), e.type === "TEXT" && (i.name = "BG_MESH"), this.scene.add(i), this.meshMap.set(e.element, i);
251
301
  }
252
- if (i.userData.domRect = t.rect, this.updateMeshProperties(i, t), t.type === "BOX")
253
- for (const s of t.children)
254
- this.reconcileNode(s, e);
302
+ if (i.userData.domRect = e.rect, this.updateMeshProperties(i, e), e.type === "BOX")
303
+ for (const s of e.children)
304
+ this.reconcileNode(s, t);
255
305
  else
256
- t.type === "TEXT" && this.reconcileTextChild(i, t);
306
+ e.type === "TEXT" && this.reconcileTextChild(i, e);
257
307
  }
258
- reconcileTextChild(t, e) {
259
- var o, l;
260
- let i = t.children.find(
261
- (d) => d.name === "TEXT_CHILD"
308
+ reconcileTextChild(e, t) {
309
+ var o, h;
310
+ let i = e.children.find(
311
+ (l) => l.name === "TEXT_CHILD"
262
312
  );
263
- const s = JSON.stringify(e.textStyles), n = (o = i == null ? void 0 : i.userData) == null ? void 0 : o.styleHash;
264
- if (!i || e.dirtyMask & E || s !== n) {
265
- i && ((l = i.material.map) == null || l.dispose(), i.geometry.dispose(), t.remove(i));
266
- const d = T.create(
313
+ const s = JSON.stringify(t.textStyles), n = (o = i == null ? void 0 : i.userData) == null ? void 0 : o.styleHash;
314
+ if (!i || t.dirtyMask & z || s !== n) {
315
+ i && ((h = i.material.map) == null || h.dispose(), i.geometry.dispose(), e.remove(i));
316
+ const l = E.create(
267
317
  "TEXT",
268
- e.textStyles,
269
- e.textContent || "",
270
- e.rect.width,
271
- e.rect.height,
318
+ t.textStyles,
319
+ t.textContent || "",
320
+ t.rect.width,
321
+ t.rect.height,
272
322
  this.textQualityFactor
273
- ), p = new h.PlaneGeometry(1, 1);
274
- i = new h.Mesh(p, d), i.name = "TEXT_CHILD", i.userData = { styleHash: s }, i.position.z = 5e-3, t.add(i);
323
+ ), p = new d.PlaneGeometry(1, 1);
324
+ i = new d.Mesh(p, l), i.name = "TEXT_CHILD", i.userData = { styleHash: s }, i.layers.set(t.visibility), i.position.z = 5e-3, e.add(i);
275
325
  }
276
326
  if (i) {
277
- const d = t.userData.domRect, p = d.x + d.width / 2, u = d.y + d.height / 2, m = e.rect.x + e.rect.width / 2, g = e.rect.y + e.rect.height / 2, y = m - p, f = -(g - u);
278
- i.position.set(y, f, 5e-3);
327
+ const l = e.userData.domRect, p = l.x + l.width / 2, f = l.y + l.height / 2, x = t.rect.x + t.rect.width / 2, w = t.rect.y + t.rect.height / 2, b = x - p, y = -(w - f);
328
+ i.position.set(b, y, 5e-3);
279
329
  }
280
330
  }
281
- updateMeshProperties(t, e) {
282
- const { rect: i, styles: s } = e, n = this.renderer.getPixelRatio(), a = this.renderer.domElement.width / n, o = this.renderer.domElement.height / n;
283
- t.scale.set(i.width, i.height, 1);
284
- const l = 1e-3;
331
+ updateMeshProperties(e, t) {
332
+ const { rect: i, styles: s } = t, n = this.renderer.getPixelRatio(), a = this.renderer.domElement.width / n, o = this.renderer.domElement.height / n;
333
+ e.scale.set(i.width, i.height, 1);
334
+ const h = 1e-3;
285
335
  this.renderOrder++;
286
- const d = this.targetRect.left + window.scrollX, p = this.targetRect.top + window.scrollY, u = i.x - d, m = i.y - p;
287
- t.position.set(
288
- u - a / 2 + i.width / 2,
289
- -m + o / 2 - i.height / 2,
290
- s.zIndex + this.renderOrder * l
291
- ), T.update(
292
- t.material,
336
+ const l = this.targetRect.left + window.scrollX, p = this.targetRect.top + window.scrollY, f = i.x - l, x = i.y - p;
337
+ e.position.set(
338
+ f - a / 2 + i.width / 2,
339
+ -x + o / 2 - i.height / 2,
340
+ s.zIndex + this.renderOrder * h
341
+ ), E.update(
342
+ e.material,
293
343
  "BOX",
294
- e.styles,
344
+ t.styles,
295
345
  "",
296
- e.rect.width,
297
- e.rect.height
346
+ t.rect.width,
347
+ t.rect.height
298
348
  );
299
349
  }
300
350
  render() {
301
351
  this.renderer.render(this.scene, this.camera);
302
352
  }
303
353
  }
304
- function N(r) {
305
- const t = document.createRange();
306
- t.selectNodeContents(r);
307
- const e = t.getBoundingClientRect();
354
+ function Q(r) {
355
+ const e = document.createRange();
356
+ e.selectNodeContents(r);
357
+ const t = e.getBoundingClientRect();
308
358
  return {
309
- left: e.left,
310
- top: e.top,
311
- width: e.width,
312
- height: e.height
359
+ left: t.left,
360
+ top: t.top,
361
+ width: t.width,
362
+ height: t.height
313
363
  };
314
364
  }
315
- function _(r) {
316
- const t = parseFloat(r.fontSize);
317
- let e = parseFloat(r.lineHeight);
318
- isNaN(e) && (e = t * 1.2);
365
+ function G(r) {
366
+ const e = parseFloat(r.fontSize);
367
+ let t = parseFloat(r.lineHeight);
368
+ isNaN(t) && (t = e * 1.2);
319
369
  let i = parseFloat(r.letterSpacing);
320
370
  return isNaN(i) && (i = 0), {
321
371
  font: `${r.fontStyle} ${r.fontWeight} ${r.fontSize} ${r.fontFamily}`,
@@ -323,11 +373,11 @@ function _(r) {
323
373
  textAlign: r.textAlign || "start",
324
374
  textBaseline: "alphabetic",
325
375
  direction: r.direction || "inherit",
326
- lineHeight: e,
376
+ lineHeight: t,
327
377
  letterSpacing: i
328
378
  };
329
379
  }
330
- function M(r, t = R | b | D | E | C) {
380
+ function N(r, e = S | B | _ | z | M, t, i) {
331
381
  if (r.nodeType === Node.TEXT_NODE) {
332
382
  const u = r;
333
383
  if (!u.textContent || !u.textContent.trim())
@@ -335,11 +385,11 @@ function M(r, t = R | b | D | E | C) {
335
385
  const m = u.textContent.replace(/\s+/g, " ").trim();
336
386
  if (m.length === 0)
337
387
  return null;
338
- const g = N(u);
388
+ const g = Q(u);
339
389
  if (g.width === 0 || g.height === 0)
340
390
  return null;
341
- const y = u.parentElement, f = y ? window.getComputedStyle(y) : null;
342
- return f ? {
391
+ const O = u.parentElement, C = O ? window.getComputedStyle(O) : null;
392
+ return C ? {
343
393
  id: Math.random().toString(36).substring(2, 9),
344
394
  type: "TEXT",
345
395
  element: u,
@@ -351,65 +401,98 @@ function M(r, t = R | b | D | E | C) {
351
401
  },
352
402
  styles: {
353
403
  backgroundColor: "transparent",
354
- opacity: parseFloat(f.opacity),
404
+ opacity: parseFloat(C.opacity),
355
405
  zIndex: 0,
356
406
  borderRadius: "0px",
357
407
  borderColor: "transparent",
358
408
  borderWidth: "0px"
359
409
  },
360
410
  textContent: m,
361
- textStyles: _(f),
362
- dirtyMask: t,
411
+ textStyles: G(C),
412
+ dirtyMask: e,
413
+ visibility: t,
363
414
  children: []
364
415
  } : null;
365
416
  }
366
- const e = r, i = e.getBoundingClientRect(), s = window.getComputedStyle(e);
367
- if (i.width === 0 || i.height === 0 || s.display === "none")
417
+ const s = r, n = s.dataset.mirageFilter;
418
+ let a = t, o = t;
419
+ if (n) {
420
+ const u = new Set(n.split(/\s+/));
421
+ for (const m of u)
422
+ if (!A.includes(m))
423
+ throw new Error(
424
+ `[MirageEngine] Invalid filter token: '${m}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`
425
+ );
426
+ if (u.has("end"))
427
+ return null;
428
+ if (u.has("include-tree") && u.has("exclude-tree"))
429
+ throw new Error(
430
+ "[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element."
431
+ );
432
+ if (u.has("include-self") && u.has("exclude-self"))
433
+ throw new Error(
434
+ "[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element."
435
+ );
436
+ u.has("include-tree") ? a = D : u.has("exclude-tree") && (a = F), o = a, u.has("include-self") ? o = D : u.has("exclude-self") && (o = F);
437
+ }
438
+ if (i && i.end && i.end.length > 0 && i.end.some(
439
+ (m) => s.classList.contains(m)
440
+ ))
368
441
  return null;
369
- let n = e.getAttribute("data-mid");
370
- n || (n = Math.random().toString(36).substring(2, 11), e.setAttribute("data-mid", n));
371
- const a = parseInt(s.zIndex), o = {
372
- backgroundColor: s.backgroundColor,
373
- opacity: parseFloat(s.opacity),
374
- zIndex: isNaN(a) ? 0 : a,
375
- borderRadius: s.borderRadius,
376
- borderColor: s.borderColor,
377
- borderWidth: s.borderWidth
442
+ const h = s.getBoundingClientRect(), l = window.getComputedStyle(s);
443
+ if (h.width === 0 || h.height === 0 || l.display === "none")
444
+ return null;
445
+ let p = s.getAttribute("data-mid");
446
+ p || (p = Math.random().toString(36).substring(2, 11), s.setAttribute("data-mid", p));
447
+ const f = parseInt(l.zIndex), x = {
448
+ backgroundColor: l.backgroundColor,
449
+ opacity: parseFloat(l.opacity),
450
+ zIndex: isNaN(f) ? 0 : f,
451
+ borderRadius: l.borderRadius,
452
+ borderColor: l.borderColor,
453
+ borderWidth: l.borderWidth
378
454
  };
379
- let l, d;
380
- const p = [];
381
- return Array.from(e.childNodes).forEach((u) => {
382
- const m = M(u, t);
383
- m && p.push(m);
455
+ let w, b;
456
+ const y = [];
457
+ return Array.from(s.childNodes).forEach((u) => {
458
+ const m = u.nodeType === Node.TEXT_NODE ? o : a, g = N(
459
+ u,
460
+ e,
461
+ m,
462
+ i
463
+ );
464
+ g && y.push(g);
384
465
  }), {
385
- id: n,
466
+ id: p,
386
467
  type: "BOX",
387
- element: e,
468
+ element: s,
388
469
  rect: {
389
- x: i.left + window.scrollX,
390
- y: i.top + window.scrollY,
391
- width: i.width,
392
- height: i.height
470
+ x: h.left + window.scrollX,
471
+ y: h.top + window.scrollY,
472
+ width: h.width,
473
+ height: h.height
393
474
  },
394
- styles: o,
395
- textContent: l,
396
- textStyles: d,
397
- dirtyMask: t,
398
- children: p
475
+ styles: x,
476
+ textContent: w,
477
+ textStyles: b,
478
+ dirtyMask: e,
479
+ visibility: o,
480
+ children: y
399
481
  };
400
482
  }
401
- class k {
402
- constructor(t, e) {
483
+ class q {
484
+ constructor(e, t, i) {
403
485
  c(this, "target");
404
486
  c(this, "renderer");
487
+ c(this, "filter");
405
488
  c(this, "observer");
406
489
  c(this, "isDomDirty", !1);
407
490
  c(this, "isRunning", !1);
408
- c(this, "pendingMask", v);
491
+ c(this, "pendingMask", T);
409
492
  c(this, "mutationTimer", null);
410
493
  c(this, "cssTimer", null);
411
- c(this, "onTransitionFinished", (t) => {
412
- this.target.contains(t.target) && this.mutationTimer === null && (this.cssTimer && clearTimeout(this.cssTimer), this.pendingMask |= R | b, this.cssTimer = window.setTimeout(() => {
494
+ c(this, "onTransitionFinished", (e) => {
495
+ this.target.contains(e.target) && this.mutationTimer === null && (this.cssTimer && clearTimeout(this.cssTimer), this.pendingMask |= S | B, this.cssTimer = window.setTimeout(() => {
413
496
  this.isDomDirty = !0, this.cssTimer = null;
414
497
  }, 50));
415
498
  });
@@ -419,12 +502,12 @@ class k {
419
502
  c(this, "renderLoop", () => {
420
503
  this.isRunning && (this.isDomDirty && this.forceUpdateScene(), this.renderer.render(), requestAnimationFrame(this.renderLoop));
421
504
  });
422
- this.target = t, this.renderer = e, this.observer = new MutationObserver((i) => {
423
- let s = v;
424
- for (const n of i)
425
- n.type === "childList" ? s |= C : n.type === "attributes" && (n.attributeName === "style" || n.attributeName === "class") && (s |= R | b);
426
- if (s !== v) {
427
- if (this.pendingMask |= s, s & C) {
505
+ this.target = e, this.renderer = t, this.filter = i, this.observer = new MutationObserver((s) => {
506
+ let n = T;
507
+ for (const a of s)
508
+ a.type === "childList" ? n |= M : a.type === "attributes" && (a.attributeName === "style" || a.attributeName === "class") && (n |= S | B);
509
+ if (n !== T) {
510
+ if (this.pendingMask |= n, n & M) {
428
511
  this.clearTimers(), console.log("Structural Change detected"), this.isDomDirty = !0;
429
512
  return;
430
513
  }
@@ -450,21 +533,21 @@ class k {
450
533
  }
451
534
  forceUpdateScene() {
452
535
  this.isDomDirty = !1;
453
- const t = M(this.target, this.pendingMask);
454
- t && this.renderer.syncScene(t), this.pendingMask = v;
536
+ const e = N(this.target, this.pendingMask, D, this.filter);
537
+ e && this.renderer.syncScene(e), this.pendingMask = T;
455
538
  }
456
539
  }
457
- class P {
458
- constructor(t, e) {
540
+ class V {
541
+ constructor(e, t) {
459
542
  c(this, "renderer");
460
543
  c(this, "syncer");
461
544
  c(this, "target");
462
545
  var s, n, a;
463
- this.target = t;
546
+ this.target = e;
464
547
  let i;
465
- if (e.mode === "duplicate" ? i = (n = (s = e.container) != null ? s : this.target.parentElement) != null ? n : void 0 : i = (a = this.target.parentElement) != null ? a : void 0, !i)
548
+ if (t.mode === "duplicate" ? i = (n = (s = t.container) != null ? s : this.target.parentElement) != null ? n : void 0 : i = (a = this.target.parentElement) != null ? a : void 0, !i)
466
549
  throw new Error("[Mirage] Cannot find a container (parent or option).");
467
- this.renderer = new X(this.target, e, i), this.renderer.mount(), this.syncer = new k(this.target, this.renderer);
550
+ this.renderer = new $(this.target, t, i), this.renderer.mount(), this.syncer = new q(this.target, this.renderer, t.filter);
468
551
  }
469
552
  start() {
470
553
  this.syncer.start();
@@ -476,12 +559,12 @@ class P {
476
559
  this.syncer.stop(), this.renderer.dispose();
477
560
  }
478
561
  }
479
- class Y {
480
- constructor(t, e = {}) {
562
+ class Z {
563
+ constructor(e, t) {
481
564
  c(this, "_engine");
482
- if (!t)
565
+ if (!e)
483
566
  throw new Error("[Mirage] Target element is required.");
484
- this._engine = new P(t, e);
567
+ this._engine = new V(e, t);
485
568
  }
486
569
  start() {
487
570
  this._engine.start();
@@ -489,13 +572,10 @@ class Y {
489
572
  stop() {
490
573
  this._engine.stop();
491
574
  }
492
- /**
493
- * 엔진 종료 및 메모리 해제
494
- */
495
575
  destroy() {
496
576
  this._engine.dispose();
497
577
  }
498
578
  }
499
579
  export {
500
- Y as Mirage
580
+ Z as Mirage
501
581
  };
@@ -1,55 +1,82 @@
1
- (function(p,f){typeof exports=="object"&&typeof module!="undefined"?f(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],f):(p=typeof globalThis!="undefined"?globalThis:p||self,f(p.MirageEngine={},p.THREE))})(this,function(p,f){"use strict";var Y=Object.defineProperty;var U=(p,f,w)=>f in p?Y(p,f,{enumerable:!0,configurable:!0,writable:!0,value:w}):p[f]=w;var c=(p,f,w)=>(U(p,typeof f!="symbol"?f+"":f,w),w);function w(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const e in r)if(e!=="default"){const i=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(t,e,i.get?i:{enumerable:!0,get:()=>r[e]})}}return t.default=r,Object.freeze(t)}const h=w(f),T=0,C=1,S=2,z=4,E=8,B=16;function F(r,t,e){const i=t.split(`
2
- `),s=[];return i.forEach(n=>{const a=n.split(" ");let o=a[0];for(let l=1;l<a.length;l++){const d=a[l];r.measureText(o+" "+d).width<e?o+=" "+d:(s.push(o),o=d)}s.push(o)}),s}function O(r,t,e,i,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=e*l,n.height=i*l,a.scale(l,l),a.font=t.font,a.fillStyle=t.color,a.textBaseline="top",a.globalAlpha=1;const d=F(a,r,e),m=t.lineHeight;d.forEach((g,y)=>{const x=y*m+2;let v=0;t.textAlign==="center"?v=e/2:t.textAlign==="right"&&(v=e),a.textAlign=t.textAlign,a.fillText(g,v,x)});const u=new h.CanvasTexture(n);return u.colorSpace=h.SRGBColorSpace,u.minFilter=h.LinearFilter,u.magFilter=h.LinearFilter,u.needsUpdate=!0,u}function b(r){return typeof r=="number"?r:parseFloat(r)||0}const A=`
1
+ (function(p,g){typeof exports=="object"&&typeof module!="undefined"?g(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],g):(p=typeof globalThis!="undefined"?globalThis:p||self,g(p.MirageEngine={},p.THREE))})(this,function(p,g){"use strict";var J=Object.defineProperty;var K=(p,g,w)=>g in p?J(p,g,{enumerable:!0,configurable:!0,writable:!0,value:w}):p[g]=w;var c=(p,g,w)=>(K(p,typeof g!="symbol"?g+"":g,w),w);function w(r){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:()=>r[t]})}}return e.default=r,Object.freeze(e)}const d=w(g),E=0,B=1,M=2,P=4,O=8,L=16,D=0,N=30,A=["include-tree","exclude-tree","include-self","exclude-self","end"];function H(r,e,t){const i=e.split(`
2
+ `),s=[];return i.forEach(n=>{const a=n.split(" ");let o=a[0];for(let h=1;h<a.length;h++){const l=a[h];r.measureText(o+" "+l).width<t?o+=" "+l:(s.push(o),o=l)}s.push(o)}),s}function X(r,e,t,i,s=2){const n=document.createElement("canvas"),a=n.getContext("2d");if(!a)throw new Error("[Mirage] Failed to create canvas context");const h=(window.devicePixelRatio||1)*s;n.width=t*h,n.height=i*h,a.scale(h,h),a.font=e.font,a.fillStyle=e.color,a.textBaseline="top",a.globalAlpha=1;const l=H(a,r,t),f=e.lineHeight;l.forEach((b,R)=>{const C=R*f+2;let v=0;e.textAlign==="center"?v=t/2:e.textAlign==="right"&&(v=t),a.textAlign=e.textAlign,a.fillText(b,v,C)});const m=new d.CanvasTexture(n);return m.colorSpace=d.SRGBColorSpace,m.minFilter=d.LinearFilter,m.magFilter=d.LinearFilter,m.needsUpdate=!0,m}function T(r){return typeof r=="number"?r:parseFloat(r)||0}function k(r,e){var o,h,l,f;if(!e){r.set(0,0,0,0);return}const t=e.split("/")[0].trim().split(/\s+/),i=T(t[0]),s=T((o=t[1])!=null?o:t[0]),n=T((h=t[2])!=null?h:t[0]),a=T((f=(l=t[3])!=null?l:t[1])!=null?f:t[0]);r.set(i,s,n,a)}const W=`
3
3
  varying vec2 vUv;
4
4
  void main() {
5
5
  vUv = uv;
6
6
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
7
7
  }
8
- `,I=`
8
+ `,Y=`
9
+
9
10
  varying vec2 vUv;
10
11
 
11
12
  uniform vec2 uSize;
12
- uniform float uRadius;
13
+ uniform vec4 uRadius;
13
14
  uniform float uBorderWidth;
14
- uniform vec3 uColor;
15
+ uniform vec3 uBgColor;
15
16
  uniform vec3 uBorderColor;
16
17
  uniform float uOpacity;
17
18
  uniform float uBgOpacity;
19
+ uniform float uBorderOpacity;
18
20
 
19
- // SDF 박스 함수
21
+ // SDF box
20
22
  float sdRoundedBox(vec2 p, vec2 b, float r) {
21
23
  vec2 q = abs(p) - b + r;
24
+ // return length(max(q, 0.0)) - r;
22
25
  return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
23
26
  }
24
27
 
25
28
  void main() {
29
+ // uVu: (0.0, 0.0) ~ (1.0, 1.0) / center: (0.5, 0.5)
30
+ // p: (-1.0, -1.0) ~ (1.0, 1.0) / center: (0.0, 0.0)
26
31
  vec2 p = (vUv - 0.5) * uSize;
27
32
  vec2 halfSize = uSize * 0.5;
28
33
 
29
- float d = sdRoundedBox(p, halfSize, uRadius);
30
-
31
- float smoothEdge = 1.0;
34
+ // # border-radius
35
+ vec2 xRadii = mix(uRadius.xw, uRadius.yz, step(0.0, p.x));
36
+ float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
37
+ float d = sdRoundedBox(p, halfSize, r);
32
38
 
33
- float fillAlpha = 1.0 - smoothstep(-uBorderWidth - smoothEdge, -uBorderWidth, d);
34
-
35
- float borderAlpha = 0.0;
36
-
37
- if (uBorderWidth > 0.01) {
38
- borderAlpha = (1.0 - smoothstep(0.0, smoothEdge, d)) - fillAlpha;
39
- }
39
+ // 1px blur for anti-aliasing
40
+ float aa = 1.0;
40
41
 
41
- vec3 color = uColor;
42
- float totalAlpha = borderAlpha + fillAlpha;
43
-
44
- if (totalAlpha > 0.001) {
45
- color = mix(uColor, uBorderColor, borderAlpha / totalAlpha);
42
+ // x == 0~aa -> 1
43
+ // x < 0 -> 0
44
+ // x > aa -> 1
45
+ float bgMask = 1.0 - smoothstep(0.0, aa, d);
46
+
47
+ // v valley
48
+ // 10px -> 5
49
+ float halfBorder = uBorderWidth * 0.5;
50
+ // 10px :
51
+ // 0 -> 0
52
+ // -10 -> 0
53
+ // -5 -> -5
54
+ float borderD = abs(d + halfBorder) - halfBorder;
55
+ // ^ border 내부는 음수/외부는 양수
56
+
57
+ // [!] 내부가 음수인 곳에서 시작점이 0이면 내부는 안티 얼리어싱 되지 않음.
58
+ // 1에서 빼든 그대로든 상관없이 경계선 밖 1px
59
+
60
+ // 최종 alpha를 위해 border 부분에 해당하는 픽셀 만 1로 반환.
61
+ float borderAlpha = (1.0 - smoothstep(0.0, aa, borderD)) * uBorderOpacity;
62
+
63
+ if (uBorderWidth <= 0.01) {
64
+ borderAlpha = 0.0;
46
65
  }
47
-
48
- float shapeAlpha = borderAlpha + (fillAlpha * uBgOpacity);
49
- float finalOpacity = shapeAlpha * uOpacity;
50
-
66
+
67
+ float aFront = borderAlpha;
68
+ float aBack = uBgOpacity;
69
+ float aOut = aFront + aBack * (1.0 - aFront);
70
+
71
+ float safeAlpha = max(aOut, 0.0001);
72
+ vec3 cOut = (uBorderColor * aFront + uBgColor * aBack * (1.0 - aFront)) / safeAlpha;
73
+
74
+ float finalOpacity = aOut * bgMask * uOpacity;
75
+
51
76
  if (finalOpacity < 0.001) discard;
52
77
 
53
- gl_FragColor = vec4(color, finalOpacity);
78
+ gl_FragColor = vec4(cOut, finalOpacity);
79
+
80
+ #include <colorspace_fragment>
54
81
  }
55
- `;function R(r){if(!r||r==="transparent")return{color:new h.Color(16777215),alpha:0};const t=r.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(t){const e=parseInt(t[1],10),i=parseInt(t[2],10),s=parseInt(t[3],10),n=t[4]!==void 0?parseFloat(t[4]):1;return{color:new h.Color(`rgb(${e}, ${i}, ${s})`),alpha:n}}return{color:new h.Color(r),alpha:1}}function L(r,t,e){var o;const i=R(r.backgroundColor),s=R(r.borderColor),n={uSize:{value:new h.Vector2(t,e)},uRadius:{value:b(r.borderRadius)},uBorderWidth:{value:b(r.borderWidth)},uColor:{value:i.color},uBorderColor:{value:s.color},uOpacity:{value:(o=r.opacity)!=null?o:1},uBgOpacity:{value:i.alpha}};return new h.ShaderMaterial({uniforms:n,vertexShader:A,fragmentShader:I,transparent:!0,side:h.FrontSide})}function X(r,t,e,i){var a;const s=R(t.backgroundColor),n=R(t.borderColor);r.uniforms.uSize.value.set(e,i),r.uniforms.uRadius.value=b(t.borderRadius),r.uniforms.uBorderWidth.value=b(t.borderWidth),r.uniforms.uColor.value.copy(s.color),r.uniforms.uBorderColor.value.copy(n.color),r.uniforms.uOpacity.value=(a=t.opacity)!=null?a:1,r.uniforms.uBgOpacity.value=s.alpha}const M={create(r,t,e,i,s,n=2){if(r==="BOX")return L(t,i,s);if(r==="TEXT"){const a=O(e||"",t,i,s,n);return new h.MeshBasicMaterial({map:a,transparent:!0,side:h.FrontSide,color:16777215})}return new h.MeshBasicMaterial({visible:!1})},update(r,t,e,i,s,n,a=2){if(t==="BOX")X(r,e,s,n);else if(t==="TEXT"){const o=r;o.map&&o.map.dispose();const l=O(i||"",e,s,n,a);o.map=l,o.needsUpdate=!0}}};class N{constructor(t,e,i){c(this,"canvas");c(this,"scene");c(this,"camera");c(this,"renderer");c(this,"renderOrder",0);c(this,"textQualityFactor",2);c(this,"mode","overlay");c(this,"customZIndex","9999");c(this,"target");c(this,"mountContainer");c(this,"targetRect");c(this,"meshMap",new Map);var a,o,l;this.target=t,this.mountContainer=i,this.mode=(a=e.mode)!=null?a:"overlay",(o=e.style)!=null&&o.zIndex&&(this.customZIndex=e.style.zIndex),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.renderer=new h.WebGLRenderer({canvas:this.canvas,alpha:!0,antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(s,n),this.applyTextQuality((l=e.textQuality)!=null?l:"medium")}applyTextQuality(t){if(typeof t=="number"){this.textQualityFactor=Math.max(.1,t);return}switch(t){case"low":this.textQualityFactor=1;break;case"high":this.textQualityFactor=4;break;case"medium":default:this.textQualityFactor=2;break}}mount(){this.mountContainer.appendChild(this.canvas),this.canvas.style.zIndex=this.customZIndex,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(t,e){this.renderer.setSize(t,e),this.camera.left=t/-2,this.camera.right=t/2,this.camera.top=e/2,this.camera.bottom=e/-2,this.camera.updateProjectionMatrix()}syncScene(t){const e=this.target.getBoundingClientRect(),i=Math.abs(e.width-this.targetRect.width)>.1||Math.abs(e.height-this.targetRect.height)>.1,s=this.mode==="overlay"&&(Math.abs(e.top-this.targetRect.top)>.1||Math.abs(e.left-this.targetRect.left)>.1);i?(this.targetRect=e,this.renderer.setSize(this.targetRect.width,this.targetRect.height),this.camera.left=this.targetRect.width/-2,this.camera.right=this.targetRect.width/2,this.camera.top=this.targetRect.height/2,this.camera.bottom=this.targetRect.height/-2,this.camera.updateProjectionMatrix(),this.updateCanvasLayout()):s?(this.targetRect=e,this.updateCanvasLayout()):this.targetRect=e,this.renderOrder=0;const n=new Set;this.reconcileNode(t,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(t,e){e.add(t.element);let i=this.meshMap.get(t.element);if(!i){const s=new h.PlaneGeometry(1,1),n=M.create("BOX",t.styles,"",t.rect.width,t.rect.height);i=new h.Mesh(s,n),t.type==="TEXT"&&(i.name="BG_MESH"),this.scene.add(i),this.meshMap.set(t.element,i)}if(i.userData.domRect=t.rect,this.updateMeshProperties(i,t),t.type==="BOX")for(const s of t.children)this.reconcileNode(s,e);else t.type==="TEXT"&&this.reconcileTextChild(i,t)}reconcileTextChild(t,e){var o,l;let i=t.children.find(d=>d.name==="TEXT_CHILD");const s=JSON.stringify(e.textStyles),n=(o=i==null?void 0:i.userData)==null?void 0:o.styleHash;if(!i||e.dirtyMask&B||s!==n){i&&((l=i.material.map)==null||l.dispose(),i.geometry.dispose(),t.remove(i));const d=M.create("TEXT",e.textStyles,e.textContent||"",e.rect.width,e.rect.height,this.textQualityFactor),m=new h.PlaneGeometry(1,1);i=new h.Mesh(m,d),i.name="TEXT_CHILD",i.userData={styleHash:s},i.position.z=.005,t.add(i)}if(i){const d=t.userData.domRect,m=d.x+d.width/2,u=d.y+d.height/2,g=e.rect.x+e.rect.width/2,y=e.rect.y+e.rect.height/2,x=g-m,v=-(y-u);i.position.set(x,v,.005)}}updateMeshProperties(t,e){const{rect:i,styles:s}=e,n=this.renderer.getPixelRatio(),a=this.renderer.domElement.width/n,o=this.renderer.domElement.height/n;t.scale.set(i.width,i.height,1);const l=.001;this.renderOrder++;const d=this.targetRect.left+window.scrollX,m=this.targetRect.top+window.scrollY,u=i.x-d,g=i.y-m;t.position.set(u-a/2+i.width/2,-g+o/2-i.height/2,s.zIndex+this.renderOrder*l),M.update(t.material,"BOX",e.styles,"",e.rect.width,e.rect.height)}render(){this.renderer.render(this.scene,this.camera)}}function _(r){const t=document.createRange();t.selectNodeContents(r);const e=t.getBoundingClientRect();return{left:e.left,top:e.top,width:e.width,height:e.height}}function k(r){const t=parseFloat(r.fontSize);let e=parseFloat(r.lineHeight);isNaN(e)&&(e=t*1.2);let i=parseFloat(r.letterSpacing);return isNaN(i)&&(i=0),{font:`${r.fontStyle} ${r.fontWeight} ${r.fontSize} ${r.fontFamily}`,color:r.color,textAlign:r.textAlign||"start",textBaseline:"alphabetic",direction:r.direction||"inherit",lineHeight:e,letterSpacing:i}}function D(r,t=C|S|z|B|E){if(r.nodeType===Node.TEXT_NODE){const u=r;if(!u.textContent||!u.textContent.trim())return null;const g=u.textContent.replace(/\s+/g," ").trim();if(g.length===0)return null;const y=_(u);if(y.width===0||y.height===0)return null;const x=u.parentElement,v=x?window.getComputedStyle(x):null;return v?{id:Math.random().toString(36).substring(2,9),type:"TEXT",element:u,rect:{x:y.left+window.scrollX,y:y.top+window.scrollY,width:y.width,height:y.height},styles:{backgroundColor:"transparent",opacity:parseFloat(v.opacity),zIndex:0,borderRadius:"0px",borderColor:"transparent",borderWidth:"0px"},textContent:g,textStyles:k(v),dirtyMask:t,children:[]}:null}const e=r,i=e.getBoundingClientRect(),s=window.getComputedStyle(e);if(i.width===0||i.height===0||s.display==="none")return null;let n=e.getAttribute("data-mid");n||(n=Math.random().toString(36).substring(2,11),e.setAttribute("data-mid",n));const a=parseInt(s.zIndex),o={backgroundColor:s.backgroundColor,opacity:parseFloat(s.opacity),zIndex:isNaN(a)?0:a,borderRadius:s.borderRadius,borderColor:s.borderColor,borderWidth:s.borderWidth};let l,d;const m=[];return Array.from(e.childNodes).forEach(u=>{const g=D(u,t);g&&m.push(g)}),{id:n,type:"BOX",element:e,rect:{x:i.left+window.scrollX,y:i.top+window.scrollY,width:i.width,height:i.height},styles:o,textContent:l,textStyles:d,dirtyMask:t,children:m}}class P{constructor(t,e){c(this,"target");c(this,"renderer");c(this,"observer");c(this,"isDomDirty",!1);c(this,"isRunning",!1);c(this,"pendingMask",T);c(this,"mutationTimer",null);c(this,"cssTimer",null);c(this,"onTransitionFinished",t=>{this.target.contains(t.target)&&this.mutationTimer===null&&(this.cssTimer&&clearTimeout(this.cssTimer),this.pendingMask|=C|S,this.cssTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.cssTimer=null},50))});c(this,"onWindowResize",()=>{this.renderer.setSize(window.innerWidth,window.innerHeight),this.isDomDirty=!0});c(this,"renderLoop",()=>{this.isRunning&&(this.isDomDirty&&this.forceUpdateScene(),this.renderer.render(),requestAnimationFrame(this.renderLoop))});this.target=t,this.renderer=e,this.observer=new MutationObserver(i=>{let s=T;for(const n of i)n.type==="childList"?s|=E:n.type==="attributes"&&(n.attributeName==="style"||n.attributeName==="class")&&(s|=C|S);if(s!==T){if(this.pendingMask|=s,s&E){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 t=D(this.target,this.pendingMask);t&&this.renderer.syncScene(t),this.pendingMask=T}}class H{constructor(t,e){c(this,"renderer");c(this,"syncer");c(this,"target");var s,n,a;this.target=t;let i;if(e.mode==="duplicate"?i=(n=(s=e.container)!=null?s:this.target.parentElement)!=null?n:void 0:i=(a=this.target.parentElement)!=null?a:void 0,!i)throw new Error("[Mirage] Cannot find a container (parent or option).");this.renderer=new N(this.target,e,i),this.renderer.mount(),this.syncer=new P(this.target,this.renderer)}start(){this.syncer.start()}stop(){this.syncer.stop()}dispose(){this.syncer.stop(),this.renderer.dispose()}}class W{constructor(t,e={}){c(this,"_engine");if(!t)throw new Error("[Mirage] Target element is required.");this._engine=new H(t,e)}start(){this._engine.start()}stop(){this._engine.stop()}destroy(){this._engine.dispose()}}p.Mirage=W,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
82
+ `;function S(r){if(!r||r==="transparent")return{color:new d.Color(16777215),alpha:0};const e=r.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(e){const t=parseInt(e[1],10),i=parseInt(e[2],10),s=parseInt(e[3],10),n=e[4]!==void 0?parseFloat(e[4]):1;return{color:new d.Color(`rgb(${t}, ${i}, ${s})`),alpha:n}}return{color:new d.Color(r),alpha:1}}function U(r,e,t){var o;const i=S(r.backgroundColor),s=S(r.borderColor),n={uSize:{value:new d.Vector2(e,t)},uRadius:{value:new d.Vector4(0,0,0,0)},uBorderWidth:{value:T(r.borderWidth)},uBgColor:{value:i.color},uBorderColor:{value:s.color},uOpacity:{value:(o=r.opacity)!=null?o:1},uBgOpacity:{value:i.alpha},uBorderOpacity:{value:s.alpha}};return k(n.uRadius.value,r.borderRadius),new d.ShaderMaterial({uniforms:n,vertexShader:W,fragmentShader:Y,transparent:!0,side:d.FrontSide})}function $(r,e,t,i){var a;const s=S(e.backgroundColor),n=S(e.borderColor);r.uniforms.uSize.value.set(t,i),k(r.uniforms.uRadius.value,e.borderRadius),r.uniforms.uBorderWidth.value=T(e.borderWidth),r.uniforms.uBgColor.value.copy(s.color),r.uniforms.uBorderColor.value.copy(n.color),r.uniforms.uOpacity.value=(a=e.opacity)!=null?a:1,r.uniforms.uBgOpacity.value=s.alpha,r.uniforms.uBorderOpacity.value=n.alpha}const F={create(r,e,t,i,s,n=2){if(r==="BOX")return U(e,i,s);if(r==="TEXT"){const a=X(t||"",e,i,s,n);return new d.MeshBasicMaterial({map:a,transparent:!0,side:d.FrontSide,color:16777215})}return new d.MeshBasicMaterial({visible:!1})},update(r,e,t,i,s,n,a=2){if(e==="BOX")$(r,t,s,n);else if(e==="TEXT"){const o=r;o.map&&o.map.dispose();const h=X(i||"",t,s,n,a);o.map=h,o.needsUpdate=!0}}};class j{constructor(e,t,i){c(this,"canvas");c(this,"scene");c(this,"camera");c(this,"renderer");c(this,"renderOrder",0);c(this,"textQualityFactor",2);c(this,"mode","overlay");c(this,"target");c(this,"mountContainer");c(this,"targetRect");c(this,"meshMap",new Map);var a,o;this.target=e,this.mountContainer=i,this.mode=(a=t.mode)!=null?a:"overlay",this.canvas=document.createElement("canvas"),this.scene=new d.Scene,this.targetRect=this.target.getBoundingClientRect();const s=this.targetRect.width,n=this.targetRect.height;this.camera=new d.OrthographicCamera(s/-2,s/2,n/2,n/-2,1,1e3),this.camera.position.z=100,this.renderer=new d.WebGLRenderer({canvas:this.canvas,alpha:!0,antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(s,n),this.applyTextQuality((o=t.textQuality)!=null?o:"medium")}applyTextQuality(e){if(typeof e=="number"){this.textQualityFactor=Math.max(.1,e);return}switch(e){case"low":this.textQualityFactor=1;break;case"high":this.textQualityFactor=4;break;case"medium":default:this.textQualityFactor=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.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(),i=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);i?(this.targetRect=t,this.renderer.setSize(this.targetRect.width,this.targetRect.height),this.camera.left=this.targetRect.width/-2,this.camera.right=this.targetRect.width/2,this.camera.top=this.targetRect.height/2,this.camera.bottom=this.targetRect.height/-2,this.camera.layers.set(0),this.camera.updateProjectionMatrix(),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 d.Material&&o.material.dispose(),this.meshMap.delete(a))}reconcileNode(e,t){t.add(e.element);let i=this.meshMap.get(e.element);if(!i){const s=new d.PlaneGeometry(1,1),n=F.create("BOX",e.styles,"",e.rect.width,e.rect.height);i=new d.Mesh(s,n),i.layers.set(e.visibility),e.type==="TEXT"&&(i.name="BG_MESH"),this.scene.add(i),this.meshMap.set(e.element,i)}if(i.userData.domRect=e.rect,this.updateMeshProperties(i,e),e.type==="BOX")for(const s of e.children)this.reconcileNode(s,t);else e.type==="TEXT"&&this.reconcileTextChild(i,e)}reconcileTextChild(e,t){var o,h;let i=e.children.find(l=>l.name==="TEXT_CHILD");const s=JSON.stringify(t.textStyles),n=(o=i==null?void 0:i.userData)==null?void 0:o.styleHash;if(!i||t.dirtyMask&L||s!==n){i&&((h=i.material.map)==null||h.dispose(),i.geometry.dispose(),e.remove(i));const l=F.create("TEXT",t.textStyles,t.textContent||"",t.rect.width,t.rect.height,this.textQualityFactor),f=new d.PlaneGeometry(1,1);i=new d.Mesh(f,l),i.name="TEXT_CHILD",i.userData={styleHash:s},i.layers.set(t.visibility),i.position.z=.005,e.add(i)}if(i){const l=e.userData.domRect,f=l.x+l.width/2,m=l.y+l.height/2,b=t.rect.x+t.rect.width/2,R=t.rect.y+t.rect.height/2,C=b-f,v=-(R-m);i.position.set(C,v,.005)}}updateMeshProperties(e,t){const{rect:i,styles:s}=t,n=this.renderer.getPixelRatio(),a=this.renderer.domElement.width/n,o=this.renderer.domElement.height/n;e.scale.set(i.width,i.height,1);const h=.001;this.renderOrder++;const l=this.targetRect.left+window.scrollX,f=this.targetRect.top+window.scrollY,m=i.x-l,b=i.y-f;e.position.set(m-a/2+i.width/2,-b+o/2-i.height/2,s.zIndex+this.renderOrder*h),F.update(e.material,"BOX",t.styles,"",t.rect.width,t.rect.height)}render(){this.renderer.render(this.scene,this.camera)}}function Q(r){const e=document.createRange();e.selectNodeContents(r);const t=e.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function G(r){const e=parseFloat(r.fontSize);let t=parseFloat(r.lineHeight);isNaN(t)&&(t=e*1.2);let i=parseFloat(r.letterSpacing);return isNaN(i)&&(i=0),{font:`${r.fontStyle} ${r.fontWeight} ${r.fontSize} ${r.fontFamily}`,color:r.color,textAlign:r.textAlign||"start",textBaseline:"alphabetic",direction:r.direction||"inherit",lineHeight:t,letterSpacing:i}}function _(r,e=B|M|P|L|O,t,i){if(r.nodeType===Node.TEXT_NODE){const u=r;if(!u.textContent||!u.textContent.trim())return null;const y=u.textContent.replace(/\s+/g," ").trim();if(y.length===0)return null;const x=Q(u);if(x.width===0||x.height===0)return null;const I=u.parentElement,z=I?window.getComputedStyle(I):null;return z?{id:Math.random().toString(36).substring(2,9),type:"TEXT",element:u,rect:{x:x.left+window.scrollX,y:x.top+window.scrollY,width:x.width,height:x.height},styles:{backgroundColor:"transparent",opacity:parseFloat(z.opacity),zIndex:0,borderRadius:"0px",borderColor:"transparent",borderWidth:"0px"},textContent:y,textStyles:G(z),dirtyMask:e,visibility:t,children:[]}:null}const s=r,n=s.dataset.mirageFilter;let a=t,o=t;if(n){const u=new Set(n.split(/\s+/));for(const y of u)if(!A.includes(y))throw new Error(`[MirageEngine] Invalid filter token: '${y}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`);if(u.has("end"))return null;if(u.has("include-tree")&&u.has("exclude-tree"))throw new Error("[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element.");if(u.has("include-self")&&u.has("exclude-self"))throw new Error("[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element.");u.has("include-tree")?a=D:u.has("exclude-tree")&&(a=N),o=a,u.has("include-self")?o=D:u.has("exclude-self")&&(o=N)}if(i&&i.end&&i.end.length>0&&i.end.some(y=>s.classList.contains(y)))return null;const h=s.getBoundingClientRect(),l=window.getComputedStyle(s);if(h.width===0||h.height===0||l.display==="none")return null;let f=s.getAttribute("data-mid");f||(f=Math.random().toString(36).substring(2,11),s.setAttribute("data-mid",f));const m=parseInt(l.zIndex),b={backgroundColor:l.backgroundColor,opacity:parseFloat(l.opacity),zIndex:isNaN(m)?0:m,borderRadius:l.borderRadius,borderColor:l.borderColor,borderWidth:l.borderWidth};let R,C;const v=[];return Array.from(s.childNodes).forEach(u=>{const y=u.nodeType===Node.TEXT_NODE?o:a,x=_(u,e,y,i);x&&v.push(x)}),{id:f,type:"BOX",element:s,rect:{x:h.left+window.scrollX,y:h.top+window.scrollY,width:h.width,height:h.height},styles:b,textContent:R,textStyles:C,dirtyMask:e,visibility:o,children:v}}class q{constructor(e,t,i){c(this,"target");c(this,"renderer");c(this,"filter");c(this,"observer");c(this,"isDomDirty",!1);c(this,"isRunning",!1);c(this,"pendingMask",E);c(this,"mutationTimer",null);c(this,"cssTimer",null);c(this,"onTransitionFinished",e=>{this.target.contains(e.target)&&this.mutationTimer===null&&(this.cssTimer&&clearTimeout(this.cssTimer),this.pendingMask|=B|M,this.cssTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.cssTimer=null},50))});c(this,"onWindowResize",()=>{this.renderer.setSize(window.innerWidth,window.innerHeight),this.isDomDirty=!0});c(this,"renderLoop",()=>{this.isRunning&&(this.isDomDirty&&this.forceUpdateScene(),this.renderer.render(),requestAnimationFrame(this.renderLoop))});this.target=e,this.renderer=t,this.filter=i,this.observer=new MutationObserver(s=>{let n=E;for(const a of s)a.type==="childList"?n|=O:a.type==="attributes"&&(a.attributeName==="style"||a.attributeName==="class")&&(n|=B|M);if(n!==E){if(this.pendingMask|=n,n&O){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=_(this.target,this.pendingMask,D,this.filter);e&&this.renderer.syncScene(e),this.pendingMask=E}}class V{constructor(e,t){c(this,"renderer");c(this,"syncer");c(this,"target");var s,n,a;this.target=e;let i;if(t.mode==="duplicate"?i=(n=(s=t.container)!=null?s:this.target.parentElement)!=null?n:void 0:i=(a=this.target.parentElement)!=null?a:void 0,!i)throw new Error("[Mirage] Cannot find a container (parent or option).");this.renderer=new j(this.target,t,i),this.renderer.mount(),this.syncer=new q(this.target,this.renderer,t.filter)}start(){this.syncer.start()}stop(){this.syncer.stop()}dispose(){this.syncer.stop(),this.renderer.dispose()}}class Z{constructor(e,t){c(this,"_engine");if(!e)throw new Error("[Mirage] Target element is required.");this._engine=new V(e,t)}start(){this._engine.start()}stop(){this._engine.stop()}destroy(){this._engine.dispose()}}p.Mirage=Z,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
@@ -1,11 +1,8 @@
1
1
  import { MirageConfig } from '../types';
2
2
  export declare class Mirage {
3
3
  private _engine;
4
- constructor(element: HTMLElement, config?: MirageConfig);
4
+ constructor(target: HTMLElement, config: MirageConfig);
5
5
  start(): void;
6
6
  stop(): void;
7
- /**
8
- * 엔진 종료 및 메모리 해제
9
- */
10
7
  destroy(): void;
11
8
  }
@@ -1,18 +1,2 @@
1
- export type TextQuality = "low" | "medium" | "high" | number;
2
- export type MirageMode = "overlay" | "duplicate";
3
- interface BaseConfig {
4
- debug?: boolean;
5
- textQuality?: TextQuality;
6
- style?: {
7
- zIndex?: string;
8
- };
9
- }
10
- export interface OverlayConfig extends BaseConfig {
11
- mode?: "overlay";
12
- }
13
- export interface DuplicateConfig extends BaseConfig {
14
- mode: "duplicate";
15
- container?: HTMLElement;
16
- }
17
- export type MirageConfig = OverlayConfig | DuplicateConfig;
18
- export {};
1
+ import { CoreConfig } from '../../packages/core/src/index.ts';
2
+ export type MirageConfig = CoreConfig;
@@ -1,3 +1 @@
1
1
  export * from './config';
2
- export * from './common';
3
- export * from './flags';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mirage-engine",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "An engine that mirrors HTML DOM elements to a WebGL scene in real-time.",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -21,7 +21,8 @@
21
21
  "dist"
22
22
  ],
23
23
  "dependencies": {
24
- "@mirage-engine/painter": "0.2.2"
24
+ "@mirage-engine/painter": "0.2.3",
25
+ "@mirage-engine/core": "0.1.0"
25
26
  },
26
27
  "peerDependencies": {
27
28
  "three": "^0.150.0"
@@ -1,10 +0,0 @@
1
- import { MirageConfig } from '../types';
2
- export declare class Engine {
3
- private renderer;
4
- private syncer;
5
- private target;
6
- constructor(target: HTMLElement, config: MirageConfig);
7
- start(): void;
8
- stop(): void;
9
- dispose(): void;
10
- }
@@ -1,19 +0,0 @@
1
- import { Renderer } from '../renderer/Renderer';
2
- export declare class Syncer {
3
- private target;
4
- private renderer;
5
- private observer;
6
- private isDomDirty;
7
- private isRunning;
8
- private pendingMask;
9
- private mutationTimer;
10
- private cssTimer;
11
- constructor(target: HTMLElement, renderer: Renderer);
12
- start(): void;
13
- stop(): void;
14
- private clearTimers;
15
- private onTransitionFinished;
16
- private onWindowResize;
17
- private forceUpdateScene;
18
- private renderLoop;
19
- }
@@ -1,2 +0,0 @@
1
- import { SceneNode } from '../types';
2
- export declare function extractSceneGraph(sourceNode: HTMLElement | Node, initialMask?: number): SceneNode | null;
@@ -1,26 +0,0 @@
1
- import { SceneNode, MirageConfig } from '../types';
2
- export declare class Renderer {
3
- readonly canvas: HTMLCanvasElement;
4
- private readonly scene;
5
- private readonly camera;
6
- private readonly renderer;
7
- private renderOrder;
8
- private textQualityFactor;
9
- private mode;
10
- private customZIndex;
11
- private target;
12
- private mountContainer;
13
- private targetRect;
14
- private meshMap;
15
- constructor(target: HTMLElement, config: MirageConfig, mountContainer: HTMLElement);
16
- private applyTextQuality;
17
- mount(): void;
18
- private updateCanvasLayout;
19
- dispose(): void;
20
- setSize(width: number, height: number): void;
21
- syncScene(graphNode: SceneNode): void;
22
- private reconcileNode;
23
- private reconcileTextChild;
24
- private updateMeshProperties;
25
- render(): void;
26
- }
@@ -1,19 +0,0 @@
1
- import { TextStyles, BoxStyles } from '../../packages/painter/src/index.ts';
2
- export type NodeType = "BOX" | "TEXT";
3
- export interface NodeRect {
4
- x: number;
5
- y: number;
6
- width: number;
7
- height: number;
8
- }
9
- export interface SceneNode {
10
- id: string;
11
- type: NodeType;
12
- element: HTMLElement;
13
- rect: NodeRect;
14
- styles: BoxStyles;
15
- textContent?: string;
16
- textStyles?: TextStyles;
17
- dirtyMask: number;
18
- children: SceneNode[];
19
- }
@@ -1,6 +0,0 @@
1
- export declare const DIRTY_NONE = 0;
2
- export declare const DIRTY_RECT: number;
3
- export declare const DIRTY_STYLE: number;
4
- export declare const DIRTY_ZINDEX: number;
5
- export declare const DIRTY_STRUCTURE: number;
6
- export declare const DIRTY_CONTENT: number;