@mirage-engine/core 0.2.0 → 0.2.2

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,85 +1,149 @@
1
- (function(u,T){typeof exports=="object"&&typeof module!="undefined"?T(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],T):(u=typeof globalThis!="undefined"?globalThis:u||self,T(u.MirageEngine={},u.THREE))})(this,function(u,T){"use strict";var ee=Object.defineProperty;var te=(u,T,w)=>T in u?ee(u,T,{enumerable:!0,configurable:!0,writable:!0,value:w}):u[T]=w;var d=(u,T,w)=>(te(u,typeof T!="symbol"?T+"":T,w),w);function w(i){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(i){for(const t in i)if(t!=="default"){const r=Object.getOwnPropertyDescriptor(i,t);Object.defineProperty(e,t,r.get?r:{enumerable:!0,get:()=>i[t]})}}return e.default=i,Object.freeze(e)}const h=w(T),M=0,B=1,O=2,A=4,D=8,L=16,R=1,E=2,q=0,X=["include-tree","exclude-tree","include-self","exclude-self","end"];function W(i,e,t){const r=e.split(`
2
- `),s=[];return r.forEach(n=>{const a=n.split(" ");let o=a[0];for(let l=1;l<a.length;l++){const c=a[l];i.measureText(o+" "+c).width<t?o+=" "+c:(s.push(o),o=c)}s.push(o)}),s}function Y(i,e,t,r,s=2){const n=document.createElement("canvas"),a=n.getContext("2d");if(!a)throw new Error("[Mirage] Failed to create canvas context");const l=(window.devicePixelRatio||1)*s;n.width=t*l,n.height=r*l,a.scale(l,l),a.font=e.font,a.fillStyle=e.color,a.textBaseline="top",a.globalAlpha=1;const c=W(a,i,t),p=e.lineHeight;c.forEach((m,v)=>{const b=v*p+2;let y=0;e.textAlign==="center"?y=t/2:e.textAlign==="right"&&(y=t),a.textAlign=e.textAlign,a.fillText(m,y,b)});const f=new h.CanvasTexture(n);return f.colorSpace=h.SRGBColorSpace,f.minFilter=h.LinearFilter,f.magFilter=h.LinearFilter,f.needsUpdate=!0,f}function S(i){return typeof i=="number"?i:parseFloat(i)||0}function P(i,e){var o,l,c,p;if(!e){i.set(0,0,0,0);return}const t=e.split("/")[0].trim().split(/\s+/),r=S(t[0]),s=S((o=t[1])!=null?o:t[0]),n=S((l=t[2])!=null?l:t[0]),a=S((p=(c=t[3])!=null?c:t[1])!=null?p:t[0]);i.set(r,s,n,a)}const H=`
3
- varying vec2 vUv;
4
- varying vec4 vScreenPos;
5
- void main() {
6
- vUv = uv;
7
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
8
- vScreenPos = gl_Position;
9
- }
10
- `,$=`
11
-
12
- varying vec2 vUv;
1
+ (function(v,T){typeof exports=="object"&&typeof module!="undefined"?T(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],T):(v=typeof globalThis!="undefined"?globalThis:v||self,T(v.MirageEngine={},v.THREE))})(this,function(v,T){"use strict";var Xe=Object.defineProperty;var Ye=(v,T,M)=>T in v?Xe(v,T,{enumerable:!0,configurable:!0,writable:!0,value:M}):v[T]=M;var u=(v,T,M)=>(Ye(v,typeof T!="symbol"?T+"":T,M),M);var fe=(v,T,M)=>new Promise((p,L)=>{var I=E=>{try{P(M.next(E))}catch(A){L(A)}},z=E=>{try{P(M.throw(E))}catch(A){L(A)}},P=E=>E.done?p(E.value):Promise.resolve(E.value).then(I,z);P((M=M.apply(v,T)).next())});function M(n){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const t in n)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:()=>n[t]})}}return e.default=n,Object.freeze(e)}const p=M(T),L=0,I=1,z=2,P=4,E=8,A=16,B=1,_=2,ge=0,ee=["include-tree","exclude-tree","include-self","exclude-self","end"];class te{static getBaseline(e){if(this.cache.has(e))return this.cache.get(e);const t=this.calculateBaselineFromDOM(e);return this.cache.set(e,t),t}static calculateBaselineFromDOM(e){if(typeof document=="undefined")return 0;const t=document.createElement("div"),i=document.createElement("span"),r=document.createElement("img");t.style.visibility="hidden",t.style.position="absolute",t.style.top="0px",t.style.left="0px",t.style.font=e,t.style.margin="0",t.style.padding="0",t.style.border="none",i.style.margin="0",i.style.padding="0",i.style.border="none",i.style.lineHeight="normal",r.width=1,r.height=1,r.style.verticalAlign="baseline",i.appendChild(document.createTextNode("Hidden Text")),t.appendChild(i),t.appendChild(r),document.body.appendChild(t);const a=r.offsetTop-i.offsetTop;return document.body.removeChild(t),a}}u(te,"cache",new Map);class pe extends p.MeshBasicMaterial{constructor(t,i,r,a,o=2){super({transparent:!0,side:p.FrontSide,color:16777215});u(this,"canvas");u(this,"ctx");u(this,"qualityFactor");if(this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),!this.ctx)throw new Error("[Mirage] Failed to create canvas context");this.qualityFactor=o,this.map=new p.CanvasTexture(this.canvas),this.map.colorSpace=p.LinearSRGBColorSpace,this.map.minFilter=p.LinearFilter,this.map.magFilter=p.LinearFilter,this.updateText(t,i,r,a)}wrapText(t,i){const r=t.split(`
2
+ `),a=[];return r.forEach(o=>{const s=o.match(/[^\s\-]+\-?|\-|\s+/g)||[];if(s.length===0){a.push("");return}let l=s[0];for(let c=1;c<s.length;c++){const d=s[c];this.ctx.measureText(l+d).width<=i+2?l+=d:(l&&a.push(l),l=d.trimStart())}l&&a.push(l)}),a}updateText(t,i,r,a,o){o!==void 0&&(this.qualityFactor=o);const l=(window.devicePixelRatio||1)*this.qualityFactor,c=r*l,d=a*l;this.canvas.width!==c||this.canvas.height!==d?(this.canvas.width=c,this.canvas.height=d):this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.setTransform(l,0,0,l,0,0),this.ctx.font=i.font,this.ctx.fillStyle=i.color,this.ctx.textBaseline="alphabetic",this.ctx.globalAlpha=1;const f=this.wrapText(t,r),h=i.lineHeight,m=te.getBaseline(i.font);f.forEach((g,C)=>{const x=C*h+m;let R=0;i.textAlign==="center"?R=r/2:i.textAlign==="right"&&(R=r),this.ctx.textAlign=i.textAlign,this.ctx.fillText(g,R,x)}),this.map&&(this.map.needsUpdate=!0)}dispose(){this.map&&this.map.dispose(),super.dispose()}}function N(n){return typeof n=="number"?n:parseFloat(n)||0}function U(n){if(!n||n==="transparent")return{color:new p.Color(16777215),alpha:0};const e=n.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(e){const t=parseInt(e[1],10),i=parseInt(e[2],10),r=parseInt(e[3],10),a=e[4]!==void 0?parseFloat(e[4]):1;return{color:new p.Color(`rgb(${t}, ${i}, ${r})`),alpha:a}}return{color:new p.Color(n),alpha:1}}function me(n){const e=[];let t="",i=0;for(let r=0;r<n.length;r++){const a=n[r];if(a==="(")i++;else if(a===")")i--;else if(a===","&&i===0){e.push(t.trim()),t="";continue}t+=a}return t&&e.push(t.trim()),e}function be(n){if(!n||typeof n!="string"||!n.includes("linear-gradient"))return null;const e=n.match(/linear-gradient\((.*)\)/);if(!e)return null;const t=e[1],i=me(t);let r=Math.PI,a=0;const o=i[0].trim();if(o.startsWith("to "))o==="to top"?r=0:o==="to right"?r=Math.PI/2:o==="to bottom"?r=Math.PI:o==="to left"?r=Math.PI*1.5:o==="to top right"||o==="to right top"?r=Math.PI/4:o==="to bottom right"||o==="to right bottom"?r=Math.PI*.75:o==="to bottom left"||o==="to left bottom"?r=Math.PI*1.25:(o==="to top left"||o==="to left top")&&(r=Math.PI*1.75),a=1;else if(o.endsWith("deg")||o.endsWith("rad")||o.endsWith("turn")){const l=parseFloat(o);o.endsWith("deg")?r=l*(Math.PI/180):o.endsWith("rad")?r=l:o.endsWith("turn")&&(r=l*Math.PI*2),a=1}const s=[];for(let l=a;l<i.length&&!(s.length>=8);l++){const c=i[l].trim(),d=c.lastIndexOf(" ");let f=c,h=null;if(d!==-1&&!c.endsWith(")")){const g=c.substring(d+1);(g.endsWith("%")||g.endsWith("px")||!isNaN(parseFloat(g)))&&(f=c.substring(0,d).trim(),h=g)}const m=U(f);s.push({color:m.color,alpha:m.alpha,rawStop:h,stop:0})}if(s.length>0){for(let c=0;c<s.length;c++)s[c].rawStop!==null&&(s[c].stop=parseFloat(s[c].rawStop)/100);s[0].rawStop===null&&(s[0].stop=0),s.length>1&&s[s.length-1].rawStop===null&&(s[s.length-1].stop=1);let l=0;for(let c=1;c<s.length;c++)if(s[c].rawStop!==null||c===s.length-1){const d=c-l;if(d>1){const f=s[l].stop,m=(s[c].stop-f)/d;for(let g=1;g<d;g++)s[l+g].stop=f+m*g}l=c}}return{angle:r,stops:s}}const ve=`varying vec2 vUv;
3
+ varying vec4 vScreenPos;
4
+ void main() {
5
+ vUv = uv;
6
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
7
+ vScreenPos = gl_Position;
8
+ }`,xe=`varying vec2 vUv;
9
+ uniform vec2 uSize;
10
+ uniform vec4 uBorderRadius;
11
+ uniform float uBorderWidth;
12
+ uniform vec4 uBgColor;
13
+ uniform vec4 uBorderColor;
14
+ uniform float uOpacity;
15
+
16
+ uniform int uGradientCount;
17
+ uniform float uGradientAngle;
18
+ uniform vec4 uGradientColors[8];
19
+ uniform float uGradientStops[8];
20
+
21
+ #INJECT_DECLARATIONS
22
+
23
+ vec3 linearToSrgb(vec3 linearColor) {
24
+ vec3 linearPart = 12.92 * linearColor;
25
+ vec3 curvePart = 1.055 * pow(linearColor, vec3(1.0 / 2.4)) - 0.055;
26
+ vec3 switchCondition = step(vec3(0.0031308), linearColor);
27
+ return mix(linearPart, curvePart, switchCondition);
28
+ }
29
+
30
+ vec3 srgbToLinear(vec3 srgbColor) {
31
+ vec3 linearPart = srgbColor / 12.92;
32
+ vec3 curvePart = pow((srgbColor + vec3(0.055)) / 1.055, vec3(2.4));
33
+ vec3 switchCondition = step(vec3(0.04045), srgbColor);
34
+ return mix(linearPart, curvePart, switchCondition);
35
+ }
36
+
37
+ vec4 blendSrcOverInLinear(vec4 front, vec4 back) {
38
+ front.rgb = srgbToLinear(front.rgb);
39
+ back.rgb = srgbToLinear(back.rgb);
40
+ float aOut = front.a + back.a * (1.0 - front.a);
41
+ float safeAlpha = max(aOut, 0.0001);
42
+ vec3 cOut = (front.rgb * front.a + back.rgb * back.a * (1.0 - front.a)) / safeAlpha;
43
+ return vec4(linearToSrgb(cOut), aOut);
44
+ }
45
+
46
+ vec4 blendSrcOver(vec4 front, vec4 back) {
47
+ float aOut = front.a + back.a * (1.0 - front.a);
48
+ float safeAlpha = max(aOut, 0.0001);
49
+ vec3 cOut = (front.rgb * front.a + back.rgb * back.a * (1.0 - front.a)) / safeAlpha;
50
+ return vec4(cOut, aOut);
51
+ }
52
+
53
+ float sdRoundedBox(vec2 p, vec2 b, float r) {
54
+ vec2 q = abs(p) - b + r;
55
+ return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
56
+ }
57
+
58
+ float sdVisualBox(vec2 p, vec2 b, float r) {
59
+ vec2 q = abs(p) - b + r;
60
+ float n = 2.01;
61
+ float d = pow(pow(max(q.x, 0.0), n) + pow(max(q.y, 0.0), n), 1.0/n) - r;
62
+ return min(max(q.x, q.y), 0.0) + d;
63
+ }
64
+
65
+ vec4 calculateGradientLayer(vec2 uv) {
66
+ if (uGradientCount < 2) return uGradientColors[0];
67
+
68
+ vec2 dir = vec2(sin(uGradientAngle), cos(uGradientAngle));
69
+ vec2 p = (uv - 0.5) * uSize;
70
+ float proj = dot(p, dir);
71
+ float L = abs(uSize.x * dir.x) + abs(uSize.y * dir.y);
72
+ float t = clamp((proj / L) + 0.5, 0.0, 1.0);
13
73
 
14
- uniform vec2 uSize;
15
- uniform vec4 uBorderRadius;
16
- uniform float uBorderWidth;
17
- uniform vec3 uBgColor;
18
- uniform vec3 uBorderColor;
19
- uniform float uOpacity;
20
- uniform float uBgOpacity;
21
- uniform float uBorderOpacity;
22
-
23
- #INJECT_DECLARATIONS
24
-
25
- float sdRoundedBox(vec2 p, vec2 b, float r) {
26
- vec2 q = abs(p) - b + r;
27
-
28
- return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
29
- }
30
-
31
- void main() {
32
- vec2 p = (vUv - 0.5) * uSize;
33
- vec2 halfSize = uSize * 0.5;
34
-
35
- #INJECT_UV_MODIFIER
74
+ vec4 color = uGradientColors[0];
75
+ for (int i = 1; i < 8; i++) {
76
+ if (i >= uGradientCount) break;
77
+ float prevStop = uGradientStops[i-1];
78
+ float currStop = uGradientStops[i];
36
79
 
37
- // color decision pipeline
38
- vec4 baseColor = vec4(uBgColor, uBgOpacity);
80
+ float factor = clamp((t - prevStop) / (currStop - prevStop + 0.00001), 0.0, 1.0);
81
+ color = mix(color, uGradientColors[i], factor);
82
+ }
83
+ // return vec4(linearToSrgb(color.rgb), color.a);
84
+ return vec4(color);
85
+ }
39
86
 
40
- #INJECT_BASE_COLOR
87
+ void main() {
88
+ vec2 p = (vUv - 0.5) * uSize;
89
+ vec2 halfSize = uSize * 0.5;
41
90
 
42
- // sdf shape pipeline
43
- vec2 xRadii = mix(uBorderRadius.xw, uBorderRadius.yz, step(0.0, p.x));
44
- float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
45
- float d = sdRoundedBox(p, halfSize, r);
91
+ #INJECT_UV_MODIFIER
46
92
 
47
- float aa = 1.0;
48
- float bgMask = 1.0 - smoothstep(0.0, aa, d);
93
+ // color decision pipeline
94
+ vec4 baseColor = vec4(uBgColor.rgb, uBgColor.a);
49
95
 
50
- float halfBorder = uBorderWidth * 0.5;
51
- float borderD = abs(d + halfBorder) - halfBorder;
52
- float borderAlpha = (1.0 - smoothstep(0.0, aa, borderD)) * uBorderOpacity;
53
- if (uBorderWidth <= 0.01) {
54
- borderAlpha = 0.0;
55
- }
96
+ if (uGradientCount > 0) {
97
+ vec4 gradColor = calculateGradientLayer(vUv);
98
+ baseColor = blendSrcOver(gradColor, baseColor);
99
+ }
56
100
 
57
- // final blending (border + background)
58
- float aFront = borderAlpha;
59
- float aBack = baseColor.a;
60
- float aOut = aFront + aBack * (1.0 - aFront);
101
+ #INJECT_BASE_COLOR
61
102
 
62
- float safeAlpha = max(aOut, 0.0001);
63
- vec3 cOut = (uBorderColor * aFront + baseColor.rgb * aBack * (1.0 - aFront)) / safeAlpha;
64
- vec4 finalColor = vec4(cOut, aOut);
103
+ // Hybrid SDF
104
+ vec2 xRadii = mix(uBorderRadius.xw, uBorderRadius.yz, step(0.0, p.x));
105
+ float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
106
+ r = min(r, min(halfSize.x, halfSize.y));
65
107
 
66
- // final color control (Tint, Noise)
67
- #INJECT_COLOR_MODIFIER
108
+ float d = sdRoundedBox(p, halfSize, r);
68
109
 
69
- float finalOpacity = finalColor.a * bgMask * uOpacity;
70
- if (finalOpacity < 0.001) discard;
110
+ float d_smooth = sdVisualBox(p, halfSize, r);
111
+ float d_visual = d_smooth / fwidth(d_smooth);
71
112
 
72
- gl_FragColor = vec4(finalColor.rgb, finalOpacity);
113
+ // rendering pipeline
114
+ float bgMask = 1.0 - smoothstep(-0.5, 0.5, d_visual);
73
115
 
74
- #include <colorspace_fragment>
116
+ float halfBorder = uBorderWidth * 0.5;
117
+ float borderD = abs(d + halfBorder) - halfBorder;
118
+ float borderAlpha = (1.0 - smoothstep(0.0, 1.0, borderD)) * uBorderColor.a;
119
+ if (uBorderWidth <= 0.01) {
120
+ borderAlpha = 0.0;
75
121
  }
76
- `;function F(i){if(!i||i==="transparent")return{color:new h.Color(16777215),alpha:0};const e=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(e){const t=parseInt(e[1],10),r=parseInt(e[2],10),s=parseInt(e[3],10),n=e[4]!==void 0?parseFloat(e[4]):1;return{color:new h.Color(`rgb(${t}, ${r}, ${s})`),alpha:n}}return{color:new h.Color(i),alpha:1}}function G(i,e,t,r=null,s){var y;const n=r!==null,a=n?`
77
- uniform sampler2D uTexture;
78
- varying vec4 vScreenPos;
79
- `:"",o=n?`
80
- vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
81
- vec2 resultUv = screenUv;
82
- ${(s==null?void 0:s.uvModifier)||""}
83
- `:"",l=n?`
84
- baseColor = texture2D(uTexture, resultUv);
85
- `:"",c=(s==null?void 0:s.colorModifier)||"",p=$.replace("#INJECT_DECLARATIONS",a).replace("#INJECT_UV_MODIFIER",o).replace("#INJECT_BASE_COLOR",l).replace("#INJECT_COLOR_MODIFIER",c),f=F(i.backgroundColor),m=F(i.borderColor),v={uSize:{value:new h.Vector2(e,t)},uBorderRadius:{value:new h.Vector4(0,0,0,0)},uBorderWidth:{value:S(i.borderWidth)},uBgColor:{value:f.color},uBorderColor:{value:m.color},uOpacity:{value:(y=i.opacity)!=null?y:1},uBgOpacity:{value:f.alpha},uBorderOpacity:{value:m.alpha},uTexture:{value:null}};return P(v.uBorderRadius.value,i.borderRadius),n&&(v.uTexture.value=r),new h.ShaderMaterial({uniforms:v,vertexShader:H,fragmentShader:p,transparent:!0,side:h.FrontSide})}function j(i,e,t,r,s){var o;const n=F(e.backgroundColor),a=F(e.borderColor);i.uniforms.uSize.value.set(t,r),P(i.uniforms.uBorderRadius.value,e.borderRadius),i.uniforms.uBorderWidth.value=S(e.borderWidth),i.uniforms.uBgColor.value.copy(n.color),i.uniforms.uBorderColor.value.copy(a.color),i.uniforms.uOpacity.value=(o=e.opacity)!=null?o:1,i.uniforms.uBgOpacity.value=n.alpha,i.uniforms.uBorderOpacity.value=a.alpha,i.uniforms.uTexture&&s!==void 0&&(i.uniforms.uTexture.value=s)}const I={create(i,e,t,r,s,n=2,a=null){if(i==="BOX")return G(e,r,s,a);if(i==="TEXT"){const o=Y(t||"",e,r,s,n);return new h.MeshBasicMaterial({map:o,transparent:!0,side:h.FrontSide,color:16777215})}return new h.MeshBasicMaterial({visible:!1})},update(i,e,t,r,s,n,a=2,o){if(e==="BOX")j(i,t,s,n,o);else if(e==="TEXT"){const l=i;l.map&&l.map.dispose();const c=Y(r||"",t,s,n,a);l.map=c,l.needsUpdate=!0}}};class J{constructor(e,t,r){d(this,"canvas");d(this,"scene");d(this,"camera");d(this,"renderer");d(this,"renderTarget",null);d(this,"renderOrder",0);d(this,"qualityFactor",2);d(this,"mode","overlay");d(this,"target");d(this,"mountContainer");d(this,"targetRect");d(this,"meshMap",new Map);var a,o;this.target=e,this.mountContainer=r,this.mode=(a=t.mode)!=null?a:"overlay",this.canvas=document.createElement("canvas"),this.scene=new h.Scene,this.targetRect=this.target.getBoundingClientRect();const s=this.targetRect.width,n=this.targetRect.height;this.camera=new h.OrthographicCamera(s/-2,s/2,n/2,n/-2,1,1e3),this.camera.position.z=100,this.camera.layers.set(0),this.renderer=new h.WebGLRenderer({canvas:this.canvas,alpha:!0,antialias:!0}),this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(s,n),this.applyTextQuality((o=t.quality)!=null?o:"medium")}createRenderTarget(){this.renderTarget=new h.WebGLRenderTarget(this.targetRect.width*this.qualityFactor,this.targetRect.height*this.qualityFactor,{minFilter:h.LinearFilter,magFilter:h.LinearFilter,format:h.RGBAFormat,stencilBuffer:!1,depthBuffer:!0,samples:4})}applyTextQuality(e){if(typeof e=="number"){this.qualityFactor=Math.max(.1,e);return}switch(e){case"low":this.qualityFactor=1;break;case"high":this.qualityFactor=4;break;case"medium":default:this.qualityFactor=2;break}}mount(){this.mountContainer.prepend(this.canvas),this.canvas.style.pointerEvents=this.mode==="overlay"?"none":"auto",this.updateCanvasLayout()}updateCanvasLayout(){this.canvas.style.width=`${this.targetRect.width}px`,this.canvas.style.height=`${this.targetRect.height}px`,this.mode==="duplicate"?(this.canvas.style.position="",this.canvas.style.top="",this.canvas.style.left="",this.canvas.style.display="block"):(this.canvas.style.position="absolute",this.canvas.style.top=`${this.target.offsetTop}px`,this.canvas.style.left=`${this.target.offsetLeft}px`,this.canvas.style.display="block")}dispose(){this.renderer.dispose(),this.canvas.remove()}setSize(e,t){this.renderer.setSize(e,t),this.renderTarget&&this.renderTarget.setSize(e*this.qualityFactor,t*this.qualityFactor),this.camera.left=e/-2,this.camera.right=e/2,this.camera.top=t/2,this.camera.bottom=t/-2,this.camera.updateProjectionMatrix()}syncScene(e){const t=this.target.getBoundingClientRect(),r=Math.abs(t.width-this.targetRect.width)>.1||Math.abs(t.height-this.targetRect.height)>.1,s=this.mode==="overlay"&&(Math.abs(t.top-this.targetRect.top)>.1||Math.abs(t.left-this.targetRect.left)>.1);r?(this.targetRect=t,this.setSize(this.targetRect.width,this.targetRect.height),this.updateCanvasLayout()):s?(this.targetRect=t,this.updateCanvasLayout()):this.targetRect=t,this.renderOrder=0;const n=new Set;this.reconcileNode(e,n);for(const[a,o]of this.meshMap.entries())n.has(a)||(this.scene.remove(o),o.geometry.dispose(),o.material instanceof h.Material&&o.material.dispose(),this.meshMap.delete(a))}reconcileNode(e,t){var s;t.add(e.element);let r=this.meshMap.get(e.element);if(!r){const n=new h.PlaneGeometry(1,1);let a;a=I.create("BOX",e.styles,"",e.rect.width,e.rect.height,this.qualityFactor,e.isTraveler?(s=this.renderTarget)==null?void 0:s.texture:void 0),r=new h.Mesh(n,a),e.type==="TEXT"&&(r.name="BG_MESH"),this.scene.add(r),this.meshMap.set(e.element,r)}if(r.userData.domRect=e.rect,this.updateMeshProperties(r,e),this.updateMeshLayers(r,e),e.isTraveler&&r.layers.enable(28),e.type==="BOX")for(const n of e.children)this.reconcileNode(n,t);else e.type==="TEXT"&&this.reconcileTextChild(r,e)}reconcileTextChild(e,t){var o,l;let r=e.children.find(c=>c.name==="TEXT_CHILD");const s=JSON.stringify(t.textStyles),n=(o=r==null?void 0:r.userData)==null?void 0:o.styleHash;if(!r||t.dirtyMask&L||s!==n){r&&((l=r.material.map)==null||l.dispose(),r.geometry.dispose(),e.remove(r));const c=I.create("TEXT",t.textStyles,t.textContent||"",t.rect.width,t.rect.height,this.qualityFactor),p=new h.PlaneGeometry(1,1);r=new h.Mesh(p,c),r.name="TEXT_CHILD",r.userData={styleHash:s},this.updateMeshLayers(r,t),r.position.z=.005,e.add(r)}if(r){const c=e.userData.domRect,p=c.x+c.width/2,f=c.y+c.height/2,m=t.rect.x+t.rect.width/2,v=t.rect.y+t.rect.height/2,b=m-p,y=-(v-f);r.position.set(b,y,.005)}}updateMeshProperties(e,t){var v;const{rect:r,styles:s}=t,n=this.renderer.getPixelRatio(),a=this.renderer.domElement.width/n,o=this.renderer.domElement.height/n;e.scale.set(r.width,r.height,1);const l=.001;this.renderOrder++;const c=this.targetRect.left+window.scrollX,p=this.targetRect.top+window.scrollY,f=r.x-c,m=r.y-p;e.position.set(f-a/2+r.width/2,-m+o/2-r.height/2,s.zIndex+this.renderOrder*l),I.update(e.material,"BOX",t.styles,"",t.rect.width,t.rect.height,this.qualityFactor,t.isTraveler?(v=this.renderTarget)==null?void 0:v.texture:void 0)}updateMeshLayers(e,t){const r=(1-(t.visibility&R))*30;e.layers.set(r),t.visibility===(R|E)&&e.layers.enable(29)}captureRenderTarget(){const e=[];for(const l of this.meshMap.values())l.layers.mask&1<<28&&e.push(l);if(e.length===0)return;const t=new h.Color,r=this.renderer.getClearAlpha();this.renderer.getClearColor(t),this.renderer.setClearColor(0,0),this.renderer.setRenderTarget(this.renderTarget),this.renderer.clear(),this.renderer.autoClear=!1,this.renderer.setScissorTest(!0),this.camera.layers.set(29);const s=new h.Vector3,n=this.targetRect.width,a=this.targetRect.height,o=this.renderer.getPixelRatio();for(const l of e){s.setFromMatrixPosition(l.matrixWorld),s.project(this.camera);const c=(s.x+1)/2*n,p=(s.y+1)/2*a,f=l.scale.x,m=l.scale.y,v=c-f/2,b=p-m/2,y=v*this.qualityFactor/o,_=b*this.qualityFactor/o,z=f*this.qualityFactor/o,g=m*this.qualityFactor/o;this.renderer.setScissor(y,_,z,g),this.renderer.render(this.scene,this.camera)}this.renderer.setScissorTest(!1),this.renderer.autoClear=!0,this.renderer.setRenderTarget(null),this.camera.layers.set(28),this.renderer.setClearColor(t,r)}render(){this.renderTarget&&this.captureRenderTarget(),this.renderer.render(this.scene,this.camera)}showScissoredRenderTarget(){if(!this.renderTarget)return;const e=this.targetRect.width,t=this.targetRect.height,r=new h.PlaneGeometry(e,t),s=new h.MeshBasicMaterial({map:this.renderTarget.texture,side:h.DoubleSide,transparent:!0,opacity:.8}),n=new h.Mesh(r,s);n.position.set(0,0,90),n.layers.set(28),this.scene.add(n)}}function V(i){const e=document.createRange();e.selectNodeContents(i);const t=e.getBoundingClientRect();return{left:t.left,top:t.top,width:t.width,height:t.height}}function Z(i){const e=parseFloat(i.fontSize);let t=parseFloat(i.lineHeight);isNaN(t)&&(t=e*1.2);let r=parseFloat(i.letterSpacing);return isNaN(r)&&(r=0),{font:`${i.fontStyle} ${i.fontWeight} ${i.fontSize} ${i.fontFamily}`,color:i.color,textAlign:i.textAlign||"start",textBaseline:"alphabetic",direction:i.direction||"inherit",lineHeight:t,letterSpacing:r}}function U(i,e=B|O|A|L|D,t,r){if(i.nodeType===Node.TEXT_NODE){const g=i;if(!g.textContent||!g.textContent.trim())return null;const x=g.textContent.replace(/\s+/g," ").trim();if(x.length===0)return null;const C=V(g);if(C.width===0||C.height===0)return null;const k=g.parentElement,N=k?window.getComputedStyle(k):null;return N?{id:Math.random().toString(36).substring(2,9),type:"TEXT",element:g,rect:{x:C.left+window.scrollX,y:C.top+window.scrollY,width:C.width,height:C.height},styles:{backgroundColor:"transparent",opacity:parseFloat(N.opacity),zIndex:0,borderRadius:"0px",borderColor:"transparent",borderWidth:"0px"},textContent:x,textStyles:Z(N),dirtyMask:e,visibility:t,isTraveler:!1,children:[]}:null}const s=i,n=s.dataset.mirageFilter;let a=t,o=t;if(n){const g=new Set(n.split(/\s+/));for(const x of g)if(!X.includes(x))throw new Error(`[MirageEngine] Invalid filter token: '${x}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`);if(g.has("end"))return null;if(g.has("include-tree")&&g.has("exclude-tree"))throw new Error("[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element.");if(g.has("include-self")&&g.has("exclude-self"))throw new Error("[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element.");g.has("include-tree")?a=a|R:g.has("exclude-tree")&&(a=a&~R),o=a,g.has("include-self")?o=o|R:g.has("exclude-self")&&(o=o&~R)}o=o|t&E;const l=s.dataset.mirageTravel;let c=!1;l&&new Set(l.split(/\s+/)).has("traveler")&&(o=o&~E,a=a&~E,c=!0);const p=s.getBoundingClientRect(),f=window.getComputedStyle(s);if(p.width===0||p.height===0||f.display==="none")return null;let m=s.getAttribute("data-mid");m||(m=Math.random().toString(36).substring(2,11),s.setAttribute("data-mid",m));const v=parseInt(f.zIndex),b={backgroundColor:f.backgroundColor,opacity:parseFloat(f.opacity),zIndex:isNaN(v)?0:v,borderRadius:f.borderRadius,borderColor:f.borderColor,borderWidth:f.borderWidth};let y,_;const z=[];return Array.from(s.childNodes).forEach(g=>{const x=g.nodeType===Node.TEXT_NODE?o:a,C=U(g,e,x);C&&z.push(C)}),{id:m,type:"BOX",element:s,rect:{x:p.left+window.scrollX,y:p.top+window.scrollY,width:p.width,height:p.height},styles:b,textContent:y,textStyles:_,dirtyMask:e,visibility:o,isTraveler:c,children:z}}class Q{constructor(e,t,r){d(this,"target");d(this,"renderer");d(this,"filter");d(this,"observer");d(this,"isDomDirty",!1);d(this,"isRunning",!1);d(this,"isTravelEnabled",!1);d(this,"pendingMask",M);d(this,"mutationTimer",null);d(this,"cssTimer",null);d(this,"resizeConfig");d(this,"resizeTimer",null);d(this,"isResizing",!1);d(this,"onTransitionFinished",e=>{this.target.contains(e.target)&&this.mutationTimer===null&&(this.cssTimer&&clearTimeout(this.cssTimer),this.pendingMask|=B|O,this.cssTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.cssTimer=null},50))});d(this,"onWindowResize",()=>{if(!this.resizeConfig.enabled){this.isDomDirty=!0;return}this.isResizing||(this.isResizing=!0,this.resizeConfig.onStart&&this.resizeConfig.onStart()),this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.resizeConfig.onEnd&&this.resizeConfig.onEnd(),this.isResizing=!1,this.resizeTimer=null},this.resizeConfig.delay)});d(this,"renderLoop",()=>{this.isRunning&&(this.isDomDirty&&this.forceUpdateScene(),this.renderer.render(),requestAnimationFrame(this.renderLoop))});var n,a;this.target=e,this.renderer=t,this.filter=r.filter;const s=(n=r.resizeDebounce)!=null?n:!0;s===!1?this.resizeConfig={enabled:!1,delay:0}:s===!0?this.resizeConfig={enabled:!0,delay:150}:this.resizeConfig={enabled:!0,delay:(a=s.delay)!=null?a:150,onStart:s.onStart,onEnd:s.onEnd},this.observer=new MutationObserver(o=>{let l=M;for(const c of o)c.type==="childList"?l|=D:c.type==="attributes"&&(c.attributeName==="style"||c.attributeName==="class")&&(l|=B|O);if(l!==M){if(this.pendingMask|=l,l&D){this.clearTimers(),console.log("Structural Change detected"),this.isDomDirty=!0;return}this.mutationTimer&&clearTimeout(this.mutationTimer),this.mutationTimer=window.setTimeout(()=>{this.mutationTimer=null,this.isDomDirty=!0},200)}})}start(){this.isRunning||(this.isRunning=!0,this.observer.observe(this.target,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),this.target.addEventListener("transitionend",this.onTransitionFinished),this.target.addEventListener("animationend",this.onTransitionFinished),window.addEventListener("resize",this.onWindowResize),this.forceUpdateScene(),this.renderLoop())}stop(){this.isRunning=!1,this.observer.disconnect(),this.clearTimers(),this.target.removeEventListener("transitionend",this.onTransitionFinished),this.target.removeEventListener("animationend",this.onTransitionFinished),window.removeEventListener("resize",this.onWindowResize)}clearTimers(){this.mutationTimer&&(clearTimeout(this.mutationTimer),this.mutationTimer=null),this.cssTimer&&(clearTimeout(this.cssTimer),this.cssTimer=null)}forceUpdateScene(){this.isDomDirty=!1;const e=document.querySelector("[data-mirage-travel='traveler']")!==null;e&&!this.isTravelEnabled&&(this.isTravelEnabled=!0,this.renderer.createRenderTarget());const t=U(this.target,this.pendingMask,e?R|E:R,this.filter);t&&this.renderer.syncScene(t),this.pendingMask=M}}class K{constructor(e,t){d(this,"renderer");d(this,"syncer");d(this,"target");var s,n,a;this.target=e;let r;if(t.mode==="duplicate"?r=(n=(s=t.container)!=null?s:this.target.parentElement)!=null?n:void 0:r=(a=this.target.parentElement)!=null?a:void 0,!r)throw new Error("[Mirage] Cannot find a container (parent or option).");this.renderer=new J(this.target,t,r),this.renderer.mount(),this.syncer=new Q(this.target,this.renderer,t)}start(){this.syncer.start()}stop(){this.syncer.stop()}dispose(){this.syncer.stop(),this.renderer.dispose()}}u.ALLOWED_FILTERS=X,u.DIRTY_CONTENT=L,u.DIRTY_NONE=M,u.DIRTY_RECT=B,u.DIRTY_STRUCTURE=D,u.DIRTY_STYLE=O,u.DIRTY_ZINDEX=A,u.EXCLUDED=q,u.Engine=K,u.SYSTEM_LAYER=E,u.USER_LAYER=R,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
122
+
123
+ // final blending (border + background) using blendSrcOver
124
+ vec4 borderLayer = vec4(uBorderColor.rgb, borderAlpha);
125
+ vec4 finalColor = blendSrcOver(borderLayer, baseColor);
126
+ // final color control (Tint, Noise)
127
+ #INJECT_COLOR_MODIFIER
128
+
129
+ float finalOpacity = finalColor.a * bgMask * uOpacity;
130
+ if (finalOpacity < 0.001) discard;
131
+
132
+ gl_FragColor = vec4(finalColor.rgb, finalOpacity);
133
+
134
+
135
+ // #include <colorspace_fragment>
136
+ }
137
+ `,ye=`uniform sampler2D uTexture;
138
+ varying vec4 vScreenPos;
139
+ uniform vec2 uTextureRepeat;
140
+ uniform vec2 uTextureOffset;`,Te=`vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
141
+ vec2 resultUv = screenUv;
142
+
143
+ `,Ce=`vec4 texColor = texture2D(uTexture, resultUv);
144
+ baseColor = blendSrcOver(baseColor, texColor);`,re={vertexShader:ve,fragmentShader:xe},j={declChunk:ye,uvChunk:Te,baseColorChunk:Ce};function we(n,e,t,i=null,r){var x;const a=i!==null||!!n.imageSrc,o=a?j.declChunk:"",s=n.isTraveler?j.uvChunk:`vec2 resultUv = vUv * uTextureRepeat + uTextureOffset;
145
+ `,l=a?s+((r==null?void 0:r.uvModifier)||""):"",c=a?j.baseColorChunk:"",d=(r==null?void 0:r.colorModifier)||"",f=re.fragmentShader.replace("#INJECT_DECLARATIONS",o).replace("#INJECT_UV_MODIFIER",l).replace("#INJECT_BASE_COLOR",c).replace("#INJECT_COLOR_MODIFIER",d),h=U(n.backgroundColor),m=U(n.borderColor),g={uSize:{value:new p.Vector2(e,t)},uBgColor:{value:new p.Vector4(h.color.r,h.color.g,h.color.b,h.alpha)},uBorderColor:{value:new p.Vector4(m.color.r,m.color.g,m.color.b,m.alpha)},uBorderRadius:{value:new p.Vector4(0,0,0,0)},uBorderWidth:{value:N(n.borderWidth)},uOpacity:{value:(x=n.opacity)!=null?x:1},uTexture:{value:null},uTextureRepeat:{value:new p.Vector2(1,1)},uTextureOffset:{value:new p.Vector2(0,0)},uGradientCount:{value:0},uGradientAngle:{value:0},uGradientColors:{value:Array.from({length:8},()=>new p.Vector4(0,0,0,0))},uGradientStops:{value:new Float32Array(8)}};ie(g.uBorderRadius.value,n.borderRadius),a&&(g.uTexture.value=i);const C=new p.ShaderMaterial({uniforms:g,vertexShader:re.vertexShader,fragmentShader:f,transparent:!0,side:p.FrontSide});return n.backgroundImage&&$(C,{backgroundImage:n.backgroundImage}),C}function Se(n,e,t,i,r){const a=N(e.borderWidth);$(n,{width:t,height:i,borderRadius:e.borderRadius,borderWidth:a,backgroundColor:e.backgroundColor,borderColor:e.borderColor,opacity:e.opacity,texture:r,backgroundImage:e.backgroundImage})}function $(n,e){var i,r,a;if(e.width!==void 0&&e.height!==void 0&&n.uniforms.uSize.value.set(e.width,e.height),e.borderRadius!==void 0&&ie(n.uniforms.uBorderRadius.value,e.borderRadius),e.borderWidth!==void 0&&(n.uniforms.uBorderWidth.value=e.borderWidth),e.backgroundColor!==void 0)if(Array.isArray(e.backgroundColor)){const o=n.uniforms.uBgColor.value.w;n.uniforms.uBgColor.value.set(e.backgroundColor[0],e.backgroundColor[1],e.backgroundColor[2],o)}else if(typeof e.backgroundColor=="string"){const o=U(e.backgroundColor);n.uniforms.uBgColor.value.set(o.color.r,o.color.g,o.color.b,o.alpha)}else{const o=n.uniforms.uBgColor.value.w;n.uniforms.uBgColor.value.set(e.backgroundColor.r,e.backgroundColor.g,e.backgroundColor.b,o)}if(e.borderColor!==void 0)if(Array.isArray(e.borderColor)){const o=n.uniforms.uBorderColor.value.w;n.uniforms.uBorderColor.value.set(e.borderColor[0],e.borderColor[1],e.borderColor[2],o)}else if(typeof e.borderColor=="string"){const o=U(e.borderColor);n.uniforms.uBorderColor.value.set(o.color.r,o.color.g,o.color.b,o.alpha)}else{const o=n.uniforms.uBorderColor.value.w;n.uniforms.uBorderColor.value.set(e.borderColor.r,e.borderColor.g,e.borderColor.b,o)}e.opacity!==void 0&&(n.uniforms.uOpacity.value=e.opacity),e.bgOpacity!==void 0&&(n.uniforms.uBgColor.value.w=e.bgOpacity),e.borderOpacity!==void 0&&(n.uniforms.uBorderColor.value.w=e.borderOpacity),n.uniforms.uTexture&&e.texture!==void 0&&(n.uniforms.uTexture.value=e.texture);const t=e.texture!==void 0?e.texture:(i=n.uniforms.uTexture)==null?void 0:i.value;if(t&&(t.image instanceof ImageBitmap||t.image instanceof HTMLImageElement||t.image instanceof HTMLCanvasElement)){const o=t.image.width,s=t.image.height,l=(r=e.width)!=null?r:n.uniforms.uSize.value.x,c=(a=e.height)!=null?a:n.uniforms.uSize.value.y;if(o&&s&&l&&c){const d=o/s,f=l/c;if(d>f){const h=f/d;n.uniforms.uTextureRepeat.value.set(h,1),n.uniforms.uTextureOffset.value.set((1-h)/2,0)}else{const h=d/f;n.uniforms.uTextureRepeat.value.set(1,h),n.uniforms.uTextureOffset.value.set(0,(1-h)/2)}}}else n.uniforms.uTextureRepeat&&(n.uniforms.uTextureRepeat.value.set(1,1),n.uniforms.uTextureOffset.value.set(0,0));if(e.backgroundImage!==void 0){const o=be(e.backgroundImage);if(o){n.uniforms.uGradientCount.value=o.stops.length,n.uniforms.uGradientAngle.value=o.angle;for(let s=0;s<8;s++)if(s<o.stops.length){const l=o.stops[s];n.uniforms.uGradientColors.value[s].set(l.color.r,l.color.g,l.color.b,l.alpha),console.log(l.color.r,l.color.g,l.color.b),n.uniforms.uGradientStops.value[s]=l.stop}else n.uniforms.uGradientColors.value[s].set(0,0,0,0),n.uniforms.uGradientStops.value[s]=1}else n.uniforms.uGradientCount.value=0}}function ie(n,e){var s,l,c,d;if(e==null){n.set(0,0,0,0);return}if(typeof e=="number"){n.set(e,e,e,e);return}if(Array.isArray(e)){n.set(e[0],e[1],e[2],e[3]);return}const t=e.split("/")[0].trim().split(/\s+/),i=N(t[0]),r=N((s=t[1])!=null?s:t[0]),a=N((l=t[2])!=null?l:t[0]),o=N((d=(c=t[3])!=null?c:t[1])!=null?d:t[0]);n.set(i,r,a,o)}const W={create(n,e,t,i,r,a=2,o=null,s){return n==="BOX"?we(e,i,r,o,s):n==="TEXT"?new pe(t||"",e,i,r,a):new p.MeshBasicMaterial({visible:!1})},update(n,e,t,i,r,a,o=2,s){e==="BOX"?Se(n,t,r,a,s):e==="TEXT"&&n.updateText(i||"",t,r,a,o)},forceUpdateUniforms(n,e){$(n,e)}};class Re{constructor(e){u(this,"observer");u(this,"textures",new WeakMap);u(this,"loadStatus",new WeakMap);u(this,"elementUrls",new WeakMap);u(this,"onUpdate");this.onUpdate=e,this.observer=new IntersectionObserver(t=>{for(const i of t){const r=i.target;i.isIntersecting?this.loadTexture(r):this.disposeTexture(r)}},{rootMargin:"300px"})}register(e,t){if(e.nodeType!==Node.ELEMENT_NODE)return;this.elementUrls.get(e)!==t&&(this.elementUrls.set(e,t),this.observer.unobserve(e),this.observer.observe(e))}unregister(e){e.nodeType===Node.ELEMENT_NODE&&this.observer.unobserve(e),this.disposeTexture(e),this.elementUrls.delete(e),this.loadStatus.delete(e)}loadTexture(e){return fe(this,null,function*(){if(this.loadStatus.get(e)||this.textures.has(e))return;const t=this.elementUrls.get(e);if(t){this.loadStatus.set(e,!0);try{const r=yield(yield fetch(t)).blob(),a=yield createImageBitmap(r,{imageOrientation:"flipY"});if(this.elementUrls.get(e)!==t){a.close();return}const o=new p.CanvasTexture(a);o.needsUpdate=!0,this.textures.set(e,o),this.onUpdate(e,o)}catch(i){console.warn("[MirageEngine] Failed to load texture:",t,i)}finally{this.elementUrls.has(e)&&this.loadStatus.set(e,!1)}}})}disposeTexture(e){const t=this.textures.get(e);t&&(t.dispose(),this.textures.delete(e),this.onUpdate(e,null)),this.loadStatus.set(e,!1)}get(e){return this.textures.get(e)}disposeAll(){this.observer.disconnect()}}class Me{constructor(e,t,i,r){u(this,"canvas");u(this,"scene");u(this,"camera");u(this,"renderer");u(this,"renderTarget",null);u(this,"renderOrder",0);u(this,"qualityFactor",2);u(this,"mode","overlay");u(this,"clipArea",1);u(this,"target");u(this,"mountContainer");u(this,"registry");u(this,"targetRect");u(this,"travelers",new Set);u(this,"textureManager");u(this,"fixedMeshes",new Set);var s,l,c;this.target=e,this.mountContainer=i,this.registry=r,this.textureManager=new Re((d,f)=>{const h=this.registry.get(d);h&&h.material instanceof p.ShaderMaterial&&W.forceUpdateUniforms(h.material,{texture:f})}),this.mode=(s=t.mode)!=null?s:"overlay",this.clipArea=(l=t.travelerClipArea)!=null?l:1,this.canvas=document.createElement("canvas"),this.scene=new p.Scene,this.targetRect=this.target.getBoundingClientRect();const a=this.targetRect.width,o=this.targetRect.height;this.camera=new p.OrthographicCamera(a/-2,a/2,o/2,o/-2,1,1e3),this.camera.position.z=100,this.camera.layers.set(0),this.renderer=new p.WebGLRenderer({canvas:this.canvas,alpha:!0,antialias:!0}),p.ColorManagement.enabled=!1,this.renderer.outputColorSpace=p.LinearSRGBColorSpace,this.renderer.setPixelRatio(window.devicePixelRatio),this.renderer.setSize(a,o),this.applyTextQuality((c=t.quality)!=null?c:"medium")}createRenderTarget(){this.renderTarget=new p.WebGLRenderTarget(this.targetRect.width*this.qualityFactor,this.targetRect.height*this.qualityFactor,{minFilter:p.LinearFilter,magFilter:p.LinearFilter,format:p.RGBAFormat,stencilBuffer:!1,depthBuffer:!0})}applyTextQuality(e){if(typeof e=="number"){this.qualityFactor=Math.max(.1,e);return}switch(e){case"low":this.qualityFactor=1;break;case"high":this.qualityFactor=4;break;case"medium":default:this.qualityFactor=2;break}}mount(){this.mountContainer.prepend(this.canvas),this.canvas.style.pointerEvents=this.mode==="overlay"?"none":"auto",this.updateCanvasLayout()}updateCanvasLayout(){this.canvas.style.width=`${this.targetRect.width}px`,this.canvas.style.height=`${this.targetRect.height}px`,this.mode==="duplicate"?(this.canvas.style.position="",this.canvas.style.top="",this.canvas.style.left="",this.canvas.style.display="block"):(this.canvas.style.position="absolute",this.canvas.style.top=`${this.target.offsetTop}px`,this.canvas.style.left=`${this.target.offsetLeft}px`,this.canvas.style.display="block")}dispose(){this.renderer.dispose(),this.canvas.remove(),this.textureManager.disposeAll()}setSize(e,t){this.renderer.setSize(e,t),this.renderTarget&&this.renderTarget.setSize(e*this.qualityFactor,t*this.qualityFactor),this.camera.left=e/-2,this.camera.right=e/2,this.camera.top=t/2,this.camera.bottom=t/-2,this.camera.updateProjectionMatrix()}syncScene(e,t){const i=this.target.getBoundingClientRect(),r=Math.abs(i.width-this.targetRect.width)>.1||Math.abs(i.height-this.targetRect.height)>.1,a=this.mode==="overlay"&&(Math.abs(i.top-this.targetRect.top)>.1||Math.abs(i.left-this.targetRect.left)>.1);r?(this.targetRect=i,this.setSize(this.targetRect.width,this.targetRect.height),this.updateCanvasLayout()):a?(this.targetRect=i,this.updateCanvasLayout()):this.targetRect=i,this.renderOrder=0,this.reconcileNode(e),t.size>0&&t.forEach(o=>{const s=this.registry.get(o);s&&(this.scene.remove(s),this.travelers.delete(s),this.fixedMeshes.delete(s),s.geometry.dispose(),s.traverse(l=>{l instanceof p.Mesh&&(l.geometry&&l.geometry.dispose(),l.material&&(Array.isArray(l.material)?l.material.forEach(c=>c.dispose()):l.material.dispose()))}),this.registry.remove(o),this.textureManager.unregister(o))})}reconcileNode(e){var i;let t=this.registry.get(e.element);if(!t){const r=new p.PlaneGeometry(1,1);let a;const o=e.isTraveler?(i=this.renderTarget)==null?void 0:i.texture:this.textureManager.get(e.element);a=W.create("BOX",e.styles,"",e.rect.width,e.rect.height,this.qualityFactor,o,e.shaderHooks),t=new p.Mesh(r,a),e.type==="TEXT"&&(t.name="BG_MESH"),this.scene.add(t),this.registry.register(e.element,t)}if(t.userData.domRect=e.rect,this.updateMeshProperties(t,e),this.updateMeshLayers(t,e),e.isTraveler?(t.layers.enable(28),this.travelers.add(t)):(t.layers.disable(28),this.travelers.delete(t)),e.isFixed?this.fixedMeshes.add(t):this.fixedMeshes.delete(t),e.styles.imageSrc?this.textureManager.register(e.element,e.styles.imageSrc):this.textureManager.unregister(e.element),e.type==="BOX")for(const r of e.children)this.reconcileNode(r);else e.type==="TEXT"&&this.reconcileTextChild(t,e)}reconcileTextChild(e,t){var s;const i=t.textLines||[{text:t.textContent||"",rect:t.rect}],r=JSON.stringify(t.textStyles)+t.textContent+i.map(l=>l.text).join("|"),a=(s=e.userData)==null?void 0:s.textChildStyleHash;if(t.dirtyMask&A||r!==a){e.children.filter(h=>h.name.startsWith("TEXT_CHILD")).forEach(h=>{var g;const m=h;(g=m.material.map)==null||g.dispose(),m.geometry.dispose(),e.remove(m)});const c=t.rect,d=c.x+c.width/2,f=c.y+c.height/2;i.forEach((h,m)=>{const g=W.create("TEXT",t.textStyles,h.text,h.rect.width,h.rect.height,this.qualityFactor),C=new p.PlaneGeometry(1,1),x=new p.Mesh(C,g);x.name=`TEXT_CHILD_${m}`,this.updateMeshLayers(x,t);const R=t.rect.width===0?1:h.rect.width/t.rect.width,D=t.rect.height===0?1:h.rect.height/t.rect.height;x.scale.set(R,D,1);const k=h.rect.x+h.rect.width/2,F=h.rect.y+h.rect.height/2,b=k-d,w=-(F-f);x.position.set(t.rect.width===0?0:b/t.rect.width,t.rect.height===0?0:w/t.rect.height,.005),e.add(x)}),e.userData.textChildStyleHash=r}}updateMeshProperties(e,t){var b;const{rect:i,styles:r}=t,a=this.renderer.getPixelRatio(),o=this.renderer.domElement.width/a,s=this.renderer.domElement.height/a;e.scale.set(i.width,i.height,1);const l=.001;this.renderOrder++;const c=this.targetRect.left+window.scrollX,d=this.targetRect.top+window.scrollY,f=i.x-c,h=i.y-d,m=f-o/2+i.width/2,g=-h+s/2-i.height/2;e.position.set(m,g,r.zIndex+this.renderOrder*l);const C=i.x,x=i.y;e.userData.basePosition={x:m,y:g},e.userData.originalBasePosition={x:m,y:g},e.userData.baseSize={width:i.width,height:i.height},e.userData.baseDOM={x:C,y:x},e.userData.isFixed=t.isFixed,e.userData.initialScroll={x:window.scrollX,y:window.scrollY};const R=t.element.nodeType===Node.TEXT_NODE?t.element.parentElement:t.element,D=window.getComputedStyle(R);let k=0,F=0;if(D.transform&&D.transform!=="none"){const w=new DOMMatrix(D.transform);k=w.m41,F=w.m42}e.userData.baseTransform={x:k,y:F},delete e.userData.originRatioX,delete e.userData.originRatioY,W.update(e.material,"BOX",t.styles,"",t.rect.width,t.rect.height,this.qualityFactor,t.isTraveler?(b=this.renderTarget)==null?void 0:b.texture:this.textureManager.get(t.element))}updateMeshLayers(e,t){const i=(1-(t.visibility&B))*30;e.layers.set(i),t.visibility===(B|_)&&e.layers.enable(29)}captureRenderTarget(){if(this.travelers.size===0)return;const e=new p.Color,t=this.renderer.getClearAlpha();this.renderer.getClearColor(e),this.renderer.setClearColor(0,0),this.renderer.setRenderTarget(this.renderTarget),this.renderer.clear(),this.renderer.autoClear=!1,this.renderer.setScissorTest(!0),this.camera.layers.set(29);const i=new p.Vector3,r=this.targetRect.width,a=this.targetRect.height,o=this.renderer.getPixelRatio();for(const s of this.travelers){i.setFromMatrixPosition(s.matrixWorld),i.project(this.camera);const l=(i.x+1)/2*r,c=(i.y+1)/2*a;let d=0,f=1;typeof this.clipArea=="number"?f=this.clipArea:this.clipArea.endsWith("%")?f=parseFloat(this.clipArea)/100:this.clipArea.endsWith("px")&&(d=parseFloat(this.clipArea));const h=s.scale.x*f+.5,m=s.scale.y*f+.5,g=l-h/2,C=c-m/2,x=(g*this.qualityFactor-d)/o,R=(C*this.qualityFactor-d)/o,D=(h*this.qualityFactor+d*2)/o,k=(m*this.qualityFactor+d*2)/o;this.renderer.setScissor(x,R,D,k),this.renderer.render(this.scene,this.camera)}this.renderer.setScissorTest(!1),this.renderer.autoClear=!0,this.renderer.setRenderTarget(null),this.camera.layers.set(0),this.renderer.setClearColor(e,t)}render(){this.renderTarget&&this.captureRenderTarget(),this.renderer.render(this.scene,this.camera)}showScissoredRenderTarget(){if(!this.renderTarget)return;const e=this.targetRect.width,t=this.targetRect.height,i=new p.PlaneGeometry(e,t),r=new p.MeshBasicMaterial({map:this.renderTarget.texture,side:p.DoubleSide,transparent:!0,opacity:.8}),a=new p.Mesh(i,r);a.position.set(0,0,90),a.layers.set(28),this.scene.add(a)}}function Ee(n){const e=n.textContent||"",t=[];let i="",r=null,a=-1;const o=(c,d)=>{for(let f=0;f<c.length;f++){const h=c[f],m=document.createRange();m.setStart(n,d+f),m.setEnd(n,d+f+1);const g=m.getBoundingClientRect();if(g.width===0&&g.height===0){i+=h;continue}a===-1||Math.abs(g.top-a)>g.height/2?(i&&r&&t.push({text:i,rect:{left:r.left,top:r.top,width:r.right-r.left,height:r.bottom-r.top}}),i=h,r={left:g.left,top:g.top,right:g.right,bottom:g.bottom},a=g.top):(i+=h,r&&(r.left=Math.min(r.left,g.left),r.top=Math.min(r.top,g.top),r.right=Math.max(r.right,g.right),r.bottom=Math.max(r.bottom,g.bottom)))}},s=e.match(/[^\s\-]+\-?|\-|\s+/g)||[];let l=0;for(const c of s){const d=document.createRange();d.setStart(n,l),d.setEnd(n,l+c.length);const f=d.getClientRects();if(f.length>1)o(c,l);else{const h=f.length===1?f[0]:d.getBoundingClientRect();if(h.width===0&&h.height===0){i+=c,l+=c.length;continue}a===-1||Math.abs(h.top-a)>h.height/2?(i&&r&&t.push({text:i,rect:{left:r.left,top:r.top,width:r.right-r.left,height:r.bottom-r.top}}),i=c,r={left:h.left,top:h.top,right:h.right,bottom:h.bottom},a=h.top):(i+=c,r&&(r.left=Math.min(r.left,h.left),r.top=Math.min(r.top,h.top),r.right=Math.max(r.right,h.right),r.bottom=Math.max(r.bottom,h.bottom)))}l+=c.length}return i&&r&&t.push({text:i,rect:{left:r.left,top:r.top,width:r.right-r.left,height:r.bottom-r.top}}),t.filter(c=>c.text.trim().length>0&&c.rect.width>0&&c.rect.height>0)}function De(n){const e=parseFloat(n.fontSize);let t=parseFloat(n.lineHeight);isNaN(t)&&(t=e*1.2);let i=parseFloat(n.letterSpacing);return isNaN(i)&&(i=0),{font:`${n.fontStyle} ${n.fontWeight} ${n.fontSize} ${n.fontFamily}`,fontSize:n.fontSize,color:n.color,textAlign:n.textAlign||"start",textBaseline:"alphabetic",direction:n.direction||"inherit",lineHeight:t,letterSpacing:i}}function ne(n,e=I|z|P|A|E,t,i){if(n.nodeType===Node.TEXT_NODE){const b=n;if(!b.textContent||!b.textContent.trim())return null;const w=b.textContent.replace(/\s+/g," ");if(w.length===0)return null;const O=Ee(b);if(O.length===0)return null;const X=b.parentElement,Y=X?window.getComputedStyle(X):null;if(!Y)return null;const G=Math.min(...O.map(y=>y.rect.left)),q=Math.min(...O.map(y=>y.rect.top)),H=Math.max(...O.map(y=>y.rect.left+y.rect.width)),V=Math.max(...O.map(y=>y.rect.top+y.rect.height));return{id:Math.random().toString(36).substring(2,9),type:"TEXT",element:b,rect:{x:G+window.scrollX,y:q+window.scrollY,width:H-G,height:V-q},styles:{backgroundColor:"transparent",backgroundImage:"",opacity:X&&X.dataset.mirageDom==="hide"?1:parseFloat(Y.opacity),zIndex:0,borderRadius:"0px",borderColor:"transparent",borderWidth:"0px",isTraveler:!1},textContent:w,textLines:O.map(y=>({text:y.text.trim(),rect:{x:y.rect.left+window.scrollX,y:y.rect.top+window.scrollY,width:y.rect.width,height:y.rect.height}})),textStyles:De(Y),dirtyMask:e,visibility:t,isTraveler:!1,isFixed:Y.position==="fixed",children:[]}}if(n.nodeType!==Node.ELEMENT_NODE)return null;const r=n,a=r.dataset.mirageFilter;let o=t,s=t;if(a){const b=new Set(a.split(/\s+/));for(const w of b)if(!ee.includes(w))throw new Error(`[MirageEngine] Invalid filter token: '${w}'. Expected one of: 'include-tree', 'exclude-tree', 'include-self', 'exclude-self', 'end'.`);if(b.has("end"))return null;if(b.has("include-tree")&&b.has("exclude-tree"))throw new Error("[MirageEngine] Conflicting filters: 'include-tree' and 'exclude-tree' cannot be used together on the same element.");if(b.has("include-self")&&b.has("exclude-self"))throw new Error("[MirageEngine] Conflicting filters: 'include-self' and 'exclude-self' cannot be used together on the same element.");b.has("include-tree")?o=o|B:b.has("exclude-tree")&&(o=o&~B),s=o,b.has("include-self")?s=s|B:b.has("exclude-self")&&(s=s&~B)}s=s|t&_;const l=r.dataset.mirageTravel;let c=!1;l&&new Set(l.split(/\s+/)).has("traveler")&&(s=s&~_,o=o&~_,c=!0);const d=r.dataset.mirageShader;let f;d&&(f=JSON.parse(d));const h=r.getBoundingClientRect(),m=window.getComputedStyle(r);if(h.width===0||h.height===0||m.display==="none")return null;let g=r.getAttribute("data-mid");g||(g=Math.random().toString(36).substring(2,11),r.setAttribute("data-mid",g));const C=parseInt(m.zIndex);let x;if(r.tagName==="IMG")x=r.src;else if(m.backgroundImage&&m.backgroundImage!=="none"){const b=m.backgroundImage.match(/url\(['"]?(.*?)['"]?\)/);b&&(x=b[1])}const R={backgroundColor:m.backgroundColor,backgroundImage:m.backgroundImage,opacity:r.dataset.mirageDom==="hide"?1:parseFloat(m.opacity),zIndex:isNaN(C)?0:C,borderRadius:m.borderRadius,borderColor:m.borderColor,borderWidth:m.borderWidth,imageSrc:x,isTraveler:c};let D,k;const F=[];return Array.from(r.childNodes).forEach(b=>{const w=b.nodeType===Node.TEXT_NODE?s:o,O=ne(b,e,w);O&&F.push(O)}),{id:g,type:"BOX",element:r,rect:{x:h.left+window.scrollX,y:h.top+window.scrollY,width:h.width,height:h.height},styles:R,textContent:D,textStyles:k,dirtyMask:e,visibility:s,isTraveler:c,isFixed:m.position==="fixed",children:F,shaderHooks:f}}function Oe(n,e){e.size!==0&&e.forEach((t,i)=>{var b,w,O,X,Y,G,q,H,V,y,oe,se,ae,ce,le,he,de,ue;const r=n.get(i);if(!r||!r.userData.basePosition)return;let{x:a,y:o}=r.userData.basePosition;const{width:s,height:l}=r.userData.baseSize,c=(b=t.width)!=null?b:s,d=(w=t.height)!=null?w:l,f=c-s,h=d-l;if(t.width!==void 0&&r.userData.originRatioX===void 0&&Math.abs(f)>.1){const J=i.getBoundingClientRect(),Z=(O=t.x)!=null?O:0,Q=(Y=(X=r.userData.baseTransform)==null?void 0:X.x)!=null?Y:0,K=r.userData.isFixed?0:window.scrollX;let S=-(J.left+K-Z+Q-r.userData.baseDOM.x)/f;Math.abs(S)<.05?S=0:Math.abs(S-1)<.05?S=1:Math.abs(S-.5)<.05&&(S=.5),r.userData.originRatioX=S}if(t.height!==void 0&&r.userData.originRatioY===void 0&&Math.abs(h)>.1){const J=i.getBoundingClientRect(),Z=(G=t.y)!=null?G:0,Q=(H=(q=r.userData.baseTransform)==null?void 0:q.y)!=null?H:0,K=r.userData.isFixed?0:window.scrollY;let S=-(J.top+K-Z+Q-r.userData.baseDOM.y)/h;Math.abs(S)<.05?S=0:Math.abs(S-1)<.05?S=1:Math.abs(S-.5)<.05&&(S=.5),r.userData.originRatioY=S}const m=(V=r.userData.originRatioX)!=null?V:.5,g=(y=r.userData.originRatioY)!=null?y:.5,C=f*(.5-m),x=h*(.5-g),R=(se=(oe=r.userData.baseTransform)==null?void 0:oe.x)!=null?se:0,D=(ce=(ae=r.userData.baseTransform)==null?void 0:ae.y)!=null?ce:0,k=((le=t.x)!=null?le:R)-R,F=((he=t.y)!=null?he:D)-D;r.position.setX(a+C+k),r.position.setY(o-(x+F)),r.scale.set(c,d,1),W.forceUpdateUniforms(r.material,{backgroundColor:t.backgroundColor,backgroundImage:t.backgroundImage,opacity:t.opacity,borderRadius:(ue=t.borderRadius)!=null?ue:(de=r.userData.baseStyles)==null?void 0:de.borderRadius,width:c,height:d})})}function ke(n,e,t){n.forEach(i=>{if(i.userData.isFixed&&i.userData.initialScroll&&i.userData.originalBasePosition){const r=e-i.userData.initialScroll.x,a=t-i.userData.initialScroll.y;i.userData.basePosition.x=i.userData.originalBasePosition.x+r,i.userData.basePosition.y=i.userData.originalBasePosition.y-a,i.position.x=i.userData.basePosition.x,i.position.y=i.userData.basePosition.y}})}function Ie(n){const e={};if(n.opacity&&(e.opacity=parseFloat(n.opacity)),n.backgroundColor&&n.backgroundColor!=="rgba(0, 0, 0, 0)"){const t=U(n.backgroundColor);e.backgroundColor=[t.color.r,t.color.g,t.color.b]}if(n.backgroundImage?e.backgroundImage=n.backgroundImage:n.background&&(e.backgroundImage=n.background),n.borderRadius&&(e.borderRadius=parseFloat(n.borderRadius)),n.width&&(e.width=parseFloat(n.width)),n.height&&(e.height=parseFloat(n.height)),n.transform&&n.transform!=="none"){const t=new DOMMatrix(n.transform);e.x=t.m41,e.y=t.m42,e.z=t.m43}return e}class Be{constructor(e,t,i,r){u(this,"target");u(this,"renderer");u(this,"registry");u(this,"filter");u(this,"observer");u(this,"pendingDeletions",new Set);u(this,"pendingStyles",new Map);u(this,"isDomDirty",!1);u(this,"isRunning",!1);u(this,"isTravelEnabled",!1);u(this,"pendingMask",L);u(this,"mutationTimer",null);u(this,"cssTimer",null);u(this,"resizeConfig");u(this,"resizeTimer",null);u(this,"isResizing",!1);u(this,"lastScrollX",0);u(this,"lastScrollY",0);u(this,"scrollTimer",null);u(this,"onTransitionFinished",e=>{this.target.contains(e.target)&&this.mutationTimer===null&&(this.cssTimer&&clearTimeout(this.cssTimer),this.pendingStyles.size==0&&(this.pendingMask|=I|z,this.cssTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.cssTimer=null},50)))});u(this,"onWindowResize",()=>{if(!this.resizeConfig.enabled){this.isDomDirty=!0;return}this.isResizing||(this.isResizing=!0,this.resizeConfig.onStart&&this.resizeConfig.onStart()),this.resizeTimer&&clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.isDomDirty=!0,this.resizeConfig.onEnd&&this.resizeConfig.onEnd(),this.isResizing=!1,this.resizeTimer=null},this.resizeConfig.delay)});u(this,"renderLoop",()=>{if(!this.isRunning)return;this.isDomDirty&&this.forceUpdateScene();const e=window.scrollX,t=window.scrollY;(e!==this.lastScrollX||t!==this.lastScrollY)&&(ke(this.renderer.fixedMeshes,e,t),this.lastScrollX=e,this.lastScrollY=t,this.scrollTimer&&clearTimeout(this.scrollTimer),this.scrollTimer=window.setTimeout(()=>{this.pendingMask|=I,this.isDomDirty=!0,this.scrollTimer=null},150)),this.pendingStyles.size>0&&(Oe(this.registry,this.pendingStyles),this.pendingStyles.clear()),this.renderer.render(),requestAnimationFrame(this.renderLoop)});var o,s;this.target=e,this.renderer=t,this.registry=i,this.filter=r.filter;const a=(o=r.resizeDebounce)!=null?o:!0;a===!1?this.resizeConfig={enabled:!1,delay:0}:a===!0?this.resizeConfig={enabled:!0,delay:150}:this.resizeConfig={enabled:!0,delay:(s=a.delay)!=null?s:150,onStart:a.onStart,onEnd:a.onEnd},this.observer=new MutationObserver(l=>{let c=L;for(const d of l)if(d.type==="childList")c|=E,d.removedNodes.length>0&&d.removedNodes.forEach(f=>{f instanceof HTMLElement&&this.pendingDeletions.add(f)});else if(d.type==="attributes")if(d.attributeName==="style"){c|=I|z;const f=d.target,h=Ie(f.style);this.pendingStyles.set(f,h)}else d.attributeName==="class"&&(c|=I|z);else d.type==="characterData"&&(c|=A|I);if(c!==L){if(this.pendingMask|=c,c&E){this.clearTimers(),this.isDomDirty=!0;return}this.mutationTimer&&clearTimeout(this.mutationTimer),this.mutationTimer=window.setTimeout(()=>{this.mutationTimer=null,this.isDomDirty=!0},200)}})}start(){this.isRunning||(this.isRunning=!0,this.observer.observe(this.target,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),this.target.addEventListener("transitionend",this.onTransitionFinished),this.target.addEventListener("animationend",this.onTransitionFinished),window.addEventListener("resize",this.onWindowResize),this.forceUpdateScene(),this.renderLoop())}stop(){this.isRunning=!1,this.observer.disconnect(),this.clearTimers(),this.target.removeEventListener("transitionend",this.onTransitionFinished),this.target.removeEventListener("animationend",this.onTransitionFinished),window.removeEventListener("resize",this.onWindowResize)}clearTimers(){this.mutationTimer&&(clearTimeout(this.mutationTimer),this.mutationTimer=null),this.cssTimer&&(clearTimeout(this.cssTimer),this.cssTimer=null),this.scrollTimer&&(clearTimeout(this.scrollTimer),this.scrollTimer=null)}forceUpdateScene(){this.isDomDirty=!1,this.lastScrollX=window.scrollX,this.lastScrollY=window.scrollY;const e=document.querySelector("[data-mirage-travel='traveler']")!==null;e&&!this.isTravelEnabled&&(this.isTravelEnabled=!0,this.renderer.createRenderTarget());const t=ne(this.target,this.pendingMask,e?B|_:B,this.filter);t&&(this.renderer.syncScene(t,this.pendingDeletions),this.pendingDeletions.clear()),this.pendingMask=L}}class Fe{constructor(){u(this,"store");this.store=new WeakMap}register(e,t){this.store.set(e,t)}get(e){return this.store.get(e)}has(e){return this.store.has(e)}remove(e){this.store.delete(e)}}class Le{constructor(e,t){u(this,"renderer");u(this,"syncer");u(this,"target");u(this,"registry");var r,a,o;if(this.target=e,this.registry=new Fe,!document.getElementById("mirage-engine-styles")){const s=document.createElement("style");s.id="mirage-engine-styles",s.textContent=`
146
+ [data-mirage-dom="hide"] {
147
+ opacity: 0 !important;
148
+ }
149
+ `,document.head.appendChild(s)}let i;if(t.mode==="duplicate"?i=(a=(r=t.container)!=null?r:this.target.parentElement)!=null?a:void 0:i=(o=this.target.parentElement)!=null?o:void 0,!i)throw new Error("[Mirage] Cannot find a container (parent or option).");this.renderer=new Me(this.target,t,i,this.registry),this.renderer.mount(),this.syncer=new Be(this.target,this.renderer,this.registry,t)}start(){this.syncer.start()}stop(){this.syncer.stop()}dispose(){this.syncer.stop(),this.renderer.dispose()}test(){const e=this.registry.get(document.querySelector("#box2"));if(!e)return;const t={ArrowRight:!1,ArrowLeft:!1,ArrowUp:!1,ArrowDown:!1};window.addEventListener("keydown",a=>{t[a.key]!==void 0&&(t[a.key]=!0)}),window.addEventListener("keyup",a=>{t[a.key]!==void 0&&(t[a.key]=!1)});const i=2,r=()=>{requestAnimationFrame(r),t.ArrowRight&&e.position.setX(e.position.x+i),t.ArrowLeft&&e.position.setX(e.position.x-i),t.ArrowUp&&e.position.setY(e.position.y+i),t.ArrowDown&&e.position.setY(e.position.y-i)};r()}}v.ALLOWED_FILTERS=ee,v.DIRTY_CONTENT=A,v.DIRTY_NONE=L,v.DIRTY_RECT=I,v.DIRTY_STRUCTURE=E,v.DIRTY_STYLE=z,v.DIRTY_ZINDEX=P,v.EXCLUDED=ge,v.Engine=Le,v.SYSTEM_LAYER=_,v.USER_LAYER=B,Object.defineProperty(v,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,11 @@
1
+ import { StyleData } from '../types';
2
+ import { MeshRegistry } from '../store/MeshRegistry';
3
+
4
+ import * as THREE from "three";
5
+ export declare function animateMeshByData(registry: MeshRegistry, data: Map<HTMLElement, StyleData>): void;
6
+ export declare function animateMeshByAttribute(_target: HTMLElement, _options: {
7
+ duration: number;
8
+ easing?: string;
9
+ }): void;
10
+ export declare function updateFixedMeshesScroll(fixedMeshes: Set<THREE.Mesh>, currentScrollX: number, currentScrollY: number): void;
11
+ export declare function extractFromStyle(style: CSSStyleDeclaration): StyleData;
@@ -4,8 +4,10 @@ export declare class Engine {
4
4
  private renderer;
5
5
  private syncer;
6
6
  private target;
7
+ private registry;
7
8
  constructor(target: HTMLElement, config: CoreConfig);
8
9
  start(): void;
9
10
  stop(): void;
10
11
  dispose(): void;
12
+ test(): void;
11
13
  }
@@ -1,11 +1,15 @@
1
1
  import { CoreConfig } from '../types/config';
2
2
  import { Renderer } from '../renderer/Renderer';
3
+ import { MeshRegistry } from '../store/MeshRegistry';
3
4
 
4
5
  export declare class Syncer {
5
6
  private target;
6
7
  private renderer;
8
+ private registry;
7
9
  private filter;
8
10
  private observer;
11
+ private pendingDeletions;
12
+ private pendingStyles;
9
13
  private isDomDirty;
10
14
  private isRunning;
11
15
  private isTravelEnabled;
@@ -15,7 +19,10 @@ export declare class Syncer {
15
19
  private resizeConfig;
16
20
  private resizeTimer;
17
21
  private isResizing;
18
- constructor(target: HTMLElement, renderer: Renderer, config: CoreConfig);
22
+ private lastScrollX;
23
+ private lastScrollY;
24
+ private scrollTimer;
25
+ constructor(target: HTMLElement, renderer: Renderer, registry: MeshRegistry, config: CoreConfig);
19
26
  start(): void;
20
27
  stop(): void;
21
28
  private clearTimers;
@@ -1,5 +1,6 @@
1
1
  import { SceneNode, CoreConfig } from '../types';
2
-
2
+ import { MeshRegistry } from '../store/MeshRegistry';
3
+ import * as THREE from "three";
3
4
  export declare class Renderer {
4
5
  readonly canvas: HTMLCanvasElement;
5
6
  private readonly scene;
@@ -9,18 +10,22 @@ export declare class Renderer {
9
10
  private renderOrder;
10
11
  private qualityFactor;
11
12
  private mode;
13
+ private clipArea;
12
14
  private target;
13
15
  private mountContainer;
16
+ private registry;
14
17
  private targetRect;
15
- private meshMap;
16
- constructor(target: HTMLElement, config: CoreConfig, mountContainer: HTMLElement);
18
+ private travelers;
19
+ private textureManager;
20
+ readonly fixedMeshes: Set<THREE.Mesh>;
21
+ constructor(target: HTMLElement, config: CoreConfig, mountContainer: HTMLElement, registry: MeshRegistry);
17
22
  createRenderTarget(): void;
18
23
  private applyTextQuality;
19
24
  mount(): void;
20
25
  private updateCanvasLayout;
21
26
  dispose(): void;
22
27
  setSize(width: number, height: number): void;
23
- syncScene(graphNode: SceneNode): void;
28
+ syncScene(graphNode: SceneNode, pendingDeletions: Set<HTMLElement>): void;
24
29
  private reconcileNode;
25
30
  private reconcileTextChild;
26
31
  private updateMeshProperties;
@@ -0,0 +1,9 @@
1
+ import * as THREE from "three";
2
+ export declare class MeshRegistry {
3
+ private store;
4
+ constructor();
5
+ register(element: HTMLElement, mesh: THREE.Mesh): void;
6
+ get(element: HTMLElement): THREE.Mesh | undefined;
7
+ has(element: HTMLElement): boolean;
8
+ remove(element: HTMLElement): void;
9
+ }
@@ -0,0 +1,16 @@
1
+ import * as THREE from "three";
2
+ export type TextureReadyCallback = (element: HTMLElement, texture: THREE.Texture | null) => void;
3
+ export declare class TextureLifecycleManager {
4
+ private observer;
5
+ private textures;
6
+ private loadStatus;
7
+ private elementUrls;
8
+ private onUpdate;
9
+ constructor(onUpdate: TextureReadyCallback);
10
+ register(element: HTMLElement, url: string): void;
11
+ unregister(element: HTMLElement): void;
12
+ private loadTexture;
13
+ private disposeTexture;
14
+ get(element: HTMLElement): THREE.Texture<unknown> | undefined;
15
+ disposeAll(): void;
16
+ }
@@ -0,0 +1,19 @@
1
+ export interface StyleData {
2
+ x?: number;
3
+ y?: number;
4
+ z?: number;
5
+ scaleX?: number;
6
+ scaleY?: number;
7
+ scaleZ?: number;
8
+ rotateX?: number;
9
+ rotateY?: number;
10
+ rotateZ?: number;
11
+ matrix?: Float32Array;
12
+ opacity?: number;
13
+ backgroundColor?: [number, number, number];
14
+ backgroundImage?: string;
15
+ borderRadius?: number | [number, number, number, number];
16
+ width?: number;
17
+ height?: number;
18
+ zIndex?: number;
19
+ }
@@ -1,4 +1,4 @@
1
- import { TextStyles, BoxStyles } from '../../packages/painter/src/index.ts';
1
+ import { TextStyles, BoxStyles, ShaderHooks } from '../../packages/painter/src/index.ts';
2
2
  import { Visibility } from './flags';
3
3
 
4
4
  export type NodeType = "BOX" | "TEXT";
@@ -16,8 +16,14 @@ export interface SceneNode {
16
16
  styles: BoxStyles;
17
17
  textContent?: string;
18
18
  textStyles?: TextStyles;
19
+ textLines?: {
20
+ text: string;
21
+ rect: NodeRect;
22
+ }[];
19
23
  dirtyMask: number;
20
24
  visibility: Visibility;
21
25
  isTraveler: boolean;
26
+ isFixed: boolean;
27
+ shaderHooks?: ShaderHooks;
22
28
  children: SceneNode[];
23
29
  }
@@ -1,5 +1,8 @@
1
1
  export type Quality = "low" | "medium" | "high" | number;
2
2
  export type MirageMode = "overlay" | "duplicate";
3
+ export type PxUnit = `${number}px`;
4
+ export type PercentUnit = `${number}%`;
5
+ export type travelerClipArea = PxUnit | PercentUnit | number;
3
6
  export interface FilterConfig {
4
7
  includeTree?: string[];
5
8
  excludeTree?: string[];
@@ -20,6 +23,7 @@ interface BaseConfig {
20
23
  };
21
24
  filter?: FilterConfig;
22
25
  resizeDebounce?: boolean | ResizeConfig;
26
+ travelerClipArea?: travelerClipArea;
23
27
  }
24
28
  export interface OverlayConfig extends BaseConfig {
25
29
  mode?: "overlay";
@@ -1,3 +1,4 @@
1
1
  export * from './config';
2
2
  export * from './common';
3
3
  export * from './flags';
4
+ export * from './animate';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mirage-engine/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "main": "src/index.ts",
5
5
  "types": "src/index.ts",
6
6
  "peerDependencies": {
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@types/three": "^0.181.0",
16
- "@mirage-engine/painter": "0.3.0"
16
+ "@mirage-engine/painter": "1.0.0"
17
17
  },
18
18
  "private": false,
19
19
  "publishConfig": {