@mirage-engine/core 0.0.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,223 +1,302 @@
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 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);
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 = [
6
+ "include-tree",
7
+ "exclude-tree",
8
+ "include-self",
9
+ "exclude-self",
10
+ "end"
11
+ ];
12
+ function Y(i, e, t) {
13
+ const r = e.split(`
8
14
  `), s = [];
9
- return i.forEach((n) => {
10
- const a = n.split(" ");
11
- 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);
15
+ return r.forEach((a) => {
16
+ const n = a.split(" ");
17
+ let o = n[0];
18
+ for (let l = 1; l < n.length; l++) {
19
+ const c = n[l];
20
+ i.measureText(o + " " + c).width < t ? o += " " + c : (s.push(o), o = c);
15
21
  }
16
22
  s.push(o);
17
23
  }), s;
18
24
  }
19
- function S(r, t, e, i, s = 2) {
20
- const n = document.createElement("canvas"), a = n.getContext("2d");
21
- if (!a)
25
+ function I(i, e, t, r, s = 2) {
26
+ const a = document.createElement("canvas"), n = a.getContext("2d");
27
+ if (!n)
22
28
  throw new Error("[Mirage] Failed to create canvas context");
23
29
  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, f) => {
27
- const y = f * p + 2;
28
- let g = 0;
29
- t.textAlign === "center" ? g = e / 2 : t.textAlign === "right" && (g = e), a.textAlign = t.textAlign, a.fillText(m, g, y);
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;
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);
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 u = new d.CanvasTexture(a);
38
+ return u.colorSpace = d.SRGBColorSpace, u.minFilter = d.LinearFilter, u.magFilter = d.LinearFilter, u.needsUpdate = !0, u;
33
39
  }
34
- function x(r) {
35
- return typeof r == "number" ? r : parseFloat(r) || 0;
40
+ function w(i) {
41
+ return typeof i == "number" ? i : parseFloat(i) || 0;
36
42
  }
37
- const O = `
43
+ function _(i, e) {
44
+ var o, l, c, g;
45
+ if (!e) {
46
+ i.set(0, 0, 0, 0);
47
+ return;
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);
51
+ }
52
+ const U = (
53
+ /* glsl */
54
+ `
38
55
  varying vec2 vUv;
56
+ varying vec4 vScreenPos;
39
57
  void main() {
40
58
  vUv = uv;
41
59
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
60
+ vScreenPos = gl_Position;
42
61
  }
43
- `, A = `
62
+ `
63
+ ), W = (
64
+ /* glsl */
65
+ `
66
+
44
67
  varying vec2 vUv;
45
68
 
46
69
  uniform vec2 uSize;
47
- uniform float uRadius;
70
+ uniform vec4 uBorderRadius;
48
71
  uniform float uBorderWidth;
49
- uniform vec3 uColor;
72
+ uniform vec3 uBgColor;
50
73
  uniform vec3 uBorderColor;
51
74
  uniform float uOpacity;
52
75
  uniform float uBgOpacity;
76
+ uniform float uBorderOpacity;
77
+
78
+ #INJECT_DECLARATIONS
53
79
 
54
- // SDF 박스 함수
55
80
  float sdRoundedBox(vec2 p, vec2 b, float r) {
56
81
  vec2 q = abs(p) - b + r;
82
+
57
83
  return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
58
84
  }
59
85
 
60
86
  void main() {
61
87
  vec2 p = (vUv - 0.5) * uSize;
62
88
  vec2 halfSize = uSize * 0.5;
63
-
64
- float d = sdRoundedBox(p, halfSize, uRadius);
65
-
66
- float smoothEdge = 1.0;
67
89
 
68
- float fillAlpha = 1.0 - smoothstep(-uBorderWidth - smoothEdge, -uBorderWidth, d);
69
-
70
- float borderAlpha = 0.0;
90
+ #INJECT_UV_MODIFIER
71
91
 
72
- if (uBorderWidth > 0.01) {
73
- borderAlpha = (1.0 - smoothstep(0.0, smoothEdge, d)) - fillAlpha;
74
- }
92
+ // color decision pipeline
93
+ vec4 baseColor = vec4(uBgColor, uBgOpacity);
75
94
 
76
- vec3 color = uColor;
77
- float totalAlpha = borderAlpha + fillAlpha;
78
-
79
- if (totalAlpha > 0.001) {
80
- color = mix(uColor, uBorderColor, borderAlpha / totalAlpha);
95
+ #INJECT_BASE_COLOR
96
+
97
+ // sdf shape pipeline
98
+ vec2 xRadii = mix(uBorderRadius.xw, uBorderRadius.yz, step(0.0, p.x));
99
+ float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
100
+ float d = sdRoundedBox(p, halfSize, r);
101
+
102
+ float aa = 1.0;
103
+ float bgMask = 1.0 - smoothstep(0.0, aa, d);
104
+
105
+ float halfBorder = uBorderWidth * 0.5;
106
+ float borderD = abs(d + halfBorder) - halfBorder;
107
+ float borderAlpha = (1.0 - smoothstep(0.0, aa, borderD)) * uBorderOpacity;
108
+ if (uBorderWidth <= 0.01) {
109
+ borderAlpha = 0.0;
81
110
  }
82
-
83
- float shapeAlpha = borderAlpha + (fillAlpha * uBgOpacity);
84
- float finalOpacity = shapeAlpha * uOpacity;
85
-
111
+
112
+ // final blending (border + background)
113
+ float aFront = borderAlpha;
114
+ float aBack = baseColor.a;
115
+ float aOut = aFront + aBack * (1.0 - aFront);
116
+
117
+ float safeAlpha = max(aOut, 0.0001);
118
+ vec3 cOut = (uBorderColor * aFront + baseColor.rgb * aBack * (1.0 - aFront)) / safeAlpha;
119
+ vec4 finalColor = vec4(cOut, aOut);
120
+
121
+ // final color control (Tint, Noise)
122
+ #INJECT_COLOR_MODIFIER
123
+
124
+ float finalOpacity = finalColor.a * bgMask * uOpacity;
86
125
  if (finalOpacity < 0.001) discard;
87
126
 
88
- gl_FragColor = vec4(color, finalOpacity);
127
+ gl_FragColor = vec4(finalColor.rgb, finalOpacity);
128
+
129
+ #include <colorspace_fragment>
89
130
  }
90
- `;
91
- function w(r) {
92
- if (!r || r === "transparent")
93
- return { color: new h.Color(16777215), alpha: 0 };
94
- const t = r.match(
131
+ `
132
+ );
133
+ function S(i) {
134
+ if (!i || i === "transparent")
135
+ return { color: new d.Color(16777215), alpha: 0 };
136
+ const e = i.match(
95
137
  /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
96
138
  );
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 };
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 };
100
142
  }
101
- return { color: new h.Color(r), alpha: 1 };
143
+ return { color: new d.Color(i), alpha: 1 };
102
144
  }
103
- function I(r, t, e) {
104
- var o;
105
- const i = w(r.backgroundColor), s = w(r.borderColor), n = {
106
- uSize: { value: new h.Vector2(t, e) },
107
- uRadius: { value: x(r.borderRadius) },
108
- uBorderWidth: { value: x(r.borderWidth) },
109
- uColor: { value: i.color },
110
- uBorderColor: { value: s.color },
111
- uOpacity: { value: (o = r.opacity) != null ? o : 1 },
112
- uBgOpacity: { value: i.alpha }
145
+ function H(i, e, t, r = null, s) {
146
+ var v;
147
+ const a = r !== null, n = a ? (
148
+ /* glsl */
149
+ `
150
+ uniform sampler2D uTexture;
151
+ varying vec4 vScreenPos;
152
+ `
153
+ ) : "", o = a ? (
154
+ /* glsl */
155
+ `
156
+ vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
157
+ vec2 resultUv = screenUv;
158
+ ${(s == null ? void 0 : s.uvModifier) || ""}
159
+ `
160
+ ) : "", l = a ? (
161
+ /* glsl */
162
+ `
163
+ baseColor = texture2D(uTexture, resultUv);
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 = {
166
+ uSize: { value: new d.Vector2(e, t) },
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 },
174
+ uTexture: { value: null }
113
175
  };
114
- return new h.ShaderMaterial({
115
- uniforms: n,
116
- vertexShader: O,
117
- fragmentShader: A,
176
+ return _(m.uBorderRadius.value, i.borderRadius), a && (m.uTexture.value = r), new d.ShaderMaterial({
177
+ uniforms: m,
178
+ vertexShader: U,
179
+ fragmentShader: g,
118
180
  transparent: !0,
119
- side: h.FrontSide
181
+ side: d.FrontSide
120
182
  // for better performance
121
183
  });
122
184
  }
123
- function L(r, t, e, i) {
124
- var a;
125
- const s = w(t.backgroundColor), n = w(t.borderColor);
126
- r.uniforms.uSize.value.set(e, i), r.uniforms.uRadius.value = x(t.borderRadius), r.uniforms.uBorderWidth.value = x(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;
185
+ function $(i, e, t, r, s) {
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);
127
189
  }
128
- const T = {
129
- create(r, t, e, i, s, n = 2) {
130
- if (r === "BOX")
131
- return I(t, i, s);
132
- if (r === "TEXT") {
133
- const a = S(
134
- e || "",
135
- t,
136
- i,
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(
196
+ t || "",
197
+ e,
198
+ r,
137
199
  s,
138
- n
200
+ a
139
201
  );
140
- return new h.MeshBasicMaterial({
141
- map: a,
202
+ return new d.MeshBasicMaterial({
203
+ map: o,
142
204
  transparent: !0,
143
- side: h.FrontSide,
205
+ side: d.FrontSide,
144
206
  color: 16777215
145
207
  });
146
208
  }
147
- return new h.MeshBasicMaterial({ visible: !1 });
209
+ return new d.MeshBasicMaterial({ visible: !1 });
148
210
  },
149
- update(r, t, e, i, s, n, a = 2) {
150
- if (t === "BOX")
151
- L(
152
- r,
153
- e,
211
+ update(i, e, t, r, s, a, n = 2, o) {
212
+ if (e === "BOX")
213
+ $(
214
+ i,
215
+ t,
154
216
  s,
155
- n
217
+ a,
218
+ o
156
219
  );
157
- else if (t === "TEXT") {
158
- const o = r;
159
- o.map && o.map.dispose();
160
- const l = S(
161
- i || "",
162
- e,
220
+ else if (e === "TEXT") {
221
+ const l = i;
222
+ l.map && l.map.dispose();
223
+ const c = I(
224
+ r || "",
225
+ t,
163
226
  s,
164
- n,
165
- a
227
+ a,
228
+ n
166
229
  );
167
- o.map = l, o.needsUpdate = !0;
230
+ l.map = c, l.needsUpdate = !0;
168
231
  }
169
232
  }
170
233
  };
171
- class X {
172
- constructor(t, e, i) {
173
- c(this, "canvas");
174
- c(this, "scene");
175
- c(this, "camera");
176
- c(this, "renderer");
177
- c(this, "renderOrder", 0);
178
- c(this, "textQualityFactor", 2);
179
- c(this, "mode", "overlay");
180
- c(this, "customZIndex", "9999");
181
- c(this, "target");
182
- c(this, "mountContainer");
183
- c(this, "targetRect");
184
- 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();
187
- const s = this.targetRect.width, n = this.targetRect.height;
188
- this.camera = new h.OrthographicCamera(
234
+ class G {
235
+ constructor(e, t, r) {
236
+ h(this, "canvas");
237
+ h(this, "scene");
238
+ h(this, "camera");
239
+ h(this, "renderer");
240
+ h(this, "renderTarget", null);
241
+ h(this, "renderOrder", 0);
242
+ h(this, "qualityFactor", 2);
243
+ h(this, "mode", "overlay");
244
+ h(this, "target");
245
+ h(this, "mountContainer");
246
+ h(this, "targetRect");
247
+ 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;
251
+ this.camera = new d.OrthographicCamera(
189
252
  s / -2,
190
253
  s / 2,
191
- n / 2,
192
- n / -2,
254
+ a / 2,
255
+ a / -2,
193
256
  1,
194
257
  1e3
195
- ), this.camera.position.z = 100, this.renderer = new h.WebGLRenderer({
258
+ ), this.camera.position.z = 100, this.camera.layers.set(0), this.renderer = new d.WebGLRenderer({
196
259
  canvas: this.canvas,
197
260
  alpha: !0,
198
261
  antialias: !0
199
- }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(s, n), this.applyTextQuality((l = e.textQuality) != null ? l : "medium");
262
+ // [new]
263
+ // premultipliedAlpha: true
264
+ }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(s, a), this.applyTextQuality((o = t.quality) != null ? o : "medium");
265
+ }
266
+ createRenderTarget() {
267
+ this.renderTarget = new d.WebGLRenderTarget(
268
+ this.targetRect.width * this.qualityFactor,
269
+ this.targetRect.height * this.qualityFactor,
270
+ {
271
+ minFilter: d.LinearFilter,
272
+ magFilter: d.LinearFilter,
273
+ format: d.RGBAFormat,
274
+ stencilBuffer: !1,
275
+ depthBuffer: !0,
276
+ samples: 4
277
+ }
278
+ );
200
279
  }
201
- applyTextQuality(t) {
202
- if (typeof t == "number") {
203
- this.textQualityFactor = Math.max(0.1, t);
280
+ applyTextQuality(e) {
281
+ if (typeof e == "number") {
282
+ this.qualityFactor = Math.max(0.1, e);
204
283
  return;
205
284
  }
206
- switch (t) {
285
+ switch (e) {
207
286
  case "low":
208
- this.textQualityFactor = 1;
287
+ this.qualityFactor = 1;
209
288
  break;
210
289
  case "high":
211
- this.textQualityFactor = 4;
290
+ this.qualityFactor = 4;
212
291
  break;
213
292
  case "medium":
214
293
  default:
215
- this.textQualityFactor = 2;
294
+ this.qualityFactor = 2;
216
295
  break;
217
296
  }
218
297
  }
219
298
  mount() {
220
- this.mountContainer.appendChild(this.canvas), this.canvas.style.zIndex = this.customZIndex, this.canvas.style.pointerEvents = this.mode === "overlay" ? "none" : "auto", this.updateCanvasLayout();
299
+ this.mountContainer.prepend(this.canvas), this.canvas.style.pointerEvents = this.mode === "overlay" ? "none" : "auto", this.updateCanvasLayout();
221
300
  }
222
301
  updateCanvasLayout() {
223
302
  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,206 +304,300 @@ class X {
225
304
  dispose() {
226
305
  this.renderer.dispose(), this.canvas.remove();
227
306
  }
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();
230
- }
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;
234
- const n = /* @__PURE__ */ new Set();
235
- this.reconcileNode(t, n);
236
- 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));
238
- }
239
- reconcileNode(t, e) {
240
- e.add(t.element);
241
- let i = this.meshMap.get(t.element);
242
- if (!i) {
243
- const s = new h.PlaneGeometry(1, 1), n = T.create(
307
+ setSize(e, t) {
308
+ this.renderer.setSize(e, t), this.renderTarget && this.renderTarget.setSize(
309
+ e * this.qualityFactor,
310
+ t * this.qualityFactor
311
+ ), 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
+ 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;
316
+ const a = /* @__PURE__ */ new Set();
317
+ this.reconcileNode(e, a);
318
+ for (const [n, o] of this.meshMap.entries())
319
+ a.has(n) || (this.scene.remove(o), o.geometry.dispose(), o.material instanceof d.Material && o.material.dispose(), this.meshMap.delete(n));
320
+ }
321
+ reconcileNode(e, t) {
322
+ var s;
323
+ t.add(e.element);
324
+ let r = this.meshMap.get(e.element);
325
+ if (!r) {
326
+ const a = new d.PlaneGeometry(1, 1);
327
+ let n;
328
+ n = F.create(
244
329
  "BOX",
245
- t.styles,
330
+ e.styles,
246
331
  "",
247
- t.rect.width,
248
- t.rect.height
249
- );
250
- i = new h.Mesh(s, n), t.type === "TEXT" && (i.name = "BG_MESH"), this.scene.add(i), this.meshMap.set(t.element, i);
332
+ e.rect.width,
333
+ e.rect.height,
334
+ this.qualityFactor,
335
+ e.isTraveler ? (s = this.renderTarget) == null ? void 0 : s.texture : void 0
336
+ ), r = new d.Mesh(a, n), e.type === "TEXT" && (r.name = "BG_MESH"), this.scene.add(r), this.meshMap.set(e.element, r);
251
337
  }
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);
338
+ if (r.userData.domRect = e.rect, this.updateMeshProperties(r, e), this.updateMeshLayers(r, e), e.isTraveler && r.layers.enable(28), e.type === "BOX")
339
+ for (const a of e.children)
340
+ this.reconcileNode(a, t);
255
341
  else
256
- t.type === "TEXT" && this.reconcileTextChild(i, t);
342
+ e.type === "TEXT" && this.reconcileTextChild(r, e);
257
343
  }
258
- reconcileTextChild(t, e) {
344
+ reconcileTextChild(e, t) {
259
345
  var o, l;
260
- let i = t.children.find(
261
- (d) => d.name === "TEXT_CHILD"
346
+ let r = e.children.find(
347
+ (c) => c.name === "TEXT_CHILD"
262
348
  );
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(
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
+ r && ((l = r.material.map) == null || l.dispose(), r.geometry.dispose(), e.remove(r));
352
+ const c = F.create(
267
353
  "TEXT",
268
- e.textStyles,
269
- e.textContent || "",
270
- e.rect.width,
271
- e.rect.height,
272
- 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);
354
+ t.textStyles,
355
+ t.textContent || "",
356
+ t.rect.width,
357
+ t.rect.height,
358
+ 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);
275
361
  }
276
- 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, f = e.rect.y + e.rect.height / 2, y = m - p, g = -(f - u);
278
- i.position.set(y, g, 5e-3);
362
+ 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);
279
365
  }
280
366
  }
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);
367
+ 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
+ e.scale.set(r.width, r.height, 1);
284
371
  const l = 1e-3;
285
372
  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,
373
+ const c = this.targetRect.left + window.scrollX, g = this.targetRect.top + window.scrollY, u = r.x - c, p = r.y - g;
374
+ e.position.set(
375
+ u - n / 2 + r.width / 2,
376
+ -p + o / 2 - r.height / 2,
290
377
  s.zIndex + this.renderOrder * l
291
- ), T.update(
292
- t.material,
378
+ ), F.update(
379
+ e.material,
293
380
  "BOX",
294
- e.styles,
381
+ t.styles,
295
382
  "",
296
- e.rect.width,
297
- e.rect.height
383
+ t.rect.width,
384
+ t.rect.height,
385
+ this.qualityFactor,
386
+ t.isTraveler ? (m = this.renderTarget) == null ? void 0 : m.texture : void 0
298
387
  );
299
388
  }
389
+ updateMeshLayers(e, t) {
390
+ const r = (1 - (t.visibility & x)) * 30;
391
+ e.layers.set(r), t.visibility === (x | R) && e.layers.enable(29);
392
+ }
393
+ captureRenderTarget() {
394
+ const e = [];
395
+ for (const l of this.meshMap.values())
396
+ l.layers.mask & 1 << 28 && e.push(l);
397
+ if (e.length === 0)
398
+ return;
399
+ const t = new d.Color(), r = this.renderer.getClearAlpha();
400
+ 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();
402
+ 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);
406
+ }
407
+ this.renderer.setScissorTest(!1), this.renderer.autoClear = !0, this.renderer.setRenderTarget(null), this.camera.layers.set(28), this.renderer.setClearColor(t, r);
408
+ }
300
409
  render() {
301
- this.renderer.render(this.scene, this.camera);
410
+ this.renderTarget && this.captureRenderTarget(), this.renderer.render(this.scene, this.camera);
411
+ }
412
+ // for debugging
413
+ showScissoredRenderTarget() {
414
+ if (!this.renderTarget)
415
+ return;
416
+ const e = this.targetRect.width, t = this.targetRect.height, r = new d.PlaneGeometry(e, t), s = new d.MeshBasicMaterial({
417
+ map: this.renderTarget.texture,
418
+ side: d.DoubleSide,
419
+ transparent: !0,
420
+ opacity: 0.8
421
+ }), a = new d.Mesh(r, s);
422
+ a.position.set(0, 0, 90), a.layers.set(28), this.scene.add(a);
302
423
  }
303
424
  }
304
- function N(r) {
305
- const t = document.createRange();
306
- t.selectNodeContents(r);
307
- const e = t.getBoundingClientRect();
425
+ function J(i) {
426
+ const e = document.createRange();
427
+ e.selectNodeContents(i);
428
+ const t = e.getBoundingClientRect();
308
429
  return {
309
- left: e.left,
310
- top: e.top,
311
- width: e.width,
312
- height: e.height
430
+ left: t.left,
431
+ top: t.top,
432
+ width: t.width,
433
+ height: t.height
313
434
  };
314
435
  }
315
- function k(r) {
316
- const t = parseFloat(r.fontSize);
317
- let e = parseFloat(r.lineHeight);
318
- isNaN(e) && (e = t * 1.2);
319
- let i = parseFloat(r.letterSpacing);
320
- return isNaN(i) && (i = 0), {
321
- font: `${r.fontStyle} ${r.fontWeight} ${r.fontSize} ${r.fontFamily}`,
322
- color: r.color,
323
- textAlign: r.textAlign || "start",
436
+ function V(i) {
437
+ const e = parseFloat(i.fontSize);
438
+ let t = parseFloat(i.lineHeight);
439
+ isNaN(t) && (t = e * 1.2);
440
+ let r = parseFloat(i.letterSpacing);
441
+ return isNaN(r) && (r = 0), {
442
+ font: `${i.fontStyle} ${i.fontWeight} ${i.fontSize} ${i.fontFamily}`,
443
+ color: i.color,
444
+ textAlign: i.textAlign || "start",
324
445
  textBaseline: "alphabetic",
325
- direction: r.direction || "inherit",
326
- lineHeight: e,
327
- letterSpacing: i
446
+ direction: i.direction || "inherit",
447
+ lineHeight: t,
448
+ letterSpacing: r
328
449
  };
329
450
  }
330
- function M(r, t = R | b | D | E | C) {
331
- if (r.nodeType === Node.TEXT_NODE) {
332
- const u = r;
333
- if (!u.textContent || !u.textContent.trim())
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())
334
455
  return null;
335
- const m = u.textContent.replace(/\s+/g, " ").trim();
336
- if (m.length === 0)
456
+ const C = f.textContent.replace(/\s+/g, " ").trim();
457
+ if (C.length === 0)
337
458
  return null;
338
- const f = N(u);
339
- if (f.width === 0 || f.height === 0)
459
+ const y = J(f);
460
+ if (y.width === 0 || y.height === 0)
340
461
  return null;
341
- const y = u.parentElement, g = y ? window.getComputedStyle(y) : null;
342
- return g ? {
462
+ const L = f.parentElement, M = L ? window.getComputedStyle(L) : null;
463
+ return M ? {
343
464
  id: Math.random().toString(36).substring(2, 9),
344
465
  type: "TEXT",
345
- element: u,
466
+ element: f,
346
467
  rect: {
347
- x: f.left + window.scrollX,
348
- y: f.top + window.scrollY,
349
- width: f.width,
350
- height: f.height
468
+ x: y.left + window.scrollX,
469
+ y: y.top + window.scrollY,
470
+ width: y.width,
471
+ height: y.height
351
472
  },
352
473
  styles: {
353
474
  backgroundColor: "transparent",
354
- opacity: parseFloat(g.opacity),
475
+ opacity: parseFloat(M.opacity),
355
476
  zIndex: 0,
356
477
  borderRadius: "0px",
357
478
  borderColor: "transparent",
358
479
  borderWidth: "0px"
359
480
  },
360
- textContent: m,
361
- textStyles: k(g),
362
- dirtyMask: t,
481
+ textContent: C,
482
+ textStyles: V(M),
483
+ dirtyMask: e,
484
+ visibility: t,
485
+ isTraveler: !1,
363
486
  children: []
364
487
  } : null;
365
488
  }
366
- const e = r, i = e.getBoundingClientRect(), s = window.getComputedStyle(e);
367
- if (i.width === 0 || i.height === 0 || s.display === "none")
489
+ const s = i, a = s.dataset.mirageFilter;
490
+ let n = t, o = t;
491
+ if (a) {
492
+ const f = new Set(a.split(/\s+/));
493
+ for (const C of f)
494
+ if (!q.includes(C))
495
+ throw new Error(
496
+ `[MirageEngine] Invalid filter token: '${C}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`
497
+ );
498
+ if (f.has("end"))
499
+ return null;
500
+ if (f.has("include-tree") && f.has("exclude-tree"))
501
+ throw new Error(
502
+ "[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element."
503
+ );
504
+ if (f.has("include-self") && f.has("exclude-self"))
505
+ throw new Error(
506
+ "[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element."
507
+ );
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);
509
+ }
510
+ o = o | t & R;
511
+ const l = s.dataset.mirageTravel;
512
+ 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")
368
516
  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
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
378
526
  };
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);
527
+ let v, B;
528
+ const b = [];
529
+ return Array.from(s.childNodes).forEach((f) => {
530
+ const C = f.nodeType === Node.TEXT_NODE ? o : n, y = X(
531
+ f,
532
+ e,
533
+ C
534
+ );
535
+ y && b.push(y);
384
536
  }), {
385
- id: n,
537
+ id: p,
386
538
  type: "BOX",
387
- element: e,
539
+ element: s,
388
540
  rect: {
389
- x: i.left + window.scrollX,
390
- y: i.top + window.scrollY,
391
- width: i.width,
392
- height: i.height
541
+ x: g.left + window.scrollX,
542
+ y: g.top + window.scrollY,
543
+ width: g.width,
544
+ height: g.height
393
545
  },
394
- styles: o,
395
- textContent: l,
396
- textStyles: d,
397
- dirtyMask: t,
398
- children: p
546
+ styles: T,
547
+ textContent: v,
548
+ textStyles: B,
549
+ dirtyMask: e,
550
+ visibility: o,
551
+ isTraveler: c,
552
+ children: b
399
553
  };
400
554
  }
401
- class P {
402
- constructor(t, e) {
403
- c(this, "target");
404
- c(this, "renderer");
405
- c(this, "observer");
406
- c(this, "isDomDirty", !1);
407
- c(this, "isRunning", !1);
408
- c(this, "pendingMask", v);
409
- c(this, "mutationTimer", null);
410
- 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(() => {
555
+ class j {
556
+ constructor(e, t, r) {
557
+ h(this, "target");
558
+ h(this, "renderer");
559
+ h(this, "filter");
560
+ h(this, "observer");
561
+ h(this, "isDomDirty", !1);
562
+ h(this, "isRunning", !1);
563
+ h(this, "isTravelEnabled", !1);
564
+ h(this, "pendingMask", E);
565
+ h(this, "mutationTimer", null);
566
+ h(this, "cssTimer", null);
567
+ h(this, "resizeConfig");
568
+ h(this, "resizeTimer", null);
569
+ h(this, "isResizing", !1);
570
+ 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(() => {
413
572
  this.isDomDirty = !0, this.cssTimer = null;
414
573
  }, 50));
415
574
  });
416
- c(this, "onWindowResize", () => {
417
- this.renderer.setSize(window.innerWidth, window.innerHeight), this.isDomDirty = !0;
575
+ h(this, "onWindowResize", () => {
576
+ if (!this.resizeConfig.enabled) {
577
+ this.isDomDirty = !0;
578
+ return;
579
+ }
580
+ this.isResizing || (this.isResizing = !0, this.resizeConfig.onStart && this.resizeConfig.onStart()), this.resizeTimer && clearTimeout(this.resizeTimer), this.resizeTimer = window.setTimeout(() => {
581
+ this.isDomDirty = !0, this.resizeConfig.onEnd && this.resizeConfig.onEnd(), this.isResizing = !1, this.resizeTimer = null;
582
+ }, this.resizeConfig.delay);
418
583
  });
419
- c(this, "renderLoop", () => {
584
+ h(this, "renderLoop", () => {
420
585
  this.isRunning && (this.isDomDirty && this.forceUpdateScene(), this.renderer.render(), requestAnimationFrame(this.renderLoop));
421
586
  });
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) {
587
+ var a, n;
588
+ 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 = {
591
+ enabled: !0,
592
+ delay: (n = s.delay) != null ? n : 150,
593
+ onStart: s.onStart,
594
+ onEnd: s.onEnd
595
+ }, this.observer = new MutationObserver((o) => {
596
+ let l = E;
597
+ 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) {
428
601
  this.clearTimers(), console.log("Structural Change detected"), this.isDomDirty = !0;
429
602
  return;
430
603
  }
@@ -450,21 +623,28 @@ class P {
450
623
  }
451
624
  forceUpdateScene() {
452
625
  this.isDomDirty = !1;
453
- const t = M(this.target, this.pendingMask);
454
- t && this.renderer.syncScene(t), this.pendingMask = v;
626
+ const e = document.querySelector("[data-mirage-travel='traveler']") !== null;
627
+ e && !this.isTravelEnabled && (this.isTravelEnabled = !0, this.renderer.createRenderTarget());
628
+ const t = X(
629
+ this.target,
630
+ this.pendingMask,
631
+ e ? x | R : x,
632
+ this.filter
633
+ );
634
+ t && this.renderer.syncScene(t), this.pendingMask = E;
455
635
  }
456
636
  }
457
- class Y {
458
- constructor(t, e) {
459
- c(this, "renderer");
460
- c(this, "syncer");
461
- c(this, "target");
462
- var s, n, a;
463
- this.target = t;
464
- 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)
637
+ class K {
638
+ constructor(e, t) {
639
+ h(this, "renderer");
640
+ h(this, "syncer");
641
+ h(this, "target");
642
+ var s, a, n;
643
+ this.target = e;
644
+ 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)
466
646
  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 P(this.target, this.renderer);
647
+ this.renderer = new G(this.target, t, r), this.renderer.mount(), this.syncer = new j(this.target, this.renderer, t);
468
648
  }
469
649
  start() {
470
650
  this.syncer.start();
@@ -477,11 +657,15 @@ class Y {
477
657
  }
478
658
  }
479
659
  export {
480
- E as DIRTY_CONTENT,
481
- v as DIRTY_NONE,
482
- R as DIRTY_RECT,
483
- C as DIRTY_STRUCTURE,
484
- b as DIRTY_STYLE,
485
- D as DIRTY_ZINDEX,
486
- Y as Engine
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,
670
+ x as USER_LAYER
487
671
  };