layershift 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -2
- package/dist/components/layershift.js +29 -29
- package/dist/npm/layershift.es.js +808 -831
- package/dist/types/components/layershift/index.d.ts +8 -0
- package/dist/types/components/layershift/index.d.ts.map +1 -1
- package/dist/types/components/layershift/layershift-element.d.ts +5 -1
- package/dist/types/components/layershift/layershift-element.d.ts.map +1 -1
- package/dist/types/components/layershift/portal-element.d.ts +5 -1
- package/dist/types/components/layershift/portal-element.d.ts.map +1 -1
- package/dist/types/components/layershift/types.d.ts +2 -0
- package/dist/types/components/layershift/types.d.ts.map +1 -1
- package/dist/types/input-handler.d.ts +14 -0
- package/dist/types/input-handler.d.ts.map +1 -1
- package/dist/types/input-helpers.d.ts +70 -0
- package/dist/types/input-helpers.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var Layershift=(function(
|
|
2
|
-
${i}`)}return n}function
|
|
3
|
-
${i}`)}return o.detachShader(n,t),o.detachShader(n,e),o.deleteShader(t),o.deleteShader(e),n}function
|
|
1
|
+
var Layershift=(function(N){"use strict";class Pt{constructor(t){this.depthData=t;const e=t.meta.width*t.meta.height;this.uint8Output=new Uint8Array(e)}uint8Output;lastFrameIndex=-1;lastNextFrameIndex=-1;lastLerpFactor=-1;sample(t){const e=ne(t*this.depthData.meta.fps,0,this.depthData.meta.frameCount-1),n=Math.floor(e),i=Math.min(n+1,this.depthData.meta.frameCount-1),r=e-n,s=n!==this.lastFrameIndex||i!==this.lastNextFrameIndex,a=Math.abs(r-this.lastLerpFactor)>.001;if(!s&&!a)return this.uint8Output;this.lastFrameIndex=n,this.lastNextFrameIndex=i,this.lastLerpFactor=r;const l=1-r,c=this.depthData.frames[n],u=this.depthData.frames[i];for(let f=0;f<this.uint8Output.length;f+=1)this.uint8Output[f]=c[f]*l+u[f]*r+.5|0;return this.uint8Output}}async function Ft(o,t,e){const[n,i]=await Promise.all([Jt(t),Qt(o)]);return te(i,n)}async function Jt(o){const t=await fetch(o);if(!t.ok)throw new Error(`Failed to fetch depth metadata (${t.status} ${t.statusText}).`);const e=await t.json();return ee(e),{frameCount:e.frameCount,fps:e.fps,width:e.width,height:e.height,sourceFps:e.sourceFps}}async function Qt(o,t){const e=await fetch(o);if(!e.ok)throw new Error(`Failed to fetch depth data (${e.status} ${e.statusText}).`);e.headers.get("content-length");const n=e.body;if(!n)return new Uint8Array(await e.arrayBuffer());const i=[];let r=0;const s=n.getReader();for(;;){const{done:c,value:u}=await s.read();if(c)break;u&&(i.push(u),r+=u.byteLength)}const a=new Uint8Array(r);let l=0;for(const c of i)a.set(c,l),l+=c.byteLength;return a}function te(o,t){if(o.byteLength<4)throw new Error("Depth data binary is missing the frame-count header.");const n=new DataView(o.buffer,o.byteOffset,o.byteLength).getUint32(0,!0),i=t.width*t.height,r=4+n*i;if(o.byteLength!==r)throw new Error(`Depth data byte length mismatch. Expected ${r} bytes, received ${o.byteLength}.`);if(n!==t.frameCount)throw new Error(`Depth frame count mismatch between metadata (${t.frameCount}) and binary header (${n}).`);const s=o.subarray(4),a=new Array(n);for(let l=0;l<n;l+=1){const c=l*i;a[l]=s.subarray(c,c+i)}return{meta:t,frames:a}}function ee(o){if(!o||typeof o.frameCount!="number"||typeof o.fps!="number"||typeof o.width!="number"||typeof o.height!="number"||typeof o.sourceFps!="number")throw new Error("Depth metadata is malformed.");if(!Number.isFinite(o.frameCount)||!Number.isFinite(o.fps)||!Number.isFinite(o.width)||!Number.isFinite(o.height)||!Number.isFinite(o.sourceFps)||o.frameCount<=0||o.fps<=0||o.width<=0||o.height<=0||o.sourceFps<=0)throw new Error("Depth metadata contains invalid numeric values.")}function H(o,t){const e=new Uint8Array(o*t);return e.fill(128),{meta:{frameCount:1,fps:1,width:o,height:t,sourceFps:1},frames:[e]}}function ne(o,t,e){return Math.min(e,Math.max(t,o))}const ie={parallaxStrength:.05,contrastLow:.05,contrastHigh:.95,verticalReduction:.5,dofStart:.6,dofStrength:.4,pomSteps:16,overscanPadding:.08};function re(o,t,e){const n=new Float32Array(256);if(o.length===0||t<=0||e<=0)return Ct(n);const i=se(o.length),r=t*e;let s=0;const a=new Uint32Array(256);for(const m of i){const T=o[m],w=Math.min(T.length,r);for(let A=0;A<w;A+=1)a[T[A]]+=1;s+=w}if(s===0)return Ct(n);const l=1/s;for(let m=0;m<256;m+=1)n[m]=a[m]*l;const c=new Float32Array(256);c[0]=n[0];for(let m=1;m<256;m+=1)c[m]=c[m-1]+n[m];const u=et(c,.05),f=et(c,.25),h=et(c,.5),x=et(c,.75),g=et(c,.95);let d=0;for(let m=0;m<256;m+=1)d+=m/255*n[m];let y=0;for(let m=0;m<256;m+=1){const T=m/255-d;y+=n[m]*T*T}const E=Math.sqrt(y),b=g-u,p=x-f,v=ae(n);return{mean:d,stdDev:E,p5:u,p25:f,median:h,p75:x,p95:g,effectiveRange:b,iqr:p,bimodality:v,histogram:n}}function oe(o){if(o.effectiveRange<.05||o.stdDev<.02)return{...ie};const t=o.effectiveRange-.5,e=o.bimodality-.4,n=k(.05-t*.03+e*.01,.035,.065),i=k(o.p5-.03,0,.25),r=k(o.p95+.03,.75,1),s=k((n-.03)/.05,0,1),a=k(.6-s*.25,.35,.6),l=k(.6-t*.2,.5,.7),c=k(.4+t*.2,.25,.5),u=16,f=k(n+.03,.06,.1);return{parallaxStrength:n,contrastLow:i,contrastHigh:r,verticalReduction:a,dofStart:l,dofStrength:c,pomSteps:u,overscanPadding:f}}function se(o){if(o<=0)return[];if(o===1)return[0];const t=o-1,e=[0,Math.floor(o/4),Math.floor(o/2),Math.floor(3*o/4),t],n=new Set,i=[];for(const r of e)n.has(r)||(n.add(r),i.push(r));return i}function et(o,t){for(let e=0;e<256;e+=1)if(o[e]>=t)return e/255;return 1}function ae(o){const t=new Float32Array(256);for(let h=0;h<256;h+=1){let x=0,g=0;for(let d=h-2;d<=h+2;d+=1)d>=0&&d<256&&(x+=o[d],g+=1);t[h]=x/g}let e=0;for(let h=0;h<256;h+=1)e+=t[h];e/=256;const n=e*2,i=25,r=[];for(let h=1;h<255;h+=1)t[h]>t[h-1]&&t[h]>t[h+1]&&t[h]>=n&&r.push({bin:h,height:t[h]});if(t[0]>t[1]&&t[0]>=n&&r.push({bin:0,height:t[0]}),t[255]>t[254]&&t[255]>=n&&r.push({bin:255,height:t[255]}),r.sort((h,x)=>x.height-h.height),r.length<2)return 0;const s=r[0];let a=null;for(let h=1;h<r.length;h+=1)if(Math.abs(r[h].bin-s.bin)>=i){a=r[h];break}if(!a)return 0;const l=Math.min(s.bin,a.bin),c=Math.max(s.bin,a.bin);let u=1/0;for(let h=l;h<=c;h+=1)t[h]<u&&(u=t[h]);const f=Math.min(s.height,a.height);return f<=0?0:k(1-u/f,0,1)}function Ct(o){return{mean:0,stdDev:0,p5:0,p25:0,median:0,p75:0,p95:0,effectiveRange:0,iqr:0,bimodality:0,histogram:o}}function k(o,t,e){return Math.min(e,Math.max(t,o))}function Y(o,t,e){const n=o.createShader(t);if(!n)throw new Error("Failed to create shader.");if(o.shaderSource(n,e),o.compileShader(n),!o.getShaderParameter(n,o.COMPILE_STATUS)){const i=o.getShaderInfoLog(n)??"";throw o.deleteShader(n),new Error(`Shader compilation failed:
|
|
2
|
+
${i}`)}return n}function Tt(o,t,e){const n=o.createProgram();if(!n)throw new Error("Failed to create program.");if(o.attachShader(n,t),o.attachShader(n,e),o.linkProgram(n),!o.getProgramParameter(n,o.LINK_STATUS)){const i=o.getProgramInfoLog(n)??"";throw o.deleteProgram(n),new Error(`Program linking failed:
|
|
3
|
+
${i}`)}return o.detachShader(n,t),o.detachShader(n,e),o.deleteShader(t),o.deleteShader(e),n}function Et(o,t,e){const n={};for(const i of e)n[i]=o.getUniformLocation(t,i);return n}const le=new Float32Array([-1,-1,1,-1,-1,1,1,1]);function Ut(o,t){const e=o.createVertexArray();if(!e)throw new Error("Failed to create VAO.");o.bindVertexArray(e);const n=o.createBuffer();o.bindBuffer(o.ARRAY_BUFFER,n),o.bufferData(o.ARRAY_BUFFER,le,o.STATIC_DRAW);const i=o.getAttribLocation(t,"aPosition");return o.enableVertexAttribArray(i),o.vertexAttribPointer(i,2,o.FLOAT,!1,0,0),o.bindVertexArray(null),e}class Lt{slots=new Map;nextUnit=0;register(t){if(this.slots.has(t))throw new Error(`TextureRegistry: slot '${t}' already registered.`);const e={name:t,unit:this.nextUnit++,texture:null};return this.slots.set(t,e),e}get(t){const e=this.slots.get(t);if(!e)throw new Error(`TextureRegistry: slot '${t}' not found.`);return e}disposeAll(t){for(const e of this.slots.values())e.texture&&(t.deleteTexture(e.texture),e.texture=null)}get size(){return this.slots.size}}function X(o,t,e,n,i){const r=Y(o,o.VERTEX_SHADER,e),s=Y(o,o.FRAGMENT_SHADER,n),a=Tt(o,r,s),l=Et(o,a,i);return{name:t,program:a,uniforms:l,dispose(c){c.deleteProgram(a)}}}const ue={high:{dprCap:2,depthMaxDim:512,pomSteps:16,bilateralRadius:2,jfaDivisor:2},medium:{dprCap:1.5,depthMaxDim:512,pomSteps:16,bilateralRadius:2,jfaDivisor:2},low:{dprCap:1,depthMaxDim:256,pomSteps:8,bilateralRadius:1,jfaDivisor:4}};function ce(o){let t="unknown";const e=o.getExtension("WEBGL_debug_renderer_info");e&&(t=o.getParameter(e.UNMASKED_RENDERER_WEBGL)||"unknown");const n=o.getParameter(o.MAX_TEXTURE_SIZE),i=typeof navigator<"u"&&navigator.hardwareConcurrency||0,r=typeof navigator<"u"&&navigator.deviceMemory||0,s=typeof window<"u"&&window.devicePixelRatio||1,a=typeof screen<"u"?(screen.width||0)*(screen.height||0):0,l=typeof navigator<"u"&&("ontouchstart"in window||navigator.maxTouchPoints>0),c=a>0&&a<1920*1080;return{gpuRenderer:t,maxTextureSize:n,hardwareConcurrency:i,deviceMemory:r,devicePixelRatio:s,screenPixels:a,isMobile:l&&c}}const he=["mali-4","mali-t","adreno 3","adreno 4","adreno 5","powervr sgx","intel hd graphics","intel uhd graphics","intel iris","llvmpipe","swiftshader","software"],fe=["nvidia","geforce","radeon rx","radeon pro","apple m","apple gpu","adreno 7","adreno 6","mali-g7","mali-g6"];function de(o){let t=0;const e=o.gpuRenderer.toLowerCase(),n=he.some(r=>e.includes(r)),i=fe.some(r=>e.includes(r));return n&&(t-=30),i&&(t+=20),o.maxTextureSize>=16384?t+=10:o.maxTextureSize>=8192?t+=5:o.maxTextureSize<=4096&&(t-=15),o.hardwareConcurrency>=8?t+=5:o.hardwareConcurrency>=4?t+=0:o.hardwareConcurrency>0&&o.hardwareConcurrency<4&&(t-=10),o.deviceMemory>=8?t+=5:o.deviceMemory>=4?t+=0:o.deviceMemory>0&&o.deviceMemory<4&&(t-=15),o.isMobile&&(t-=10),t>=0?"high":t>=-25?"medium":"low"}function _t(o,t){const e=t&&t!=="auto"?t:de(ce(o));return{tier:e,...ue[e]}}class at{static RESIZE_DEBOUNCE_MS=100;canvas;container;depthWidth=0;depthHeight=0;sourceDepthWidth=0;sourceDepthHeight=0;depthSubsampleBuffer=null;videoAspect=1.7777777777777777;isCameraSource=!1;uvOffset=[0,0];uvScale=[1,1];readDepth=null;readInput=null;mediaSource=null;onVideoFrame=null;animationFrameHandle=0;rvfcHandle=0;rvfcSupported=!1;resizeObserver=null;resizeTimer=null;qualityParams;constructor(t){this.container=t,this.canvas=document.createElement("canvas"),this.container.appendChild(this.canvas),this.canvas.addEventListener("webglcontextlost",this._handleContextLost),this.canvas.addEventListener("webglcontextrestored",this._handleContextRestored)}get canvasElement(){return this.canvas}start(t,e,n,i){this.stop(),this.mediaSource=t,this.readDepth=e,this.readInput=n,this.onVideoFrame=i??null,this.rvfcSupported=t.isLive&&typeof t.requestVideoFrameCallback=="function",this.rvfcSupported?this.rvfcHandle=t.requestVideoFrameCallback(this._videoFrameLoop):t.isLive||this.onDepthUpdate(t.currentTime),this.animationFrameHandle=window.requestAnimationFrame(this._rafLoop)}stop(){this.animationFrameHandle&&(window.cancelAnimationFrame(this.animationFrameHandle),this.animationFrameHandle=0),this.rvfcHandle&&this.mediaSource?.cancelVideoFrameCallback&&(this.mediaSource.cancelVideoFrameCallback(this.rvfcHandle),this.rvfcHandle=0),this.mediaSource=null,this.readDepth=null,this.readInput=null,this.onVideoFrame=null,this.rvfcSupported=!1}dispose(){this.stop(),this.disposeRenderer(),this.canvas.removeEventListener("webglcontextlost",this._handleContextLost),this.canvas.removeEventListener("webglcontextrestored",this._handleContextRestored),this.canvas.remove(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),window.removeEventListener("resize",this.scheduleResizeRecalculate),this.resizeTimer!==null&&(window.clearTimeout(this.resizeTimer),this.resizeTimer=null)}static isRVFCSupported(){return"requestVideoFrameCallback"in HTMLVideoElement.prototype}_rafLoop=()=>{this.animationFrameHandle=window.requestAnimationFrame(this._rafLoop),this.onRenderFrame()};_videoFrameLoop=(t,e)=>{const n=this.mediaSource;if(!n||!n.requestVideoFrameCallback)return;this.rvfcHandle=n.requestVideoFrameCallback(this._videoFrameLoop);const i=e.mediaTime??n.currentTime;this.onDepthUpdate(i),this.onVideoFrame&&this.onVideoFrame(i,e.presentedFrames??0)};_handleContextLost=t=>{t.preventDefault(),this.animationFrameHandle&&(window.cancelAnimationFrame(this.animationFrameHandle),this.animationFrameHandle=0)};_handleContextRestored=()=>{this.onContextRestored()};setupResizeHandling(){typeof ResizeObserver<"u"&&(this.resizeObserver=new ResizeObserver(()=>{this.scheduleResizeRecalculate()}),this.resizeObserver.observe(this.container)),window.addEventListener("resize",this.scheduleResizeRecalculate),this.recalculateViewportLayout()}scheduleResizeRecalculate=()=>{this.resizeTimer!==null&&window.clearTimeout(this.resizeTimer),this.resizeTimer=window.setTimeout(()=>{this.resizeTimer=null,this.recalculateViewportLayout()},at.RESIZE_DEBOUNCE_MS)};getViewportSize(){const t=Math.max(1,Math.round(this.container.clientWidth||window.innerWidth)),e=Math.max(1,Math.round(this.container.clientHeight||window.innerHeight));return{width:t,height:e}}clampDepthDimensions(t,e,n){this.sourceDepthWidth=t,this.sourceDepthHeight=e;let i=t,r=e;if(i>n||r>n){const s=n/Math.max(i,r);i=Math.max(1,Math.round(i*s)),r=Math.max(1,Math.round(r*s))}this.depthWidth=i,this.depthHeight=r,i!==t||r!==e?this.depthSubsampleBuffer=new Uint8Array(i*r):this.depthSubsampleBuffer=null}subsampleDepth(t){if(!this.depthSubsampleBuffer)return t;const e=this.depthSubsampleBuffer,n=this.sourceDepthWidth,i=this.depthWidth,r=this.depthHeight;for(let s=0;s<r;s++){const l=Math.min(Math.round(s*n/i),this.sourceDepthHeight-1)*n,c=s*i;for(let u=0;u<i;u++){const f=Math.min(Math.round(u*n/i),n-1);e[c+u]=t[l+f]}}return e}computeCoverFitUV(t,e){const{width:n,height:i}=this.getViewportSize(),r=n/i,s=t+e;let a=1,l=1;r>this.videoAspect?l=this.videoAspect/r:a=r/this.videoAspect;const c=1+s*2;a/=c,l/=c,this.uvOffset=[(1-a)/2,(1-l)/2],this.uvScale=[a,l],this.isCameraSource&&(this.uvOffset[0]+=this.uvScale[0],this.uvScale[0]=-this.uvScale[0])}}const me=`#version 300 es
|
|
4
4
|
in vec2 aPosition;
|
|
5
5
|
|
|
6
6
|
// UV coordinates for cover-fit + overscan.
|
|
@@ -21,7 +21,7 @@ void main() {
|
|
|
21
21
|
vScreenUv = baseUv;
|
|
22
22
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
23
23
|
}
|
|
24
|
-
`,
|
|
24
|
+
`,pe=`#version 300 es
|
|
25
25
|
in vec2 aPosition;
|
|
26
26
|
out vec2 vUv;
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ void main() {
|
|
|
29
29
|
vUv = aPosition * 0.5 + 0.5;
|
|
30
30
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
31
31
|
}
|
|
32
|
-
`,
|
|
32
|
+
`,ge=`#version 300 es
|
|
33
33
|
precision highp float;
|
|
34
34
|
|
|
35
35
|
// BILATERAL_RADIUS is injected as a #define at compile time.
|
|
@@ -67,7 +67,7 @@ void main() {
|
|
|
67
67
|
|
|
68
68
|
fragColor = vec4(totalDepth / totalWeight, 0.0, 0.0, 1.0);
|
|
69
69
|
}
|
|
70
|
-
`,
|
|
70
|
+
`,ve=`#version 300 es
|
|
71
71
|
precision highp float;
|
|
72
72
|
|
|
73
73
|
// ---- Uniforms ----
|
|
@@ -464,9 +464,9 @@ void main() {
|
|
|
464
464
|
|
|
465
465
|
fragColor = color;
|
|
466
466
|
}
|
|
467
|
-
`,
|
|
468
|
-
#define BILATERAL_RADIUS ${t}`),n=
|
|
469
|
-
#define MAX_POM_STEPS ${Ae}`),e=z(o,o.VERTEX_SHADER,ge),n=z(o,o.FRAGMENT_SHADER,t),i=Et(o,e,n),r=bt(o,i,Se);return{name:"depth-effect",program:i,uniforms:r,setStaticUniforms(s,a,l,u){s.useProgram(i),s.uniform1i(r.uImage,0),s.uniform1i(r.uDepth,1),s.uniform1f(r.uStrength,a.parallaxStrength),s.uniform1i(r.uPomEnabled,a.pomEnabled?1:0),s.uniform1i(r.uPomSteps,a.pomSteps),s.uniform1f(r.uContrastLow,a.contrastLow),s.uniform1f(r.uContrastHigh,a.contrastHigh),s.uniform1f(r.uVerticalReduction,a.verticalReduction),s.uniform1f(r.uDofStart,a.dofStart),s.uniform1f(r.uDofStrength,a.dofStrength),s.uniform2f(r.uImageTexelSize,1/l,1/u),s.uniform1i(r.uDisplacementCurve,3),s.uniform1i(r.uBlurCurve,4),s.uniform1i(r.uCurvesEnabled,0),s.uniform1f(r.uBlurRadius,a.blurRadius),s.uniform1f(r.uFocalBandOffset,0),s.uniform1i(r.uGlowCurve,5),s.uniform1i(r.uGlowEnabled,0),s.uniform3f(r.uGlowColor,a.glowColor[0],a.glowColor[1],a.glowColor[2]),s.uniform1f(r.uGlowRadius,a.glowRadius),s.uniform1f(r.uGlowSoftness,a.glowSoftness),s.uniform1i(r.uColorShiftCurve,6),s.uniform1i(r.uColorShiftEnabled,0),s.uniform1f(r.uColorShiftHue,0),s.uniform1f(r.uColorShiftSaturation,1),s.uniform1f(r.uColorShiftBrightness,1),s.uniform1f(r.uColorShiftTintStrength,0),s.uniform3f(r.uColorShiftTintColor,.7,.8,.9),s.uniform1i(r.uTiltEnabled,a.tiltEnabled?1:0),s.uniform1f(r.uTiltHalfTanFov,a.tiltHalfTanFov),s.uniform1f(r.uTiltTransitionWidth,a.tiltTransitionWidth),s.uniform1f(r.uTiltPeakIntensity,a.tiltPeakIntensity),s.uniform3f(r.uTiltPlaneNormal,0,0,1),s.uniform1f(r.uTiltPlaneD,2.75)},updateUvTransform(s,a,l){s.useProgram(i),s.uniform2f(r.uUvOffset,a[0],a[1]),s.uniform2f(r.uUvScale,l[0],l[1])},dispose(s){s.deleteProgram(i)}}}class Re extends at{gl=null;quadVao=null;bilateralPass=null;effectPass=null;textures=new Mt;videoSlot;filteredDepthSlot;rawDepthSlot;displacementLutSlot;blurLutSlot;glowLutSlot;colorShiftLutSlot;config;constructor(t,e){super(t),this.videoSlot=this.textures.register("video"),this.filteredDepthSlot=this.textures.register("filteredDepth"),this.rawDepthSlot=this.textures.register("rawDepth"),this.displacementLutSlot=this.textures.register("displacementLut"),this.blurLutSlot=this.textures.register("blurLut"),this.glowLutSlot=this.textures.register("glowLut"),this.colorShiftLutSlot=this.textures.register("colorShiftLut"),this.config={parallaxStrength:e.parallaxStrength,pomEnabled:e.pomEnabled,pomSteps:e.pomSteps,overscanPadding:e.overscanPadding,contrastLow:e.contrastLow??I.contrastLow,contrastHigh:e.contrastHigh??I.contrastHigh,verticalReduction:e.verticalReduction??I.verticalReduction,dofStart:e.dofStart??I.dofStart,dofStrength:e.dofStrength??I.dofStrength,blurRadius:e.blurRadius??I.blurRadius,glowColor:e.glowColor??[...I.glowColor],glowRadius:e.glowRadius??I.glowRadius,glowSoftness:e.glowSoftness??I.glowSoftness,tiltEnabled:e.tiltEnabled??I.tiltEnabled,tiltHalfTanFov:e.tiltHalfTanFov??I.tiltHalfTanFov,tiltTransitionWidth:e.tiltTransitionWidth??I.tiltTransitionWidth,tiltPeakIntensity:e.tiltPeakIntensity??I.tiltPeakIntensity};const n=this.canvas.getContext("webgl2",{antialias:!1,alpha:!1,desynchronized:!0,powerPreference:"high-performance"});if(!n)throw new Error("WebGL 2 is not supported.");this.gl=n,this.qualityParams=It(n,e.quality),"drawingBufferColorSpace"in n&&(n.drawingBufferColorSpace="srgb"),n.clearColor(0,0,0,1),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.setupResizeHandling()}initialize(t,e,n){const i=this.gl;i&&(this.disposeTextures(),this.isCameraSource=t.type==="camera",this.videoAspect=t.width/t.height,this.clampDepthDimensions(e,n,this.qualityParams.depthMaxDim),this.videoSlot.texture=i.createTexture(),i.activeTexture(i.TEXTURE0+this.videoSlot.unit),i.bindTexture(i.TEXTURE_2D,this.videoSlot.texture),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),this.rawDepthSlot.texture=i.createTexture(),i.activeTexture(i.TEXTURE0+this.rawDepthSlot.unit),i.bindTexture(i.TEXTURE_2D,this.rawDepthSlot.texture),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),i.texStorage2D(i.TEXTURE_2D,1,i.R8,e,n),this.filteredDepthSlot.texture=i.createTexture(),i.activeTexture(i.TEXTURE0+this.filteredDepthSlot.unit),i.bindTexture(i.TEXTURE_2D,this.filteredDepthSlot.texture),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),i.texStorage2D(i.TEXTURE_2D,1,i.R8,e,n),this.bilateralPass&&this.filteredDepthSlot.texture&&this.bilateralPass.initFBO(i,this.filteredDepthSlot.texture,e,n),this.effectPass&&this.effectPass.setStaticUniforms(i,this.config,t.width,t.height),this.recalculateViewportLayout())}updateConfig(t){const e=this.gl;if(!e||!this.effectPass)return;t.parallaxStrength!==void 0&&(this.config.parallaxStrength=t.parallaxStrength),t.pomEnabled!==void 0&&(this.config.pomEnabled=t.pomEnabled),t.pomSteps!==void 0&&(this.config.pomSteps=t.pomSteps),t.overscanPadding!==void 0&&(this.config.overscanPadding=t.overscanPadding),t.contrastLow!==void 0&&(this.config.contrastLow=t.contrastLow),t.contrastHigh!==void 0&&(this.config.contrastHigh=t.contrastHigh),t.verticalReduction!==void 0&&(this.config.verticalReduction=t.verticalReduction),t.dofStart!==void 0&&(this.config.dofStart=t.dofStart),t.dofStrength!==void 0&&(this.config.dofStrength=t.dofStrength),t.blurRadius!==void 0&&(this.config.blurRadius=t.blurRadius),t.glowColor!==void 0&&(this.config.glowColor=t.glowColor),t.glowRadius!==void 0&&(this.config.glowRadius=t.glowRadius),t.glowSoftness!==void 0&&(this.config.glowSoftness=t.glowSoftness),t.tiltEnabled!==void 0&&(this.config.tiltEnabled=t.tiltEnabled),t.tiltHalfTanFov!==void 0&&(this.config.tiltHalfTanFov=t.tiltHalfTanFov),t.tiltTransitionWidth!==void 0&&(this.config.tiltTransitionWidth=t.tiltTransitionWidth),t.tiltPeakIntensity!==void 0&&(this.config.tiltPeakIntensity=t.tiltPeakIntensity);const{uniforms:n,program:i}=this.effectPass;e.useProgram(i),e.uniform1f(n.uStrength,this.config.parallaxStrength),e.uniform1i(n.uPomEnabled,this.config.pomEnabled?1:0),e.uniform1i(n.uPomSteps,this.config.pomSteps),e.uniform1f(n.uContrastLow,this.config.contrastLow),e.uniform1f(n.uContrastHigh,this.config.contrastHigh),e.uniform1f(n.uVerticalReduction,this.config.verticalReduction),e.uniform1f(n.uDofStart,this.config.dofStart),e.uniform1f(n.uDofStrength,this.config.dofStrength),e.uniform1f(n.uBlurRadius,this.config.blurRadius),e.uniform3f(n.uGlowColor,this.config.glowColor[0],this.config.glowColor[1],this.config.glowColor[2]),e.uniform1f(n.uGlowRadius,this.config.glowRadius),e.uniform1f(n.uGlowSoftness,this.config.glowSoftness),e.uniform1i(n.uTiltEnabled,this.config.tiltEnabled?1:0),e.uniform1f(n.uTiltHalfTanFov,this.config.tiltHalfTanFov),e.uniform1f(n.uTiltTransitionWidth,this.config.tiltTransitionWidth),e.uniform1f(n.uTiltPeakIntensity,this.config.tiltPeakIntensity),(t.parallaxStrength!==void 0||t.overscanPadding!==void 0)&&this.recalculateViewportLayout()}updateCurveLUTs(t,e,n,i,r){const s=this.gl;if(!s||!this.effectPass)return;const a=!!(t||e),l=!!n,u=!!i;if(t&&this.uploadLUT(this.displacementLutSlot,t),e&&this.uploadLUT(this.blurLutSlot,e),n&&this.uploadLUT(this.glowLutSlot,n),i&&this.uploadLUT(this.colorShiftLutSlot,i),s.useProgram(this.effectPass.program),s.uniform1i(this.effectPass.uniforms.uCurvesEnabled,a?1:0),s.uniform1i(this.effectPass.uniforms.uGlowEnabled,l?1:0),s.uniform1i(this.effectPass.uniforms.uColorShiftEnabled,u?1:0),u&&r){const h=this.effectPass.uniforms;s.uniform1f(h.uColorShiftHue,r.hueShift*(Math.PI/180)),s.uniform1f(h.uColorShiftSaturation,r.saturation),s.uniform1f(h.uColorShiftBrightness,r.brightness),s.uniform1f(h.uColorShiftTintStrength,r.tintStrength),s.uniform3f(h.uColorShiftTintColor,r.tintColor[0],r.tintColor[1],r.tintColor[2])}}initGPUResources(){const t=this.gl;t&&(this.bilateralPass=ye(t,this.qualityParams.bilateralRadius),this.effectPass=we(t),this.quadVao=_t(t,this.effectPass.program),t.disable(t.DEPTH_TEST))}uploadLUT(t,e){const n=this.gl;n&&(n.activeTexture(n.TEXTURE0+t.unit),t.texture?n.bindTexture(n.TEXTURE_2D,t.texture):(t.texture=n.createTexture(),n.bindTexture(n.TEXTURE_2D,t.texture),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.texStorage2D(n.TEXTURE_2D,1,n.R8,256,1)),n.texSubImage2D(n.TEXTURE_2D,0,0,0,256,1,n.RED,n.UNSIGNED_BYTE,e))}onRenderFrame(){const t=this.gl,e=this.mediaSource;if(!t||!this.effectPass||!this.quadVao)return;const n=e?.getImageSource();if(n){if(!this.rvfcSupported&&e.isLive&&this.onDepthUpdate(e.currentTime),t.useProgram(this.effectPass.program),t.activeTexture(t.TEXTURE0+this.videoSlot.unit),t.bindTexture(t.TEXTURE_2D,this.videoSlot.texture),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,n),this.readInput){const i=this.readInput();t.uniform2f(this.effectPass.uniforms.uOffset,-i.x,i.y),i.focalBandOffset!==void 0&&t.uniform1f(this.effectPass.uniforms.uFocalBandOffset,i.focalBandOffset),i.tiltPlaneNormal!==void 0&&t.uniform3f(this.effectPass.uniforms.uTiltPlaneNormal,i.tiltPlaneNormal[0],i.tiltPlaneNormal[1],i.tiltPlaneNormal[2]),i.tiltPlaneD!==void 0&&t.uniform1f(this.effectPass.uniforms.uTiltPlaneD,i.tiltPlaneD)}t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4)}}onDepthUpdate(t){const e=this.gl;if(!e||!this.readDepth||!this.rawDepthSlot.texture||!this.bilateralPass)return;const n=this.subsampleDepth(this.readDepth(t));this.bilateralPass.execute(e,this.quadVao,this.rawDepthSlot.texture,n,this.depthWidth,this.depthHeight,this.canvas.width,this.canvas.height)}recalculateViewportLayout(){const t=this.gl;if(!t)return;const{width:e,height:n}=this.getViewportSize(),i=Math.min(window.devicePixelRatio,this.qualityParams.dprCap),r=Math.round(e*i),s=Math.round(n*i);(this.canvas.width!==r||this.canvas.height!==s)&&(this.canvas.width=r,this.canvas.height=s,t.viewport(0,0,r,s)),this.computeCoverFitUV(this.config.parallaxStrength,this.config.overscanPadding),this.effectPass&&this.effectPass.updateUvTransform(t,this.uvOffset,this.uvScale)}disposeRenderer(){this.disposeTextures(),this.disposeGPUResources(),this.gl&&(this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null)}onContextRestored(){const t=this.canvas.getContext("webgl2");t&&(this.gl=t,t.clearColor(0,0,0,1),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.mediaSource&&this.depthWidth>0&&this.initialize(this.mediaSource,this.depthWidth,this.depthHeight),this.mediaSource&&(this.animationFrameHandle=window.requestAnimationFrame(()=>this.onRenderFrame())))}disposeTextures(){const t=this.gl;t&&this.textures.disposeAll(t)}disposeGPUResources(){const t=this.gl;t&&(this.bilateralPass&&(this.bilateralPass.dispose(t),this.bilateralPass=null),this.effectPass&&(this.effectPass.dispose(t),this.effectPass=null),this.quadVao&&(t.deleteVertexArray(this.quadVao),this.quadVao=null))}}async function lt(o,t={}){const{parent:e=document.body,loop:n=!0,muted:i=!0}=t,r=document.createElement("video");return r.crossOrigin="anonymous",r.setAttribute("crossorigin","anonymous"),r.playsInline=!0,r.setAttribute("playsinline",""),r.setAttribute("webkit-playsinline","true"),r.muted=i,r.defaultMuted=i,i&&r.setAttribute("muted",""),r.loop=n,r.preload="auto",r.style.display="none",r.src=o,e.appendChild(r),await Vt(r),new De(r)}class De{constructor(t){this.video=t}type="video";isLive=!0;get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}get currentTime(){return this.video.currentTime}get duration(){return this.video.duration}get paused(){return this.video.paused}getImageSource(){return this.video.readyState<HTMLMediaElement.HAVE_CURRENT_DATA?null:this.video}requestVideoFrameCallback(t){return this.video.requestVideoFrameCallback(t)}cancelVideoFrameCallback(t){this.video.cancelVideoFrameCallback(t)}play(){return this.video.play()}pause(){this.video.pause()}addEventListener(t,e){this.video.addEventListener(t,e)}removeEventListener(t,e){this.video.removeEventListener(t,e)}dispose(){this.video.pause(),this.video.removeAttribute("src"),this.video.load(),this.video.remove()}}async function ht(o,t={}){const e=new Image;return e.crossOrigin="anonymous",e.src=o,await new Promise((n,i)=>{if(e.complete&&e.naturalWidth>0){n();return}e.addEventListener("load",()=>n(),{once:!0}),e.addEventListener("error",()=>i(new Error(`Failed to load image: ${o}`)),{once:!0})}),new Pe(e)}class Pe{constructor(t){this.img=t}type="image";isLive=!1;currentTime=0;duration=0;paused=!1;get width(){return this.img.naturalWidth}get height(){return this.img.naturalHeight}getImageSource(){return this.img}dispose(){this.img.removeAttribute("src")}}async function Bt(o={video:!0},t={}){const{parent:e=document.body}=t,n=await navigator.mediaDevices.getUserMedia(o),i=document.createElement("video");return i.playsInline=!0,i.setAttribute("playsinline",""),i.muted=!0,i.defaultMuted=!0,i.style.display="none",i.srcObject=n,e.appendChild(i),await Vt(i),await i.play(),new Fe(i,n)}class Fe{constructor(t,e){this.video=t,this.stream=e}type="camera";isLive=!0;duration=1/0;get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}get currentTime(){return this.video.currentTime}get paused(){return this.video.paused}getImageSource(){return this.video.readyState<HTMLMediaElement.HAVE_CURRENT_DATA?null:this.video}requestVideoFrameCallback(t){return this.video.requestVideoFrameCallback(t)}cancelVideoFrameCallback(t){this.video.cancelVideoFrameCallback(t)}play(){return this.video.play()}pause(){this.video.pause()}addEventListener(t,e){this.video.addEventListener(t,e)}removeEventListener(t,e){this.video.removeEventListener(t,e)}dispose(){this.video.pause(),this.video.srcObject=null,this.video.remove();for(const t of this.stream.getTracks())t.stop()}}async function Vt(o){o.readyState>=HTMLMediaElement.HAVE_METADATA||await new Promise((t,e)=>{const n=()=>{r(),t()},i=()=>{r(),e(new Error("Failed to load video metadata."))},r=()=>{o.removeEventListener("loadedmetadata",n),o.removeEventListener("error",i)};o.addEventListener("loadedmetadata",n),o.addEventListener("error",i),o.load()})}const yt=[.485,.456,.406],St=[.229,.224,.225],q=518;async function Ce(){return await import("onnxruntime-web/webgpu")}class Le{constructor(t,e){this.depthWidth=t,this.depthHeight=e;const n=t*e;this.frontBuffer=new Uint8Array(n),this.frontBuffer.fill(128),this.backBuffer=new Uint8Array(n),this.backBuffer.fill(128),this.readyPromise=new Promise(i=>{this.readyResolve=i})}ort=null;session=null;inputName="";outputName="";frontBuffer;backBuffer;inferenceInFlight=!1;readyResolve=null;readyPromise;captureCanvas=null;captureCtx=null;disposed=!1;async init(t,e){const n=await Ce();if(this.ort=n,this.captureCanvas=document.createElement("canvas"),this.captureCanvas.width=q,this.captureCanvas.height=q,this.captureCtx=this.captureCanvas.getContext("2d",{willReadFrequently:!0}),!this.captureCtx)throw new Error("[DepthEstimator] Failed to create 2D canvas context.");e?.({receivedBytes:0,totalBytes:null,fraction:0,label:"Downloading depth model…"});const i=await Ue(t,e);e?.({receivedBytes:i.byteLength,totalBytes:i.byteLength,fraction:1,label:"Initialising depth model…"});let r;try{r=await n.InferenceSession.create(i,{executionProviders:["webgpu"]}),console.log("[DepthEstimator] Using WebGPU execution provider")}catch(s){console.warn("[DepthEstimator] WebGPU EP unavailable, falling back to WASM:",s),n.env.wasm.proxy=!0,r=await n.InferenceSession.create(i,{executionProviders:["wasm"]}),console.log("[DepthEstimator] Using WASM execution provider (proxy worker)")}this.session=r,this.inputName=r.inputNames[0],this.outputName=r.outputNames[0],this.readyResolve?.(),this.readyResolve=null}waitUntilReady(){return this.readyPromise}submitFrame(t){this.inferenceInFlight||!this.session||this.disposed||(this.inferenceInFlight=!0,this.runInference(t))}async submitFrameAndWait(t){return!this.session||this.disposed?this.frontBuffer:(await this.runInference(t),this.frontBuffer)}getLatestDepth(){return this.frontBuffer}dispose(){this.disposed=!0,this.session?.release(),this.session=null,this.ort=null,this.captureCanvas=null,this.captureCtx=null}async runInference(t){try{if(!this.session||!this.captureCtx||!this.ort)return;this.captureCtx.drawImage(t,0,0,q,q);const e=this.captureCtx.getImageData(0,0,q,q),n=this.preprocess(e),r=(await this.session.run({[this.inputName]:n}))[this.outputName],s=r.data,a=r.dims,l=a.length===3?a[1]:a[2],u=a.length===3?a[2]:a[3];this.postProcess(s,u,l);const h=this.frontBuffer;this.frontBuffer=this.backBuffer,this.backBuffer=h}catch(e){console.error("[DepthEstimator] Inference failed:",e)}finally{this.inferenceInFlight=!1}}preprocess(t){const{data:e,width:n,height:i}=t,r=n*i,s=new Float32Array(3*r);for(let a=0;a<r;a++){const l=a*4;s[a]=(e[l]/255-yt[0])/St[0],s[r+a]=(e[l+1]/255-yt[1])/St[1],s[2*r+a]=(e[l+2]/255-yt[2])/St[2]}return new this.ort.Tensor("float32",s,[1,3,i,n])}postProcess(t,e,n){const{depthWidth:i,depthHeight:r}=this;let s=1/0,a=-1/0;for(let f=0;f<t.length;f++){const c=t[f];c<s&&(s=c),c>a&&(a=c)}const l=a-s||1,u=e/i,h=n/r;for(let f=0;f<r;f++)for(let c=0;c<i;c++){const E=c*u,v=f*h,p=Math.floor(E),P=Math.floor(v),x=Math.min(p+1,e-1),y=Math.min(P+1,n-1),d=E-p,g=v-P,b=t[P*e+p],T=t[P*e+x],m=t[y*e+p],S=t[y*e+x],F=(b*(1-d)*(1-g)+T*d*(1-g)+m*(1-d)*g+S*d*g-s)/l;this.backBuffer[f*i+c]=F*255+.5|0}}}async function ut(o,t,e,n){const i=new Le(t,e);return await i.init(o,n),i}async function Ue(o,t){const e=await fetch(o);if(!e.ok)throw new Error(`[DepthEstimator] Failed to fetch model (${e.status} ${e.statusText}).`);const n=e.headers.get("content-length"),i=n?Number(n):null,r=e.body;if(!r){const f=await e.arrayBuffer();return t?.({receivedBytes:f.byteLength,totalBytes:f.byteLength,fraction:1,label:"Downloading depth model…"}),f}const s=[];let a=0;const l=r.getReader();for(;;){const{done:f,value:c}=await l.read();if(f)break;c&&(s.push(c),a+=c.byteLength,t?.({receivedBytes:a,totalBytes:i,fraction:i?Math.min(a/i,1):0,label:"Downloading depth model…"}))}const u=new Uint8Array(a);let h=0;for(const f of s)u.set(f,h),h+=f.byteLength;return u.buffer}const Ot={sensitivityX:.4,sensitivityY:1,lerpFactor:.08};function At(o,t){const e=o.points;if(e.length===0)return 0;if(e.length===1||t<=e[0].x)return e[0].y;if(t>=e[e.length-1].x)return e[e.length-1].y;let n=0;for(;n<e.length-1&&e[n+1].x<t;)n++;const i=e[n],r=e[n+1],s=(t-i.x)/(r.x-i.x);switch(o.interpolation){case"step":return i.y;case"linear":return i.y+(r.y-i.y)*s;case"smooth":{const a=s*s*(3-2*s);return i.y+(r.y-i.y)*a}default:return i.y+(r.y-i.y)*s}}function ct(o,t=256){const e=new Uint8Array(t);for(let n=0;n<t;n++){const i=n/(t-1);e[n]=Math.round(At(o,i)*255)}return e}function X(o,t){return o.find(e=>e.channel===t&&e.enabled)}function kt(o,t){const e=X(o,"displacement"),n=X(o,"blur"),i=X(o,"glow"),r=e?.params;let s=.6,a=0;if(n){const l=n.curve;for(let u=0;u<=1;u+=.01)if(At(l,u)>.01){s=u;break}a=At(l,1)}return{parallaxStrength:r?.strength??.05,pomEnabled:r?.pomEnabled??!0,pomSteps:r?.pomSteps??16,contrastLow:t.contrastLow,contrastHigh:t.contrastHigh,verticalReduction:t.verticalReduction,dofStart:s,dofStrength:a,blurRadius:n?.params?.maxRadius??.01,glowColor:i?.params?.color??[1,.95,.85],glowRadius:i?.params?.radius??.02,glowSoftness:i?.params?.softness??.6,tiltEnabled:n?.params?.tiltEnabled??!1,tiltHalfTanFov:Math.tan((n?.params?.tiltFov??50)*Math.PI/360),tiltTransitionWidth:(n?.params?.focalWidth??.3)*4.5,tiltPeakIntensity:n?.params?.peakIntensity??.8}}function Nt(o){const t=X(o,"displacement"),e=X(o,"blur"),n=X(o,"glow"),i=X(o,"color-shift"),r=i?.params;return{displacementLUT:t?ct(t.curve):null,blurLUT:e?ct(e.curve):null,glowLUT:n?ct(n.curve):null,colorShiftLUT:i?ct(i.curve):null,colorShiftParams:r?{hueShift:r.hueShift??0,saturation:r.saturation??1,brightness:r.brightness??1,tintStrength:r.tintStrength??0,tintColor:r.tintColor??[.7,.8,.9]}:null}}class Ht{abortController=null;initialized=!1;initializing=!1;element;constructor(t){this.element=t}onConnected(){this.element.setupShadowDOM(),this.tryInit()}onDisconnected(){this.cancelInit(),this.element.doDispose(),this.initialized=!1}onAttributeChanged(t,e,n){this.element.reinitAttributes.includes(t)&&e!==n&&(this.initialized?(this.cancelInit(),this.element.doDispose(),this.initialized=!1,this.element.setupShadowDOM(),this.tryInit()):this.initializing||this.tryInit())}get isInitialized(){return this.initialized}markInitialized(){this.initialized=!0,this.initializing=!1}async tryInit(){if(this.initializing)return;const t=this.element;if(!t.isConnected)return;if(t.canInit){if(!t.canInit())return}else for(const n of t.reinitAttributes)if(!t.getAttribute(n))return;this.cancelInit();const e=new AbortController;this.abortController=e,this.initializing=!0;try{if(await t.doInit(e.signal),e.signal.aborted){this.initializing=!1;return}}catch{this.initializing=!1}}cancelInit(){this.abortController?.abort(),this.abortController=null,this.initializing=!1}}const G={parallaxX:.4,parallaxY:1,parallaxMax:30,overscan:.05,autoplay:!0,loop:!0,muted:!0},Y=512,j=512;let _e=class Qt{constructor(t,e=.08,n=.06){this.host=t,this.lerpFactor=e,this.motionLerpFactor=n,this.host.addEventListener("mousemove",this.handleMouseMove),this.host.addEventListener("mouseleave",this.resetPointerTarget),this.host.addEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.host.addEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.host.addEventListener("touchend",this.handleTouchEnd,{passive:!0}),this.host.addEventListener("touchcancel",this.handleTouchEnd,{passive:!0})}pointerTarget={x:0,y:0};motionTarget={x:0,y:0};smoothedOutput={x:0,y:0};usingMotionInput=!1;motionListenerAttached=!1;motionRequested=!1;touchActive=!1;touchAnchorX=0;touchAnchorY=0;lerpFactor;motionLerpFactor;static TOUCH_DRAG_RANGE=100;update(){const t=this.touchActive?this.pointerTarget:this.usingMotionInput?this.motionTarget:this.pointerTarget,e=this.usingMotionInput&&!this.touchActive?this.motionLerpFactor:this.lerpFactor;return this.smoothedOutput.x=dt(this.smoothedOutput.x,t.x,e),this.smoothedOutput.y=dt(this.smoothedOutput.y,t.y,e),this.smoothedOutput}dispose(){this.host.removeEventListener("mousemove",this.handleMouseMove),this.host.removeEventListener("mouseleave",this.resetPointerTarget),this.host.removeEventListener("touchstart",this.handleTouchStart),this.host.removeEventListener("touchmove",this.handleTouchMove),this.host.removeEventListener("touchend",this.handleTouchEnd),this.host.removeEventListener("touchcancel",this.handleTouchEnd),this.motionListenerAttached&&(window.removeEventListener("deviceorientation",this.handleDeviceOrientation),this.motionListenerAttached=!1)}handleMouseMove=t=>{const e=this.host.getBoundingClientRect(),n=(t.clientX-e.left)/e.width*2-1,i=(t.clientY-e.top)/e.height*2-1;this.pointerTarget.x=Z(n,-1,1),this.pointerTarget.y=Z(i,-1,1)};resetPointerTarget=()=>{this.pointerTarget.x=0,this.pointerTarget.y=0};handleTouchStart=t=>{const e=t.touches[0];e&&(this.touchActive=!0,this.touchAnchorX=e.clientX,this.touchAnchorY=e.clientY,this.pointerTarget.x=0,this.pointerTarget.y=0,this.motionRequested||(this.motionRequested=!0,this.requestMotionPermission()))};handleTouchMove=t=>{const e=t.touches[0];if(!e)return;const n=e.clientX-this.touchAnchorX,i=e.clientY-this.touchAnchorY,r=Qt.TOUCH_DRAG_RANGE;this.pointerTarget.x=Z(n/r,-1,1),this.pointerTarget.y=Z(i/r,-1,1)};handleTouchEnd=()=>{this.touchActive=!1,this.pointerTarget.x=0,this.pointerTarget.y=0};async requestMotionPermission(){if(typeof DeviceOrientationEvent>"u")return;const t=DeviceOrientationEvent;if(typeof t.requestPermission=="function")try{if(await t.requestPermission()!=="granted")return}catch{return}this.motionListenerAttached||(window.addEventListener("deviceorientation",this.handleDeviceOrientation),this.motionListenerAttached=!0),this.usingMotionInput=!0}handleDeviceOrientation=t=>{const e=Z((t.gamma??0)/45,-1,1),n=Z((t.beta??0)/45,-1,1);this.motionTarget.x=dt(this.motionTarget.x,e,this.motionLerpFactor),this.motionTarget.y=dt(this.motionTarget.y,n,this.motionLerpFactor)}};class ft extends HTMLElement{static TAG_NAME="layershift-effect";static get observedAttributes(){return["src","depth-src","depth-meta","depth-model","source-type","config","parallax-x","parallax-y","parallax-max","layers","overscan","quality","gpu-backend","autoplay","loop","muted"]}reinitAttributes=["src","depth-src","depth-meta","depth-model","source-type","config"];canInit(){if(this.sourceType==="camera")return!0;const t=!!this.getAttribute("src"),e=!!this.getAttribute("depth-src")&&!!this.getAttribute("depth-meta"),n=!!this.getAttribute("depth-model");return t&&(e||n)}shadow;container=null;renderer=null;inputHandler=null;source=null;depthEstimator=null;loopCount=0;lifecycle;depthFallback=null;constructor(){super(),this.shadow=this.attachShadow({mode:"open"}),this.lifecycle=new Ht(this)}getAttrFloat(t,e){const n=this.getAttribute(t);if(n===null)return e;const i=parseFloat(n);return Number.isFinite(i)?i:e}getAttrBool(t,e){if(!this.hasAttribute(t))return e;const n=this.getAttribute(t);return!(n==="false"||n==="0")}get parallaxX(){return this.getAttrFloat("parallax-x",G.parallaxX)}get parallaxY(){return this.getAttrFloat("parallax-y",G.parallaxY)}get parallaxMax(){return this.getAttrFloat("parallax-max",G.parallaxMax)}get overscan(){return this.getAttrFloat("overscan",G.overscan)}get quality(){const t=this.getAttribute("quality");if(t==="auto"||t==="high"||t==="medium"||t==="low")return t}get gpuBackend(){return"webgl2"}get sourceType(){const t=this.getAttribute("source-type");return t==="camera"?"camera":t==="image"?"image":"video"}get depthModel(){return this.getAttribute("depth-model")}get shouldAutoplay(){return this.getAttrBool("autoplay",G.autoplay)}get shouldLoop(){return this.getAttrBool("loop",G.loop)}get shouldMute(){return this.getAttrBool("muted",G.muted)}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}attachSourceEventListeners(t){t.addEventListener&&(t.addEventListener("play",(()=>{this.emit("layershift-effect:play",{currentTime:t.currentTime})})),t.addEventListener("pause",(()=>{this.emit("layershift-effect:pause",{currentTime:t.currentTime})})),t.addEventListener("ended",(()=>{this.loopCount+=1,this.emit("layershift-effect:loop",{loopCount:this.loopCount})})))}connectedCallback(){this.lifecycle.onConnected()}disconnectedCallback(){this.lifecycle.onDisconnected()}attributeChangedCallback(t,e,n){this.lifecycle.onAttributeChanged(t,e,n)}setupShadowDOM(){this.shadow.innerHTML="";const t=document.createElement("style");t.textContent=`
|
|
467
|
+
`,B={contrastLow:.05,contrastHigh:.95,verticalReduction:.5,dofStart:.6,dofStrength:.4,blurRadius:.01,glowColor:[1,.95,.85],glowRadius:.02,glowSoftness:.6,tiltEnabled:!1,tiltHalfTanFov:Math.tan(50*Math.PI/360),tiltTransitionWidth:.3*4.5,tiltPeakIntensity:.8},xe=["uRawDepth","uTexelSize","uSpatialSigma2"],Te={2:2.25,1:.5625};function Ee(o,t){const e=ge.replace("#version 300 es",`#version 300 es
|
|
468
|
+
#define BILATERAL_RADIUS ${t}`),n=Y(o,o.VERTEX_SHADER,pe),i=Y(o,o.FRAGMENT_SHADER,e),r=Tt(o,n,i),s=Et(o,r,xe),a=Te[t]??2.25;let l=null;const c={name:"bilateral-filter",program:r,uniforms:s,fbo:null,outputs:[],width:0,height:0,resize(u,f,h){},initFBO(u,f,h,x){l&&u.deleteFramebuffer(l),c.width=h,c.height=x,l=u.createFramebuffer(),c.fbo=l,u.bindFramebuffer(u.FRAMEBUFFER,l),u.framebufferTexture2D(u.FRAMEBUFFER,u.COLOR_ATTACHMENT0,u.TEXTURE_2D,f,0),u.bindFramebuffer(u.FRAMEBUFFER,null),u.useProgram(r),u.uniform1i(s.uRawDepth,2),u.uniform2f(s.uTexelSize,1/h,1/x),u.uniform1f(s.uSpatialSigma2,a)},execute(u,f,h,x,g,d,y,E){l&&(u.activeTexture(u.TEXTURE2),u.bindTexture(u.TEXTURE_2D,h),u.texSubImage2D(u.TEXTURE_2D,0,0,0,g,d,u.RED,u.UNSIGNED_BYTE,x),u.bindFramebuffer(u.FRAMEBUFFER,l),u.viewport(0,0,g,d),u.useProgram(r),u.bindVertexArray(f),u.drawArrays(u.TRIANGLE_STRIP,0,4),u.bindFramebuffer(u.FRAMEBUFFER,null),u.viewport(0,0,y,E))},dispose(u){l&&(u.deleteFramebuffer(l),l=null,c.fbo=null),u.deleteProgram(r)}};return c}const be=["uImage","uDepth","uOffset","uStrength","uPomEnabled","uPomSteps","uContrastLow","uContrastHigh","uVerticalReduction","uDofStart","uDofStrength","uImageTexelSize","uUvOffset","uUvScale","uDisplacementCurve","uBlurCurve","uCurvesEnabled","uBlurRadius","uFocalBandOffset","uGlowCurve","uGlowEnabled","uGlowColor","uGlowRadius","uGlowSoftness","uColorShiftCurve","uColorShiftEnabled","uColorShiftHue","uColorShiftSaturation","uColorShiftBrightness","uColorShiftTintStrength","uColorShiftTintColor","uTiltEnabled","uTiltHalfTanFov","uTiltTransitionWidth","uTiltPeakIntensity","uTiltPlaneNormal","uTiltPlaneD"],ye=64;function Se(o){const t=ve.replace("#version 300 es",`#version 300 es
|
|
469
|
+
#define MAX_POM_STEPS ${ye}`),e=Y(o,o.VERTEX_SHADER,me),n=Y(o,o.FRAGMENT_SHADER,t),i=Tt(o,e,n),r=Et(o,i,be);return{name:"depth-effect",program:i,uniforms:r,setStaticUniforms(s,a,l,c){s.useProgram(i),s.uniform1i(r.uImage,0),s.uniform1i(r.uDepth,1),s.uniform1f(r.uStrength,a.parallaxStrength),s.uniform1i(r.uPomEnabled,a.pomEnabled?1:0),s.uniform1i(r.uPomSteps,a.pomSteps),s.uniform1f(r.uContrastLow,a.contrastLow),s.uniform1f(r.uContrastHigh,a.contrastHigh),s.uniform1f(r.uVerticalReduction,a.verticalReduction),s.uniform1f(r.uDofStart,a.dofStart),s.uniform1f(r.uDofStrength,a.dofStrength),s.uniform2f(r.uImageTexelSize,1/l,1/c),s.uniform1i(r.uDisplacementCurve,3),s.uniform1i(r.uBlurCurve,4),s.uniform1i(r.uCurvesEnabled,0),s.uniform1f(r.uBlurRadius,a.blurRadius),s.uniform1f(r.uFocalBandOffset,0),s.uniform1i(r.uGlowCurve,5),s.uniform1i(r.uGlowEnabled,0),s.uniform3f(r.uGlowColor,a.glowColor[0],a.glowColor[1],a.glowColor[2]),s.uniform1f(r.uGlowRadius,a.glowRadius),s.uniform1f(r.uGlowSoftness,a.glowSoftness),s.uniform1i(r.uColorShiftCurve,6),s.uniform1i(r.uColorShiftEnabled,0),s.uniform1f(r.uColorShiftHue,0),s.uniform1f(r.uColorShiftSaturation,1),s.uniform1f(r.uColorShiftBrightness,1),s.uniform1f(r.uColorShiftTintStrength,0),s.uniform3f(r.uColorShiftTintColor,.7,.8,.9),s.uniform1i(r.uTiltEnabled,a.tiltEnabled?1:0),s.uniform1f(r.uTiltHalfTanFov,a.tiltHalfTanFov),s.uniform1f(r.uTiltTransitionWidth,a.tiltTransitionWidth),s.uniform1f(r.uTiltPeakIntensity,a.tiltPeakIntensity),s.uniform3f(r.uTiltPlaneNormal,0,0,1),s.uniform1f(r.uTiltPlaneD,2.75)},updateUvTransform(s,a,l){s.useProgram(i),s.uniform2f(r.uUvOffset,a[0],a[1]),s.uniform2f(r.uUvScale,l[0],l[1])},dispose(s){s.deleteProgram(i)}}}class we extends at{gl=null;quadVao=null;bilateralPass=null;effectPass=null;textures=new Lt;videoSlot;filteredDepthSlot;rawDepthSlot;displacementLutSlot;blurLutSlot;glowLutSlot;colorShiftLutSlot;config;constructor(t,e){super(t),this.videoSlot=this.textures.register("video"),this.filteredDepthSlot=this.textures.register("filteredDepth"),this.rawDepthSlot=this.textures.register("rawDepth"),this.displacementLutSlot=this.textures.register("displacementLut"),this.blurLutSlot=this.textures.register("blurLut"),this.glowLutSlot=this.textures.register("glowLut"),this.colorShiftLutSlot=this.textures.register("colorShiftLut"),this.config={parallaxStrength:e.parallaxStrength,pomEnabled:e.pomEnabled,pomSteps:e.pomSteps,overscanPadding:e.overscanPadding,contrastLow:e.contrastLow??B.contrastLow,contrastHigh:e.contrastHigh??B.contrastHigh,verticalReduction:e.verticalReduction??B.verticalReduction,dofStart:e.dofStart??B.dofStart,dofStrength:e.dofStrength??B.dofStrength,blurRadius:e.blurRadius??B.blurRadius,glowColor:e.glowColor??[...B.glowColor],glowRadius:e.glowRadius??B.glowRadius,glowSoftness:e.glowSoftness??B.glowSoftness,tiltEnabled:e.tiltEnabled??B.tiltEnabled,tiltHalfTanFov:e.tiltHalfTanFov??B.tiltHalfTanFov,tiltTransitionWidth:e.tiltTransitionWidth??B.tiltTransitionWidth,tiltPeakIntensity:e.tiltPeakIntensity??B.tiltPeakIntensity};const n=this.canvas.getContext("webgl2",{antialias:!1,alpha:!1,desynchronized:!0,powerPreference:"high-performance"});if(!n)throw new Error("WebGL 2 is not supported.");this.gl=n,this.qualityParams=_t(n,e.quality),"drawingBufferColorSpace"in n&&(n.drawingBufferColorSpace="srgb"),n.clearColor(0,0,0,1),n.pixelStorei(n.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.setupResizeHandling()}initialize(t,e,n){const i=this.gl;i&&(this.disposeTextures(),this.isCameraSource=t.type==="camera",this.videoAspect=t.width/t.height,this.clampDepthDimensions(e,n,this.qualityParams.depthMaxDim),this.videoSlot.texture=i.createTexture(),i.activeTexture(i.TEXTURE0+this.videoSlot.unit),i.bindTexture(i.TEXTURE_2D,this.videoSlot.texture),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),this.rawDepthSlot.texture=i.createTexture(),i.activeTexture(i.TEXTURE0+this.rawDepthSlot.unit),i.bindTexture(i.TEXTURE_2D,this.rawDepthSlot.texture),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),i.texStorage2D(i.TEXTURE_2D,1,i.R8,e,n),this.filteredDepthSlot.texture=i.createTexture(),i.activeTexture(i.TEXTURE0+this.filteredDepthSlot.unit),i.bindTexture(i.TEXTURE_2D,this.filteredDepthSlot.texture),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),i.texStorage2D(i.TEXTURE_2D,1,i.R8,e,n),this.bilateralPass&&this.filteredDepthSlot.texture&&this.bilateralPass.initFBO(i,this.filteredDepthSlot.texture,e,n),this.effectPass&&this.effectPass.setStaticUniforms(i,this.config,t.width,t.height),this.recalculateViewportLayout())}updateConfig(t){const e=this.gl;if(!e||!this.effectPass)return;t.parallaxStrength!==void 0&&(this.config.parallaxStrength=t.parallaxStrength),t.pomEnabled!==void 0&&(this.config.pomEnabled=t.pomEnabled),t.pomSteps!==void 0&&(this.config.pomSteps=t.pomSteps),t.overscanPadding!==void 0&&(this.config.overscanPadding=t.overscanPadding),t.contrastLow!==void 0&&(this.config.contrastLow=t.contrastLow),t.contrastHigh!==void 0&&(this.config.contrastHigh=t.contrastHigh),t.verticalReduction!==void 0&&(this.config.verticalReduction=t.verticalReduction),t.dofStart!==void 0&&(this.config.dofStart=t.dofStart),t.dofStrength!==void 0&&(this.config.dofStrength=t.dofStrength),t.blurRadius!==void 0&&(this.config.blurRadius=t.blurRadius),t.glowColor!==void 0&&(this.config.glowColor=t.glowColor),t.glowRadius!==void 0&&(this.config.glowRadius=t.glowRadius),t.glowSoftness!==void 0&&(this.config.glowSoftness=t.glowSoftness),t.tiltEnabled!==void 0&&(this.config.tiltEnabled=t.tiltEnabled),t.tiltHalfTanFov!==void 0&&(this.config.tiltHalfTanFov=t.tiltHalfTanFov),t.tiltTransitionWidth!==void 0&&(this.config.tiltTransitionWidth=t.tiltTransitionWidth),t.tiltPeakIntensity!==void 0&&(this.config.tiltPeakIntensity=t.tiltPeakIntensity);const{uniforms:n,program:i}=this.effectPass;e.useProgram(i),e.uniform1f(n.uStrength,this.config.parallaxStrength),e.uniform1i(n.uPomEnabled,this.config.pomEnabled?1:0),e.uniform1i(n.uPomSteps,this.config.pomSteps),e.uniform1f(n.uContrastLow,this.config.contrastLow),e.uniform1f(n.uContrastHigh,this.config.contrastHigh),e.uniform1f(n.uVerticalReduction,this.config.verticalReduction),e.uniform1f(n.uDofStart,this.config.dofStart),e.uniform1f(n.uDofStrength,this.config.dofStrength),e.uniform1f(n.uBlurRadius,this.config.blurRadius),e.uniform3f(n.uGlowColor,this.config.glowColor[0],this.config.glowColor[1],this.config.glowColor[2]),e.uniform1f(n.uGlowRadius,this.config.glowRadius),e.uniform1f(n.uGlowSoftness,this.config.glowSoftness),e.uniform1i(n.uTiltEnabled,this.config.tiltEnabled?1:0),e.uniform1f(n.uTiltHalfTanFov,this.config.tiltHalfTanFov),e.uniform1f(n.uTiltTransitionWidth,this.config.tiltTransitionWidth),e.uniform1f(n.uTiltPeakIntensity,this.config.tiltPeakIntensity),(t.parallaxStrength!==void 0||t.overscanPadding!==void 0)&&this.recalculateViewportLayout()}updateCurveLUTs(t,e,n,i,r){const s=this.gl;if(!s||!this.effectPass)return;const a=!!(t||e),l=!!n,c=!!i;if(t&&this.uploadLUT(this.displacementLutSlot,t),e&&this.uploadLUT(this.blurLutSlot,e),n&&this.uploadLUT(this.glowLutSlot,n),i&&this.uploadLUT(this.colorShiftLutSlot,i),s.useProgram(this.effectPass.program),s.uniform1i(this.effectPass.uniforms.uCurvesEnabled,a?1:0),s.uniform1i(this.effectPass.uniforms.uGlowEnabled,l?1:0),s.uniform1i(this.effectPass.uniforms.uColorShiftEnabled,c?1:0),c&&r){const u=this.effectPass.uniforms;s.uniform1f(u.uColorShiftHue,r.hueShift*(Math.PI/180)),s.uniform1f(u.uColorShiftSaturation,r.saturation),s.uniform1f(u.uColorShiftBrightness,r.brightness),s.uniform1f(u.uColorShiftTintStrength,r.tintStrength),s.uniform3f(u.uColorShiftTintColor,r.tintColor[0],r.tintColor[1],r.tintColor[2])}}initGPUResources(){const t=this.gl;t&&(this.bilateralPass=Ee(t,this.qualityParams.bilateralRadius),this.effectPass=Se(t),this.quadVao=Ut(t,this.effectPass.program),t.disable(t.DEPTH_TEST))}uploadLUT(t,e){const n=this.gl;n&&(n.activeTexture(n.TEXTURE0+t.unit),t.texture?n.bindTexture(n.TEXTURE_2D,t.texture):(t.texture=n.createTexture(),n.bindTexture(n.TEXTURE_2D,t.texture),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.texStorage2D(n.TEXTURE_2D,1,n.R8,256,1)),n.texSubImage2D(n.TEXTURE_2D,0,0,0,256,1,n.RED,n.UNSIGNED_BYTE,e))}onRenderFrame(){const t=this.gl,e=this.mediaSource;if(!t||!this.effectPass||!this.quadVao)return;const n=e?.getImageSource();if(n){if(!this.rvfcSupported&&e.isLive&&this.onDepthUpdate(e.currentTime),t.useProgram(this.effectPass.program),t.activeTexture(t.TEXTURE0+this.videoSlot.unit),t.bindTexture(t.TEXTURE_2D,this.videoSlot.texture),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,n),this.readInput){const i=this.readInput();t.uniform2f(this.effectPass.uniforms.uOffset,-i.x,i.y),i.focalBandOffset!==void 0&&t.uniform1f(this.effectPass.uniforms.uFocalBandOffset,i.focalBandOffset),i.tiltPlaneNormal!==void 0&&t.uniform3f(this.effectPass.uniforms.uTiltPlaneNormal,i.tiltPlaneNormal[0],i.tiltPlaneNormal[1],i.tiltPlaneNormal[2]),i.tiltPlaneD!==void 0&&t.uniform1f(this.effectPass.uniforms.uTiltPlaneD,i.tiltPlaneD)}t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4)}}onDepthUpdate(t){const e=this.gl;if(!e||!this.readDepth||!this.rawDepthSlot.texture||!this.bilateralPass)return;const n=this.subsampleDepth(this.readDepth(t));this.bilateralPass.execute(e,this.quadVao,this.rawDepthSlot.texture,n,this.depthWidth,this.depthHeight,this.canvas.width,this.canvas.height)}recalculateViewportLayout(){const t=this.gl;if(!t)return;const{width:e,height:n}=this.getViewportSize(),i=Math.min(window.devicePixelRatio,this.qualityParams.dprCap),r=Math.round(e*i),s=Math.round(n*i);(this.canvas.width!==r||this.canvas.height!==s)&&(this.canvas.width=r,this.canvas.height=s,t.viewport(0,0,r,s)),this.computeCoverFitUV(this.config.parallaxStrength,this.config.overscanPadding),this.effectPass&&this.effectPass.updateUvTransform(t,this.uvOffset,this.uvScale)}disposeRenderer(){this.disposeTextures(),this.disposeGPUResources(),this.gl&&(this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null)}onContextRestored(){const t=this.canvas.getContext("webgl2");t&&(this.gl=t,t.clearColor(0,0,0,1),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.mediaSource&&this.depthWidth>0&&this.initialize(this.mediaSource,this.depthWidth,this.depthHeight),this.mediaSource&&(this.animationFrameHandle=window.requestAnimationFrame(()=>this.onRenderFrame())))}disposeTextures(){const t=this.gl;t&&this.textures.disposeAll(t)}disposeGPUResources(){const t=this.gl;t&&(this.bilateralPass&&(this.bilateralPass.dispose(t),this.bilateralPass=null),this.effectPass&&(this.effectPass.dispose(t),this.effectPass=null),this.quadVao&&(t.deleteVertexArray(this.quadVao),this.quadVao=null))}}async function lt(o,t={}){const{parent:e=document.body,loop:n=!0,muted:i=!0}=t,r=document.createElement("video");return r.crossOrigin="anonymous",r.setAttribute("crossorigin","anonymous"),r.playsInline=!0,r.setAttribute("playsinline",""),r.setAttribute("webkit-playsinline","true"),r.muted=i,r.defaultMuted=i,i&&r.setAttribute("muted",""),r.loop=n,r.preload="auto",r.style.display="none",r.src=o,e.appendChild(r),await It(r),new Ae(r)}class Ae{constructor(t){this.video=t}type="video";isLive=!0;get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}get currentTime(){return this.video.currentTime}get duration(){return this.video.duration}get paused(){return this.video.paused}getImageSource(){return this.video.readyState<HTMLMediaElement.HAVE_CURRENT_DATA?null:this.video}requestVideoFrameCallback(t){return this.video.requestVideoFrameCallback(t)}cancelVideoFrameCallback(t){this.video.cancelVideoFrameCallback(t)}play(){return this.video.play()}pause(){this.video.pause()}addEventListener(t,e){this.video.addEventListener(t,e)}removeEventListener(t,e){this.video.removeEventListener(t,e)}dispose(){this.video.pause(),this.video.removeAttribute("src"),this.video.load(),this.video.remove()}}async function ut(o,t={}){const e=new Image;return e.crossOrigin="anonymous",e.src=o,await new Promise((n,i)=>{if(e.complete&&e.naturalWidth>0){n();return}e.addEventListener("load",()=>n(),{once:!0}),e.addEventListener("error",()=>i(new Error(`Failed to load image: ${o}`)),{once:!0})}),new Re(e)}class Re{constructor(t){this.img=t}type="image";isLive=!1;currentTime=0;duration=0;paused=!1;get width(){return this.img.naturalWidth}get height(){return this.img.naturalHeight}getImageSource(){return this.img}dispose(){this.img.removeAttribute("src")}}async function Mt(o={video:!0},t={}){const{parent:e=document.body}=t,n=await navigator.mediaDevices.getUserMedia(o),i=document.createElement("video");return i.playsInline=!0,i.setAttribute("playsinline",""),i.muted=!0,i.defaultMuted=!0,i.style.display="none",i.srcObject=n,e.appendChild(i),await It(i),await i.play(),new De(i,n)}class De{constructor(t,e){this.video=t,this.stream=e}type="camera";isLive=!0;duration=1/0;get width(){return this.video.videoWidth}get height(){return this.video.videoHeight}get currentTime(){return this.video.currentTime}get paused(){return this.video.paused}getImageSource(){return this.video.readyState<HTMLMediaElement.HAVE_CURRENT_DATA?null:this.video}requestVideoFrameCallback(t){return this.video.requestVideoFrameCallback(t)}cancelVideoFrameCallback(t){this.video.cancelVideoFrameCallback(t)}play(){return this.video.play()}pause(){this.video.pause()}addEventListener(t,e){this.video.addEventListener(t,e)}removeEventListener(t,e){this.video.removeEventListener(t,e)}dispose(){this.video.pause(),this.video.srcObject=null,this.video.remove();for(const t of this.stream.getTracks())t.stop()}}async function It(o){o.readyState>=HTMLMediaElement.HAVE_METADATA||await new Promise((t,e)=>{const n=()=>{r(),t()},i=()=>{r(),e(new Error("Failed to load video metadata."))},r=()=>{o.removeEventListener("loadedmetadata",n),o.removeEventListener("error",i)};o.addEventListener("loadedmetadata",n),o.addEventListener("error",i),o.load()})}const bt=[.485,.456,.406],yt=[.229,.224,.225],j=518;async function Pe(){return await import("onnxruntime-web/webgpu")}class Fe{constructor(t,e){this.depthWidth=t,this.depthHeight=e;const n=t*e;this.frontBuffer=new Uint8Array(n),this.frontBuffer.fill(128),this.backBuffer=new Uint8Array(n),this.backBuffer.fill(128),this.readyPromise=new Promise(i=>{this.readyResolve=i})}ort=null;session=null;inputName="";outputName="";frontBuffer;backBuffer;inferenceInFlight=!1;readyResolve=null;readyPromise;captureCanvas=null;captureCtx=null;disposed=!1;async init(t,e){const n=await Pe();if(this.ort=n,this.captureCanvas=document.createElement("canvas"),this.captureCanvas.width=j,this.captureCanvas.height=j,this.captureCtx=this.captureCanvas.getContext("2d",{willReadFrequently:!0}),!this.captureCtx)throw new Error("[DepthEstimator] Failed to create 2D canvas context.");e?.({receivedBytes:0,totalBytes:null,fraction:0,label:"Downloading depth model…"});const i=await Ce(t,e);e?.({receivedBytes:i.byteLength,totalBytes:i.byteLength,fraction:1,label:"Initialising depth model…"});let r;try{r=await n.InferenceSession.create(i,{executionProviders:["webgpu"]}),console.log("[DepthEstimator] Using WebGPU execution provider")}catch(s){console.warn("[DepthEstimator] WebGPU EP unavailable, falling back to WASM:",s),n.env.wasm.proxy=!0,r=await n.InferenceSession.create(i,{executionProviders:["wasm"]}),console.log("[DepthEstimator] Using WASM execution provider (proxy worker)")}this.session=r,this.inputName=r.inputNames[0],this.outputName=r.outputNames[0],this.readyResolve?.(),this.readyResolve=null}waitUntilReady(){return this.readyPromise}submitFrame(t){this.inferenceInFlight||!this.session||this.disposed||(this.inferenceInFlight=!0,this.runInference(t))}async submitFrameAndWait(t){return!this.session||this.disposed?this.frontBuffer:(await this.runInference(t),this.frontBuffer)}getLatestDepth(){return this.frontBuffer}dispose(){this.disposed=!0,this.session?.release(),this.session=null,this.ort=null,this.captureCanvas=null,this.captureCtx=null}async runInference(t){try{if(!this.session||!this.captureCtx||!this.ort)return;this.captureCtx.drawImage(t,0,0,j,j);const e=this.captureCtx.getImageData(0,0,j,j),n=this.preprocess(e),r=(await this.session.run({[this.inputName]:n}))[this.outputName],s=r.data,a=r.dims,l=a.length===3?a[1]:a[2],c=a.length===3?a[2]:a[3];this.postProcess(s,c,l);const u=this.frontBuffer;this.frontBuffer=this.backBuffer,this.backBuffer=u}catch(e){console.error("[DepthEstimator] Inference failed:",e)}finally{this.inferenceInFlight=!1}}preprocess(t){const{data:e,width:n,height:i}=t,r=n*i,s=new Float32Array(3*r);for(let a=0;a<r;a++){const l=a*4;s[a]=(e[l]/255-bt[0])/yt[0],s[r+a]=(e[l+1]/255-bt[1])/yt[1],s[2*r+a]=(e[l+2]/255-bt[2])/yt[2]}return new this.ort.Tensor("float32",s,[1,3,i,n])}postProcess(t,e,n){const{depthWidth:i,depthHeight:r}=this;let s=1/0,a=-1/0;for(let f=0;f<t.length;f++){const h=t[f];h<s&&(s=h),h>a&&(a=h)}const l=a-s||1,c=e/i,u=n/r;for(let f=0;f<r;f++)for(let h=0;h<i;h++){const x=h*c,g=f*u,d=Math.floor(x),y=Math.floor(g),E=Math.min(d+1,e-1),b=Math.min(y+1,n-1),p=x-d,v=g-y,m=t[y*e+d],T=t[y*e+E],w=t[b*e+d],A=t[b*e+E],P=(m*(1-p)*(1-v)+T*p*(1-v)+w*(1-p)*v+A*p*v-s)/l;this.backBuffer[f*i+h]=P*255+.5|0}}}async function ct(o,t,e,n){const i=new Fe(t,e);return await i.init(o,n),i}async function Ce(o,t){const e=await fetch(o);if(!e.ok)throw new Error(`[DepthEstimator] Failed to fetch model (${e.status} ${e.statusText}).`);const n=e.headers.get("content-length"),i=n?Number(n):null,r=e.body;if(!r){const f=await e.arrayBuffer();return t?.({receivedBytes:f.byteLength,totalBytes:f.byteLength,fraction:1,label:"Downloading depth model…"}),f}const s=[];let a=0;const l=r.getReader();for(;;){const{done:f,value:h}=await l.read();if(f)break;h&&(s.push(h),a+=h.byteLength,t?.({receivedBytes:a,totalBytes:i,fraction:i?Math.min(a/i,1):0,label:"Downloading depth model…"}))}const c=new Uint8Array(a);let u=0;for(const f of s)c.set(f,u),u+=f.byteLength;return c.buffer}const Bt={sensitivityX:.4,sensitivityY:1,lerpFactor:.08};function St(o,t){const e=o.points;if(e.length===0)return 0;if(e.length===1||t<=e[0].x)return e[0].y;if(t>=e[e.length-1].x)return e[e.length-1].y;let n=0;for(;n<e.length-1&&e[n+1].x<t;)n++;const i=e[n],r=e[n+1],s=(t-i.x)/(r.x-i.x);switch(o.interpolation){case"step":return i.y;case"linear":return i.y+(r.y-i.y)*s;case"smooth":{const a=s*s*(3-2*s);return i.y+(r.y-i.y)*a}default:return i.y+(r.y-i.y)*s}}function ht(o,t=256){const e=new Uint8Array(t);for(let n=0;n<t;n++){const i=n/(t-1);e[n]=Math.round(St(o,i)*255)}return e}function W(o,t){return o.find(e=>e.channel===t&&e.enabled)}function Vt(o,t){const e=W(o,"displacement"),n=W(o,"blur"),i=W(o,"glow"),r=e?.params;let s=.6,a=0;if(n){const l=n.curve;for(let c=0;c<=1;c+=.01)if(St(l,c)>.01){s=c;break}a=St(l,1)}return{parallaxStrength:r?.strength??.05,pomEnabled:r?.pomEnabled??!0,pomSteps:r?.pomSteps??16,contrastLow:t.contrastLow,contrastHigh:t.contrastHigh,verticalReduction:t.verticalReduction,dofStart:s,dofStrength:a,blurRadius:n?.params?.maxRadius??.01,glowColor:i?.params?.color??[1,.95,.85],glowRadius:i?.params?.radius??.02,glowSoftness:i?.params?.softness??.6,tiltEnabled:n?.params?.tiltEnabled??!1,tiltHalfTanFov:Math.tan((n?.params?.tiltFov??50)*Math.PI/360),tiltTransitionWidth:(n?.params?.focalWidth??.3)*4.5,tiltPeakIntensity:n?.params?.peakIntensity??.8}}function Ot(o){const t=W(o,"displacement"),e=W(o,"blur"),n=W(o,"glow"),i=W(o,"color-shift"),r=i?.params;return{displacementLUT:t?ht(t.curve):null,blurLUT:e?ht(e.curve):null,glowLUT:n?ht(n.curve):null,colorShiftLUT:i?ht(i.curve):null,colorShiftParams:r?{hueShift:r.hueShift??0,saturation:r.saturation??1,brightness:r.brightness??1,tintStrength:r.tintStrength??0,tintColor:r.tintColor??[.7,.8,.9]}:null}}class kt{abortController=null;initialized=!1;initializing=!1;element;constructor(t){this.element=t}onConnected(){this.element.setupShadowDOM(),this.tryInit()}onDisconnected(){this.cancelInit(),this.element.doDispose(),this.initialized=!1}onAttributeChanged(t,e,n){this.element.reinitAttributes.includes(t)&&e!==n&&(this.initialized?(this.cancelInit(),this.element.doDispose(),this.initialized=!1,this.element.setupShadowDOM(),this.tryInit()):this.initializing||this.tryInit())}get isInitialized(){return this.initialized}markInitialized(){this.initialized=!0,this.initializing=!1}async tryInit(){if(this.initializing)return;const t=this.element;if(!t.isConnected)return;if(t.canInit){if(!t.canInit())return}else for(const n of t.reinitAttributes)if(!t.getAttribute(n))return;this.cancelInit();const e=new AbortController;this.abortController=e,this.initializing=!0;try{if(await t.doInit(e.signal),e.signal.aborted){this.initializing=!1;return}}catch{this.initializing=!1}}cancelInit(){this.abortController?.abort(),this.abortController=null,this.initializing=!1}}const z={parallaxX:.4,parallaxY:1,parallaxMax:30,overscan:.05,autoplay:!0,loop:!0,muted:!0},Z=512,$=512;class ft extends HTMLElement{static TAG_NAME="layershift-effect";static get observedAttributes(){return["src","depth-src","depth-meta","depth-model","source-type","config","parallax-x","parallax-y","parallax-max","layers","overscan","quality","gpu-backend","autoplay","loop","muted"]}reinitAttributes=["src","depth-src","depth-meta","depth-model","source-type","config"];canInit(){if(this.sourceType==="camera")return!0;const t=!!this.getAttribute("src"),e=!!this.getAttribute("depth-src")&&!!this.getAttribute("depth-meta"),n=!!this.getAttribute("depth-model");return t&&(e||n)}shadow;container=null;renderer=null;_input={x:0,y:0};source=null;depthEstimator=null;loopCount=0;lifecycle;depthFallback=null;constructor(){super(),this.shadow=this.attachShadow({mode:"open"}),this.lifecycle=new kt(this)}get input(){return{x:this._input.x,y:this._input.y}}set input(t){this._input.x=t.x,this._input.y=t.y}getAttrFloat(t,e){const n=this.getAttribute(t);if(n===null)return e;const i=parseFloat(n);return Number.isFinite(i)?i:e}getAttrBool(t,e){if(!this.hasAttribute(t))return e;const n=this.getAttribute(t);return!(n==="false"||n==="0")}get parallaxX(){return this.getAttrFloat("parallax-x",z.parallaxX)}get parallaxY(){return this.getAttrFloat("parallax-y",z.parallaxY)}get parallaxMax(){return this.getAttrFloat("parallax-max",z.parallaxMax)}get overscan(){return this.getAttrFloat("overscan",z.overscan)}get quality(){const t=this.getAttribute("quality");if(t==="auto"||t==="high"||t==="medium"||t==="low")return t}get gpuBackend(){return"webgl2"}get sourceType(){const t=this.getAttribute("source-type");return t==="camera"?"camera":t==="image"?"image":"video"}get depthModel(){return this.getAttribute("depth-model")}get shouldAutoplay(){return this.getAttrBool("autoplay",z.autoplay)}get shouldLoop(){return this.getAttrBool("loop",z.loop)}get shouldMute(){return this.getAttrBool("muted",z.muted)}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}attachSourceEventListeners(t){t.addEventListener&&(t.addEventListener("play",(()=>{this.emit("layershift-effect:play",{currentTime:t.currentTime})})),t.addEventListener("pause",(()=>{this.emit("layershift-effect:pause",{currentTime:t.currentTime})})),t.addEventListener("ended",(()=>{this.loopCount+=1,this.emit("layershift-effect:loop",{loopCount:this.loopCount})})))}connectedCallback(){this.lifecycle.onConnected()}disconnectedCallback(){this.lifecycle.onDisconnected()}attributeChangedCallback(t,e,n){this.lifecycle.onAttributeChanged(t,e,n)}setupShadowDOM(){this.shadow.innerHTML="";const t=document.createElement("style");t.textContent=`
|
|
470
470
|
:host {
|
|
471
471
|
display: block;
|
|
472
472
|
width: 100%;
|
|
@@ -486,34 +486,34 @@ void main() {
|
|
|
486
486
|
width: 100%;
|
|
487
487
|
height: 100%;
|
|
488
488
|
}
|
|
489
|
-
`,this.shadow.appendChild(t),this.container=document.createElement("div"),this.container.className="container",this.shadow.appendChild(this.container)}async fetchFilterConfig(t){const e=this.getAttribute("config");if(!e)return null;try{const n=await fetch(e,{signal:t});if(!n.ok)return console.warn(`<layershift-effect>: Failed to fetch config from "${e}" (${n.status})`),null;const i=await n.json();return{channels:i.channels??[],motion:i.motion??
|
|
489
|
+
`,this.shadow.appendChild(t),this.container=document.createElement("div"),this.container.className="container",this.shadow.appendChild(this.container)}async fetchFilterConfig(t){const e=this.getAttribute("config");if(!e)return null;try{const n=await fetch(e,{signal:t});if(!n.ok)return console.warn(`<layershift-effect>: Failed to fetch config from "${e}" (${n.status})`),null;const i=await n.json();return{channels:i.channels??[],motion:i.motion??Bt,overscanPadding:i.overscanPadding??.05,quality:i.quality??"auto"}}catch(n){return n.name==="AbortError"||console.warn("<layershift-effect>: Failed to parse config.",n),null}}buildLegacyConfig(t,e){const n=this.container?.clientWidth||e,i=this.hasAttribute("parallax-max")?this.parallaxMax/Math.max(n,1):t.parallaxStrength,r=this.hasAttribute("overscan")?this.overscan:t.overscanPadding;return{parallaxStrength:i,pomEnabled:!0,pomSteps:t.pomSteps,overscanPadding:r,quality:this.quality,contrastLow:t.contrastLow,contrastHigh:t.contrastHigh,verticalReduction:t.verticalReduction,dofStart:t.dofStart,dofStrength:t.dofStrength}}async doInit(t){if(!this.container)return;const e=this.sourceType==="camera",n=this.depthModel;try{let i,r,s=null;const a=m=>{this.emit("layershift-effect:model-progress",m)};if(e){if(i=await Mt({video:{facingMode:"user"}},{parent:this.shadow}),t.aborted){i.dispose();return}if(n){if(s=await ct(n,Z,$,a),t.aborted){s.dispose(),i.dispose();return}r=H(Z,$)}else r=H(i.width,i.height)}else{const m=this.getAttribute("src"),T=this.getAttribute("depth-src"),w=this.getAttribute("depth-meta"),A=!!T&&!!w,D=this.sourceType==="image"||/\.(jpe?g|png|webp|gif|avif|bmp)(\?|$)/i.test(m);if(A){const[P,_]=await Promise.all([D?ut(m):lt(m,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),Ft(T,w)]);if(t.aborted){P.dispose();return}i=P,r=_}else if(n){const[P,_]=await Promise.all([D?ut(m):lt(m,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),ct(n,Z,$,a)]);if(t.aborted){P.dispose(),_.dispose();return}if(i=P,s=_,D||!i.isLive){const M=i.getImageSource();if(M){const C=await s.submitFrameAndWait(M);r={meta:{frameCount:1,fps:1,width:Z,height:$,sourceFps:1},frames:[C]}}else r=H(Z,$)}else r=H(Z,$)}else throw new Error("Either depth-src/depth-meta or depth-model must be provided.")}this.source=i,this.depthEstimator=s,this.loopCount=0,this.attachSourceEventListeners(i);const l=re(r.frames,r.meta.width,r.meta.height),c=oe(l);this.depthFallback={contrastLow:c.contrastLow,contrastHigh:c.contrastHigh,verticalReduction:c.verticalReduction};let u;if(s)u=()=>s.getLatestDepth();else{const m=new Pt(r);u=T=>m.sample(T)}if(t.aborted)return;let f,h=null,x=Bt;const g=await this.fetchFilterConfig(t);if(t.aborted)return;if(g&&g.channels.length>0){const m=Vt(g.channels,{contrastLow:c.contrastLow,contrastHigh:c.contrastHigh,verticalReduction:c.verticalReduction});f={parallaxStrength:m.parallaxStrength,pomEnabled:m.pomEnabled,pomSteps:m.pomSteps,overscanPadding:g.overscanPadding,quality:g.quality,contrastLow:m.contrastLow,contrastHigh:m.contrastHigh,verticalReduction:m.verticalReduction,dofStart:m.dofStart,dofStrength:m.dofStrength,blurRadius:m.blurRadius,glowColor:m.glowColor,glowRadius:m.glowRadius,glowSoftness:m.glowSoftness,tiltEnabled:m.tiltEnabled,tiltHalfTanFov:m.tiltHalfTanFov,tiltTransitionWidth:m.tiltTransitionWidth,tiltPeakIntensity:m.tiltPeakIntensity},h=Ot(g.channels),x=g.motion}else f=this.buildLegacyConfig(c,i.width);this.renderer=new we(this.container,f),this.renderer.initialize(i,r.meta.width,r.meta.height),h&&this.renderer.updateCurveLUTs(h.displacementLUT,h.blurLUT,h.glowLUT,h.colorShiftLUT,h.colorShiftParams??void 0);const d=x.tiltPlaneInput??!1,y=x.tiltPitchSensitivity??.35,E=x.tiltYawSensitivity??.15,p=g?.channels.find(m=>m.channel==="blur"&&m.enabled)?.params?.focalCenter??.5,v=s;if(this.renderer.start(i,u,()=>{const m=this._input;if(d){const A=m.y*y,D=m.x*E,P=Math.cos(A),_=Math.sin(A),M=Math.cos(D),S=Math.sin(D)*P,F=-_,U=M*P,I=.5+p*(5-.5);return{x:m.x*.3,y:m.y*.3,tiltPlaneNormal:[S,F,U],tiltPlaneD:U*I}}return{x:m.x,y:m.y}},(m,T)=>{if(v){const w=i.getImageSource();w&&v.submitFrame(w)}this.emit("layershift-effect:frame",{currentTime:m,frameNumber:T})}),!e&&i.isLive&&this.shouldAutoplay&&i.play)try{await i.play()}catch{}if(t.aborted)return;this.lifecycle.markInitialized(),this.emit("layershift-effect:ready",{videoWidth:i.width,videoHeight:i.height,duration:i.duration,depthProfile:l,derivedParams:c,motionConfig:x})}catch(i){const r=i instanceof Error?i.message:"Failed to initialize.";console.error("<layershift-effect>: Failed to initialize.",i),this.emit("layershift-effect:error",{message:r})}}updateConfig(t){if(!this.renderer)return;const e=this.depthFallback??{contrastLow:.05,contrastHigh:.95,verticalReduction:.5},n=Vt(t,e);this.renderer.updateConfig(n);const i=Ot(t);this.renderer.updateCurveLUTs(i.displacementLUT,i.blurLUT,i.glowLUT,i.colorShiftLUT,i.colorShiftParams??void 0)}doDispose(){this.renderer?.dispose(),this.renderer=null,this.depthEstimator?.dispose(),this.depthEstimator=null,this.source?.dispose(),this.source=null,this.depthFallback=null,this.loopCount=0,this.container=null}}class wt{gl;hasColorBufferFloat;maskFbo=null;maskTex=null;pingFbo=null;pingTex=null;pongFbo=null;pongTex=null;distFbo=null;distTex=null;_width=0;_height=0;_dirty=!0;constructor(t,e){this.gl=t,this.hasColorBufferFloat=e}get width(){return this._width}get height(){return this._height}get isDirty(){return this._dirty}get distanceTexture(){return this.distTex}get maskTexture(){return this.maskTex}markDirty(){this._dirty=!0}createResources(t,e,n){const i=this.gl;this.dispose();const r=Math.max(1,Math.round(t/n)),s=Math.max(1,Math.round(e/n));this._width=r,this._height=s;const a=(c,u,f,h)=>{const x=i.createFramebuffer();return i.bindFramebuffer(i.FRAMEBUFFER,x),i.bindTexture(i.TEXTURE_2D,c),i.texStorage2D(i.TEXTURE_2D,1,u,f,h),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MAG_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE),i.framebufferTexture2D(i.FRAMEBUFFER,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,c,0),i.bindFramebuffer(i.FRAMEBUFFER,null),x};this.maskTex=i.createTexture(),this.maskFbo=a(this.maskTex,i.R8,r,s);const l=this.hasColorBufferFloat?i.RG16F:i.RGBA8;this.pingTex=i.createTexture(),this.pingFbo=a(this.pingTex,l,r,s),this.pongTex=i.createTexture(),this.pongFbo=a(this.pongTex,l,r,s),this.distTex=i.createTexture(),this.distFbo=a(this.distTex,i.RGBA8,r,s),this._dirty=!0}compute(t){const e=this.gl;if(!this.maskFbo||!this.pingFbo||!this.pongFbo||!this.distFbo)return;const n=this._width,i=this._height;if(n===0||i===0)return;e.viewport(0,0,n,i),e.disable(e.STENCIL_TEST),e.disable(e.BLEND),e.bindFramebuffer(e.FRAMEBUFFER,this.maskFbo),e.clearColor(0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),e.useProgram(t.maskPass.program),e.uniform2f(t.maskPass.uniforms.uMeshScale,t.meshScaleX,t.meshScaleY),e.bindVertexArray(t.maskVao),e.drawElements(e.TRIANGLES,t.stencilIndexCount,e.UNSIGNED_SHORT,0),e.bindFramebuffer(e.FRAMEBUFFER,this.pingFbo),e.clearColor(-1,-1,0,0),e.clear(e.COLOR_BUFFER_BIT),e.useProgram(t.seedPass.program),e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,this.maskTex),e.uniform1i(t.seedPass.uniforms.uMask,5),e.uniform2f(t.seedPass.uniforms.uTexelSize,1/n,1/i),e.bindVertexArray(t.quadVao),e.drawArrays(e.TRIANGLE_STRIP,0,4);const r=wt.computeFloodIterations(n,i);e.useProgram(t.floodPass.program);let s=this.pingTex,a=this.pongFbo,l=this.pongTex;for(let c=0;c<r.length;c++){const u=r[c]/Math.max(n,i);e.bindFramebuffer(e.FRAMEBUFFER,a),e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,s),e.uniform1i(t.floodPass.uniforms.uSeedTex,5),e.uniform1f(t.floodPass.uniforms.uStepSize,u),e.bindVertexArray(t.quadVao),e.drawArrays(e.TRIANGLE_STRIP,0,4);const f=s,h=a;s=l,a=h===this.pongFbo?this.pingFbo:this.pongFbo,l=f}e.bindFramebuffer(e.FRAMEBUFFER,this.distFbo),e.clearColor(0,0,0,1),e.clear(e.COLOR_BUFFER_BIT),e.useProgram(t.distPass.program),e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,s),e.uniform1i(t.distPass.uniforms.uSeedTex,5),e.activeTexture(e.TEXTURE6),e.bindTexture(e.TEXTURE_2D,this.maskTex),e.uniform1i(t.distPass.uniforms.uMask,6),e.uniform1f(t.distPass.uniforms.uBevelWidth,t.distRange),e.bindVertexArray(t.quadVao),e.drawArrays(e.TRIANGLE_STRIP,0,4),e.activeTexture(e.TEXTURE4),e.bindTexture(e.TEXTURE_2D,this.distTex),e.bindFramebuffer(e.FRAMEBUFFER,null),this._dirty=!1}static computeFloodIterations(t,e){const n=Math.max(t,e),i=[];let r=Math.ceil(n/2);for(;r>=1;)i.push(r),r=Math.floor(r/2);return i}dispose(){const t=this.gl;this.maskTex&&(t.deleteTexture(this.maskTex),this.maskTex=null),this.maskFbo&&(t.deleteFramebuffer(this.maskFbo),this.maskFbo=null),this.pingTex&&(t.deleteTexture(this.pingTex),this.pingTex=null),this.pingFbo&&(t.deleteFramebuffer(this.pingFbo),this.pingFbo=null),this.pongTex&&(t.deleteTexture(this.pongTex),this.pongTex=null),this.pongFbo&&(t.deleteFramebuffer(this.pongFbo),this.pongFbo=null),this.distTex&&(t.deleteTexture(this.distTex),this.distTex=null),this.distFbo&&(t.deleteFramebuffer(this.distFbo),this.distFbo=null),this._width=0,this._height=0,this._dirty=!0}}const Ue=`#version 300 es
|
|
490
490
|
in vec2 aPosition;
|
|
491
491
|
uniform vec2 uMeshScale;
|
|
492
492
|
void main() {
|
|
493
493
|
gl_Position = vec4(aPosition * uMeshScale, 0.0, 1.0);
|
|
494
494
|
}
|
|
495
|
-
`,
|
|
495
|
+
`,Le=`#version 300 es
|
|
496
496
|
precision lowp float;
|
|
497
497
|
out vec4 fragColor;
|
|
498
498
|
void main() { fragColor = vec4(0.0); }
|
|
499
|
-
`,
|
|
499
|
+
`,_e=`#version 300 es
|
|
500
500
|
in vec2 aPosition;
|
|
501
501
|
uniform vec2 uMeshScale;
|
|
502
502
|
void main() {
|
|
503
503
|
gl_Position = vec4(aPosition * uMeshScale, 0.0, 1.0);
|
|
504
504
|
}
|
|
505
|
-
`,
|
|
505
|
+
`,Me=`#version 300 es
|
|
506
506
|
precision lowp float;
|
|
507
507
|
out vec4 fragColor;
|
|
508
508
|
void main() { fragColor = vec4(1.0); }
|
|
509
|
-
`,
|
|
509
|
+
`,Ie=`#version 300 es
|
|
510
510
|
in vec2 aPosition;
|
|
511
511
|
out vec2 vUv;
|
|
512
512
|
void main() {
|
|
513
513
|
vUv = aPosition * 0.5 + 0.5;
|
|
514
514
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
515
515
|
}
|
|
516
|
-
`,
|
|
516
|
+
`,Be=`#version 300 es
|
|
517
517
|
precision highp float;
|
|
518
518
|
uniform sampler2D uMask;
|
|
519
519
|
uniform vec2 uTexelSize;
|
|
@@ -538,14 +538,14 @@ void main() {
|
|
|
538
538
|
fragSeed = vec2(-1.0);
|
|
539
539
|
}
|
|
540
540
|
}
|
|
541
|
-
`,
|
|
541
|
+
`,Ve=`#version 300 es
|
|
542
542
|
in vec2 aPosition;
|
|
543
543
|
out vec2 vUv;
|
|
544
544
|
void main() {
|
|
545
545
|
vUv = aPosition * 0.5 + 0.5;
|
|
546
546
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
547
547
|
}
|
|
548
|
-
`,
|
|
548
|
+
`,Oe=`#version 300 es
|
|
549
549
|
precision highp float;
|
|
550
550
|
uniform sampler2D uSeedTex;
|
|
551
551
|
uniform float uStepSize;
|
|
@@ -574,14 +574,14 @@ void main() {
|
|
|
574
574
|
|
|
575
575
|
fragSeed = bestSeed;
|
|
576
576
|
}
|
|
577
|
-
`,
|
|
577
|
+
`,ke=`#version 300 es
|
|
578
578
|
in vec2 aPosition;
|
|
579
579
|
out vec2 vUv;
|
|
580
580
|
void main() {
|
|
581
581
|
vUv = aPosition * 0.5 + 0.5;
|
|
582
582
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
583
583
|
}
|
|
584
|
-
`,
|
|
584
|
+
`,Xe=`#version 300 es
|
|
585
585
|
precision highp float;
|
|
586
586
|
uniform sampler2D uSeedTex;
|
|
587
587
|
uniform sampler2D uMask;
|
|
@@ -606,7 +606,7 @@ void main() {
|
|
|
606
606
|
float normalized = clamp(d / max(uBevelWidth, 0.001), 0.0, 1.0);
|
|
607
607
|
fragDist = vec4(normalized, 0.0, 0.0, 1.0);
|
|
608
608
|
}
|
|
609
|
-
`,
|
|
609
|
+
`,Ne=`#version 300 es
|
|
610
610
|
in vec2 aPosition;
|
|
611
611
|
uniform vec2 uUvOffset;
|
|
612
612
|
uniform vec2 uUvScale;
|
|
@@ -618,7 +618,7 @@ void main() {
|
|
|
618
618
|
vScreenUv = baseUv;
|
|
619
619
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
620
620
|
}
|
|
621
|
-
`,
|
|
621
|
+
`,He=`#version 300 es
|
|
622
622
|
precision highp float;
|
|
623
623
|
|
|
624
624
|
#define MAX_POM_STEPS 32
|
|
@@ -749,14 +749,14 @@ void main() {
|
|
|
749
749
|
// Write lens-transformed depth to second attachment for boundary effects
|
|
750
750
|
fragDepth = vec4(lensD, 0.0, 0.0, 1.0);
|
|
751
751
|
}
|
|
752
|
-
`,
|
|
752
|
+
`,Ge=`#version 300 es
|
|
753
753
|
in vec2 aPosition;
|
|
754
754
|
out vec2 vUv;
|
|
755
755
|
void main() {
|
|
756
756
|
vUv = aPosition * 0.5 + 0.5;
|
|
757
757
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
758
758
|
}
|
|
759
|
-
`,
|
|
759
|
+
`,We=`#version 300 es
|
|
760
760
|
precision highp float;
|
|
761
761
|
uniform sampler2D uInteriorColor;
|
|
762
762
|
uniform sampler2D uDistField;
|
|
@@ -786,7 +786,7 @@ void main() {
|
|
|
786
786
|
|
|
787
787
|
fragColor = vec4(toSRGB(linear), color.a);
|
|
788
788
|
}
|
|
789
|
-
`,
|
|
789
|
+
`,ze=`#version 300 es
|
|
790
790
|
in vec2 aPosition;
|
|
791
791
|
in vec2 aNormal;
|
|
792
792
|
uniform float uRimWidth;
|
|
@@ -809,7 +809,7 @@ void main() {
|
|
|
809
809
|
|
|
810
810
|
gl_Position = vec4(pos, 0.0, 1.0);
|
|
811
811
|
}
|
|
812
|
-
`,
|
|
812
|
+
`,qe=`#version 300 es
|
|
813
813
|
precision highp float;
|
|
814
814
|
|
|
815
815
|
uniform sampler2D uInteriorColor;
|
|
@@ -911,7 +911,7 @@ void main() {
|
|
|
911
911
|
|
|
912
912
|
fragColor = vec4(color * alpha, alpha);
|
|
913
913
|
}
|
|
914
|
-
|
|
914
|
+
`,Ye=`#version 300 es
|
|
915
915
|
in vec2 aPosition;
|
|
916
916
|
in vec3 aNormal3;
|
|
917
917
|
in float aLerpT; // 0 = inner (at silhouette), 1 = outer edge
|
|
@@ -927,7 +927,7 @@ void main() {
|
|
|
927
927
|
vLerpT = aLerpT;
|
|
928
928
|
gl_Position = vec4(sp, 0.0, 1.0);
|
|
929
929
|
}
|
|
930
|
-
`,
|
|
930
|
+
`,je=`#version 300 es
|
|
931
931
|
precision highp float;
|
|
932
932
|
uniform vec3 uLightDir3;
|
|
933
933
|
uniform vec3 uChamferColor;
|
|
@@ -994,7 +994,7 @@ void main() {
|
|
|
994
994
|
vec3 lit = base * (uChamferAmbient + (1.0 - uChamferAmbient) * diff) + vec3(spec);
|
|
995
995
|
fragColor = vec4(toSRGB(lit), 1.0);
|
|
996
996
|
}
|
|
997
|
-
`;function Je(o){const t=[];let e=0;for(let n=0;n<o.length-2;n+=2){const i=o[n],r=o[n+1],s=o[n+2],a=o[n+3],l=s-i,u=a-r,h=Math.sqrt(l*l+u*u);if(h<1e-6)continue;const f=-u/h,c=l/h;t.push(i,r,f,c,i,r,-f,-c,s,a,f,c,s,a,f,c,i,r,-f,-c,s,a,-f,-c),e+=6}return{vertices:new Float32Array(t),count:e}}function Qe(o,t,e,n,i){if(n<=0)return{vertices:new Float32Array(0),count:0};const r=i*Math.PI/180,s=-Math.cos(r),a=Math.sin(r),l=[];let u=0;for(let h=0;h<t.length;h++){const f=t[h],v=((h+1<t.length?t[h+1]:o.length)-f)/2;if(v<3)continue;const p=v-1;let P=0;for(let T=0;T<p;T++){const m=f+T*2,S=o[m],w=o[m+1],F=o[m+2],U=o[m+3];P+=S*U-F*w}const x=P>=0?1:-1,y=[],d=[];for(let T=0;T<p;T++){const m=f+T*2,S=o[m+2]-o[m],w=o[m+3]-o[m+1],F=Math.sqrt(S*S+w*w);F<1e-8?(y.push(T>0?y[T-1]:0),d.push(T>0?d[T-1]:0)):(y.push(-w/F*x),d.push(S/F*x))}const g=[],b=[];for(let T=0;T<p;T++){const m=(T-1+p)%p;let S=y[m]+y[T],w=d[m]+d[T];const F=Math.sqrt(S*S+w*w);F>1e-8?(S/=F,w/=F):(S=y[T],w=d[T]),g.push(S),b.push(w)}for(let T=0;T<p;T++){const m=T,S=(T+1)%p,w=f+T*2,F=f+(T+1)%p*2,U=o[w],_=o[w+1],R=o[F],D=o[F+1],L=g[m]*a,M=b[m]*a,V=s,B=g[S]*a,H=b[S]*a,ot=s,Tt=U+g[m]*n,Jt=_+b[m]*n,Fn=R+g[S]*n,Cn=D+b[S]*n;l.push(U,_,L,M,V,0),l.push(Tt,Jt,L,M,V,1),l.push(R,D,B,H,ot,0),l.push(R,D,B,H,ot,0),l.push(Tt,Jt,L,M,V,1),l.push(Fn,Cn,B,H,ot,1),u+=6}}return{vertices:new Float32Array(l),count:u}}class tn extends at{gl=null;stencilPass=null;maskPass=null;jfaSeedPass=null;jfaFloodPass=null;jfaDistPass=null;interiorPass=null;compositePass=null;boundaryPass=null;chamferPass=null;quadVao=null;stencilVao=null;stencilIndexCount=0;maskVao=null;boundaryVao=null;boundaryVertexCount=0;chamferVao=null;chamferVertexCount=0;textures=new Mt;videoSlot;depthSlot;interiorFbo=null;interiorColorTex=null;interiorDepthTex=null;fboWidth=0;fboHeight=0;jfa=null;hasColorBufferFloat=!1;meshAspect=1;meshScaleX=.65;meshScaleY=.65;lightDirX=-.707;lightDirY=.707;lightDir3=[-.5,.7,-.3];config;constructor(t,e){super(t),this.config={...e},this.videoSlot=this.textures.register("video"),this.depthSlot=this.textures.register("depth");const n=this.config.bevelLightAngle*Math.PI/180;this.lightDirX=Math.cos(n),this.lightDirY=Math.sin(n);const i=this.config.lightDirection,r=Math.sqrt(i[0]*i[0]+i[1]*i[1]+i[2]*i[2]);r>1e-6&&(this.lightDir3=[i[0]/r,i[1]/r,i[2]/r]);const s=this.canvas.getContext("webgl2",{antialias:!0,alpha:!0,premultipliedAlpha:!0,stencil:!0,desynchronized:!0,powerPreference:"high-performance"});if(!s)throw new Error("WebGL 2 is not supported.");this.gl=s,this.qualityParams=It(s,e.quality),"drawingBufferColorSpace"in s&&(s.drawingBufferColorSpace="srgb"),this.hasColorBufferFloat=!!s.getExtension("EXT_color_buffer_float"),s.clearColor(0,0,0,0),s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.setupResizeHandling()}initialize(t,e,n,i){const r=this.gl;r&&(this.disposeTextures(),this.disposeFBO(),this.jfa&&(this.jfa.dispose(),this.jfa=null),this.disposeStencilGeometry(),this.disposeBoundaryGeometry(),this.disposeChamferGeometry(),this.isCameraSource=t.type==="camera",this.videoAspect=t.width/t.height,this.meshAspect=i.aspect,this.clampDepthDimensions(e,n,this.qualityParams.depthMaxDim),this.videoSlot.texture=r.createTexture(),r.activeTexture(r.TEXTURE0+this.videoSlot.unit),r.bindTexture(r.TEXTURE_2D,this.videoSlot.texture),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),this.depthSlot.texture=r.createTexture(),r.activeTexture(r.TEXTURE0+this.depthSlot.unit),r.bindTexture(r.TEXTURE_2D,this.depthSlot.texture),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),r.texStorage2D(r.TEXTURE_2D,1,r.R8,this.depthWidth,this.depthHeight),this.uploadStencilMesh(i),this.uploadMaskMesh(i),this.uploadBoundaryMesh(i),this.uploadChamferMesh(i),this.interiorPass&&(r.useProgram(this.interiorPass.program),r.uniform1i(this.interiorPass.uniforms.uImage,0),r.uniform1i(this.interiorPass.uniforms.uDepth,1),r.uniform1f(this.interiorPass.uniforms.uStrength,this.config.parallaxStrength),r.uniform1i(this.interiorPass.uniforms.uPomSteps,this.config.pomSteps),r.uniform1f(this.interiorPass.uniforms.uDepthPower,this.config.depthPower),r.uniform1f(this.interiorPass.uniforms.uDepthScale,this.config.depthScale),r.uniform1f(this.interiorPass.uniforms.uDepthBias,this.config.depthBias),r.uniform1f(this.interiorPass.uniforms.uContrastLow,this.config.contrastLow),r.uniform1f(this.interiorPass.uniforms.uContrastHigh,this.config.contrastHigh),r.uniform1f(this.interiorPass.uniforms.uVerticalReduction,this.config.verticalReduction),r.uniform1f(this.interiorPass.uniforms.uDofStart,this.config.dofStart),r.uniform1f(this.interiorPass.uniforms.uDofStrength,this.config.dofStrength),r.uniform2f(this.interiorPass.uniforms.uImageTexelSize,1/t.width,1/t.height),r.uniform1f(this.interiorPass.uniforms.uFogDensity,this.config.fogDensity),r.uniform3f(this.interiorPass.uniforms.uFogColor,...this.config.fogColor),r.uniform1f(this.interiorPass.uniforms.uColorShift,this.config.colorShift),r.uniform1f(this.interiorPass.uniforms.uBrightnessBias,this.config.brightnessBias)),this.compositePass&&(r.useProgram(this.compositePass.program),r.uniform1i(this.compositePass.uniforms.uInteriorColor,2),r.uniform1i(this.compositePass.uniforms.uDistField,4),r.uniform1f(this.compositePass.uniforms.uEdgeOcclusionWidth,this.config.edgeOcclusionWidth),r.uniform1f(this.compositePass.uniforms.uEdgeOcclusionStrength,this.config.edgeOcclusionStrength)),this.chamferPass&&(r.useProgram(this.chamferPass.program),r.uniform3f(this.chamferPass.uniforms.uLightDir3,...this.lightDir3),r.uniform3f(this.chamferPass.uniforms.uChamferColor,...this.config.chamferColor),r.uniform1f(this.chamferPass.uniforms.uChamferAmbient,this.config.chamferAmbient),r.uniform1f(this.chamferPass.uniforms.uChamferSpecular,this.config.chamferSpecular),r.uniform1f(this.chamferPass.uniforms.uChamferShininess,this.config.chamferShininess),r.uniform1i(this.chamferPass.uniforms.uInteriorColor,2)),this.boundaryPass&&(r.useProgram(this.boundaryPass.program),r.uniform1i(this.boundaryPass.uniforms.uInteriorColor,2),r.uniform1i(this.boundaryPass.uniforms.uInteriorDepth,3),r.uniform1i(this.boundaryPass.uniforms.uDistField,4),r.uniform1f(this.boundaryPass.uniforms.uRimIntensity,this.config.rimLightIntensity),r.uniform3f(this.boundaryPass.uniforms.uRimColor,...this.config.rimLightColor),r.uniform1f(this.boundaryPass.uniforms.uRefractionStrength,this.config.refractionStrength),r.uniform1f(this.boundaryPass.uniforms.uChromaticStrength,this.config.chromaticStrength),r.uniform1f(this.boundaryPass.uniforms.uOcclusionIntensity,this.config.occlusionIntensity),r.uniform1f(this.boundaryPass.uniforms.uEdgeThickness,this.config.edgeThickness),r.uniform1f(this.boundaryPass.uniforms.uEdgeSpecular,this.config.edgeSpecular),r.uniform3f(this.boundaryPass.uniforms.uEdgeColor,...this.config.edgeColor),r.uniform2f(this.boundaryPass.uniforms.uLightDir,this.lightDirX,this.lightDirY),r.uniform1f(this.boundaryPass.uniforms.uBevelIntensity,this.config.bevelIntensity)),this.recalculateViewportLayout())}uploadStencilMesh(t){const e=this.gl;if(!e||!this.stencilPass)return;this.stencilVao=e.createVertexArray(),e.bindVertexArray(this.stencilVao);const n=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,n),e.bufferData(e.ARRAY_BUFFER,t.vertices,e.STATIC_DRAW);const i=e.getAttribLocation(this.stencilPass.program,"aPosition");e.enableVertexAttribArray(i),e.vertexAttribPointer(i,2,e.FLOAT,!1,0,0);const r=e.createBuffer();e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,r),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t.indices,e.STATIC_DRAW),this.stencilIndexCount=t.indices.length,e.bindVertexArray(null)}uploadMaskMesh(t){const e=this.gl;if(!e||!this.maskPass)return;this.maskVao=e.createVertexArray(),e.bindVertexArray(this.maskVao);const n=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,n),e.bufferData(e.ARRAY_BUFFER,t.vertices,e.STATIC_DRAW);const i=e.getAttribLocation(this.maskPass.program,"aPosition");e.enableVertexAttribArray(i),e.vertexAttribPointer(i,2,e.FLOAT,!1,0,0);const r=e.createBuffer();e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,r),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t.indices,e.STATIC_DRAW),e.bindVertexArray(null)}uploadBoundaryMesh(t){const e=this.gl;if(!e||!this.boundaryPass)return;const n=Je(t.edgeVertices);if(n.count===0)return;this.boundaryVao=e.createVertexArray(),e.bindVertexArray(this.boundaryVao);const i=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,n.vertices,e.STATIC_DRAW);const r=16,s=e.getAttribLocation(this.boundaryPass.program,"aPosition");e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,r,0);const a=e.getAttribLocation(this.boundaryPass.program,"aNormal");a>=0&&(e.enableVertexAttribArray(a),e.vertexAttribPointer(a,2,e.FLOAT,!1,r,8)),this.boundaryVertexCount=n.count,e.bindVertexArray(null)}uploadChamferMesh(t){const e=this.gl;if(!e||!this.chamferPass||this.config.chamferWidth<=0)return;const n=Qe(t.edgeVertices,t.contourOffsets,t.contourIsHole,this.config.chamferWidth,this.config.chamferAngle);if(n.count===0)return;this.chamferVao=e.createVertexArray(),e.bindVertexArray(this.chamferVao);const i=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,n.vertices,e.STATIC_DRAW);const r=24,s=e.getAttribLocation(this.chamferPass.program,"aPosition");e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,r,0);const a=e.getAttribLocation(this.chamferPass.program,"aNormal3");a>=0&&(e.enableVertexAttribArray(a),e.vertexAttribPointer(a,3,e.FLOAT,!1,r,8));const l=e.getAttribLocation(this.chamferPass.program,"aLerpT");l>=0&&(e.enableVertexAttribArray(l),e.vertexAttribPointer(l,1,e.FLOAT,!1,r,20)),this.chamferVertexCount=n.count,e.bindVertexArray(null)}disposeChamferGeometry(){const t=this.gl;t&&(this.chamferVao&&(t.deleteVertexArray(this.chamferVao),this.chamferVao=null),this.chamferVertexCount=0)}createFBO(t,e){const n=this.gl;if(!n)return;this.disposeFBO(),this.fboWidth=t,this.fboHeight=e,this.interiorFbo=n.createFramebuffer(),n.bindFramebuffer(n.FRAMEBUFFER,this.interiorFbo),this.interiorColorTex=n.createTexture(),n.activeTexture(n.TEXTURE2),n.bindTexture(n.TEXTURE_2D,this.interiorColorTex),n.texStorage2D(n.TEXTURE_2D,1,n.RGBA8,t,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT0,n.TEXTURE_2D,this.interiorColorTex,0),this.interiorDepthTex=n.createTexture(),n.activeTexture(n.TEXTURE3),n.bindTexture(n.TEXTURE_2D,this.interiorDepthTex),n.texStorage2D(n.TEXTURE_2D,1,n.RGBA8,t,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT1,n.TEXTURE_2D,this.interiorDepthTex,0),n.drawBuffers([n.COLOR_ATTACHMENT0,n.COLOR_ATTACHMENT1]);const i=n.checkFramebufferStatus(n.FRAMEBUFFER);i!==n.FRAMEBUFFER_COMPLETE&&console.error("Interior FBO incomplete:",i),n.bindFramebuffer(n.FRAMEBUFFER,null)}createJFAResources(t,e){const n=this.gl;n&&(this.jfa||(this.jfa=new wt(n,this.hasColorBufferFloat)),this.jfa.createResources(t,e,this.qualityParams.jfaDivisor))}computeDistanceField(){!this.jfa||!this.maskPass||!this.jfaSeedPass||!this.jfaFloodPass||!this.jfaDistPass||!this.maskVao||!this.quadVao||this.jfa.compute({maskPass:this.maskPass,seedPass:this.jfaSeedPass,floodPass:this.jfaFloodPass,distPass:this.jfaDistPass,maskVao:this.maskVao,quadVao:this.quadVao,meshScaleX:this.meshScaleX,meshScaleY:this.meshScaleY,stencilIndexCount:this.stencilIndexCount,distRange:Math.max(this.config.bevelWidth,this.config.edgeOcclusionWidth)})}initGPUResources(){const t=this.gl;t&&(this.stencilPass=k(t,"stencil",Me,Ie,["uMeshScale"]),this.maskPass=k(t,"mask",Be,Ve,["uMeshScale"]),this.jfaSeedPass=k(t,"jfa-seed",Oe,ke,["uMask","uTexelSize"]),this.jfaFloodPass=k(t,"jfa-flood",Ne,He,["uSeedTex","uStepSize"]),this.jfaDistPass=k(t,"jfa-dist",Xe,Ge,["uSeedTex","uMask","uBevelWidth"]),this.interiorPass=k(t,"interior",We,ze,["uImage","uDepth","uOffset","uStrength","uPomSteps","uDepthPower","uDepthScale","uDepthBias","uContrastLow","uContrastHigh","uVerticalReduction","uDofStart","uDofStrength","uImageTexelSize","uFogDensity","uFogColor","uColorShift","uBrightnessBias","uUvOffset","uUvScale"]),this.compositePass=k(t,"composite",qe,Ye,["uInteriorColor","uDistField","uEdgeOcclusionWidth","uEdgeOcclusionStrength"]),this.boundaryPass=k(t,"boundary",je,Ze,["uInteriorColor","uInteriorDepth","uDistField","uRimIntensity","uRimColor","uRimWidth","uMeshScale","uRefractionStrength","uChromaticStrength","uOcclusionIntensity","uTexelSize","uEdgeThickness","uEdgeSpecular","uEdgeColor","uLightDir","uBevelIntensity"]),this.chamferPass=k(t,"chamfer",$e,Ke,["uMeshScale","uLightDir3","uChamferColor","uChamferAmbient","uChamferSpecular","uChamferShininess","uInteriorColor","uTexelSize"]),this.quadVao=_t(t,this.interiorPass.program),t.disable(t.DEPTH_TEST))}onRenderFrame(){const t=this.gl,e=this.mediaSource;if(!t||!this.interiorPass||!this.quadVao)return;const n=e?.getImageSource();if(!n||!this.interiorFbo||!this.interiorColorTex||!this.interiorDepthTex)return;this.jfa?.isDirty&&this.maskVao&&(this.computeDistanceField(),t.viewport(0,0,this.canvas.width,this.canvas.height)),t.activeTexture(t.TEXTURE0+this.videoSlot.unit),t.bindTexture(t.TEXTURE_2D,this.videoSlot.texture),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,n),this.rvfcSupported||this.onDepthUpdate(e.currentTime);let i=0,r=0;if(this.readInput){const s=this.readInput();i=-s.x,r=s.y}if(t.bindFramebuffer(t.FRAMEBUFFER,this.interiorFbo),t.checkFramebufferStatus(t.FRAMEBUFFER)!==t.FRAMEBUFFER_COMPLETE){t.bindFramebuffer(t.FRAMEBUFFER,null);return}t.viewport(0,0,this.fboWidth,this.fboHeight),t.clearColor(0,0,0,1),t.clear(t.COLOR_BUFFER_BIT),t.useProgram(this.interiorPass.program),t.uniform2f(this.interiorPass.uniforms.uOffset,i,r),t.activeTexture(t.TEXTURE0+this.videoSlot.unit),t.bindTexture(t.TEXTURE_2D,this.videoSlot.texture),t.activeTexture(t.TEXTURE0+this.depthSlot.unit),t.bindTexture(t.TEXTURE_2D,this.depthSlot.texture),t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4),t.bindFramebuffer(t.FRAMEBUFFER,null),t.clearColor(0,0,0,0),t.viewport(0,0,this.canvas.width,this.canvas.height),t.clear(t.COLOR_BUFFER_BIT|t.STENCIL_BUFFER_BIT),this.stencilVao&&this.stencilPass&&this.stencilIndexCount>0&&(t.enable(t.STENCIL_TEST),t.stencilFunc(t.ALWAYS,1,255),t.stencilOp(t.KEEP,t.KEEP,t.REPLACE),t.stencilMask(255),t.colorMask(!1,!1,!1,!1),t.useProgram(this.stencilPass.program),t.bindVertexArray(this.stencilVao),t.drawElements(t.TRIANGLES,this.stencilIndexCount,t.UNSIGNED_SHORT,0),t.colorMask(!0,!0,!0,!0)),t.stencilFunc(t.EQUAL,1,255),t.stencilMask(0),t.activeTexture(t.TEXTURE2),t.bindTexture(t.TEXTURE_2D,this.interiorColorTex),t.activeTexture(t.TEXTURE3),t.bindTexture(t.TEXTURE_2D,this.interiorDepthTex),t.activeTexture(t.TEXTURE4),t.bindTexture(t.TEXTURE_2D,this.jfa?.distanceTexture??null),t.useProgram(this.compositePass.program),t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4),t.disable(t.STENCIL_TEST),this.chamferVao&&this.chamferPass&&this.chamferVertexCount>0&&(t.useProgram(this.chamferPass.program),t.uniform2f(this.chamferPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY),t.uniform2f(this.chamferPass.uniforms.uTexelSize,1/this.canvas.width,1/this.canvas.height),t.bindVertexArray(this.chamferVao),t.drawArrays(t.TRIANGLES,0,this.chamferVertexCount)),this.boundaryVao&&this.boundaryPass&&this.boundaryVertexCount>0&&this.config.rimLightIntensity>0&&(t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA),t.useProgram(this.boundaryPass.program),t.bindVertexArray(this.boundaryVao),t.drawArrays(t.TRIANGLES,0,this.boundaryVertexCount),t.disable(t.BLEND))}onDepthUpdate(t){const e=this.gl;if(!e||!this.readDepth||!this.depthSlot.texture)return;const n=this.subsampleDepth(this.readDepth(t));e.activeTexture(e.TEXTURE0+this.depthSlot.unit),e.bindTexture(e.TEXTURE_2D,this.depthSlot.texture),e.texSubImage2D(e.TEXTURE_2D,0,0,0,this.depthWidth,this.depthHeight,e.RED,e.UNSIGNED_BYTE,n)}recalculateViewportLayout(){const t=this.gl;if(!t)return;const{width:e,height:n}=this.getViewportSize(),i=Math.min(window.devicePixelRatio,this.qualityParams.dprCap),r=Math.round(e*i),s=Math.round(n*i);(this.canvas.width!==r||this.canvas.height!==s)&&(this.canvas.width=r,this.canvas.height=s,t.viewport(0,0,r,s)),(this.fboWidth!==r||this.fboHeight!==s)&&this.createFBO(r,s);const a=this.qualityParams.jfaDivisor,l=Math.max(1,Math.round(r/a)),u=Math.max(1,Math.round(s/a));(!this.jfa||this.jfa.width!==l||this.jfa.height!==u)&&this.createJFAResources(r,s),this.computeCoverFitUV(this.config.parallaxStrength,this.config.overscanPadding),this.interiorPass&&(t.useProgram(this.interiorPass.program),t.uniform2f(this.interiorPass.uniforms.uUvOffset,this.uvOffset[0],this.uvOffset[1]),t.uniform2f(this.interiorPass.uniforms.uUvScale,this.uvScale[0],this.uvScale[1]));const h=e/n,f=.65;this.meshScaleX=f,this.meshScaleY=f,h>this.meshAspect?this.meshScaleX=f*(this.meshAspect/h):this.meshScaleY=f*(h/this.meshAspect),this.stencilPass&&(t.useProgram(this.stencilPass.program),t.uniform2f(this.stencilPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY)),this.boundaryPass&&(t.useProgram(this.boundaryPass.program),t.uniform2f(this.boundaryPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY),t.uniform1f(this.boundaryPass.uniforms.uRimWidth,this.config.rimLightWidth),t.uniform2f(this.boundaryPass.uniforms.uTexelSize,1/r,1/s)),this.chamferPass&&(t.useProgram(this.chamferPass.program),t.uniform2f(this.chamferPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY)),this.jfa&&this.jfa.markDirty()}onContextRestored(){const t=this.canvas.getContext("webgl2",{alpha:!0,premultipliedAlpha:!0,stencil:!0});t&&(this.gl=t,this.hasColorBufferFloat=!!t.getExtension("EXT_color_buffer_float"),t.clearColor(0,0,0,0),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.recalculateViewportLayout(),this.mediaSource&&(this.animationFrameHandle=window.requestAnimationFrame(()=>this.onRenderFrame())))}disposeTextures(){const t=this.gl;t&&this.textures.disposeAll(t)}disposeFBO(){const t=this.gl;t&&(this.interiorColorTex&&(t.deleteTexture(this.interiorColorTex),this.interiorColorTex=null),this.interiorDepthTex&&(t.deleteTexture(this.interiorDepthTex),this.interiorDepthTex=null),this.interiorFbo&&(t.deleteFramebuffer(this.interiorFbo),this.interiorFbo=null),this.fboWidth=0,this.fboHeight=0)}disposeStencilGeometry(){const t=this.gl;t&&(this.stencilVao&&(t.deleteVertexArray(this.stencilVao),this.stencilVao=null),this.maskVao&&(t.deleteVertexArray(this.maskVao),this.maskVao=null),this.stencilIndexCount=0)}disposeBoundaryGeometry(){const t=this.gl;t&&(this.boundaryVao&&(t.deleteVertexArray(this.boundaryVao),this.boundaryVao=null),this.boundaryVertexCount=0)}disposeRenderer(){this.disposeTextures(),this.disposeFBO(),this.jfa&&(this.jfa.dispose(),this.jfa=null),this.disposeStencilGeometry(),this.disposeBoundaryGeometry(),this.disposeChamferGeometry(),this.disposeGPUResources(),this.gl&&(this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null)}disposeGPUResources(){const t=this.gl;if(!t)return;const e=[this.stencilPass,this.maskPass,this.jfaSeedPass,this.jfaFloodPass,this.jfaDistPass,this.interiorPass,this.compositePass,this.boundaryPass,this.chamferPass];for(const n of e)n&&n.dispose(t);this.stencilPass=null,this.maskPass=null,this.jfaSeedPass=null,this.jfaFloodPass=null,this.jfaDistPass=null,this.interiorPass=null,this.compositePass=null,this.boundaryPass=null,this.chamferPass=null,this.quadVao&&(t.deleteVertexArray(this.quadVao),this.quadVao=null)}}async function Rt(o){const t=await fetch(o);if(!t.ok)throw new Error(`Failed to fetch SVG: ${t.status} ${t.statusText}`);const e=await t.text();return en(e)}function en(o){const n=new DOMParser().parseFromString(o,"image/svg+xml").querySelector("svg");if(!n)throw new Error("No <svg> element found in document.");const i=nn(n);if(i.length===0)throw new Error("No path data found in SVG.");let r=1/0,s=1/0,a=-1/0,l=-1/0;for(const R of i)for(let D=0;D<R.length;D+=2)r=Math.min(r,R[D]),a=Math.max(a,R[D]),s=Math.min(s,R[D+1]),l=Math.max(l,R[D+1]);const u=a-r,h=l-s,f=(r+a)/2,c=(s+l)/2,E=2/Math.max(u,h),v=u/h,p=i.map(R=>{const D=[];for(let L=0;L<R.length;L+=2)D.push((R[L]-f)*E),D.push(-((R[L+1]-c)*E));return D}),P=cn(p),x=[],y=[];for(const R of P){const{flatCoords:D,holeIndices:L}=un(R),M=fn(D,L),V=x.length/2;for(const B of M)y.push(B+V);for(const B of D)x.push(B)}const d=x,g=y,b=[],T=[],m=[],S=zt(p);for(let R=0;R<p.length;R++){const D=p[R];T.push(b.length),m.push(S[R]);for(let L=0;L<D.length;L++)b.push(D[L]);D.length>=2&&b.push(D[0],D[1])}let w=1/0,F=1/0,U=-1/0,_=-1/0;for(let R=0;R<d.length;R+=2)w=Math.min(w,d[R]),U=Math.max(U,d[R]),F=Math.min(F,d[R+1]),_=Math.max(_,d[R+1]);return{vertices:new Float32Array(d),indices:new Uint16Array(g),edgeVertices:new Float32Array(b),contourOffsets:T,contourIsHole:m,bounds:{minX:w,maxX:U,minY:F,maxY:_},aspect:v}}function nn(o){const t=[];return o.querySelectorAll("path").forEach(l=>{const u=l.getAttribute("d");if(!u)return;const h=sn(u);t.push(...h)}),o.querySelectorAll("polygon").forEach(l=>{const u=l.getAttribute("points");if(!u)return;const h=Xt(u);h.length>=6&&t.push(h)}),o.querySelectorAll("polyline").forEach(l=>{const u=l.getAttribute("points");if(!u)return;const h=Xt(u);h.length>=6&&t.push(h)}),o.querySelectorAll("rect").forEach(l=>{const u=parseFloat(l.getAttribute("x")||"0"),h=parseFloat(l.getAttribute("y")||"0"),f=parseFloat(l.getAttribute("width")||"0"),c=parseFloat(l.getAttribute("height")||"0");f>0&&c>0&&t.push([u,h,u+f,h,u+f,h+c,u,h+c])}),o.querySelectorAll("circle").forEach(l=>{const u=parseFloat(l.getAttribute("cx")||"0"),h=parseFloat(l.getAttribute("cy")||"0"),f=parseFloat(l.getAttribute("r")||"0");f>0&&t.push(rn(u,h,f))}),o.querySelectorAll("ellipse").forEach(l=>{const u=parseFloat(l.getAttribute("cx")||"0"),h=parseFloat(l.getAttribute("cy")||"0"),f=parseFloat(l.getAttribute("rx")||"0"),c=parseFloat(l.getAttribute("ry")||"0");f>0&&c>0&&t.push(on(u,h,f,c))}),t}function Xt(o){const t=[],e=o.trim().split(/[\s,]+/);for(let n=0;n<e.length-1;n+=2){const i=parseFloat(e[n]),r=parseFloat(e[n+1]);Number.isFinite(i)&&Number.isFinite(r)&&t.push(i,r)}return t}function rn(o,t,e,n=64){const i=[];for(let r=0;r<n;r++){const s=2*Math.PI*r/n;i.push(o+e*Math.cos(s),t+e*Math.sin(s))}return i}function on(o,t,e,n,i=64){const r=[];for(let s=0;s<i;s++){const a=2*Math.PI*s/i;r.push(o+e*Math.cos(a),t+n*Math.sin(a))}return r}function sn(o){const t=[];let e=[],n=0,i=0,r=0,s=0,a=0,l=0,u="";const h=an(o);let f=0;function c(){return f>=h.length?0:parseFloat(h[f++])}for(;f<h.length;){const E=h[f];let v;/^[a-zA-Z]$/.test(E)?(v=E,f++):v=u==="M"?"L":u==="m"?"l":u;const p=v===v.toLowerCase();switch(v.toUpperCase()){case"M":{e.length>0&&t.push(e),e=[];const x=c()+(p?n:0),y=c()+(p?i:0);n=x,i=y,r=x,s=y,e.push(n,i),a=n,l=i;break}case"L":{n=c()+(p?n:0),i=c()+(p?i:0),e.push(n,i),a=n,l=i;break}case"H":{n=c()+(p?n:0),e.push(n,i),a=n,l=i;break}case"V":{i=c()+(p?i:0),e.push(n,i),a=n,l=i;break}case"C":{const x=c()+(p?n:0),y=c()+(p?i:0),d=c()+(p?n:0),g=c()+(p?i:0),b=c()+(p?n:0),T=c()+(p?i:0);et(e,n,i,x,y,d,g,b,T),n=b,i=T,a=d,l=g;break}case"S":{const x=2*n-a,y=2*i-l,d=c()+(p?n:0),g=c()+(p?i:0),b=c()+(p?n:0),T=c()+(p?i:0);et(e,n,i,x,y,d,g,b,T),n=b,i=T,a=d,l=g;break}case"Q":{const x=c()+(p?n:0),y=c()+(p?i:0),d=c()+(p?n:0),g=c()+(p?i:0);Gt(e,n,i,x,y,d,g),n=d,i=g,a=x,l=y;break}case"T":{const x=2*n-a,y=2*i-l,d=c()+(p?n:0),g=c()+(p?i:0);Gt(e,n,i,x,y,d,g),n=d,i=g,a=x,l=y;break}case"A":{const x=c(),y=c(),d=c(),g=c(),b=c(),T=c()+(p?n:0),m=c()+(p?i:0);hn(e,n,i,x,y,d,!!g,!!b,T,m),n=T,i=m,a=n,l=i;break}case"Z":{n=r,i=s,e.length>0&&t.push(e),e=[],a=n,l=i;break}default:f++;break}u=v}return e.length>=6&&t.push(e),t}function an(o){const t=[],e=/([a-zA-Z])|([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)/g;let n;for(;(n=e.exec(o))!==null;)t.push(n[0]);return t}const ln=.5;function et(o,t,e,n,i,r,s,a,l,u=0){if(u>12){o.push(a,l);return}const h=a-t,f=l-e,c=Math.sqrt(h*h+f*f);if(c<1e-6){o.push(a,l);return}const E=Math.abs((n-a)*f-(i-l)*h)/c,v=Math.abs((r-a)*f-(s-l)*h)/c;if(E+v<ln){o.push(a,l);return}const p=(t+n)/2,P=(e+i)/2,x=(n+r)/2,y=(i+s)/2,d=(r+a)/2,g=(s+l)/2,b=(p+x)/2,T=(P+y)/2,m=(x+d)/2,S=(y+g)/2,w=(b+m)/2,F=(T+S)/2;et(o,t,e,p,P,b,T,w,F,u+1),et(o,w,F,m,S,d,g,a,l,u+1)}function Gt(o,t,e,n,i,r,s){const a=t+.6666666666666666*(n-t),l=e+2/3*(i-e),u=r+2/3*(n-r),h=s+2/3*(i-s);et(o,t,e,a,l,u,h,r,s)}function hn(o,t,e,n,i,r,s,a,l,u){if(n===0||i===0){o.push(l,u);return}let h=Math.abs(n),f=Math.abs(i);const c=r*Math.PI/180,E=Math.cos(c),v=Math.sin(c),p=(t-l)/2,P=(e-u)/2,x=E*p+v*P,y=-v*p+E*P;let d=x*x/(h*h)+y*y/(f*f);if(d>1){const M=Math.sqrt(d);h*=M,f*=M,d=1}const g=h*h,b=f*f,T=x*x,m=y*y;let S=Math.max(0,(g*b-g*m-b*T)/(g*m+b*T));S=Math.sqrt(S),s===a&&(S=-S);const w=S*(h*y)/f,F=S*-(f*x)/h,U=E*w-v*F+(t+l)/2,_=v*w+E*F+(e+u)/2,R=Wt(1,0,(x-w)/h,(y-F)/f);let D=Wt((x-w)/h,(y-F)/f,(-x-w)/h,(-y-F)/f);!a&&D>0&&(D-=2*Math.PI),a&&D<0&&(D+=2*Math.PI);const L=Math.max(4,Math.ceil(Math.abs(D)/(Math.PI/16)));for(let M=1;M<=L;M++){const V=R+M/L*D,B=Math.cos(V),H=Math.sin(V),ot=E*h*B-v*f*H+U,Tt=v*h*B+E*f*H+_;o.push(ot,Tt)}}function Wt(o,t,e,n){const i=o*n-t*e<0?-1:1,r=o*e+t*n,s=Math.sqrt(o*o+t*t),a=Math.sqrt(e*e+n*n),l=r/(s*a);return i*Math.acos(Math.max(-1,Math.min(1,l)))}function un(o){const t=[],e=[];for(let n=0;n<o.length;n++){n>0&&e.push(t.length/2);for(const i of o[n])t.push(i)}return{flatCoords:t,holeIndices:e}}function zt(o){const t=o.length,e=o.map(i=>Math.abs(qt(i))),n=new Array(t).fill(!1);for(let i=0;i<t;i++){let r=0;const s=o[i][0],a=o[i][1];for(let l=0;l<t;l++)i!==l&&e[l]>e[i]&&Yt(s,a,o[l])&&r++;n[i]=r%2===1}return n}function cn(o){if(o.length<=1)return[o];const t=zt(o),e=o.map((s,a)=>{const l=qt(s);return{index:a,contour:s,area:l,isOuter:!t[a]}}),n=e.filter(s=>s.isOuter),i=e.filter(s=>!s.isOuter);if(n.length===0)return o.map(s=>[s]);const r=n.map(s=>({outer:s.contour,holes:[]}));for(const s of i){const a=s.contour[0],l=s.contour[1];let u=-1,h=1/0;for(let f=0;f<n.length;f++)if(Yt(a,l,n[f].contour)){const c=Math.abs(n[f].area);c<h&&(h=c,u=f)}u>=0?r[u].holes.push(s.contour):r.push({outer:s.contour,holes:[]})}return r.map(s=>[s.outer,...s.holes])}function qt(o){let t=0;const e=o.length;for(let n=0;n<e;n+=2){const i=o[n],r=o[n+1],s=o[(n+2)%e],a=o[(n+3)%e];t+=i*a-s*r}return t/2}function Yt(o,t,e){let n=!1;const i=e.length;for(let r=0,s=i-2;r<i;s=r,r+=2){const a=e[r],l=e[r+1],u=e[s],h=e[s+1];l>t!=h>t&&o<(u-a)*(t-l)/(h-l)+a&&(n=!n)}return n}function fn(o,t,e=2){const n=t&&t.length>0,i=n?t[0]*e:o.length;let r=jt(o,0,i,e,!0);const s=[];if(!r||r.next===r.prev)return s;n&&(r=vn(o,t,r,e));let a=1/0,l=1/0,u=-1/0,h=-1/0,f=0;if(o.length>80*e){for(let c=0;c<i;c+=e){const E=o[c],v=o[c+1];E<a&&(a=E),v<l&&(l=v),E>u&&(u=E),v>h&&(h=v)}f=Math.max(u-a,h-l),f=f!==0?32767/f:0}return nt(r,s,e,a,l,f,0),s}function jt(o,t,e,n,i){let r=null;if(i===Dn(o,t,e,n)>0)for(let s=t;s<e;s+=n)r=Kt(s,o[s],o[s+1],r);else for(let s=e-n;s>=t;s-=n)r=Kt(s,o[s],o[s+1],r);return r&&mt(r,r.next)&&(rt(r),r=r.next),r?(r.next.prev=r,r.prev.next=r,r.next):null}function W(o,t){t||(t=o);let e=o,n;do if(n=!1,!e.steiner&&(mt(e,e.next)||C(e.prev,e,e.next)===0)){if(rt(e),e=t=e.prev,e===e.next)break;n=!0}else e=e.next;while(n||e!==t);return t}function nt(o,t,e,n,i,r,s){if(!o)return;!s&&r&&bn(o,n,i,r);let a=o,l,u;for(;o.prev!==o.next;){if(l=o.prev,u=o.next,r?mn(o,n,i,r):dn(o)){t.push(l.i/e,o.i/e,u.i/e),rt(o),o=u.next,a=u.next;continue}if(o=u,o===a){s?s===1?(o=pn(W(o),t,e),nt(o,t,e,n,i,r,2)):s===2&&gn(o,t,e,n,i,r):nt(W(o),t,e,n,i,r,1);break}}}function dn(o){const t=o.prev,e=o,n=o.next;if(C(t,e,n)>=0)return!1;const i=t.x,r=e.x,s=n.x,a=t.y,l=e.y,u=n.y,h=i<r?i<s?i:s:r<s?r:s,f=a<l?a<u?a:u:l<u?l:u,c=i>r?i>s?i:s:r>s?r:s,E=a>l?a>u?a:u:l>u?l:u;let v=n.next;for(;v!==t;){if(v.x>=h&&v.x<=c&&v.y>=f&&v.y<=E&&$(i,a,r,l,s,u,v.x,v.y)&&C(v.prev,v,v.next)>=0)return!1;v=v.next}return!0}function mn(o,t,e,n){const i=o.prev,r=o,s=o.next;if(C(i,r,s)>=0)return!1;const a=i.x,l=r.x,u=s.x,h=i.y,f=r.y,c=s.y,E=a<l?a<u?a:u:l<u?l:u,v=h<f?h<c?h:c:f<c?f:c,p=a>l?a>u?a:u:l>u?l:u,P=h>f?h>c?h:c:f>c?f:c,x=Dt(E,v,t,e,n),y=Dt(p,P,t,e,n);let d=o.prevZ,g=o.nextZ;for(;d&&d.z>=x&&g&&g.z<=y;){if(d.x>=E&&d.x<=p&&d.y>=v&&d.y<=P&&d!==i&&d!==s&&$(a,h,l,f,u,c,d.x,d.y)&&C(d.prev,d,d.next)>=0||(d=d.prevZ,g.x>=E&&g.x<=p&&g.y>=v&&g.y<=P&&g!==i&&g!==s&&$(a,h,l,f,u,c,g.x,g.y)&&C(g.prev,g,g.next)>=0))return!1;g=g.nextZ}for(;d&&d.z>=x;){if(d.x>=E&&d.x<=p&&d.y>=v&&d.y<=P&&d!==i&&d!==s&&$(a,h,l,f,u,c,d.x,d.y)&&C(d.prev,d,d.next)>=0)return!1;d=d.prevZ}for(;g&&g.z<=y;){if(g.x>=E&&g.x<=p&&g.y>=v&&g.y<=P&&g!==i&&g!==s&&$(a,h,l,f,u,c,g.x,g.y)&&C(g.prev,g,g.next)>=0)return!1;g=g.nextZ}return!0}function pn(o,t,e){let n=o;do{const i=n.prev,r=n.next.next;!mt(i,r)&&Zt(i,n,n.next,r)&&it(i,r)&&it(r,i)&&(t.push(i.i/e,n.i/e,r.i/e),rt(n),rt(n.next),n=o=r),n=n.next}while(n!==o);return W(n)}function gn(o,t,e,n,i,r){let s=o;do{let a=s.next.next;for(;a!==s.prev;){if(s.i!==a.i&&An(s,a)){let l=$t(s,a);s=W(s,s.next),l=W(l,l.next),nt(s,t,e,n,i,r,0),nt(l,t,e,n,i,r,0);return}a=a.next}s=s.next}while(s!==o)}function vn(o,t,e,n){const i=[];for(let r=0;r<t.length;r++){const s=t[r]*n,a=r<t.length-1?t[r+1]*n:o.length,l=jt(o,s,a,n,!1);l&&(l===l.next&&(l.steiner=!0),i.push(Sn(l)))}i.sort((r,s)=>r.x-s.x);for(const r of i)e=xn(r,e);return e}function xn(o,t){const e=Tn(o,t);if(!e)return t;const n=$t(e,o);return W(n,n.next),W(e,e.next)}function Tn(o,t){let e=t;const n=o.x,i=o.y;let r=-1/0,s=null;do{if(i<=e.y&&i>=e.next.y&&e.next.y!==e.y){const f=e.x+(i-e.y)/(e.next.y-e.y)*(e.next.x-e.x);if(f<=n&&f>r&&(r=f,s=e.x<e.next.x?e:e.next,f===n))return s}e=e.next}while(e!==t);if(!s)return null;const a=s,l=s.x,u=s.y;let h=1/0;e=s;do{if(n>=e.x&&e.x>=l&&n!==e.x&&$(i<u?n:r,i,l,u,i<u?r:n,i,e.x,e.y)){const f=Math.abs(i-e.y)/(n-e.x);it(e,o)&&(f<h||f===h&&(e.x>s.x||En(s,e)))&&(s=e,h=f)}e=e.next}while(e!==a);return s}function En(o,t){return C(o.prev,o,t.prev)<0&&C(t.next,o,o.next)<0}function bn(o,t,e,n){let i=o;do i.z===0&&(i.z=Dt(i.x,i.y,t,e,n)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next;while(i!==o);i.prevZ.nextZ=null,i.prevZ=null,yn(i)}function yn(o){let t=1,e;do{let n=o;o=null;let i=null;for(e=0;n;){e++;let r=n,s=0;for(let l=0;l<t&&(s++,r=r.nextZ,!!r);l++);let a=t;for(;s>0||a>0&&r;){let l;s!==0&&(a===0||!r||n.z<=r.z)?(l=n,n=n.nextZ,s--):(l=r,r=r.nextZ,a--),i?i.nextZ=l:o=l,l.prevZ=i,i=l}n=r}i.nextZ=null,t*=2}while(e>1);return o}function Dt(o,t,e,n,i){let r=(o-e)*i|0,s=(t-n)*i|0;return r=(r|r<<8)&16711935,r=(r|r<<4)&252645135,r=(r|r<<2)&858993459,r=(r|r<<1)&1431655765,s=(s|s<<8)&16711935,s=(s|s<<4)&252645135,s=(s|s<<2)&858993459,s=(s|s<<1)&1431655765,r|s<<1}function Sn(o){let t=o,e=o;do(t.x<e.x||t.x===e.x&&t.y<e.y)&&(e=t),t=t.next;while(t!==o);return e}function $(o,t,e,n,i,r,s,a){return(i-s)*(t-a)-(o-s)*(r-a)>=0&&(o-s)*(n-a)-(e-s)*(t-a)>=0&&(e-s)*(r-a)-(i-s)*(n-a)>=0}function An(o,t){return o.next.i!==t.i&&o.prev.i!==t.i&&!wn(o,t)&&(it(o,t)&&it(t,o)&&Rn(o,t)&&(C(o.prev,o,t.prev)!==0||C(o,t.prev,t)!==0)||mt(o,t)&&C(o.prev,o,o.next)>0&&C(t.prev,t,t.next)>0)}function C(o,t,e){return(t.y-o.y)*(e.x-t.x)-(t.x-o.x)*(e.y-t.y)}function mt(o,t){return o.x===t.x&&o.y===t.y}function Zt(o,t,e,n){const i=gt(C(o,t,e)),r=gt(C(o,t,n)),s=gt(C(e,n,o)),a=gt(C(e,n,t));return!!(i!==r&&s!==a||i===0&&pt(o,e,t)||r===0&&pt(o,n,t)||s===0&&pt(e,o,n)||a===0&&pt(e,t,n))}function pt(o,t,e){return t.x<=Math.max(o.x,e.x)&&t.x>=Math.min(o.x,e.x)&&t.y<=Math.max(o.y,e.y)&&t.y>=Math.min(o.y,e.y)}function gt(o){return o>0?1:o<0?-1:0}function wn(o,t){let e=o;do{if(e.i!==o.i&&e.next.i!==o.i&&e.i!==t.i&&e.next.i!==t.i&&Zt(e,e.next,o,t))return!0;e=e.next}while(e!==o);return!1}function it(o,t){return C(o.prev,o,o.next)<0?C(o,t,o.next)>=0&&C(o,o.prev,t)>=0:C(o,t,o.prev)<0||C(o,o.next,t)<0}function Rn(o,t){let e=o,n=!1;const i=(o.x+t.x)/2,r=(o.y+t.y)/2;do e.y>r!=e.next.y>r&&e.next.y!==e.y&&i<(e.next.x-e.x)*(r-e.y)/(e.next.y-e.y)+e.x&&(n=!n),e=e.next;while(e!==o);return n}function $t(o,t){const e=Pt(o.i,o.x,o.y),n=Pt(t.i,t.x,t.y),i=o.next,r=t.prev;return o.next=t,t.prev=o,e.next=i,i.prev=e,n.next=e,e.prev=n,r.next=n,n.prev=r,n}function Kt(o,t,e,n){const i=Pt(o,t,e);return n?(i.next=n.next,i.prev=n,n.next.prev=i,n.next=i):(i.prev=i,i.next=i),i}function rt(o){o.next.prev=o.prev,o.prev.next=o.next,o.prevZ&&(o.prevZ.nextZ=o.nextZ),o.nextZ&&(o.nextZ.prevZ=o.prevZ)}function Pt(o,t,e){return{i:o,x:t,y:e,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function Dn(o,t,e,n){let i=0;for(let r=t,s=e-n;r<e;r+=n)i+=(o[s]-o[r])*(o[r+1]+o[s+1]),s=r;return i}const A={parallaxX:.4,parallaxY:.8,parallaxMax:30,overscan:.06,pomSteps:16,rimIntensity:.6,rimColor:"#ffffff",rimWidth:.025,refractionStrength:.015,chromaticStrength:.008,occlusionIntensity:.4,depthPower:.7,depthScale:1.2,depthBias:-.05,fogDensity:.15,fogColor:"#1a1a2e",colorShift:.6,brightnessBias:.05,contrastLow:.02,contrastHigh:.98,verticalReduction:.5,dofStart:.5,dofStrength:.5,bevelIntensity:.5,bevelWidth:.04,bevelDarkening:.2,bevelDesaturation:.12,bevelLightAngle:135,edgeThickness:.01,edgeSpecular:.35,edgeColor:"#a0a0a0",chamferWidth:.025,chamferAngle:45,chamferColor:"#262630",chamferAmbient:.12,chamferSpecular:.3,chamferShininess:24,edgeOcclusionWidth:.03,edgeOcclusionStrength:.2,lightDirection:"-0.5,0.7,-0.3",autoplay:!0,loop:!0,muted:!0},K=512,J=512;class Ft{constructor(t,e=.08,n=.06){this.host=t,this.lerpFactor=e,this.motionLerpFactor=n,this.host.addEventListener("mousemove",this.handleMouseMove),this.host.addEventListener("mouseleave",this.resetPointerTarget),this.host.addEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.host.addEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.host.addEventListener("touchend",this.handleTouchEnd,{passive:!0}),this.host.addEventListener("touchcancel",this.handleTouchEnd,{passive:!0})}pointerTarget={x:0,y:0};motionTarget={x:0,y:0};smoothedOutput={x:0,y:0};usingMotionInput=!1;motionListenerAttached=!1;motionRequested=!1;touchActive=!1;touchAnchorX=0;touchAnchorY=0;lerpFactor;motionLerpFactor;static TOUCH_DRAG_RANGE=100;update(){const t=this.touchActive?this.pointerTarget:this.usingMotionInput?this.motionTarget:this.pointerTarget,e=this.usingMotionInput&&!this.touchActive?this.motionLerpFactor:this.lerpFactor;return this.smoothedOutput.x=xt(this.smoothedOutput.x,t.x,e),this.smoothedOutput.y=xt(this.smoothedOutput.y,t.y,e),this.smoothedOutput}dispose(){this.host.removeEventListener("mousemove",this.handleMouseMove),this.host.removeEventListener("mouseleave",this.resetPointerTarget),this.host.removeEventListener("touchstart",this.handleTouchStart),this.host.removeEventListener("touchmove",this.handleTouchMove),this.host.removeEventListener("touchend",this.handleTouchEnd),this.host.removeEventListener("touchcancel",this.handleTouchEnd),this.motionListenerAttached&&(window.removeEventListener("deviceorientation",this.handleDeviceOrientation),this.motionListenerAttached=!1)}handleMouseMove=t=>{const e=this.host.getBoundingClientRect(),n=(t.clientX-e.left)/e.width*2-1,i=(t.clientY-e.top)/e.height*2-1;this.pointerTarget.x=Q(n,-1,1),this.pointerTarget.y=Q(i,-1,1)};resetPointerTarget=()=>{this.pointerTarget.x=0,this.pointerTarget.y=0};handleTouchStart=t=>{const e=t.touches[0];e&&(this.touchActive=!0,this.touchAnchorX=e.clientX,this.touchAnchorY=e.clientY,this.pointerTarget.x=0,this.pointerTarget.y=0,this.motionRequested||(this.motionRequested=!0,this.requestMotionPermission()))};handleTouchMove=t=>{const e=t.touches[0];if(!e)return;const n=e.clientX-this.touchAnchorX,i=e.clientY-this.touchAnchorY,r=Ft.TOUCH_DRAG_RANGE;this.pointerTarget.x=Q(n/r,-1,1),this.pointerTarget.y=Q(i/r,-1,1)};handleTouchEnd=()=>{this.touchActive=!1,this.pointerTarget.x=0,this.pointerTarget.y=0};async requestMotionPermission(){if(typeof DeviceOrientationEvent>"u")return;const t=DeviceOrientationEvent;if(typeof t.requestPermission=="function")try{if(await t.requestPermission()!=="granted")return}catch{return}this.motionListenerAttached||(window.addEventListener("deviceorientation",this.handleDeviceOrientation),this.motionListenerAttached=!0),this.usingMotionInput=!0}handleDeviceOrientation=t=>{const e=Q((t.gamma??0)/45,-1,1),n=Q((t.beta??0)/45,-1,1);this.motionTarget.x=xt(this.motionTarget.x,e,this.motionLerpFactor),this.motionTarget.y=xt(this.motionTarget.y,n,this.motionLerpFactor)}}class vt extends HTMLElement{static TAG_NAME="layershift-portal";static get observedAttributes(){return["src","depth-src","depth-meta","depth-model","logo-src","source-type","parallax-x","parallax-y","parallax-max","overscan","pom-steps","quality","gpu-backend","rim-intensity","rim-color","rim-width","refraction-strength","chromatic-strength","occlusion-intensity","depth-power","depth-scale","depth-bias","fog-density","fog-color","color-shift","brightness-bias","contrast-low","contrast-high","vertical-reduction","dof-start","dof-strength","bevel-intensity","bevel-width","bevel-darkening","bevel-desaturation","bevel-light-angle","edge-thickness","edge-specular","edge-color","chamfer-width","chamfer-angle","chamfer-color","chamfer-ambient","chamfer-specular","chamfer-shininess","edge-occlusion-width","edge-occlusion-strength","light-direction","autoplay","loop","muted"]}reinitAttributes=["src","depth-src","depth-meta","depth-model","logo-src","source-type"];canInit(){const t=!!this.getAttribute("logo-src");if(this.sourceType==="camera")return t;const e=!!this.getAttribute("src"),n=!!this.getAttribute("depth-src")&&!!this.getAttribute("depth-meta"),i=!!this.getAttribute("depth-model");return e&&t&&(n||i)}shadow;container=null;renderer=null;inputHandler=null;source=null;depthEstimator=null;mesh=null;loopCount=0;lifecycle;constructor(){super(),this.shadow=this.attachShadow({mode:"open"}),this.lifecycle=new Ht(this)}getAttrFloat(t,e){const n=this.getAttribute(t);if(n===null)return e;const i=parseFloat(n);return Number.isFinite(i)?i:e}getAttrBool(t,e){if(!this.hasAttribute(t))return e;const n=this.getAttribute(t);return!(n==="false"||n==="0")}getAttrColor(t,e){const n=this.getAttribute(t)??e;return Pn(n)}getAttrVec3(t,e){const i=(this.getAttribute(t)??e).split(",").map(s=>parseFloat(s.trim()));if(i.length>=3&&i.every(Number.isFinite))return[i[0],i[1],i[2]];const r=e.split(",").map(s=>parseFloat(s.trim()));return[r[0],r[1],r[2]]}get sourceType(){const t=this.getAttribute("source-type");return t==="camera"?"camera":t==="image"?"image":"video"}get parallaxX(){return this.getAttrFloat("parallax-x",A.parallaxX)}get parallaxY(){return this.getAttrFloat("parallax-y",A.parallaxY)}get parallaxMax(){return this.getAttrFloat("parallax-max",A.parallaxMax)}get overscan(){return this.getAttrFloat("overscan",A.overscan)}get pomSteps(){return this.getAttrFloat("pom-steps",A.pomSteps)}get quality(){const t=this.getAttribute("quality");if(t==="auto"||t==="high"||t==="medium"||t==="low")return t}get gpuBackend(){return"webgl2"}get rimIntensity(){return this.getAttrFloat("rim-intensity",A.rimIntensity)}get rimWidth(){return this.getAttrFloat("rim-width",A.rimWidth)}get rimColor(){return this.getAttrColor("rim-color",A.rimColor)}get refractionStrength(){return this.getAttrFloat("refraction-strength",A.refractionStrength)}get chromaticStrength(){return this.getAttrFloat("chromatic-strength",A.chromaticStrength)}get occlusionIntensity(){return this.getAttrFloat("occlusion-intensity",A.occlusionIntensity)}get depthPower(){return this.getAttrFloat("depth-power",A.depthPower)}get depthScale(){return this.getAttrFloat("depth-scale",A.depthScale)}get depthBias(){return this.getAttrFloat("depth-bias",A.depthBias)}get fogDensity(){return this.getAttrFloat("fog-density",A.fogDensity)}get fogColor(){return this.getAttrColor("fog-color",A.fogColor)}get colorShift(){return this.getAttrFloat("color-shift",A.colorShift)}get brightnessBias(){return this.getAttrFloat("brightness-bias",A.brightnessBias)}get contrastLow(){return this.getAttrFloat("contrast-low",A.contrastLow)}get contrastHigh(){return this.getAttrFloat("contrast-high",A.contrastHigh)}get verticalReduction(){return this.getAttrFloat("vertical-reduction",A.verticalReduction)}get dofStart(){return this.getAttrFloat("dof-start",A.dofStart)}get dofStrength(){return this.getAttrFloat("dof-strength",A.dofStrength)}get bevelIntensity(){return this.getAttrFloat("bevel-intensity",A.bevelIntensity)}get bevelWidth(){return this.getAttrFloat("bevel-width",A.bevelWidth)}get bevelDarkening(){return this.getAttrFloat("bevel-darkening",A.bevelDarkening)}get bevelDesaturation(){return this.getAttrFloat("bevel-desaturation",A.bevelDesaturation)}get bevelLightAngle(){return this.getAttrFloat("bevel-light-angle",A.bevelLightAngle)}get edgeThickness(){return this.getAttrFloat("edge-thickness",A.edgeThickness)}get edgeSpecular(){return this.getAttrFloat("edge-specular",A.edgeSpecular)}get edgeColor(){return this.getAttrColor("edge-color",A.edgeColor)}get chamferWidth(){return this.getAttrFloat("chamfer-width",A.chamferWidth)}get chamferAngle(){return this.getAttrFloat("chamfer-angle",A.chamferAngle)}get chamferColor(){return this.getAttrColor("chamfer-color",A.chamferColor)}get chamferAmbient(){return this.getAttrFloat("chamfer-ambient",A.chamferAmbient)}get chamferSpecular(){return this.getAttrFloat("chamfer-specular",A.chamferSpecular)}get chamferShininess(){return this.getAttrFloat("chamfer-shininess",A.chamferShininess)}get edgeOcclusionWidth(){return this.getAttrFloat("edge-occlusion-width",A.edgeOcclusionWidth)}get edgeOcclusionStrength(){return this.getAttrFloat("edge-occlusion-strength",A.edgeOcclusionStrength)}get lightDirection3(){return this.getAttrVec3("light-direction",A.lightDirection)}get depthModel(){return this.getAttribute("depth-model")}get shouldAutoplay(){return this.getAttrBool("autoplay",A.autoplay)}get shouldLoop(){return this.getAttrBool("loop",A.loop)}get shouldMute(){return this.getAttrBool("muted",A.muted)}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}attachSourceEventListeners(t){t.addEventListener&&(t.addEventListener("play",(()=>{this.emit("layershift-portal:play",{currentTime:t.currentTime})})),t.addEventListener("pause",(()=>{this.emit("layershift-portal:pause",{currentTime:t.currentTime})})),t.addEventListener("ended",(()=>{this.loopCount+=1,this.emit("layershift-portal:loop",{loopCount:this.loopCount})})))}connectedCallback(){console.warn("[layershift] <layershift-portal> is deprecated and will be removed in a future major version. Use <layershift-effect> with a filter-config.json instead. See https://layershift.io/docs/migration"),this.lifecycle.onConnected()}disconnectedCallback(){this.lifecycle.onDisconnected()}attributeChangedCallback(t,e,n){this.lifecycle.onAttributeChanged(t,e,n)}setupShadowDOM(){this.shadow.innerHTML="";const t=document.createElement("style");t.textContent=`
|
|
997
|
+
`;function Ze(o){const t=[];let e=0;for(let n=0;n<o.length-2;n+=2){const i=o[n],r=o[n+1],s=o[n+2],a=o[n+3],l=s-i,c=a-r,u=Math.sqrt(l*l+c*c);if(u<1e-6)continue;const f=-c/u,h=l/u;t.push(i,r,f,h,i,r,-f,-h,s,a,f,h,s,a,f,h,i,r,-f,-h,s,a,-f,-h),e+=6}return{vertices:new Float32Array(t),count:e}}function $e(o,t,e,n,i){if(n<=0)return{vertices:new Float32Array(0),count:0};const r=i*Math.PI/180,s=-Math.cos(r),a=Math.sin(r),l=[];let c=0;for(let u=0;u<t.length;u++){const f=t[u],g=((u+1<t.length?t[u+1]:o.length)-f)/2;if(g<3)continue;const d=g-1;let y=0;for(let T=0;T<d;T++){const w=f+T*2,A=o[w],D=o[w+1],P=o[w+2],_=o[w+3];y+=A*_-P*D}const E=y>=0?1:-1,b=[],p=[];for(let T=0;T<d;T++){const w=f+T*2,A=o[w+2]-o[w],D=o[w+3]-o[w+1],P=Math.sqrt(A*A+D*D);P<1e-8?(b.push(T>0?b[T-1]:0),p.push(T>0?p[T-1]:0)):(b.push(-D/P*E),p.push(A/P*E))}const v=[],m=[];for(let T=0;T<d;T++){const w=(T-1+d)%d;let A=b[w]+b[T],D=p[w]+p[T];const P=Math.sqrt(A*A+D*D);P>1e-8?(A/=P,D/=P):(A=b[T],D=p[T]),v.push(A),m.push(D)}for(let T=0;T<d;T++){const w=T,A=(T+1)%d,D=f+T*2,P=f+(T+1)%d*2,_=o[D],M=o[D+1],C=o[P],S=o[P+1],F=v[w]*a,U=m[w]*a,I=s,O=v[A]*a,tt=m[A]*a,st=s,xt=_+v[w]*n,Kt=M+m[w]*n,Cn=C+v[A]*n,Un=S+m[A]*n;l.push(_,M,F,U,I,0),l.push(xt,Kt,F,U,I,1),l.push(C,S,O,tt,st,0),l.push(C,S,O,tt,st,0),l.push(xt,Kt,F,U,I,1),l.push(Cn,Un,O,tt,st,1),c+=6}}return{vertices:new Float32Array(l),count:c}}class Ke extends at{gl=null;stencilPass=null;maskPass=null;jfaSeedPass=null;jfaFloodPass=null;jfaDistPass=null;interiorPass=null;compositePass=null;boundaryPass=null;chamferPass=null;quadVao=null;stencilVao=null;stencilIndexCount=0;maskVao=null;boundaryVao=null;boundaryVertexCount=0;chamferVao=null;chamferVertexCount=0;textures=new Lt;videoSlot;depthSlot;interiorFbo=null;interiorColorTex=null;interiorDepthTex=null;fboWidth=0;fboHeight=0;jfa=null;hasColorBufferFloat=!1;meshAspect=1;meshScaleX=.65;meshScaleY=.65;lightDirX=-.707;lightDirY=.707;lightDir3=[-.5,.7,-.3];config;constructor(t,e){super(t),this.config={...e},this.videoSlot=this.textures.register("video"),this.depthSlot=this.textures.register("depth");const n=this.config.bevelLightAngle*Math.PI/180;this.lightDirX=Math.cos(n),this.lightDirY=Math.sin(n);const i=this.config.lightDirection,r=Math.sqrt(i[0]*i[0]+i[1]*i[1]+i[2]*i[2]);r>1e-6&&(this.lightDir3=[i[0]/r,i[1]/r,i[2]/r]);const s=this.canvas.getContext("webgl2",{antialias:!0,alpha:!0,premultipliedAlpha:!0,stencil:!0,desynchronized:!0,powerPreference:"high-performance"});if(!s)throw new Error("WebGL 2 is not supported.");this.gl=s,this.qualityParams=_t(s,e.quality),"drawingBufferColorSpace"in s&&(s.drawingBufferColorSpace="srgb"),this.hasColorBufferFloat=!!s.getExtension("EXT_color_buffer_float"),s.clearColor(0,0,0,0),s.pixelStorei(s.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.setupResizeHandling()}initialize(t,e,n,i){const r=this.gl;r&&(this.disposeTextures(),this.disposeFBO(),this.jfa&&(this.jfa.dispose(),this.jfa=null),this.disposeStencilGeometry(),this.disposeBoundaryGeometry(),this.disposeChamferGeometry(),this.isCameraSource=t.type==="camera",this.videoAspect=t.width/t.height,this.meshAspect=i.aspect,this.clampDepthDimensions(e,n,this.qualityParams.depthMaxDim),this.videoSlot.texture=r.createTexture(),r.activeTexture(r.TEXTURE0+this.videoSlot.unit),r.bindTexture(r.TEXTURE_2D,this.videoSlot.texture),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),this.depthSlot.texture=r.createTexture(),r.activeTexture(r.TEXTURE0+this.depthSlot.unit),r.bindTexture(r.TEXTURE_2D,this.depthSlot.texture),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),r.texStorage2D(r.TEXTURE_2D,1,r.R8,this.depthWidth,this.depthHeight),this.uploadStencilMesh(i),this.uploadMaskMesh(i),this.uploadBoundaryMesh(i),this.uploadChamferMesh(i),this.interiorPass&&(r.useProgram(this.interiorPass.program),r.uniform1i(this.interiorPass.uniforms.uImage,0),r.uniform1i(this.interiorPass.uniforms.uDepth,1),r.uniform1f(this.interiorPass.uniforms.uStrength,this.config.parallaxStrength),r.uniform1i(this.interiorPass.uniforms.uPomSteps,this.config.pomSteps),r.uniform1f(this.interiorPass.uniforms.uDepthPower,this.config.depthPower),r.uniform1f(this.interiorPass.uniforms.uDepthScale,this.config.depthScale),r.uniform1f(this.interiorPass.uniforms.uDepthBias,this.config.depthBias),r.uniform1f(this.interiorPass.uniforms.uContrastLow,this.config.contrastLow),r.uniform1f(this.interiorPass.uniforms.uContrastHigh,this.config.contrastHigh),r.uniform1f(this.interiorPass.uniforms.uVerticalReduction,this.config.verticalReduction),r.uniform1f(this.interiorPass.uniforms.uDofStart,this.config.dofStart),r.uniform1f(this.interiorPass.uniforms.uDofStrength,this.config.dofStrength),r.uniform2f(this.interiorPass.uniforms.uImageTexelSize,1/t.width,1/t.height),r.uniform1f(this.interiorPass.uniforms.uFogDensity,this.config.fogDensity),r.uniform3f(this.interiorPass.uniforms.uFogColor,...this.config.fogColor),r.uniform1f(this.interiorPass.uniforms.uColorShift,this.config.colorShift),r.uniform1f(this.interiorPass.uniforms.uBrightnessBias,this.config.brightnessBias)),this.compositePass&&(r.useProgram(this.compositePass.program),r.uniform1i(this.compositePass.uniforms.uInteriorColor,2),r.uniform1i(this.compositePass.uniforms.uDistField,4),r.uniform1f(this.compositePass.uniforms.uEdgeOcclusionWidth,this.config.edgeOcclusionWidth),r.uniform1f(this.compositePass.uniforms.uEdgeOcclusionStrength,this.config.edgeOcclusionStrength)),this.chamferPass&&(r.useProgram(this.chamferPass.program),r.uniform3f(this.chamferPass.uniforms.uLightDir3,...this.lightDir3),r.uniform3f(this.chamferPass.uniforms.uChamferColor,...this.config.chamferColor),r.uniform1f(this.chamferPass.uniforms.uChamferAmbient,this.config.chamferAmbient),r.uniform1f(this.chamferPass.uniforms.uChamferSpecular,this.config.chamferSpecular),r.uniform1f(this.chamferPass.uniforms.uChamferShininess,this.config.chamferShininess),r.uniform1i(this.chamferPass.uniforms.uInteriorColor,2)),this.boundaryPass&&(r.useProgram(this.boundaryPass.program),r.uniform1i(this.boundaryPass.uniforms.uInteriorColor,2),r.uniform1i(this.boundaryPass.uniforms.uInteriorDepth,3),r.uniform1i(this.boundaryPass.uniforms.uDistField,4),r.uniform1f(this.boundaryPass.uniforms.uRimIntensity,this.config.rimLightIntensity),r.uniform3f(this.boundaryPass.uniforms.uRimColor,...this.config.rimLightColor),r.uniform1f(this.boundaryPass.uniforms.uRefractionStrength,this.config.refractionStrength),r.uniform1f(this.boundaryPass.uniforms.uChromaticStrength,this.config.chromaticStrength),r.uniform1f(this.boundaryPass.uniforms.uOcclusionIntensity,this.config.occlusionIntensity),r.uniform1f(this.boundaryPass.uniforms.uEdgeThickness,this.config.edgeThickness),r.uniform1f(this.boundaryPass.uniforms.uEdgeSpecular,this.config.edgeSpecular),r.uniform3f(this.boundaryPass.uniforms.uEdgeColor,...this.config.edgeColor),r.uniform2f(this.boundaryPass.uniforms.uLightDir,this.lightDirX,this.lightDirY),r.uniform1f(this.boundaryPass.uniforms.uBevelIntensity,this.config.bevelIntensity)),this.recalculateViewportLayout())}uploadStencilMesh(t){const e=this.gl;if(!e||!this.stencilPass)return;this.stencilVao=e.createVertexArray(),e.bindVertexArray(this.stencilVao);const n=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,n),e.bufferData(e.ARRAY_BUFFER,t.vertices,e.STATIC_DRAW);const i=e.getAttribLocation(this.stencilPass.program,"aPosition");e.enableVertexAttribArray(i),e.vertexAttribPointer(i,2,e.FLOAT,!1,0,0);const r=e.createBuffer();e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,r),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t.indices,e.STATIC_DRAW),this.stencilIndexCount=t.indices.length,e.bindVertexArray(null)}uploadMaskMesh(t){const e=this.gl;if(!e||!this.maskPass)return;this.maskVao=e.createVertexArray(),e.bindVertexArray(this.maskVao);const n=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,n),e.bufferData(e.ARRAY_BUFFER,t.vertices,e.STATIC_DRAW);const i=e.getAttribLocation(this.maskPass.program,"aPosition");e.enableVertexAttribArray(i),e.vertexAttribPointer(i,2,e.FLOAT,!1,0,0);const r=e.createBuffer();e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,r),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t.indices,e.STATIC_DRAW),e.bindVertexArray(null)}uploadBoundaryMesh(t){const e=this.gl;if(!e||!this.boundaryPass)return;const n=Ze(t.edgeVertices);if(n.count===0)return;this.boundaryVao=e.createVertexArray(),e.bindVertexArray(this.boundaryVao);const i=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,n.vertices,e.STATIC_DRAW);const r=16,s=e.getAttribLocation(this.boundaryPass.program,"aPosition");e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,r,0);const a=e.getAttribLocation(this.boundaryPass.program,"aNormal");a>=0&&(e.enableVertexAttribArray(a),e.vertexAttribPointer(a,2,e.FLOAT,!1,r,8)),this.boundaryVertexCount=n.count,e.bindVertexArray(null)}uploadChamferMesh(t){const e=this.gl;if(!e||!this.chamferPass||this.config.chamferWidth<=0)return;const n=$e(t.edgeVertices,t.contourOffsets,t.contourIsHole,this.config.chamferWidth,this.config.chamferAngle);if(n.count===0)return;this.chamferVao=e.createVertexArray(),e.bindVertexArray(this.chamferVao);const i=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,n.vertices,e.STATIC_DRAW);const r=24,s=e.getAttribLocation(this.chamferPass.program,"aPosition");e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,r,0);const a=e.getAttribLocation(this.chamferPass.program,"aNormal3");a>=0&&(e.enableVertexAttribArray(a),e.vertexAttribPointer(a,3,e.FLOAT,!1,r,8));const l=e.getAttribLocation(this.chamferPass.program,"aLerpT");l>=0&&(e.enableVertexAttribArray(l),e.vertexAttribPointer(l,1,e.FLOAT,!1,r,20)),this.chamferVertexCount=n.count,e.bindVertexArray(null)}disposeChamferGeometry(){const t=this.gl;t&&(this.chamferVao&&(t.deleteVertexArray(this.chamferVao),this.chamferVao=null),this.chamferVertexCount=0)}createFBO(t,e){const n=this.gl;if(!n)return;this.disposeFBO(),this.fboWidth=t,this.fboHeight=e,this.interiorFbo=n.createFramebuffer(),n.bindFramebuffer(n.FRAMEBUFFER,this.interiorFbo),this.interiorColorTex=n.createTexture(),n.activeTexture(n.TEXTURE2),n.bindTexture(n.TEXTURE_2D,this.interiorColorTex),n.texStorage2D(n.TEXTURE_2D,1,n.RGBA8,t,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT0,n.TEXTURE_2D,this.interiorColorTex,0),this.interiorDepthTex=n.createTexture(),n.activeTexture(n.TEXTURE3),n.bindTexture(n.TEXTURE_2D,this.interiorDepthTex),n.texStorage2D(n.TEXTURE_2D,1,n.RGBA8,t,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MAG_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.framebufferTexture2D(n.FRAMEBUFFER,n.COLOR_ATTACHMENT1,n.TEXTURE_2D,this.interiorDepthTex,0),n.drawBuffers([n.COLOR_ATTACHMENT0,n.COLOR_ATTACHMENT1]);const i=n.checkFramebufferStatus(n.FRAMEBUFFER);i!==n.FRAMEBUFFER_COMPLETE&&console.error("Interior FBO incomplete:",i),n.bindFramebuffer(n.FRAMEBUFFER,null)}createJFAResources(t,e){const n=this.gl;n&&(this.jfa||(this.jfa=new wt(n,this.hasColorBufferFloat)),this.jfa.createResources(t,e,this.qualityParams.jfaDivisor))}computeDistanceField(){!this.jfa||!this.maskPass||!this.jfaSeedPass||!this.jfaFloodPass||!this.jfaDistPass||!this.maskVao||!this.quadVao||this.jfa.compute({maskPass:this.maskPass,seedPass:this.jfaSeedPass,floodPass:this.jfaFloodPass,distPass:this.jfaDistPass,maskVao:this.maskVao,quadVao:this.quadVao,meshScaleX:this.meshScaleX,meshScaleY:this.meshScaleY,stencilIndexCount:this.stencilIndexCount,distRange:Math.max(this.config.bevelWidth,this.config.edgeOcclusionWidth)})}initGPUResources(){const t=this.gl;t&&(this.stencilPass=X(t,"stencil",Ue,Le,["uMeshScale"]),this.maskPass=X(t,"mask",_e,Me,["uMeshScale"]),this.jfaSeedPass=X(t,"jfa-seed",Ie,Be,["uMask","uTexelSize"]),this.jfaFloodPass=X(t,"jfa-flood",Ve,Oe,["uSeedTex","uStepSize"]),this.jfaDistPass=X(t,"jfa-dist",ke,Xe,["uSeedTex","uMask","uBevelWidth"]),this.interiorPass=X(t,"interior",Ne,He,["uImage","uDepth","uOffset","uStrength","uPomSteps","uDepthPower","uDepthScale","uDepthBias","uContrastLow","uContrastHigh","uVerticalReduction","uDofStart","uDofStrength","uImageTexelSize","uFogDensity","uFogColor","uColorShift","uBrightnessBias","uUvOffset","uUvScale"]),this.compositePass=X(t,"composite",Ge,We,["uInteriorColor","uDistField","uEdgeOcclusionWidth","uEdgeOcclusionStrength"]),this.boundaryPass=X(t,"boundary",ze,qe,["uInteriorColor","uInteriorDepth","uDistField","uRimIntensity","uRimColor","uRimWidth","uMeshScale","uRefractionStrength","uChromaticStrength","uOcclusionIntensity","uTexelSize","uEdgeThickness","uEdgeSpecular","uEdgeColor","uLightDir","uBevelIntensity"]),this.chamferPass=X(t,"chamfer",Ye,je,["uMeshScale","uLightDir3","uChamferColor","uChamferAmbient","uChamferSpecular","uChamferShininess","uInteriorColor","uTexelSize"]),this.quadVao=Ut(t,this.interiorPass.program),t.disable(t.DEPTH_TEST))}onRenderFrame(){const t=this.gl,e=this.mediaSource;if(!t||!this.interiorPass||!this.quadVao)return;const n=e?.getImageSource();if(!n||!this.interiorFbo||!this.interiorColorTex||!this.interiorDepthTex)return;this.jfa?.isDirty&&this.maskVao&&(this.computeDistanceField(),t.viewport(0,0,this.canvas.width,this.canvas.height)),t.activeTexture(t.TEXTURE0+this.videoSlot.unit),t.bindTexture(t.TEXTURE_2D,this.videoSlot.texture),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,n),this.rvfcSupported||this.onDepthUpdate(e.currentTime);let i=0,r=0;if(this.readInput){const s=this.readInput();i=-s.x,r=s.y}if(t.bindFramebuffer(t.FRAMEBUFFER,this.interiorFbo),t.checkFramebufferStatus(t.FRAMEBUFFER)!==t.FRAMEBUFFER_COMPLETE){t.bindFramebuffer(t.FRAMEBUFFER,null);return}t.viewport(0,0,this.fboWidth,this.fboHeight),t.clearColor(0,0,0,1),t.clear(t.COLOR_BUFFER_BIT),t.useProgram(this.interiorPass.program),t.uniform2f(this.interiorPass.uniforms.uOffset,i,r),t.activeTexture(t.TEXTURE0+this.videoSlot.unit),t.bindTexture(t.TEXTURE_2D,this.videoSlot.texture),t.activeTexture(t.TEXTURE0+this.depthSlot.unit),t.bindTexture(t.TEXTURE_2D,this.depthSlot.texture),t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4),t.bindFramebuffer(t.FRAMEBUFFER,null),t.clearColor(0,0,0,0),t.viewport(0,0,this.canvas.width,this.canvas.height),t.clear(t.COLOR_BUFFER_BIT|t.STENCIL_BUFFER_BIT),this.stencilVao&&this.stencilPass&&this.stencilIndexCount>0&&(t.enable(t.STENCIL_TEST),t.stencilFunc(t.ALWAYS,1,255),t.stencilOp(t.KEEP,t.KEEP,t.REPLACE),t.stencilMask(255),t.colorMask(!1,!1,!1,!1),t.useProgram(this.stencilPass.program),t.bindVertexArray(this.stencilVao),t.drawElements(t.TRIANGLES,this.stencilIndexCount,t.UNSIGNED_SHORT,0),t.colorMask(!0,!0,!0,!0)),t.stencilFunc(t.EQUAL,1,255),t.stencilMask(0),t.activeTexture(t.TEXTURE2),t.bindTexture(t.TEXTURE_2D,this.interiorColorTex),t.activeTexture(t.TEXTURE3),t.bindTexture(t.TEXTURE_2D,this.interiorDepthTex),t.activeTexture(t.TEXTURE4),t.bindTexture(t.TEXTURE_2D,this.jfa?.distanceTexture??null),t.useProgram(this.compositePass.program),t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4),t.disable(t.STENCIL_TEST),this.chamferVao&&this.chamferPass&&this.chamferVertexCount>0&&(t.useProgram(this.chamferPass.program),t.uniform2f(this.chamferPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY),t.uniform2f(this.chamferPass.uniforms.uTexelSize,1/this.canvas.width,1/this.canvas.height),t.bindVertexArray(this.chamferVao),t.drawArrays(t.TRIANGLES,0,this.chamferVertexCount)),this.boundaryVao&&this.boundaryPass&&this.boundaryVertexCount>0&&this.config.rimLightIntensity>0&&(t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA),t.useProgram(this.boundaryPass.program),t.bindVertexArray(this.boundaryVao),t.drawArrays(t.TRIANGLES,0,this.boundaryVertexCount),t.disable(t.BLEND))}onDepthUpdate(t){const e=this.gl;if(!e||!this.readDepth||!this.depthSlot.texture)return;const n=this.subsampleDepth(this.readDepth(t));e.activeTexture(e.TEXTURE0+this.depthSlot.unit),e.bindTexture(e.TEXTURE_2D,this.depthSlot.texture),e.texSubImage2D(e.TEXTURE_2D,0,0,0,this.depthWidth,this.depthHeight,e.RED,e.UNSIGNED_BYTE,n)}recalculateViewportLayout(){const t=this.gl;if(!t)return;const{width:e,height:n}=this.getViewportSize(),i=Math.min(window.devicePixelRatio,this.qualityParams.dprCap),r=Math.round(e*i),s=Math.round(n*i);(this.canvas.width!==r||this.canvas.height!==s)&&(this.canvas.width=r,this.canvas.height=s,t.viewport(0,0,r,s)),(this.fboWidth!==r||this.fboHeight!==s)&&this.createFBO(r,s);const a=this.qualityParams.jfaDivisor,l=Math.max(1,Math.round(r/a)),c=Math.max(1,Math.round(s/a));(!this.jfa||this.jfa.width!==l||this.jfa.height!==c)&&this.createJFAResources(r,s),this.computeCoverFitUV(this.config.parallaxStrength,this.config.overscanPadding),this.interiorPass&&(t.useProgram(this.interiorPass.program),t.uniform2f(this.interiorPass.uniforms.uUvOffset,this.uvOffset[0],this.uvOffset[1]),t.uniform2f(this.interiorPass.uniforms.uUvScale,this.uvScale[0],this.uvScale[1]));const u=e/n,f=.65;this.meshScaleX=f,this.meshScaleY=f,u>this.meshAspect?this.meshScaleX=f*(this.meshAspect/u):this.meshScaleY=f*(u/this.meshAspect),this.stencilPass&&(t.useProgram(this.stencilPass.program),t.uniform2f(this.stencilPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY)),this.boundaryPass&&(t.useProgram(this.boundaryPass.program),t.uniform2f(this.boundaryPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY),t.uniform1f(this.boundaryPass.uniforms.uRimWidth,this.config.rimLightWidth),t.uniform2f(this.boundaryPass.uniforms.uTexelSize,1/r,1/s)),this.chamferPass&&(t.useProgram(this.chamferPass.program),t.uniform2f(this.chamferPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY)),this.jfa&&this.jfa.markDirty()}onContextRestored(){const t=this.canvas.getContext("webgl2",{alpha:!0,premultipliedAlpha:!0,stencil:!0});t&&(this.gl=t,this.hasColorBufferFloat=!!t.getExtension("EXT_color_buffer_float"),t.clearColor(0,0,0,0),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),this.initGPUResources(),this.recalculateViewportLayout(),this.mediaSource&&(this.animationFrameHandle=window.requestAnimationFrame(()=>this.onRenderFrame())))}disposeTextures(){const t=this.gl;t&&this.textures.disposeAll(t)}disposeFBO(){const t=this.gl;t&&(this.interiorColorTex&&(t.deleteTexture(this.interiorColorTex),this.interiorColorTex=null),this.interiorDepthTex&&(t.deleteTexture(this.interiorDepthTex),this.interiorDepthTex=null),this.interiorFbo&&(t.deleteFramebuffer(this.interiorFbo),this.interiorFbo=null),this.fboWidth=0,this.fboHeight=0)}disposeStencilGeometry(){const t=this.gl;t&&(this.stencilVao&&(t.deleteVertexArray(this.stencilVao),this.stencilVao=null),this.maskVao&&(t.deleteVertexArray(this.maskVao),this.maskVao=null),this.stencilIndexCount=0)}disposeBoundaryGeometry(){const t=this.gl;t&&(this.boundaryVao&&(t.deleteVertexArray(this.boundaryVao),this.boundaryVao=null),this.boundaryVertexCount=0)}disposeRenderer(){this.disposeTextures(),this.disposeFBO(),this.jfa&&(this.jfa.dispose(),this.jfa=null),this.disposeStencilGeometry(),this.disposeBoundaryGeometry(),this.disposeChamferGeometry(),this.disposeGPUResources(),this.gl&&(this.gl.getExtension("WEBGL_lose_context")?.loseContext(),this.gl=null)}disposeGPUResources(){const t=this.gl;if(!t)return;const e=[this.stencilPass,this.maskPass,this.jfaSeedPass,this.jfaFloodPass,this.jfaDistPass,this.interiorPass,this.compositePass,this.boundaryPass,this.chamferPass];for(const n of e)n&&n.dispose(t);this.stencilPass=null,this.maskPass=null,this.jfaSeedPass=null,this.jfaFloodPass=null,this.jfaDistPass=null,this.interiorPass=null,this.compositePass=null,this.boundaryPass=null,this.chamferPass=null,this.quadVao&&(t.deleteVertexArray(this.quadVao),this.quadVao=null)}}async function At(o){const t=await fetch(o);if(!t.ok)throw new Error(`Failed to fetch SVG: ${t.status} ${t.statusText}`);const e=await t.text();return Je(e)}function Je(o){const n=new DOMParser().parseFromString(o,"image/svg+xml").querySelector("svg");if(!n)throw new Error("No <svg> element found in document.");const i=Qe(n);if(i.length===0)throw new Error("No path data found in SVG.");let r=1/0,s=1/0,a=-1/0,l=-1/0;for(const C of i)for(let S=0;S<C.length;S+=2)r=Math.min(r,C[S]),a=Math.max(a,C[S]),s=Math.min(s,C[S+1]),l=Math.max(l,C[S+1]);const c=a-r,u=l-s,f=(r+a)/2,h=(s+l)/2,x=2/Math.max(c,u),g=c/u,d=i.map(C=>{const S=[];for(let F=0;F<C.length;F+=2)S.push((C[F]-f)*x),S.push(-((C[F+1]-h)*x));return S}),y=ln(d),E=[],b=[];for(const C of y){const{flatCoords:S,holeIndices:F}=an(C),U=un(S,F),I=E.length/2;for(const O of U)b.push(O+I);for(const O of S)E.push(O)}const p=E,v=b,m=[],T=[],w=[],A=Gt(d);for(let C=0;C<d.length;C++){const S=d[C];T.push(m.length),w.push(A[C]);for(let F=0;F<S.length;F++)m.push(S[F]);S.length>=2&&m.push(S[0],S[1])}let D=1/0,P=1/0,_=-1/0,M=-1/0;for(let C=0;C<p.length;C+=2)D=Math.min(D,p[C]),_=Math.max(_,p[C]),P=Math.min(P,p[C+1]),M=Math.max(M,p[C+1]);return{vertices:new Float32Array(p),indices:new Uint16Array(v),edgeVertices:new Float32Array(m),contourOffsets:T,contourIsHole:w,bounds:{minX:D,maxX:_,minY:P,maxY:M},aspect:g}}function Qe(o){const t=[];return o.querySelectorAll("path").forEach(l=>{const c=l.getAttribute("d");if(!c)return;const u=nn(c);t.push(...u)}),o.querySelectorAll("polygon").forEach(l=>{const c=l.getAttribute("points");if(!c)return;const u=Xt(c);u.length>=6&&t.push(u)}),o.querySelectorAll("polyline").forEach(l=>{const c=l.getAttribute("points");if(!c)return;const u=Xt(c);u.length>=6&&t.push(u)}),o.querySelectorAll("rect").forEach(l=>{const c=parseFloat(l.getAttribute("x")||"0"),u=parseFloat(l.getAttribute("y")||"0"),f=parseFloat(l.getAttribute("width")||"0"),h=parseFloat(l.getAttribute("height")||"0");f>0&&h>0&&t.push([c,u,c+f,u,c+f,u+h,c,u+h])}),o.querySelectorAll("circle").forEach(l=>{const c=parseFloat(l.getAttribute("cx")||"0"),u=parseFloat(l.getAttribute("cy")||"0"),f=parseFloat(l.getAttribute("r")||"0");f>0&&t.push(tn(c,u,f))}),o.querySelectorAll("ellipse").forEach(l=>{const c=parseFloat(l.getAttribute("cx")||"0"),u=parseFloat(l.getAttribute("cy")||"0"),f=parseFloat(l.getAttribute("rx")||"0"),h=parseFloat(l.getAttribute("ry")||"0");f>0&&h>0&&t.push(en(c,u,f,h))}),t}function Xt(o){const t=[],e=o.trim().split(/[\s,]+/);for(let n=0;n<e.length-1;n+=2){const i=parseFloat(e[n]),r=parseFloat(e[n+1]);Number.isFinite(i)&&Number.isFinite(r)&&t.push(i,r)}return t}function tn(o,t,e,n=64){const i=[];for(let r=0;r<n;r++){const s=2*Math.PI*r/n;i.push(o+e*Math.cos(s),t+e*Math.sin(s))}return i}function en(o,t,e,n,i=64){const r=[];for(let s=0;s<i;s++){const a=2*Math.PI*s/i;r.push(o+e*Math.cos(a),t+n*Math.sin(a))}return r}function nn(o){const t=[];let e=[],n=0,i=0,r=0,s=0,a=0,l=0,c="";const u=rn(o);let f=0;function h(){return f>=u.length?0:parseFloat(u[f++])}for(;f<u.length;){const x=u[f];let g;/^[a-zA-Z]$/.test(x)?(g=x,f++):g=c==="M"?"L":c==="m"?"l":c;const d=g===g.toLowerCase();switch(g.toUpperCase()){case"M":{e.length>0&&t.push(e),e=[];const E=h()+(d?n:0),b=h()+(d?i:0);n=E,i=b,r=E,s=b,e.push(n,i),a=n,l=i;break}case"L":{n=h()+(d?n:0),i=h()+(d?i:0),e.push(n,i),a=n,l=i;break}case"H":{n=h()+(d?n:0),e.push(n,i),a=n,l=i;break}case"V":{i=h()+(d?i:0),e.push(n,i),a=n,l=i;break}case"C":{const E=h()+(d?n:0),b=h()+(d?i:0),p=h()+(d?n:0),v=h()+(d?i:0),m=h()+(d?n:0),T=h()+(d?i:0);nt(e,n,i,E,b,p,v,m,T),n=m,i=T,a=p,l=v;break}case"S":{const E=2*n-a,b=2*i-l,p=h()+(d?n:0),v=h()+(d?i:0),m=h()+(d?n:0),T=h()+(d?i:0);nt(e,n,i,E,b,p,v,m,T),n=m,i=T,a=p,l=v;break}case"Q":{const E=h()+(d?n:0),b=h()+(d?i:0),p=h()+(d?n:0),v=h()+(d?i:0);Nt(e,n,i,E,b,p,v),n=p,i=v,a=E,l=b;break}case"T":{const E=2*n-a,b=2*i-l,p=h()+(d?n:0),v=h()+(d?i:0);Nt(e,n,i,E,b,p,v),n=p,i=v,a=E,l=b;break}case"A":{const E=h(),b=h(),p=h(),v=h(),m=h(),T=h()+(d?n:0),w=h()+(d?i:0);sn(e,n,i,E,b,p,!!v,!!m,T,w),n=T,i=w,a=n,l=i;break}case"Z":{n=r,i=s,e.length>0&&t.push(e),e=[],a=n,l=i;break}default:f++;break}c=g}return e.length>=6&&t.push(e),t}function rn(o){const t=[],e=/([a-zA-Z])|([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)/g;let n;for(;(n=e.exec(o))!==null;)t.push(n[0]);return t}const on=.5;function nt(o,t,e,n,i,r,s,a,l,c=0){if(c>12){o.push(a,l);return}const u=a-t,f=l-e,h=Math.sqrt(u*u+f*f);if(h<1e-6){o.push(a,l);return}const x=Math.abs((n-a)*f-(i-l)*u)/h,g=Math.abs((r-a)*f-(s-l)*u)/h;if(x+g<on){o.push(a,l);return}const d=(t+n)/2,y=(e+i)/2,E=(n+r)/2,b=(i+s)/2,p=(r+a)/2,v=(s+l)/2,m=(d+E)/2,T=(y+b)/2,w=(E+p)/2,A=(b+v)/2,D=(m+w)/2,P=(T+A)/2;nt(o,t,e,d,y,m,T,D,P,c+1),nt(o,D,P,w,A,p,v,a,l,c+1)}function Nt(o,t,e,n,i,r,s){const a=t+.6666666666666666*(n-t),l=e+2/3*(i-e),c=r+2/3*(n-r),u=s+2/3*(i-s);nt(o,t,e,a,l,c,u,r,s)}function sn(o,t,e,n,i,r,s,a,l,c){if(n===0||i===0){o.push(l,c);return}let u=Math.abs(n),f=Math.abs(i);const h=r*Math.PI/180,x=Math.cos(h),g=Math.sin(h),d=(t-l)/2,y=(e-c)/2,E=x*d+g*y,b=-g*d+x*y;let p=E*E/(u*u)+b*b/(f*f);if(p>1){const U=Math.sqrt(p);u*=U,f*=U,p=1}const v=u*u,m=f*f,T=E*E,w=b*b;let A=Math.max(0,(v*m-v*w-m*T)/(v*w+m*T));A=Math.sqrt(A),s===a&&(A=-A);const D=A*(u*b)/f,P=A*-(f*E)/u,_=x*D-g*P+(t+l)/2,M=g*D+x*P+(e+c)/2,C=Ht(1,0,(E-D)/u,(b-P)/f);let S=Ht((E-D)/u,(b-P)/f,(-E-D)/u,(-b-P)/f);!a&&S>0&&(S-=2*Math.PI),a&&S<0&&(S+=2*Math.PI);const F=Math.max(4,Math.ceil(Math.abs(S)/(Math.PI/16)));for(let U=1;U<=F;U++){const I=C+U/F*S,O=Math.cos(I),tt=Math.sin(I),st=x*u*O-g*f*tt+_,xt=g*u*O+x*f*tt+M;o.push(st,xt)}}function Ht(o,t,e,n){const i=o*n-t*e<0?-1:1,r=o*e+t*n,s=Math.sqrt(o*o+t*t),a=Math.sqrt(e*e+n*n),l=r/(s*a);return i*Math.acos(Math.max(-1,Math.min(1,l)))}function an(o){const t=[],e=[];for(let n=0;n<o.length;n++){n>0&&e.push(t.length/2);for(const i of o[n])t.push(i)}return{flatCoords:t,holeIndices:e}}function Gt(o){const t=o.length,e=o.map(i=>Math.abs(Wt(i))),n=new Array(t).fill(!1);for(let i=0;i<t;i++){let r=0;const s=o[i][0],a=o[i][1];for(let l=0;l<t;l++)i!==l&&e[l]>e[i]&&zt(s,a,o[l])&&r++;n[i]=r%2===1}return n}function ln(o){if(o.length<=1)return[o];const t=Gt(o),e=o.map((s,a)=>{const l=Wt(s);return{index:a,contour:s,area:l,isOuter:!t[a]}}),n=e.filter(s=>s.isOuter),i=e.filter(s=>!s.isOuter);if(n.length===0)return o.map(s=>[s]);const r=n.map(s=>({outer:s.contour,holes:[]}));for(const s of i){const a=s.contour[0],l=s.contour[1];let c=-1,u=1/0;for(let f=0;f<n.length;f++)if(zt(a,l,n[f].contour)){const h=Math.abs(n[f].area);h<u&&(u=h,c=f)}c>=0?r[c].holes.push(s.contour):r.push({outer:s.contour,holes:[]})}return r.map(s=>[s.outer,...s.holes])}function Wt(o){let t=0;const e=o.length;for(let n=0;n<e;n+=2){const i=o[n],r=o[n+1],s=o[(n+2)%e],a=o[(n+3)%e];t+=i*a-s*r}return t/2}function zt(o,t,e){let n=!1;const i=e.length;for(let r=0,s=i-2;r<i;s=r,r+=2){const a=e[r],l=e[r+1],c=e[s],u=e[s+1];l>t!=u>t&&o<(c-a)*(t-l)/(u-l)+a&&(n=!n)}return n}function un(o,t,e=2){const n=t&&t.length>0,i=n?t[0]*e:o.length;let r=qt(o,0,i,e,!0);const s=[];if(!r||r.next===r.prev)return s;n&&(r=mn(o,t,r,e));let a=1/0,l=1/0,c=-1/0,u=-1/0,f=0;if(o.length>80*e){for(let h=0;h<i;h+=e){const x=o[h],g=o[h+1];x<a&&(a=x),g<l&&(l=g),x>c&&(c=x),g>u&&(u=g)}f=Math.max(c-a,u-l),f=f!==0?32767/f:0}return it(r,s,e,a,l,f,0),s}function qt(o,t,e,n,i){let r=null;if(i===wn(o,t,e,n)>0)for(let s=t;s<e;s+=n)r=Zt(s,o[s],o[s+1],r);else for(let s=e-n;s>=t;s-=n)r=Zt(s,o[s],o[s+1],r);return r&&dt(r,r.next)&&(ot(r),r=r.next),r?(r.next.prev=r,r.prev.next=r,r.next):null}function q(o,t){t||(t=o);let e=o,n;do if(n=!1,!e.steiner&&(dt(e,e.next)||L(e.prev,e,e.next)===0)){if(ot(e),e=t=e.prev,e===e.next)break;n=!0}else e=e.next;while(n||e!==t);return t}function it(o,t,e,n,i,r,s){if(!o)return;!s&&r&&xn(o,n,i,r);let a=o,l,c;for(;o.prev!==o.next;){if(l=o.prev,c=o.next,r?hn(o,n,i,r):cn(o)){t.push(l.i/e,o.i/e,c.i/e),ot(o),o=c.next,a=c.next;continue}if(o=c,o===a){s?s===1?(o=fn(q(o),t,e),it(o,t,e,n,i,r,2)):s===2&&dn(o,t,e,n,i,r):it(q(o),t,e,n,i,r,1);break}}}function cn(o){const t=o.prev,e=o,n=o.next;if(L(t,e,n)>=0)return!1;const i=t.x,r=e.x,s=n.x,a=t.y,l=e.y,c=n.y,u=i<r?i<s?i:s:r<s?r:s,f=a<l?a<c?a:c:l<c?l:c,h=i>r?i>s?i:s:r>s?r:s,x=a>l?a>c?a:c:l>c?l:c;let g=n.next;for(;g!==t;){if(g.x>=u&&g.x<=h&&g.y>=f&&g.y<=x&&K(i,a,r,l,s,c,g.x,g.y)&&L(g.prev,g,g.next)>=0)return!1;g=g.next}return!0}function hn(o,t,e,n){const i=o.prev,r=o,s=o.next;if(L(i,r,s)>=0)return!1;const a=i.x,l=r.x,c=s.x,u=i.y,f=r.y,h=s.y,x=a<l?a<c?a:c:l<c?l:c,g=u<f?u<h?u:h:f<h?f:h,d=a>l?a>c?a:c:l>c?l:c,y=u>f?u>h?u:h:f>h?f:h,E=Rt(x,g,t,e,n),b=Rt(d,y,t,e,n);let p=o.prevZ,v=o.nextZ;for(;p&&p.z>=E&&v&&v.z<=b;){if(p.x>=x&&p.x<=d&&p.y>=g&&p.y<=y&&p!==i&&p!==s&&K(a,u,l,f,c,h,p.x,p.y)&&L(p.prev,p,p.next)>=0||(p=p.prevZ,v.x>=x&&v.x<=d&&v.y>=g&&v.y<=y&&v!==i&&v!==s&&K(a,u,l,f,c,h,v.x,v.y)&&L(v.prev,v,v.next)>=0))return!1;v=v.nextZ}for(;p&&p.z>=E;){if(p.x>=x&&p.x<=d&&p.y>=g&&p.y<=y&&p!==i&&p!==s&&K(a,u,l,f,c,h,p.x,p.y)&&L(p.prev,p,p.next)>=0)return!1;p=p.prevZ}for(;v&&v.z<=b;){if(v.x>=x&&v.x<=d&&v.y>=g&&v.y<=y&&v!==i&&v!==s&&K(a,u,l,f,c,h,v.x,v.y)&&L(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function fn(o,t,e){let n=o;do{const i=n.prev,r=n.next.next;!dt(i,r)&&Yt(i,n,n.next,r)&&rt(i,r)&&rt(r,i)&&(t.push(i.i/e,n.i/e,r.i/e),ot(n),ot(n.next),n=o=r),n=n.next}while(n!==o);return q(n)}function dn(o,t,e,n,i,r){let s=o;do{let a=s.next.next;for(;a!==s.prev;){if(s.i!==a.i&&bn(s,a)){let l=jt(s,a);s=q(s,s.next),l=q(l,l.next),it(s,t,e,n,i,r,0),it(l,t,e,n,i,r,0);return}a=a.next}s=s.next}while(s!==o)}function mn(o,t,e,n){const i=[];for(let r=0;r<t.length;r++){const s=t[r]*n,a=r<t.length-1?t[r+1]*n:o.length,l=qt(o,s,a,n,!1);l&&(l===l.next&&(l.steiner=!0),i.push(En(l)))}i.sort((r,s)=>r.x-s.x);for(const r of i)e=pn(r,e);return e}function pn(o,t){const e=gn(o,t);if(!e)return t;const n=jt(e,o);return q(n,n.next),q(e,e.next)}function gn(o,t){let e=t;const n=o.x,i=o.y;let r=-1/0,s=null;do{if(i<=e.y&&i>=e.next.y&&e.next.y!==e.y){const f=e.x+(i-e.y)/(e.next.y-e.y)*(e.next.x-e.x);if(f<=n&&f>r&&(r=f,s=e.x<e.next.x?e:e.next,f===n))return s}e=e.next}while(e!==t);if(!s)return null;const a=s,l=s.x,c=s.y;let u=1/0;e=s;do{if(n>=e.x&&e.x>=l&&n!==e.x&&K(i<c?n:r,i,l,c,i<c?r:n,i,e.x,e.y)){const f=Math.abs(i-e.y)/(n-e.x);rt(e,o)&&(f<u||f===u&&(e.x>s.x||vn(s,e)))&&(s=e,u=f)}e=e.next}while(e!==a);return s}function vn(o,t){return L(o.prev,o,t.prev)<0&&L(t.next,o,o.next)<0}function xn(o,t,e,n){let i=o;do i.z===0&&(i.z=Rt(i.x,i.y,t,e,n)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next;while(i!==o);i.prevZ.nextZ=null,i.prevZ=null,Tn(i)}function Tn(o){let t=1,e;do{let n=o;o=null;let i=null;for(e=0;n;){e++;let r=n,s=0;for(let l=0;l<t&&(s++,r=r.nextZ,!!r);l++);let a=t;for(;s>0||a>0&&r;){let l;s!==0&&(a===0||!r||n.z<=r.z)?(l=n,n=n.nextZ,s--):(l=r,r=r.nextZ,a--),i?i.nextZ=l:o=l,l.prevZ=i,i=l}n=r}i.nextZ=null,t*=2}while(e>1);return o}function Rt(o,t,e,n,i){let r=(o-e)*i|0,s=(t-n)*i|0;return r=(r|r<<8)&16711935,r=(r|r<<4)&252645135,r=(r|r<<2)&858993459,r=(r|r<<1)&1431655765,s=(s|s<<8)&16711935,s=(s|s<<4)&252645135,s=(s|s<<2)&858993459,s=(s|s<<1)&1431655765,r|s<<1}function En(o){let t=o,e=o;do(t.x<e.x||t.x===e.x&&t.y<e.y)&&(e=t),t=t.next;while(t!==o);return e}function K(o,t,e,n,i,r,s,a){return(i-s)*(t-a)-(o-s)*(r-a)>=0&&(o-s)*(n-a)-(e-s)*(t-a)>=0&&(e-s)*(r-a)-(i-s)*(n-a)>=0}function bn(o,t){return o.next.i!==t.i&&o.prev.i!==t.i&&!yn(o,t)&&(rt(o,t)&&rt(t,o)&&Sn(o,t)&&(L(o.prev,o,t.prev)!==0||L(o,t.prev,t)!==0)||dt(o,t)&&L(o.prev,o,o.next)>0&&L(t.prev,t,t.next)>0)}function L(o,t,e){return(t.y-o.y)*(e.x-t.x)-(t.x-o.x)*(e.y-t.y)}function dt(o,t){return o.x===t.x&&o.y===t.y}function Yt(o,t,e,n){const i=pt(L(o,t,e)),r=pt(L(o,t,n)),s=pt(L(e,n,o)),a=pt(L(e,n,t));return!!(i!==r&&s!==a||i===0&&mt(o,e,t)||r===0&&mt(o,n,t)||s===0&&mt(e,o,n)||a===0&&mt(e,t,n))}function mt(o,t,e){return t.x<=Math.max(o.x,e.x)&&t.x>=Math.min(o.x,e.x)&&t.y<=Math.max(o.y,e.y)&&t.y>=Math.min(o.y,e.y)}function pt(o){return o>0?1:o<0?-1:0}function yn(o,t){let e=o;do{if(e.i!==o.i&&e.next.i!==o.i&&e.i!==t.i&&e.next.i!==t.i&&Yt(e,e.next,o,t))return!0;e=e.next}while(e!==o);return!1}function rt(o,t){return L(o.prev,o,o.next)<0?L(o,t,o.next)>=0&&L(o,o.prev,t)>=0:L(o,t,o.prev)<0||L(o,o.next,t)<0}function Sn(o,t){let e=o,n=!1;const i=(o.x+t.x)/2,r=(o.y+t.y)/2;do e.y>r!=e.next.y>r&&e.next.y!==e.y&&i<(e.next.x-e.x)*(r-e.y)/(e.next.y-e.y)+e.x&&(n=!n),e=e.next;while(e!==o);return n}function jt(o,t){const e=Dt(o.i,o.x,o.y),n=Dt(t.i,t.x,t.y),i=o.next,r=t.prev;return o.next=t,t.prev=o,e.next=i,i.prev=e,n.next=e,e.prev=n,r.next=n,n.prev=r,n}function Zt(o,t,e,n){const i=Dt(o,t,e);return n?(i.next=n.next,i.prev=n,n.next.prev=i,n.next=i):(i.prev=i,i.next=i),i}function ot(o){o.next.prev=o.prev,o.prev.next=o.next,o.prevZ&&(o.prevZ.nextZ=o.nextZ),o.nextZ&&(o.nextZ.prevZ=o.prevZ)}function Dt(o,t,e){return{i:o,x:t,y:e,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function wn(o,t,e,n){let i=0;for(let r=t,s=e-n;r<e;r+=n)i+=(o[s]-o[r])*(o[r+1]+o[s+1]),s=r;return i}const R={parallaxX:.4,parallaxY:.8,parallaxMax:30,overscan:.06,pomSteps:16,rimIntensity:.6,rimColor:"#ffffff",rimWidth:.025,refractionStrength:.015,chromaticStrength:.008,occlusionIntensity:.4,depthPower:.7,depthScale:1.2,depthBias:-.05,fogDensity:.15,fogColor:"#1a1a2e",colorShift:.6,brightnessBias:.05,contrastLow:.02,contrastHigh:.98,verticalReduction:.5,dofStart:.5,dofStrength:.5,bevelIntensity:.5,bevelWidth:.04,bevelDarkening:.2,bevelDesaturation:.12,bevelLightAngle:135,edgeThickness:.01,edgeSpecular:.35,edgeColor:"#a0a0a0",chamferWidth:.025,chamferAngle:45,chamferColor:"#262630",chamferAmbient:.12,chamferSpecular:.3,chamferShininess:24,edgeOcclusionWidth:.03,edgeOcclusionStrength:.2,lightDirection:"-0.5,0.7,-0.3",autoplay:!0,loop:!0,muted:!0},J=512,Q=512;class gt extends HTMLElement{static TAG_NAME="layershift-portal";static get observedAttributes(){return["src","depth-src","depth-meta","depth-model","logo-src","source-type","parallax-x","parallax-y","parallax-max","overscan","pom-steps","quality","gpu-backend","rim-intensity","rim-color","rim-width","refraction-strength","chromatic-strength","occlusion-intensity","depth-power","depth-scale","depth-bias","fog-density","fog-color","color-shift","brightness-bias","contrast-low","contrast-high","vertical-reduction","dof-start","dof-strength","bevel-intensity","bevel-width","bevel-darkening","bevel-desaturation","bevel-light-angle","edge-thickness","edge-specular","edge-color","chamfer-width","chamfer-angle","chamfer-color","chamfer-ambient","chamfer-specular","chamfer-shininess","edge-occlusion-width","edge-occlusion-strength","light-direction","autoplay","loop","muted"]}reinitAttributes=["src","depth-src","depth-meta","depth-model","logo-src","source-type"];canInit(){const t=!!this.getAttribute("logo-src");if(this.sourceType==="camera")return t;const e=!!this.getAttribute("src"),n=!!this.getAttribute("depth-src")&&!!this.getAttribute("depth-meta"),i=!!this.getAttribute("depth-model");return e&&t&&(n||i)}_input={x:0,y:0};get input(){return{x:this._input.x,y:this._input.y}}set input(t){this._input.x=t.x,this._input.y=t.y}shadow;container=null;renderer=null;source=null;depthEstimator=null;mesh=null;loopCount=0;lifecycle;constructor(){super(),this.shadow=this.attachShadow({mode:"open"}),this.lifecycle=new kt(this)}getAttrFloat(t,e){const n=this.getAttribute(t);if(n===null)return e;const i=parseFloat(n);return Number.isFinite(i)?i:e}getAttrBool(t,e){if(!this.hasAttribute(t))return e;const n=this.getAttribute(t);return!(n==="false"||n==="0")}getAttrColor(t,e){const n=this.getAttribute(t)??e;return An(n)}getAttrVec3(t,e){const i=(this.getAttribute(t)??e).split(",").map(s=>parseFloat(s.trim()));if(i.length>=3&&i.every(Number.isFinite))return[i[0],i[1],i[2]];const r=e.split(",").map(s=>parseFloat(s.trim()));return[r[0],r[1],r[2]]}get sourceType(){const t=this.getAttribute("source-type");return t==="camera"?"camera":t==="image"?"image":"video"}get parallaxX(){return this.getAttrFloat("parallax-x",R.parallaxX)}get parallaxY(){return this.getAttrFloat("parallax-y",R.parallaxY)}get parallaxMax(){return this.getAttrFloat("parallax-max",R.parallaxMax)}get overscan(){return this.getAttrFloat("overscan",R.overscan)}get pomSteps(){return this.getAttrFloat("pom-steps",R.pomSteps)}get quality(){const t=this.getAttribute("quality");if(t==="auto"||t==="high"||t==="medium"||t==="low")return t}get gpuBackend(){return"webgl2"}get rimIntensity(){return this.getAttrFloat("rim-intensity",R.rimIntensity)}get rimWidth(){return this.getAttrFloat("rim-width",R.rimWidth)}get rimColor(){return this.getAttrColor("rim-color",R.rimColor)}get refractionStrength(){return this.getAttrFloat("refraction-strength",R.refractionStrength)}get chromaticStrength(){return this.getAttrFloat("chromatic-strength",R.chromaticStrength)}get occlusionIntensity(){return this.getAttrFloat("occlusion-intensity",R.occlusionIntensity)}get depthPower(){return this.getAttrFloat("depth-power",R.depthPower)}get depthScale(){return this.getAttrFloat("depth-scale",R.depthScale)}get depthBias(){return this.getAttrFloat("depth-bias",R.depthBias)}get fogDensity(){return this.getAttrFloat("fog-density",R.fogDensity)}get fogColor(){return this.getAttrColor("fog-color",R.fogColor)}get colorShift(){return this.getAttrFloat("color-shift",R.colorShift)}get brightnessBias(){return this.getAttrFloat("brightness-bias",R.brightnessBias)}get contrastLow(){return this.getAttrFloat("contrast-low",R.contrastLow)}get contrastHigh(){return this.getAttrFloat("contrast-high",R.contrastHigh)}get verticalReduction(){return this.getAttrFloat("vertical-reduction",R.verticalReduction)}get dofStart(){return this.getAttrFloat("dof-start",R.dofStart)}get dofStrength(){return this.getAttrFloat("dof-strength",R.dofStrength)}get bevelIntensity(){return this.getAttrFloat("bevel-intensity",R.bevelIntensity)}get bevelWidth(){return this.getAttrFloat("bevel-width",R.bevelWidth)}get bevelDarkening(){return this.getAttrFloat("bevel-darkening",R.bevelDarkening)}get bevelDesaturation(){return this.getAttrFloat("bevel-desaturation",R.bevelDesaturation)}get bevelLightAngle(){return this.getAttrFloat("bevel-light-angle",R.bevelLightAngle)}get edgeThickness(){return this.getAttrFloat("edge-thickness",R.edgeThickness)}get edgeSpecular(){return this.getAttrFloat("edge-specular",R.edgeSpecular)}get edgeColor(){return this.getAttrColor("edge-color",R.edgeColor)}get chamferWidth(){return this.getAttrFloat("chamfer-width",R.chamferWidth)}get chamferAngle(){return this.getAttrFloat("chamfer-angle",R.chamferAngle)}get chamferColor(){return this.getAttrColor("chamfer-color",R.chamferColor)}get chamferAmbient(){return this.getAttrFloat("chamfer-ambient",R.chamferAmbient)}get chamferSpecular(){return this.getAttrFloat("chamfer-specular",R.chamferSpecular)}get chamferShininess(){return this.getAttrFloat("chamfer-shininess",R.chamferShininess)}get edgeOcclusionWidth(){return this.getAttrFloat("edge-occlusion-width",R.edgeOcclusionWidth)}get edgeOcclusionStrength(){return this.getAttrFloat("edge-occlusion-strength",R.edgeOcclusionStrength)}get lightDirection3(){return this.getAttrVec3("light-direction",R.lightDirection)}get depthModel(){return this.getAttribute("depth-model")}get shouldAutoplay(){return this.getAttrBool("autoplay",R.autoplay)}get shouldLoop(){return this.getAttrBool("loop",R.loop)}get shouldMute(){return this.getAttrBool("muted",R.muted)}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}attachSourceEventListeners(t){t.addEventListener&&(t.addEventListener("play",(()=>{this.emit("layershift-portal:play",{currentTime:t.currentTime})})),t.addEventListener("pause",(()=>{this.emit("layershift-portal:pause",{currentTime:t.currentTime})})),t.addEventListener("ended",(()=>{this.loopCount+=1,this.emit("layershift-portal:loop",{loopCount:this.loopCount})})))}connectedCallback(){console.warn("[layershift] <layershift-portal> is deprecated and will be removed in a future major version. Use <layershift-effect> with a filter-config.json instead. See https://layershift.io/docs/migration"),this.lifecycle.onConnected()}disconnectedCallback(){this.lifecycle.onDisconnected()}attributeChangedCallback(t,e,n){this.lifecycle.onAttributeChanged(t,e,n)}setupShadowDOM(){this.shadow.innerHTML="";const t=document.createElement("style");t.textContent=`
|
|
998
998
|
:host {
|
|
999
999
|
display: block;
|
|
1000
1000
|
width: 100%;
|
|
@@ -1014,4 +1014,4 @@ void main() {
|
|
|
1014
1014
|
width: 100%;
|
|
1015
1015
|
height: 100%;
|
|
1016
1016
|
}
|
|
1017
|
-
`,this.shadow.appendChild(t),this.container=document.createElement("div"),this.container.className="container",this.shadow.appendChild(this.container)}async doInit(t){const e=this.getAttribute("logo-src");if(!this.container)return;const n=this.sourceType==="camera",i=this.depthModel;try{let r,s,a,l=null;const
|
|
1017
|
+
`,this.shadow.appendChild(t),this.container=document.createElement("div"),this.container.className="container",this.shadow.appendChild(this.container)}async doInit(t){const e=this.getAttribute("logo-src");if(!this.container)return;const n=this.sourceType==="camera",i=this.depthModel;try{let r,s,a,l=null;const c=d=>{this.emit("layershift-portal:model-progress",d)};if(n){const[d,y]=await Promise.all([Mt({video:{facingMode:"user"}},{parent:this.shadow}),At(e)]);if(t.aborted){d.dispose();return}if(r=d,a=y,i){if(l=await ct(i,J,Q,c),t.aborted){l.dispose(),r.dispose();return}s=H(J,Q)}else s=H(r.width,r.height)}else{const d=this.getAttribute("src"),y=this.getAttribute("depth-src"),E=this.getAttribute("depth-meta"),b=!!y&&!!E,p=this.sourceType==="image"||/\.(jpe?g|png|webp|gif|avif|bmp)(\?|$)/i.test(d);if(b){const[v,m,T]=await Promise.all([p?ut(d):lt(d,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),Ft(y,E),At(e)]);if(t.aborted){v.dispose();return}r=v,s=m,a=T}else if(i){const[v,m,T]=await Promise.all([p?ut(d):lt(d,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),ct(i,J,Q,c),At(e)]);if(t.aborted){v.dispose(),m.dispose();return}if(r=v,l=m,a=T,p||!r.isLive){const w=r.getImageSource();if(w){const A=await l.submitFrameAndWait(w);s={meta:{frameCount:1,fps:1,width:J,height:Q,sourceFps:1},frames:[A]}}else s=H(J,Q)}else s=H(J,Q)}else throw new Error("Either depth-src/depth-meta or depth-model must be provided.")}this.source=r,this.depthEstimator=l,this.mesh=a,this.loopCount=0,this.attachSourceEventListeners(r);const u=this.container?.clientWidth||r.width,f=this.parallaxMax/Math.max(u,1);let h;if(l)h=()=>l.getLatestDepth();else{const d=new Pt(s);h=y=>d.sample(y)}const x={parallaxStrength:f,overscanPadding:this.overscan,pomSteps:this.pomSteps,quality:this.quality,rimLightIntensity:this.rimIntensity,rimLightColor:this.rimColor,rimLightWidth:this.rimWidth,refractionStrength:this.refractionStrength,chromaticStrength:this.chromaticStrength,occlusionIntensity:this.occlusionIntensity,depthPower:this.depthPower,depthScale:this.depthScale,depthBias:this.depthBias,fogDensity:this.fogDensity,fogColor:this.fogColor,colorShift:this.colorShift,brightnessBias:this.brightnessBias,contrastLow:this.contrastLow,contrastHigh:this.contrastHigh,verticalReduction:this.verticalReduction,dofStart:this.dofStart,dofStrength:this.dofStrength,bevelIntensity:this.bevelIntensity,bevelWidth:this.bevelWidth,bevelDarkening:this.bevelDarkening,bevelDesaturation:this.bevelDesaturation,bevelLightAngle:this.bevelLightAngle,edgeThickness:this.edgeThickness,edgeSpecular:this.edgeSpecular,edgeColor:this.edgeColor,chamferWidth:this.chamferWidth,chamferAngle:this.chamferAngle,chamferColor:this.chamferColor,chamferAmbient:this.chamferAmbient,chamferSpecular:this.chamferSpecular,chamferShininess:this.chamferShininess,edgeOcclusionWidth:this.edgeOcclusionWidth,edgeOcclusionStrength:this.edgeOcclusionStrength,lightDirection:this.lightDirection3};if(t.aborted)return;this.renderer=new Ke(this.container,x),this.renderer.initialize(r,s.meta.width,s.meta.height,a);const g=l;if(this.renderer.start(r,h,()=>({x:this._input.x,y:this._input.y}),(d,y)=>{if(g){const E=r.getImageSource();E&&g.submitFrame(E)}this.emit("layershift-portal:frame",{currentTime:d,frameNumber:y})}),!n&&r.isLive&&this.shouldAutoplay&&r.play)try{await r.play()}catch{}if(t.aborted)return;this.lifecycle.markInitialized(),this.emit("layershift-portal:ready",{videoWidth:r.width,videoHeight:r.height,duration:r.duration})}catch(r){const s=r instanceof Error?r.message:"Failed to initialize.";console.error("<layershift-portal>: Failed to initialize.",r),this.emit("layershift-portal:error",{message:s})}}doDispose(){this.renderer?.dispose(),this.renderer=null,this.depthEstimator?.dispose(),this.depthEstimator=null,this.source?.dispose(),this.source=null,this.mesh=null,this.loopCount=0,this.container=null}}function An(o){const t=o.replace("#","");if(t.length===3){const e=parseInt(t[0]+t[0],16)/255,n=parseInt(t[1]+t[1],16)/255,i=parseInt(t[2]+t[2],16)/255;return[e,n,i]}if(t.length===6){const e=parseInt(t.substring(0,2),16)/255,n=parseInt(t.substring(2,4),16)/255,i=parseInt(t.substring(4,6),16)/255;return[e,n,i]}return[0,0,0]}function V(o,t,e){return Math.min(e,Math.max(t,o))}function G(o,t,e){return o+(t-o)*e}const vt=100,$t=.06;function Rn(o,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??.08;let r=0,s=0,a=0,l=0,c=0,u=!0;const f=g=>{const d=o.getBoundingClientRect(),y=(g.clientX-d.left)/d.width*2-1,E=(g.clientY-d.top)/d.height*2-1;r=V(y,-1,1),s=V(E,-1,1)},h=()=>{r=0,s=0},x=()=>{u&&(a=G(a,r,i),l=G(l,s,i),o.input={x:a*e,y:l*n},c=requestAnimationFrame(x))};return o.addEventListener("mousemove",f),o.addEventListener("mouseleave",h),c=requestAnimationFrame(x),()=>{u=!1,cancelAnimationFrame(c),o.removeEventListener("mousemove",f),o.removeEventListener("mouseleave",h)}}function Dn(o,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??.08;let r=0,s=0,a=0,l=0,c=0,u=0,f=0,h=!0;const x=E=>{const b=E.touches[0];b&&(c=b.clientX,u=b.clientY,r=0,s=0)},g=E=>{const b=E.touches[0];if(!b)return;const p=b.clientX-c,v=b.clientY-u;r=V(p/vt,-1,1),s=V(v/vt,-1,1)},d=()=>{r=0,s=0},y=()=>{h&&(a=G(a,r,i),l=G(l,s,i),o.input={x:a*e,y:l*n},f=requestAnimationFrame(y))};return o.addEventListener("touchstart",x,{passive:!0}),o.addEventListener("touchmove",g,{passive:!0}),o.addEventListener("touchend",d,{passive:!0}),o.addEventListener("touchcancel",d,{passive:!0}),f=requestAnimationFrame(y),()=>{h=!1,cancelAnimationFrame(f),o.removeEventListener("touchstart",x),o.removeEventListener("touchmove",g),o.removeEventListener("touchend",d),o.removeEventListener("touchcancel",d)}}function Pn(o,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??$t;let r=0,s=0,a=0,l=0,c=0,u=!0,f=!1;const h=y=>{r=V((y.gamma??0)/45,-1,1),s=V((y.beta??0)/45,-1,1)},x=()=>{u&&(a=G(a,r,i),l=G(l,s,i),o.input={x:a*e,y:l*n},c=requestAnimationFrame(x))},g=()=>{u&&!f&&(window.addEventListener("deviceorientation",h),f=!0)},d=DeviceOrientationEvent;return typeof d.requestPermission=="function"?d.requestPermission().then(y=>{y==="granted"&&g()}).catch(()=>{}):g(),c=requestAnimationFrame(x),()=>{u=!1,cancelAnimationFrame(c),f&&(window.removeEventListener("deviceorientation",h),f=!1)}}function Fn(o,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??.08,r=t?.lerpFactor??$t;let s=0,a=0,l=0,c=0,u=0,f=0,h=0,x=0,g=!1,d=!1,y=!1,E=0,b=0,p=0,v=!0;const m=S=>{const F=o.getBoundingClientRect(),U=(S.clientX-F.left)/F.width*2-1,I=(S.clientY-F.top)/F.height*2-1;s=V(U,-1,1),a=V(I,-1,1)},T=()=>{s=0,a=0},w=S=>{const F=S.touches[0];F&&(g=!0,E=F.clientX,b=F.clientY,l=0,c=0,!d&&!y&&M())},A=S=>{const F=S.touches[0];if(!F)return;const U=F.clientX-E,I=F.clientY-b;l=V(U/vt,-1,1),c=V(I/vt,-1,1)},D=()=>{g=!1,l=0,c=0},P=S=>{u=V((S.gamma??0)/45,-1,1),f=V((S.beta??0)/45,-1,1)},_=()=>{v&&!y&&(window.addEventListener("deviceorientation",P),y=!0,d=!0)},M=()=>{if(typeof DeviceOrientationEvent>"u")return;const S=DeviceOrientationEvent;typeof S.requestPermission=="function"?S.requestPermission().then(F=>{F==="granted"&&_()}).catch(()=>{}):_()},C=()=>{if(!v)return;let S,F,U;g?(S=l,F=c,U=i):d?(S=u,F=f,U=r):(S=s,F=a,U=i),h=G(h,S,U),x=G(x,F,U),o.input={x:h*e,y:x*n},p=requestAnimationFrame(C)};return o.addEventListener("mousemove",m),o.addEventListener("mouseleave",T),o.addEventListener("touchstart",w,{passive:!0}),o.addEventListener("touchmove",A,{passive:!0}),o.addEventListener("touchend",D,{passive:!0}),o.addEventListener("touchcancel",D,{passive:!0}),p=requestAnimationFrame(C),()=>{v=!1,cancelAnimationFrame(p),o.removeEventListener("mousemove",m),o.removeEventListener("mouseleave",T),o.removeEventListener("touchstart",w),o.removeEventListener("touchmove",A),o.removeEventListener("touchend",D),o.removeEventListener("touchcancel",D),y&&(window.removeEventListener("deviceorientation",P),y=!1)}}return customElements.get(ft.TAG_NAME)||customElements.define(ft.TAG_NAME,ft),customElements.get(gt.TAG_NAME)||customElements.define(gt.TAG_NAME,gt),N.LayershiftElement=ft,N.LayershiftPortalElement=gt,N.connectGyro=Pn,N.connectMouse=Rn,N.connectPointer=Fn,N.connectTouch=Dn,Object.defineProperty(N,Symbol.toStringTag,{value:"Module"}),N})({});
|