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