@mirage-engine/core 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,71 +1,73 @@
1
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);
2
+ var q = (s, e, t) => e in s ? k(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var h = (s, e, t) => (q(s, typeof e != "symbol" ? e + "" : e, t), t);
4
4
  import * as d from "three";
5
- const T = 0, S = 1, B = 2, A = 4, M = 8, z = 16, D = 0, j = 29, F = 30, _ = [
5
+ const S = 0, z = 1, L = 2, Y = 4, I = 8, _ = 16, x = 1, w = 2, ee = 0, W = [
6
6
  "include-tree",
7
7
  "exclude-tree",
8
8
  "include-self",
9
9
  "exclude-self",
10
10
  "end"
11
11
  ];
12
- function P(r, t, e) {
13
- const i = t.split(`
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);
12
+ function U(s, e, t) {
13
+ const r = e.split(`
14
+ `), i = [];
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
+ s.measureText(o + " " + c).width < t ? o += " " + c : (i.push(o), o = c);
21
21
  }
22
- s.push(o);
23
- }), s;
22
+ i.push(o);
23
+ }), i;
24
24
  }
25
- function L(r, t, e, i, s = 2) {
26
- const n = document.createElement("canvas"), a = n.getContext("2d");
27
- if (!a)
25
+ function N(s, e, t, r, i = 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) * i;
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 = U(n, s, t), m = e.lineHeight;
32
+ c.forEach((g, p) => {
33
+ const y = p * m + 2;
34
+ let v = 0;
35
+ e.textAlign === "center" ? v = t / 2 : e.textAlign === "right" && (v = t), n.textAlign = e.textAlign, n.fillText(g, v, y);
36
36
  });
37
- const f = new d.CanvasTexture(n);
37
+ const f = new d.CanvasTexture(a);
38
38
  return f.colorSpace = d.SRGBColorSpace, f.minFilter = d.LinearFilter, f.magFilter = d.LinearFilter, f.needsUpdate = !0, f;
39
39
  }
40
- function v(r) {
41
- return typeof r == "number" ? r : parseFloat(r) || 0;
40
+ function R(s) {
41
+ return typeof s == "number" ? s : parseFloat(s) || 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 X(s, e) {
44
+ var o, l, c, m;
45
+ if (!e) {
46
+ s.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 = R(t[0]), i = R((o = t[1]) != null ? o : t[0]), a = R((l = t[2]) != null ? l : t[0]), n = R((m = (c = t[3]) != null ? c : t[1]) != null ? m : t[0]);
50
+ s.set(r, i, a, n);
51
51
  }
52
- const Y = (
52
+ const H = (
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
- ), W = (
63
+ ), $ = (
62
64
  /* glsl */
63
65
  `
64
66
 
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 E(s) {
134
+ if (!s || s === "transparent")
141
135
  return { color: new d.Color(16777215), alpha: 0 };
142
- const t = r.match(
136
+ const e = s.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), i = parseInt(e[3], 10), a = e[4] !== void 0 ? parseFloat(e[4]) : 1;
141
+ return { color: new d.Color(`rgb(${t}, ${r}, ${i})`), alpha: a };
148
142
  }
149
- return { color: new d.Color(r), alpha: 1 };
143
+ return { color: new d.Color(s), 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 G(s, e, t, r = null, i) {
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
+ ${(i == null ? void 0 : i.uvModifier) || ""}
159
+ `
160
+ ) : "", l = a ? (
161
+ /* glsl */
162
+ `
163
+ baseColor = texture2D(uTexture, resultUv);
164
+ `
165
+ ) : "", c = (i == null ? void 0 : i.colorModifier) || "", m = $.replace("#INJECT_DECLARATIONS", n).replace("#INJECT_UV_MODIFIER", o).replace("#INJECT_BASE_COLOR", l).replace("#INJECT_COLOR_MODIFIER", c), f = E(s.backgroundColor), g = E(s.borderColor), p = {
166
+ uSize: { value: new d.Vector2(e, t) },
167
+ uBorderRadius: { value: new d.Vector4(0, 0, 0, 0) },
168
+ uBorderWidth: { value: R(s.borderWidth) },
169
+ uBgColor: { value: f.color },
170
+ uBorderColor: { value: g.color },
171
+ uOpacity: { value: (v = s.opacity) != null ? v : 1 },
172
+ uBgOpacity: { value: f.alpha },
173
+ uBorderOpacity: { value: g.alpha },
174
+ 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 X(p.uBorderRadius.value, s.borderRadius), a && (p.uTexture.value = r), new d.ShaderMaterial({
177
+ uniforms: p,
178
+ vertexShader: H,
179
+ fragmentShader: m,
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 J(s, e, t, r, i) {
186
+ var o;
187
+ const a = E(e.backgroundColor), n = E(e.borderColor);
188
+ s.uniforms.uSize.value.set(t, r), X(s.uniforms.uBorderRadius.value, e.borderRadius), s.uniforms.uBorderWidth.value = R(e.borderWidth), s.uniforms.uBgColor.value.copy(a.color), s.uniforms.uBorderColor.value.copy(n.color), s.uniforms.uOpacity.value = (o = e.opacity) != null ? o : 1, s.uniforms.uBgOpacity.value = a.alpha, s.uniforms.uBorderOpacity.value = n.alpha, s.uniforms.uTexture && i !== void 0 && (s.uniforms.uTexture.value = i);
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,
190
+ const D = {
191
+ create(s, e, t, r, i, a = 2, n = null, o) {
192
+ if (s === "BOX")
193
+ return G(e, r, i, n, o);
194
+ if (s === "TEXT") {
195
+ const l = N(
196
+ t || "",
197
+ e,
198
+ r,
185
199
  i,
186
- s,
187
- n
200
+ a
188
201
  );
189
202
  return new d.MeshBasicMaterial({
190
- map: a,
203
+ map: l,
191
204
  transparent: !0,
192
205
  side: d.FrontSide,
193
206
  color: 16777215
@@ -195,74 +208,91 @@ 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(s, e, t, r, i, a, n = 2, o) {
212
+ if (e === "BOX")
213
+ J(
203
214
  s,
204
- n
215
+ t,
216
+ i,
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,
212
- s,
213
- n,
214
- a
220
+ else if (e === "TEXT") {
221
+ const l = s;
222
+ l.map && l.map.dispose();
223
+ const c = N(
224
+ r || "",
225
+ t,
226
+ i,
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 V {
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, "clipArea", 1);
245
+ h(this, "target");
246
+ h(this, "mountContainer");
247
+ h(this, "targetRect");
248
+ h(this, "meshMap", /* @__PURE__ */ new Map());
249
+ var n, o, l;
250
+ this.target = e, this.mountContainer = r, this.mode = (n = t.mode) != null ? n : "overlay", this.clipArea = (o = t.travelerClipArea) != null ? o : 1, this.canvas = document.createElement("canvas"), this.scene = new d.Scene(), this.targetRect = this.target.getBoundingClientRect();
251
+ const i = this.targetRect.width, a = this.targetRect.height;
236
252
  this.camera = new d.OrthographicCamera(
237
- s / -2,
238
- s / 2,
239
- n / 2,
240
- n / -2,
253
+ i / -2,
254
+ i / 2,
255
+ a / 2,
256
+ a / -2,
241
257
  1,
242
258
  1e3
243
- ), this.camera.position.z = 100, this.renderer = new d.WebGLRenderer({
259
+ ), this.camera.position.z = 100, this.camera.layers.set(0), this.renderer = new d.WebGLRenderer({
244
260
  canvas: this.canvas,
245
261
  alpha: !0,
246
262
  antialias: !0
247
263
  // [new]
248
264
  // premultipliedAlpha: true
249
- }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(s, n), this.applyTextQuality((o = e.textQuality) != null ? o : "medium");
265
+ }), this.renderer.setPixelRatio(window.devicePixelRatio), this.renderer.setSize(i, a), this.applyTextQuality((l = t.quality) != null ? l : "medium");
266
+ }
267
+ createRenderTarget() {
268
+ this.renderTarget = new d.WebGLRenderTarget(
269
+ this.targetRect.width * this.qualityFactor,
270
+ this.targetRect.height * this.qualityFactor,
271
+ {
272
+ minFilter: d.LinearFilter,
273
+ magFilter: d.LinearFilter,
274
+ format: d.RGBAFormat,
275
+ stencilBuffer: !1,
276
+ depthBuffer: !0,
277
+ samples: 4
278
+ }
279
+ );
250
280
  }
251
- applyTextQuality(t) {
252
- if (typeof t == "number") {
253
- this.textQualityFactor = Math.max(0.1, t);
281
+ applyTextQuality(e) {
282
+ if (typeof e == "number") {
283
+ this.qualityFactor = Math.max(0.1, e);
254
284
  return;
255
285
  }
256
- switch (t) {
286
+ switch (e) {
257
287
  case "low":
258
- this.textQualityFactor = 1;
288
+ this.qualityFactor = 1;
259
289
  break;
260
290
  case "high":
261
- this.textQualityFactor = 4;
291
+ this.qualityFactor = 4;
262
292
  break;
263
293
  case "medium":
264
294
  default:
265
- this.textQualityFactor = 2;
295
+ this.qualityFactor = 2;
266
296
  break;
267
297
  }
268
298
  }
@@ -275,153 +305,200 @@ class $ {
275
305
  dispose() {
276
306
  this.renderer.dispose(), this.canvas.remove();
277
307
  }
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(
308
+ setSize(e, t) {
309
+ this.renderer.setSize(e, t), this.renderTarget && this.renderTarget.setSize(
310
+ e * this.qualityFactor,
311
+ t * this.qualityFactor
312
+ ), this.camera.left = e / -2, this.camera.right = e / 2, this.camera.top = t / 2, this.camera.bottom = t / -2, this.camera.updateProjectionMatrix();
313
+ }
314
+ syncScene(e) {
315
+ const t = this.target.getBoundingClientRect(), r = Math.abs(t.width - this.targetRect.width) > 0.1 || Math.abs(t.height - this.targetRect.height) > 0.1, i = this.mode === "overlay" && (Math.abs(t.top - this.targetRect.top) > 0.1 || Math.abs(t.left - this.targetRect.left) > 0.1);
316
+ r ? (this.targetRect = t, this.setSize(this.targetRect.width, this.targetRect.height), this.updateCanvasLayout()) : i ? (this.targetRect = t, this.updateCanvasLayout()) : this.targetRect = t, this.renderOrder = 0;
317
+ const a = /* @__PURE__ */ new Set();
318
+ this.reconcileNode(e, a);
319
+ for (const [n, o] of this.meshMap.entries())
320
+ a.has(n) || (this.scene.remove(o), o.geometry.dispose(), o.material instanceof d.Material && o.material.dispose(), this.meshMap.delete(n));
321
+ }
322
+ reconcileNode(e, t) {
323
+ var i;
324
+ t.add(e.element);
325
+ let r = this.meshMap.get(e.element);
326
+ if (!r) {
327
+ const a = new d.PlaneGeometry(1, 1);
328
+ let n;
329
+ n = D.create(
294
330
  "BOX",
295
- t.styles,
331
+ e.styles,
296
332
  "",
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);
333
+ e.rect.width,
334
+ e.rect.height,
335
+ this.qualityFactor,
336
+ e.isTraveler ? (i = this.renderTarget) == null ? void 0 : i.texture : void 0,
337
+ e.shaderHooks
338
+ ), r = new d.Mesh(a, n), e.type === "TEXT" && (r.name = "BG_MESH"), this.scene.add(r), this.meshMap.set(e.element, r);
301
339
  }
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);
340
+ if (r.userData.domRect = e.rect, this.updateMeshProperties(r, e), this.updateMeshLayers(r, e), e.isTraveler && r.layers.enable(28), e.type === "BOX")
341
+ for (const a of e.children)
342
+ this.reconcileNode(a, t);
305
343
  else
306
- t.type === "TEXT" && this.reconcileTextChild(i, t);
344
+ e.type === "TEXT" && this.reconcileTextChild(r, e);
307
345
  }
308
- reconcileTextChild(t, e) {
309
- var o, h;
310
- let i = t.children.find(
346
+ reconcileTextChild(e, t) {
347
+ var o, l;
348
+ let r = e.children.find(
311
349
  (c) => c.name === "TEXT_CHILD"
312
350
  );
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(
351
+ const i = JSON.stringify(t.textStyles), a = (o = r == null ? void 0 : r.userData) == null ? void 0 : o.styleHash;
352
+ if (!r || t.dirtyMask & _ || i !== a) {
353
+ r && ((l = r.material.map) == null || l.dispose(), r.geometry.dispose(), e.remove(r));
354
+ const c = D.create(
317
355
  "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);
356
+ t.textStyles,
357
+ t.textContent || "",
358
+ t.rect.width,
359
+ t.rect.height,
360
+ this.qualityFactor
361
+ ), m = new d.PlaneGeometry(1, 1);
362
+ r = new d.Mesh(m, c), r.name = "TEXT_CHILD", r.userData = { styleHash: i }, this.updateMeshLayers(r, t), r.position.z = 5e-3, e.add(r);
325
363
  }
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);
364
+ if (r) {
365
+ const c = e.userData.domRect, m = c.x + c.width / 2, f = c.y + c.height / 2, g = t.rect.x + t.rect.width / 2, p = t.rect.y + t.rect.height / 2, y = g - m, v = -(p - f);
366
+ r.position.set(y, v, 5e-3);
329
367
  }
330
368
  }
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;
369
+ updateMeshProperties(e, t) {
370
+ var p;
371
+ const { rect: r, styles: i } = t, a = this.renderer.getPixelRatio(), n = this.renderer.domElement.width / a, o = this.renderer.domElement.height / a;
372
+ e.scale.set(r.width, r.height, 1);
373
+ const l = 1e-3;
335
374
  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,
375
+ const c = this.targetRect.left + window.scrollX, m = this.targetRect.top + window.scrollY, f = r.x - c, g = r.y - m;
376
+ e.position.set(
377
+ f - n / 2 + r.width / 2,
378
+ -g + o / 2 - r.height / 2,
379
+ i.zIndex + this.renderOrder * l
380
+ ), D.update(
381
+ e.material,
343
382
  "BOX",
344
- e.styles,
383
+ t.styles,
345
384
  "",
346
- e.rect.width,
347
- e.rect.height
385
+ t.rect.width,
386
+ t.rect.height,
387
+ this.qualityFactor,
388
+ t.isTraveler ? (p = this.renderTarget) == null ? void 0 : p.texture : void 0
348
389
  );
349
390
  }
391
+ updateMeshLayers(e, t) {
392
+ const r = (1 - (t.visibility & x)) * 30;
393
+ e.layers.set(r), t.visibility === (x | w) && e.layers.enable(29);
394
+ }
395
+ captureRenderTarget() {
396
+ const e = [];
397
+ for (const l of this.meshMap.values())
398
+ l.layers.mask & 1 << 28 && e.push(l);
399
+ if (e.length === 0)
400
+ return;
401
+ const t = new d.Color(), r = this.renderer.getClearAlpha();
402
+ this.renderer.getClearColor(t), this.renderer.setClearColor(0, 0), this.renderer.setRenderTarget(this.renderTarget), this.renderer.clear(), this.renderer.autoClear = !1, this.renderer.setScissorTest(!0), this.camera.layers.set(29);
403
+ const i = new d.Vector3(), a = this.targetRect.width, n = this.targetRect.height, o = this.renderer.getPixelRatio();
404
+ for (const l of e) {
405
+ i.setFromMatrixPosition(l.matrixWorld), i.project(this.camera);
406
+ const c = (i.x + 1) / 2 * a, m = (i.y + 1) / 2 * n;
407
+ let f = 0, g = 1;
408
+ typeof this.clipArea == "number" ? g = this.clipArea : this.clipArea.endsWith("%") ? g = parseFloat(this.clipArea) / 100 : this.clipArea.endsWith("px") && (f = parseFloat(this.clipArea));
409
+ const p = l.scale.x * g + 0.5, y = l.scale.y * g + 0.5, v = c - p / 2, B = m - y / 2, M = (v * this.qualityFactor - f) / o, F = (B * this.qualityFactor - f) / o, b = (p * this.qualityFactor + f * 2) / o, u = (y * this.qualityFactor + f * 2) / o;
410
+ this.renderer.setScissor(M, F, b, u), this.renderer.render(this.scene, this.camera);
411
+ }
412
+ this.renderer.setScissorTest(!1), this.renderer.autoClear = !0, this.renderer.setRenderTarget(null), this.camera.layers.set(28), this.renderer.setClearColor(t, r);
413
+ }
350
414
  render() {
351
- this.renderer.render(this.scene, this.camera);
415
+ this.renderTarget && this.captureRenderTarget(), this.renderer.render(this.scene, this.camera);
416
+ }
417
+ // for debugging
418
+ showScissoredRenderTarget() {
419
+ if (!this.renderTarget)
420
+ return;
421
+ const e = this.targetRect.width, t = this.targetRect.height, r = new d.PlaneGeometry(e, t), i = new d.MeshBasicMaterial({
422
+ map: this.renderTarget.texture,
423
+ side: d.DoubleSide,
424
+ transparent: !0,
425
+ opacity: 0.8
426
+ }), a = new d.Mesh(r, i);
427
+ a.position.set(0, 0, 90), a.layers.set(28), this.scene.add(a);
352
428
  }
353
429
  }
354
- function Q(r) {
355
- const t = document.createRange();
356
- t.selectNodeContents(r);
357
- const e = t.getBoundingClientRect();
430
+ function j(s) {
431
+ const e = document.createRange();
432
+ e.selectNodeContents(s);
433
+ const t = e.getBoundingClientRect();
358
434
  return {
359
- left: e.left,
360
- top: e.top,
361
- width: e.width,
362
- height: e.height
435
+ left: t.left,
436
+ top: t.top,
437
+ width: t.width,
438
+ height: t.height
363
439
  };
364
440
  }
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",
441
+ function Q(s) {
442
+ const e = parseFloat(s.fontSize);
443
+ let t = parseFloat(s.lineHeight);
444
+ isNaN(t) && (t = e * 1.2);
445
+ let r = parseFloat(s.letterSpacing);
446
+ return isNaN(r) && (r = 0), {
447
+ font: `${s.fontStyle} ${s.fontWeight} ${s.fontSize} ${s.fontFamily}`,
448
+ color: s.color,
449
+ textAlign: s.textAlign || "start",
374
450
  textBaseline: "alphabetic",
375
- direction: r.direction || "inherit",
376
- lineHeight: e,
377
- letterSpacing: i
451
+ direction: s.direction || "inherit",
452
+ lineHeight: t,
453
+ letterSpacing: r
378
454
  };
379
455
  }
380
- function N(r, t = S | B | A | z | M, e, i) {
381
- if (r.nodeType === Node.TEXT_NODE) {
382
- const u = r;
456
+ function P(s, e = z | L | Y | _ | I, t, r) {
457
+ if (s.nodeType === Node.TEXT_NODE) {
458
+ const u = s;
383
459
  if (!u.textContent || !u.textContent.trim())
384
460
  return null;
385
- const m = u.textContent.replace(/\s+/g, " ").trim();
386
- if (m.length === 0)
461
+ const C = u.textContent.replace(/\s+/g, " ").trim();
462
+ if (C.length === 0)
387
463
  return null;
388
- const g = Q(u);
389
- if (g.width === 0 || g.height === 0)
464
+ const T = j(u);
465
+ if (T.width === 0 || T.height === 0)
390
466
  return null;
391
- const O = u.parentElement, C = O ? window.getComputedStyle(O) : null;
392
- return C ? {
467
+ const A = u.parentElement, O = A ? window.getComputedStyle(A) : null;
468
+ return O ? {
393
469
  id: Math.random().toString(36).substring(2, 9),
394
470
  type: "TEXT",
395
471
  element: u,
396
472
  rect: {
397
- x: g.left + window.scrollX,
398
- y: g.top + window.scrollY,
399
- width: g.width,
400
- height: g.height
473
+ x: T.left + window.scrollX,
474
+ y: T.top + window.scrollY,
475
+ width: T.width,
476
+ height: T.height
401
477
  },
402
478
  styles: {
403
479
  backgroundColor: "transparent",
404
- opacity: parseFloat(C.opacity),
480
+ opacity: parseFloat(O.opacity),
405
481
  zIndex: 0,
406
482
  borderRadius: "0px",
407
483
  borderColor: "transparent",
408
484
  borderWidth: "0px"
409
485
  },
410
- textContent: m,
411
- textStyles: G(C),
412
- dirtyMask: t,
413
- visibility: e,
486
+ textContent: C,
487
+ textStyles: Q(O),
488
+ dirtyMask: e,
489
+ visibility: t,
490
+ isTraveler: !1,
414
491
  children: []
415
492
  } : null;
416
493
  }
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))
494
+ const i = s, a = i.dataset.mirageFilter;
495
+ let n = t, o = t;
496
+ if (a) {
497
+ const u = new Set(a.split(/\s+/));
498
+ for (const C of u)
499
+ if (!W.includes(C))
423
500
  throw new Error(
424
- `[MirageEngine] Invalid filter token: '${m}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`
501
+ `[MirageEngine] Invalid filter token: '${C}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`
425
502
  );
426
503
  if (u.has("end"))
427
504
  return null;
@@ -433,81 +510,103 @@ function N(r, t = S | B | A | z | M, e, i) {
433
510
  throw new Error(
434
511
  "[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element."
435
512
  );
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);
513
+ u.has("include-tree") ? n = n | x : u.has("exclude-tree") && (n = n & ~x), o = n, u.has("include-self") ? o = o | x : u.has("exclude-self") && (o = o & ~x);
437
514
  }
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")
515
+ o = o | t & w;
516
+ const l = i.dataset.mirageTravel;
517
+ let c = !1;
518
+ l && new Set(l.split(/\s+/)).has("traveler") && (o = o & ~w, n = n & ~w, c = !0);
519
+ const m = i.dataset.mirageShader;
520
+ let f;
521
+ m && (f = JSON.parse(m));
522
+ const g = i.getBoundingClientRect(), p = window.getComputedStyle(i);
523
+ if (g.width === 0 || g.height === 0 || p.display === "none")
444
524
  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(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
525
+ let y = i.getAttribute("data-mid");
526
+ y || (y = Math.random().toString(36).substring(2, 11), i.setAttribute("data-mid", y));
527
+ const v = parseInt(p.zIndex), B = {
528
+ backgroundColor: p.backgroundColor,
529
+ opacity: parseFloat(p.opacity),
530
+ zIndex: isNaN(v) ? 0 : v,
531
+ borderRadius: p.borderRadius,
532
+ borderColor: p.borderColor,
533
+ borderWidth: p.borderWidth
454
534
  };
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(
535
+ let M, F;
536
+ const b = [];
537
+ return Array.from(i.childNodes).forEach((u) => {
538
+ const C = u.nodeType === Node.TEXT_NODE ? o : n, T = P(
459
539
  u,
460
- t,
461
- m,
462
- i
540
+ e,
541
+ C
463
542
  );
464
- g && x.push(g);
543
+ T && b.push(T);
465
544
  }), {
466
- id: p,
545
+ id: y,
467
546
  type: "BOX",
468
- element: s,
547
+ element: i,
469
548
  rect: {
470
- x: h.left + window.scrollX,
471
- y: h.top + window.scrollY,
472
- width: h.width,
473
- height: h.height
549
+ x: g.left + window.scrollX,
550
+ y: g.top + window.scrollY,
551
+ width: g.width,
552
+ height: g.height
474
553
  },
475
- styles: y,
476
- textContent: w,
477
- textStyles: b,
478
- dirtyMask: t,
554
+ styles: B,
555
+ textContent: M,
556
+ textStyles: F,
557
+ dirtyMask: e,
479
558
  visibility: o,
480
- children: x
559
+ isTraveler: c,
560
+ children: b,
561
+ shaderHooks: f
481
562
  };
482
563
  }
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(() => {
564
+ class Z {
565
+ constructor(e, t, r) {
566
+ h(this, "target");
567
+ h(this, "renderer");
568
+ h(this, "filter");
569
+ h(this, "observer");
570
+ h(this, "isDomDirty", !1);
571
+ h(this, "isRunning", !1);
572
+ h(this, "isTravelEnabled", !1);
573
+ h(this, "pendingMask", S);
574
+ h(this, "mutationTimer", null);
575
+ h(this, "cssTimer", null);
576
+ h(this, "resizeConfig");
577
+ h(this, "resizeTimer", null);
578
+ h(this, "isResizing", !1);
579
+ h(this, "onTransitionFinished", (e) => {
580
+ this.target.contains(e.target) && this.mutationTimer === null && (this.cssTimer && clearTimeout(this.cssTimer), this.pendingMask |= z | L, this.cssTimer = window.setTimeout(() => {
496
581
  this.isDomDirty = !0, this.cssTimer = null;
497
582
  }, 50));
498
583
  });
499
- l(this, "onWindowResize", () => {
500
- this.renderer.setSize(window.innerWidth, window.innerHeight), this.isDomDirty = !0;
584
+ h(this, "onWindowResize", () => {
585
+ if (!this.resizeConfig.enabled) {
586
+ this.isDomDirty = !0;
587
+ return;
588
+ }
589
+ this.isResizing || (this.isResizing = !0, this.resizeConfig.onStart && this.resizeConfig.onStart()), this.resizeTimer && clearTimeout(this.resizeTimer), this.resizeTimer = window.setTimeout(() => {
590
+ this.isDomDirty = !0, this.resizeConfig.onEnd && this.resizeConfig.onEnd(), this.isResizing = !1, this.resizeTimer = null;
591
+ }, this.resizeConfig.delay);
501
592
  });
502
- l(this, "renderLoop", () => {
593
+ h(this, "renderLoop", () => {
503
594
  this.isRunning && (this.isDomDirty && this.forceUpdateScene(), this.renderer.render(), requestAnimationFrame(this.renderLoop));
504
595
  });
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) {
596
+ var a, n;
597
+ this.target = e, this.renderer = t, this.filter = r.filter;
598
+ const i = (a = r.resizeDebounce) != null ? a : !0;
599
+ i === !1 ? this.resizeConfig = { enabled: !1, delay: 0 } : i === !0 ? this.resizeConfig = { enabled: !0, delay: 150 } : this.resizeConfig = {
600
+ enabled: !0,
601
+ delay: (n = i.delay) != null ? n : 150,
602
+ onStart: i.onStart,
603
+ onEnd: i.onEnd
604
+ }, this.observer = new MutationObserver((o) => {
605
+ let l = S;
606
+ for (const c of o)
607
+ c.type === "childList" ? l |= I : c.type === "attributes" && (c.attributeName === "style" || c.attributeName === "class") && (l |= z | L);
608
+ if (l !== S) {
609
+ if (this.pendingMask |= l, l & I) {
511
610
  this.clearTimers(), console.log("Structural Change detected"), this.isDomDirty = !0;
512
611
  return;
513
612
  }
@@ -533,21 +632,28 @@ class V {
533
632
  }
534
633
  forceUpdateScene() {
535
634
  this.isDomDirty = !1;
536
- const t = N(this.target, this.pendingMask, D, this.filter);
537
- t && this.renderer.syncScene(t), this.pendingMask = T;
635
+ const e = document.querySelector("[data-mirage-travel='traveler']") !== null;
636
+ e && !this.isTravelEnabled && (this.isTravelEnabled = !0, this.renderer.createRenderTarget());
637
+ const t = P(
638
+ this.target,
639
+ this.pendingMask,
640
+ e ? x | w : x,
641
+ this.filter
642
+ );
643
+ t && this.renderer.syncScene(t), this.pendingMask = S;
538
644
  }
539
645
  }
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)
646
+ class te {
647
+ constructor(e, t) {
648
+ h(this, "renderer");
649
+ h(this, "syncer");
650
+ h(this, "target");
651
+ var i, a, n;
652
+ this.target = e;
653
+ let r;
654
+ if (t.mode === "duplicate" ? r = (a = (i = t.container) != null ? i : this.target.parentElement) != null ? a : void 0 : r = (n = this.target.parentElement) != null ? n : void 0, !r)
549
655
  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);
656
+ this.renderer = new V(this.target, t, r), this.renderer.mount(), this.syncer = new Z(this.target, this.renderer, t);
551
657
  }
552
658
  start() {
553
659
  this.syncer.start();
@@ -560,15 +666,15 @@ class Z {
560
666
  }
561
667
  }
562
668
  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
669
+ W as ALLOWED_FILTERS,
670
+ _ as DIRTY_CONTENT,
671
+ S as DIRTY_NONE,
672
+ z as DIRTY_RECT,
673
+ I as DIRTY_STRUCTURE,
674
+ L as DIRTY_STYLE,
675
+ Y as DIRTY_ZINDEX,
676
+ ee as EXCLUDED,
677
+ te as Engine,
678
+ w as SYSTEM_LAYER,
679
+ x as USER_LAYER
574
680
  };