layershift 0.5.0 → 0.6.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 +30 -9
- package/dist/components/layershift.js +88 -46
- package/dist/npm/layershift.es.js +1151 -990
- package/dist/types/components/layershift/global.d.ts +3 -1
- package/dist/types/components/layershift/index.d.ts +2 -2
- package/dist/types/components/layershift/index.d.ts.map +1 -1
- package/dist/types/components/layershift/layershift-element.d.ts +1 -2
- package/dist/types/components/layershift/layershift-element.d.ts.map +1 -1
- package/dist/types/components/layershift/lifecycle.d.ts +1 -1
- package/dist/types/components/layershift/portal-element.d.ts +1 -2
- package/dist/types/components/layershift/portal-element.d.ts.map +1 -1
- package/dist/types/components/layershift/types.d.ts +8 -4
- package/dist/types/components/layershift/types.d.ts.map +1 -1
- package/dist/types/depth/depth-analysis.d.ts.map +1 -0
- package/dist/types/{depth-estimator.d.ts → depth/depth-estimator.d.ts} +4 -15
- package/dist/types/depth/depth-estimator.d.ts.map +1 -0
- package/dist/types/depth/depth-preprocess.d.ts +26 -0
- package/dist/types/depth/depth-preprocess.d.ts.map +1 -0
- package/dist/types/{precomputed-depth.d.ts → depth/precomputed-depth.d.ts} +4 -8
- package/dist/types/depth/precomputed-depth.d.ts.map +1 -0
- package/dist/types/depth/workers/preprocess-worker.d.ts +36 -0
- package/dist/types/depth/workers/preprocess-worker.d.ts.map +1 -0
- package/dist/types/{quality.d.ts → gpu/quality.d.ts} +4 -4
- package/dist/types/gpu/quality.d.ts.map +1 -0
- package/dist/types/gpu/webgl-utils.d.ts.map +1 -0
- package/dist/types/media/input-handler.d.ts.map +1 -0
- package/dist/types/media/input-helpers.d.ts.map +1 -0
- package/dist/types/media/media-source.d.ts.map +1 -0
- package/dist/types/{depth-effect-renderer.d.ts → renderers/depth-effect-renderer.d.ts} +21 -4
- package/dist/types/renderers/depth-effect-renderer.d.ts.map +1 -0
- package/dist/types/renderers/jfa-distance-field.d.ts.map +1 -0
- package/dist/types/{portal-renderer.d.ts → renderers/portal-renderer.d.ts} +4 -3
- package/dist/types/renderers/portal-renderer.d.ts.map +1 -0
- package/dist/types/renderers/render-pass.d.ts.map +1 -0
- package/dist/types/{renderer-base.d.ts → renderers/renderer-base.d.ts} +3 -3
- package/dist/types/renderers/renderer-base.d.ts.map +1 -0
- package/dist/types/renderers/shape-generator.d.ts.map +1 -0
- package/dist/types/shared/filter-config.d.ts +0 -1
- package/dist/types/shared/filter-config.d.ts.map +1 -1
- package/package.json +18 -5
- package/dist/types/depth-analysis.d.ts.map +0 -1
- package/dist/types/depth-effect-renderer.d.ts.map +0 -1
- package/dist/types/depth-estimator.d.ts.map +0 -1
- package/dist/types/input-handler.d.ts.map +0 -1
- package/dist/types/input-helpers.d.ts.map +0 -1
- package/dist/types/jfa-distance-field.d.ts.map +0 -1
- package/dist/types/media-source.d.ts.map +0 -1
- package/dist/types/portal-renderer.d.ts.map +0 -1
- package/dist/types/precomputed-depth.d.ts.map +0 -1
- package/dist/types/quality.d.ts.map +0 -1
- package/dist/types/render-pass.d.ts.map +0 -1
- package/dist/types/renderer-base.d.ts.map +0 -1
- package/dist/types/shape-generator.d.ts.map +0 -1
- package/dist/types/video-source.d.ts +0 -22
- package/dist/types/video-source.d.ts.map +0 -1
- package/dist/types/webgl-utils.d.ts.map +0 -1
- /package/dist/types/{depth-analysis.d.ts → depth/depth-analysis.d.ts} +0 -0
- /package/dist/types/{webgl-utils.d.ts → gpu/webgl-utils.d.ts} +0 -0
- /package/dist/types/{input-handler.d.ts → media/input-handler.d.ts} +0 -0
- /package/dist/types/{input-helpers.d.ts → media/input-helpers.d.ts} +0 -0
- /package/dist/types/{media-source.d.ts → media/media-source.d.ts} +0 -0
- /package/dist/types/{jfa-distance-field.d.ts → renderers/jfa-distance-field.d.ts} +0 -0
- /package/dist/types/{render-pass.d.ts → renderers/render-pass.d.ts} +0 -0
- /package/dist/types/{shape-generator.d.ts → renderers/shape-generator.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var Layershift=(function(
|
|
2
|
-
${i}`)}return n}function
|
|
3
|
-
${i}`)}return
|
|
1
|
+
var Layershift=(function(X){"use strict";var bt=typeof document<"u"?document.currentScript:null;class Dt{constructor(t){this.depthData=t;const e=t.width*t.height;this.uint8Output=new Uint8Array(e)}uint8Output;lastFrameIndex=-1;lastNextFrameIndex=-1;lastLerpFactor=-1;sample(t){const e=ne(t*this.depthData.fps,0,this.depthData.frameCount-1),n=Math.floor(e),i=Math.min(n+1,this.depthData.frameCount-1),r=e-n,o=n!==this.lastFrameIndex||i!==this.lastNextFrameIndex,l=Math.abs(r-this.lastLerpFactor)>.001;if(!o&&!l)return this.uint8Output;this.lastFrameIndex=n,this.lastNextFrameIndex=i,this.lastLerpFactor=r;const a=1-r,h=this.depthData.frames[n],c=this.depthData.frames[i];for(let f=0;f<this.uint8Output.length;f+=1)this.uint8Output[f]=h[f]*a+c[f]*r+.5|0;return this.uint8Output}}async function Ft(s,t=512,e=512,n=5,i){const r=await te(s);return ee(r,t,e,n)}async function te(s,t){const e=await fetch(s);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 o=n.getReader();for(;;){const{done:h,value:c}=await o.read();if(h)break;c&&(i.push(c),r+=c.byteLength)}const l=new Uint8Array(r);let a=0;for(const h of i)l.set(h,a),a+=h.byteLength;return l}function ee(s,t,e,n){const i=t*e;if(i===0)throw new Error("Depth frame dimensions must be non-zero.");if(s.byteLength%i!==0)throw new Error(`Depth data byte length (${s.byteLength}) is not evenly divisible by frame size (${i} = ${t}×${e}).`);const r=s.byteLength/i,o=new Array(r);for(let l=0;l<r;l+=1){const a=l*i;o[l]=s.subarray(a,a+i)}return{width:t,height:e,fps:n,frameCount:r,frames:o}}function N(s,t){const e=new Uint8Array(s*t);return e.fill(128),{width:s,height:t,fps:1,frameCount:1,frames:[e]}}function ne(s,t,e){return Math.min(e,Math.max(t,s))}const ie={parallaxStrength:.05,contrastLow:.05,contrastHigh:.95,verticalReduction:.5,dofStart:.6,dofStrength:.4,pomSteps:16,overscanPadding:.08};function re(s,t,e){const n=new Float32Array(256);if(s.length===0||t<=0||e<=0)return Ct(n);const i=oe(s.length),r=t*e;let o=0;const l=new Uint32Array(256);for(const m of i){const T=s[m],R=Math.min(T.length,r);for(let A=0;A<R;A+=1)l[T[A]]+=1;o+=R}if(o===0)return Ct(n);const a=1/o;for(let m=0;m<256;m+=1)n[m]=l[m]*a;const h=new Float32Array(256);h[0]=n[0];for(let m=1;m<256;m+=1)h[m]=h[m-1]+n[m];const c=nt(h,.05),f=nt(h,.25),u=nt(h,.5),x=nt(h,.75),p=nt(h,.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 b=Math.sqrt(y),E=p-c,g=x-f,v=ae(n);return{mean:d,stdDev:b,p5:c,p25:f,median:u,p75:x,p95:p,effectiveRange:E,iqr:g,bimodality:v,histogram:n}}function se(s){if(s.effectiveRange<.05||s.stdDev<.02)return{...ie};const t=s.effectiveRange-.5,e=s.bimodality-.4,n=k(.05-t*.03+e*.01,.035,.065),i=k(s.p5-.03,0,.25),r=k(s.p95+.03,.75,1),o=k((n-.03)/.05,0,1),l=k(.6-o*.25,.35,.6),a=k(.6-t*.2,.5,.7),h=k(.4+t*.2,.25,.5),c=16,f=k(n+.03,.06,.1);return{parallaxStrength:n,contrastLow:i,contrastHigh:r,verticalReduction:l,dofStart:a,dofStrength:h,pomSteps:c,overscanPadding:f}}function oe(s){if(s<=0)return[];if(s===1)return[0];const t=s-1,e=[0,Math.floor(s/4),Math.floor(s/2),Math.floor(3*s/4),t],n=new Set,i=[];for(const r of e)n.has(r)||(n.add(r),i.push(r));return i}function nt(s,t){for(let e=0;e<256;e+=1)if(s[e]>=t)return e/255;return 1}function ae(s){const t=new Float32Array(256);for(let u=0;u<256;u+=1){let x=0,p=0;for(let d=u-2;d<=u+2;d+=1)d>=0&&d<256&&(x+=s[d],p+=1);t[u]=x/p}let e=0;for(let u=0;u<256;u+=1)e+=t[u];e/=256;const n=e*2,i=25,r=[];for(let u=1;u<255;u+=1)t[u]>t[u-1]&&t[u]>t[u+1]&&t[u]>=n&&r.push({bin:u,height:t[u]});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((u,x)=>x.height-u.height),r.length<2)return 0;const o=r[0];let l=null;for(let u=1;u<r.length;u+=1)if(Math.abs(r[u].bin-o.bin)>=i){l=r[u];break}if(!l)return 0;const a=Math.min(o.bin,l.bin),h=Math.max(o.bin,l.bin);let c=1/0;for(let u=a;u<=h;u+=1)t[u]<c&&(c=t[u]);const f=Math.min(o.height,l.height);return f<=0?0:k(1-c/f,0,1)}function Ct(s){return{mean:0,stdDev:0,p5:0,p25:0,median:0,p75:0,p95:0,effectiveRange:0,iqr:0,bimodality:0,histogram:s}}function k(s,t,e){return Math.min(e,Math.max(t,s))}function G(s,t,e){const n=s.createShader(t);if(!n)throw new Error("Failed to create shader.");if(s.shaderSource(n,e),s.compileShader(n),!s.getShaderParameter(n,s.COMPILE_STATUS)){const i=s.getShaderInfoLog(n)??"";throw s.deleteShader(n),new Error(`Shader compilation failed:
|
|
2
|
+
${i}`)}return n}function lt(s,t,e){const n=s.createProgram();if(!n)throw new Error("Failed to create program.");if(s.attachShader(n,t),s.attachShader(n,e),s.linkProgram(n),!s.getProgramParameter(n,s.LINK_STATUS)){const i=s.getProgramInfoLog(n)??"";throw s.deleteProgram(n),new Error(`Program linking failed:
|
|
3
|
+
${i}`)}return s.detachShader(n,t),s.detachShader(n,e),s.deleteShader(t),s.deleteShader(e),n}function ut(s,t,e){const n={};for(const i of e)n[i]=s.getUniformLocation(t,i);return n}const le=new Float32Array([-1,-1,1,-1,-1,1,1,1]);function Ut(s,t){const e=s.createVertexArray();if(!e)throw new Error("Failed to create VAO.");s.bindVertexArray(e);const n=s.createBuffer();s.bindBuffer(s.ARRAY_BUFFER,n),s.bufferData(s.ARRAY_BUFFER,le,s.STATIC_DRAW);const i=s.getAttribLocation(t,"aPosition");return s.enableVertexAttribArray(i),s.vertexAttribPointer(i,2,s.FLOAT,!1,0,0),s.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 H(s,t,e,n,i){const r=G(s,s.VERTEX_SHADER,e),o=G(s,s.FRAGMENT_SHADER,n),l=lt(s,r,o),a=ut(s,l,i);return{name:t,program:l,uniforms:a,dispose(h){h.deleteProgram(l)}}}function _t(s,t,e,n,i,r){const o=G(s,s.VERTEX_SHADER,e),l=G(s,s.FRAGMENT_SHADER,n),a=lt(s,o,l),h=ut(s,a,i),c={texture:null,unit:r.textureUnit,attachment:s.COLOR_ATTACHMENT0},f={name:t,program:a,uniforms:h,fbo:null,outputs:[c],width:0,height:0,resize(u,x,p){f.fbo&&u.deleteFramebuffer(f.fbo),c.texture&&u.deleteTexture(c.texture),f.width=x,f.height=p,c.texture=u.createTexture(),u.activeTexture(u.TEXTURE0+c.unit),u.bindTexture(u.TEXTURE_2D,c.texture),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_MIN_FILTER,u.LINEAR),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_MAG_FILTER,u.LINEAR),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_WRAP_S,u.CLAMP_TO_EDGE),u.texParameteri(u.TEXTURE_2D,u.TEXTURE_WRAP_T,u.CLAMP_TO_EDGE),u.texImage2D(u.TEXTURE_2D,0,r.internalFormat,x,p,0,r.format,r.type,null),f.fbo=u.createFramebuffer(),u.bindFramebuffer(u.FRAMEBUFFER,f.fbo),u.framebufferTexture2D(u.FRAMEBUFFER,u.COLOR_ATTACHMENT0,u.TEXTURE_2D,c.texture,0),u.bindFramebuffer(u.FRAMEBUFFER,null)},dispose(u){f.fbo&&(u.deleteFramebuffer(f.fbo),f.fbo=null),c.texture&&(u.deleteTexture(c.texture),c.texture=null),u.deleteProgram(a)}};return r.width>0&&r.height>0&&f.resize(s,r.width,r.height),f}const ue={high:{dprCap:2,depthMaxDim:512,pomSteps:16,bilateralRadius:2,jfaDivisor:2},medium:{dprCap:1.5,depthMaxDim:384,pomSteps:12,bilateralRadius:2,jfaDivisor:2},low:{dprCap:1,depthMaxDim:256,pomSteps:8,bilateralRadius:1,jfaDivisor:4}};function ce(s){let t="unknown";const e=s.getExtension("WEBGL_debug_renderer_info");e&&(t=s.getParameter(e.UNMASKED_RENDERER_WEBGL)||"unknown");const n=s.getParameter(s.MAX_TEXTURE_SIZE),i=typeof navigator<"u"&&navigator.hardwareConcurrency||0,r=typeof navigator<"u"&&navigator.deviceMemory||0,o=typeof window<"u"&&window.devicePixelRatio||1,l=typeof screen<"u"?(screen.width||0)*(screen.height||0):0,a=typeof navigator<"u"&&("ontouchstart"in window||navigator.maxTouchPoints>0),h=l>0&&l<1920*1080;return{gpuRenderer:t,maxTextureSize:n,hardwareConcurrency:i,deviceMemory:r,devicePixelRatio:o,screenPixels:l,isMobile:a&&h}}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(s){let t=0;const e=s.gpuRenderer.toLowerCase(),n=he.some(r=>e.includes(r)),i=fe.some(r=>e.includes(r));return n&&(t-=30),i&&(t+=20),s.maxTextureSize>=16384?t+=10:s.maxTextureSize>=8192?t+=5:s.maxTextureSize<=4096&&(t-=15),s.hardwareConcurrency>=8?t+=5:s.hardwareConcurrency>=4?t+=0:s.hardwareConcurrency>0&&s.hardwareConcurrency<4&&(t-=10),s.deviceMemory>=8?t+=5:s.deviceMemory>=4?t+=0:s.deviceMemory>0&&s.deviceMemory<4&&(t-=15),s.isMobile&&(t-=10),t>=0?"high":t>=-25?"medium":"low"}function It(s,t){const e=t&&t!=="auto"?t:de(ce(s));return{tier:e,...ue[e]}}class ct{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.canvas.style.display="block",this.canvas.style.width="100%",this.canvas.style.height="100%",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()},ct.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 o=n/Math.max(i,r);i=Math.max(1,Math.round(i*o)),r=Math.max(1,Math.round(r*o))}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 o=0;o<r;o++){const a=Math.min(Math.round(o*this.sourceDepthHeight/r),this.sourceDepthHeight-1)*n,h=o*i;for(let c=0;c<i;c++){const f=Math.min(Math.round(c*n/i),n-1);e[h+c]=t[a+f]}}return e}computeCoverFitUV(t,e){const{width:n,height:i}=this.getViewportSize(),r=n/i,o=t+e;let l=1,a=1;r>this.videoAspect?a=this.videoAspect/r:l=r/this.videoAspect;const h=1+o*2;l/=h,a/=h,this.uvOffset=[(1-l)/2,(1-a)/2],this.uvScale=[l,a],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
|
+
`,St=`#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
|
+
`,pe=`#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
|
+
`,ge=`#version 300 es
|
|
71
71
|
precision highp float;
|
|
72
72
|
|
|
73
73
|
// ---- Uniforms ----
|
|
@@ -183,6 +183,9 @@ uniform float uGlowRadius;
|
|
|
183
183
|
/** Glow edge softness — controls blending of the glow mask. */
|
|
184
184
|
uniform float uGlowSoftness;
|
|
185
185
|
|
|
186
|
+
/** Pre-blurred glow mask from separable blur passes (R channel). */
|
|
187
|
+
uniform sampler2D uGlowBlurred;
|
|
188
|
+
|
|
186
189
|
/**
|
|
187
190
|
* Color-shift curve LUT — 256×1 R8 texture.
|
|
188
191
|
* Maps depth → color-shift intensity [0,1].
|
|
@@ -331,6 +334,8 @@ vec2 pomDisplace(vec2 uv) {
|
|
|
331
334
|
return mix(uv, hitUV, fade);
|
|
332
335
|
}
|
|
333
336
|
|
|
337
|
+
if (abs(currentLayerDepth - depthAtUV) < 0.001) break;
|
|
338
|
+
|
|
334
339
|
currentUV += deltaUV;
|
|
335
340
|
currentLayerDepth += layerDepth;
|
|
336
341
|
}
|
|
@@ -404,27 +409,12 @@ void main() {
|
|
|
404
409
|
}
|
|
405
410
|
|
|
406
411
|
// ---- Glow pass ----
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
// The glow is additive: it brightens pixels without replacing color.
|
|
412
|
+
// Reads the pre-blurred glow mask (computed via separable blur at RVFC rate)
|
|
413
|
+
// and the direct glow curve. Blending via softness controls sharp vs spread.
|
|
410
414
|
if (uGlowEnabled) {
|
|
411
415
|
float glowDepth = texture(uDepth, displaced).r;
|
|
412
416
|
float glowMask = texture(uGlowCurve, vec2(glowDepth, 0.5)).r;
|
|
413
|
-
|
|
414
|
-
// Spread glow to neighbors for a soft halo effect
|
|
415
|
-
float spreadMask = 0.0;
|
|
416
|
-
float spreadSamples = 0.0;
|
|
417
|
-
for (int x = -3; x <= 3; x++) {
|
|
418
|
-
for (int y = -3; y <= 3; y++) {
|
|
419
|
-
vec2 sampleOffset = vec2(float(x), float(y)) * uImageTexelSize * uGlowRadius * 100.0;
|
|
420
|
-
float d = texture(uDepth, displaced + sampleOffset).r;
|
|
421
|
-
spreadMask += texture(uGlowCurve, vec2(d, 0.5)).r;
|
|
422
|
-
spreadSamples += 1.0;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
spreadMask /= spreadSamples;
|
|
426
|
-
|
|
427
|
-
// Combine direct glow mask with spread, apply softness
|
|
417
|
+
float spreadMask = texture(uGlowBlurred, displaced).r;
|
|
428
418
|
float finalGlow = mix(spreadMask * 0.5, glowMask, uGlowSoftness);
|
|
429
419
|
color.rgb += uGlowColor * finalGlow;
|
|
430
420
|
}
|
|
@@ -464,9 +454,61 @@ void main() {
|
|
|
464
454
|
|
|
465
455
|
fragColor = color;
|
|
466
456
|
}
|
|
467
|
-
`,
|
|
468
|
-
|
|
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=`
|
|
457
|
+
`,Mt=`#version 300 es
|
|
458
|
+
precision highp float;
|
|
459
|
+
|
|
460
|
+
// Separable glow blur — 7-tap box filter.
|
|
461
|
+
// Compile with #define PASS_HORIZONTAL for the H pass;
|
|
462
|
+
// without it, runs as the vertical pass reading from the H result.
|
|
463
|
+
|
|
464
|
+
in vec2 vUv;
|
|
465
|
+
out vec4 fragColor;
|
|
466
|
+
|
|
467
|
+
#ifdef PASS_HORIZONTAL
|
|
468
|
+
/** Single-channel depth map (filtered, unit 1). */
|
|
469
|
+
uniform sampler2D uDepth;
|
|
470
|
+
|
|
471
|
+
/** Glow curve LUT — maps depth → glow intensity (unit 5). */
|
|
472
|
+
uniform sampler2D uGlowCurve;
|
|
473
|
+
#else
|
|
474
|
+
/** Horizontal pass output (unit 7). */
|
|
475
|
+
uniform sampler2D uHorizResult;
|
|
476
|
+
#endif
|
|
477
|
+
|
|
478
|
+
/** Texel size of the depth texture (1.0 / depthDimension). */
|
|
479
|
+
uniform vec2 uTexelSize;
|
|
480
|
+
|
|
481
|
+
/** Glow spread radius multiplier. */
|
|
482
|
+
uniform float uGlowRadius;
|
|
483
|
+
|
|
484
|
+
/** Blur direction: (1,0) for horizontal, (0,1) for vertical. */
|
|
485
|
+
uniform vec2 uBlurDir;
|
|
486
|
+
|
|
487
|
+
void main() {
|
|
488
|
+
float accum = 0.0;
|
|
489
|
+
vec2 step = uBlurDir * uTexelSize * uGlowRadius * 100.0;
|
|
490
|
+
|
|
491
|
+
for (int i = -3; i <= 3; i++) {
|
|
492
|
+
vec2 sampleUV = vUv + float(i) * step;
|
|
493
|
+
sampleUV = clamp(sampleUV, vec2(0.0), vec2(1.0));
|
|
494
|
+
|
|
495
|
+
#ifdef PASS_HORIZONTAL
|
|
496
|
+
// Sample depth → look up glow curve
|
|
497
|
+
float d = texture(uDepth, sampleUV).r;
|
|
498
|
+
accum += texture(uGlowCurve, vec2(d, 0.5)).r;
|
|
499
|
+
#else
|
|
500
|
+
// Sample the horizontal blur result
|
|
501
|
+
accum += texture(uHorizResult, sampleUV).r;
|
|
502
|
+
#endif
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
accum /= 7.0;
|
|
506
|
+
fragColor = vec4(accum, 0.0, 0.0, 1.0);
|
|
507
|
+
}
|
|
508
|
+
`,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},ve=["uRawDepth","uTexelSize","uSpatialSigma2"],xe={2:2.25,1:.5625};function Te(s,t){const e=pe.replace("#version 300 es",`#version 300 es
|
|
509
|
+
#define BILATERAL_RADIUS ${t}`),n=G(s,s.VERTEX_SHADER,St),i=G(s,s.FRAGMENT_SHADER,e),r=lt(s,n,i),o=ut(s,r,ve),l=xe[t]??2.25;let a=null;const h={name:"bilateral-filter",program:r,uniforms:o,fbo:null,outputs:[],width:0,height:0,resize(c,f,u){},initFBO(c,f,u,x){a&&c.deleteFramebuffer(a),h.width=u,h.height=x,a=c.createFramebuffer(),h.fbo=a,c.bindFramebuffer(c.FRAMEBUFFER,a),c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,f,0),c.bindFramebuffer(c.FRAMEBUFFER,null),c.useProgram(r),c.uniform1i(o.uRawDepth,2),c.uniform2f(o.uTexelSize,1/u,1/x),c.uniform1f(o.uSpatialSigma2,l)},execute(c,f,u,x,p,d,y,b){a&&(c.activeTexture(c.TEXTURE2),c.bindTexture(c.TEXTURE_2D,u),c.texSubImage2D(c.TEXTURE_2D,0,0,0,p,d,c.RED,c.UNSIGNED_BYTE,x),c.bindFramebuffer(c.FRAMEBUFFER,a),c.viewport(0,0,p,d),c.useProgram(r),c.bindVertexArray(f),c.drawArrays(c.TRIANGLE_STRIP,0,4),c.bindFramebuffer(c.FRAMEBUFFER,null),c.viewport(0,0,y,b))},dispose(c){a&&(c.deleteFramebuffer(a),a=null,h.fbo=null),c.deleteProgram(r)}};return h}const Ee=["uImage","uDepth","uOffset","uStrength","uPomEnabled","uPomSteps","uContrastLow","uContrastHigh","uVerticalReduction","uDofStart","uDofStrength","uImageTexelSize","uUvOffset","uUvScale","uDisplacementCurve","uBlurCurve","uCurvesEnabled","uBlurRadius","uFocalBandOffset","uGlowCurve","uGlowEnabled","uGlowColor","uGlowRadius","uGlowSoftness","uGlowBlurred","uColorShiftCurve","uColorShiftEnabled","uColorShiftHue","uColorShiftSaturation","uColorShiftBrightness","uColorShiftTintStrength","uColorShiftTintColor","uTiltEnabled","uTiltHalfTanFov","uTiltTransitionWidth","uTiltPeakIntensity","uTiltPlaneNormal","uTiltPlaneD"],be=64;function Se(s){const t=ge.replace("#version 300 es",`#version 300 es
|
|
510
|
+
#define MAX_POM_STEPS ${be}`),e=G(s,s.VERTEX_SHADER,me),n=G(s,s.FRAGMENT_SHADER,t),i=lt(s,e,n),r=ut(s,i,Ee);return{name:"depth-effect",program:i,uniforms:r,setStaticUniforms(o,l,a,h){o.useProgram(i),o.uniform1i(r.uImage,0),o.uniform1i(r.uDepth,1),o.uniform1f(r.uStrength,l.parallaxStrength),o.uniform1i(r.uPomEnabled,l.pomEnabled?1:0),o.uniform1i(r.uPomSteps,l.pomSteps),o.uniform1f(r.uContrastLow,l.contrastLow),o.uniform1f(r.uContrastHigh,l.contrastHigh),o.uniform1f(r.uVerticalReduction,l.verticalReduction),o.uniform1f(r.uDofStart,l.dofStart),o.uniform1f(r.uDofStrength,l.dofStrength),o.uniform2f(r.uImageTexelSize,1/a,1/h),o.uniform1i(r.uDisplacementCurve,3),o.uniform1i(r.uBlurCurve,4),o.uniform1i(r.uCurvesEnabled,0),o.uniform1f(r.uBlurRadius,l.blurRadius),o.uniform1f(r.uFocalBandOffset,0),o.uniform1i(r.uGlowCurve,5),o.uniform1i(r.uGlowEnabled,0),o.uniform3f(r.uGlowColor,l.glowColor[0],l.glowColor[1],l.glowColor[2]),o.uniform1f(r.uGlowRadius,l.glowRadius),o.uniform1f(r.uGlowSoftness,l.glowSoftness),o.uniform1i(r.uGlowBlurred,8),o.uniform1i(r.uColorShiftCurve,6),o.uniform1i(r.uColorShiftEnabled,0),o.uniform1f(r.uColorShiftHue,0),o.uniform1f(r.uColorShiftSaturation,1),o.uniform1f(r.uColorShiftBrightness,1),o.uniform1f(r.uColorShiftTintStrength,0),o.uniform3f(r.uColorShiftTintColor,.7,.8,.9),o.uniform1i(r.uTiltEnabled,l.tiltEnabled?1:0),o.uniform1f(r.uTiltHalfTanFov,l.tiltHalfTanFov),o.uniform1f(r.uTiltTransitionWidth,l.tiltTransitionWidth),o.uniform1f(r.uTiltPeakIntensity,l.tiltPeakIntensity),o.uniform3f(r.uTiltPlaneNormal,0,0,1),o.uniform1f(r.uTiltPlaneD,2.75)},updateUvTransform(o,l,a){o.useProgram(i),o.uniform2f(r.uUvOffset,l[0],l[1]),o.uniform2f(r.uUvScale,a[0],a[1])},dispose(o){o.deleteProgram(i)}}}class ye extends ct{gl=null;quadVao=null;bilateralPass=null;effectPass=null;textures=new Lt;videoSlot;filteredDepthSlot;rawDepthSlot;displacementLutSlot;blurLutSlot;glowLutSlot;colorShiftLutSlot;glowBlurHorizSlot;glowBlurResultSlot;glowBlurHPass=null;glowBlurVPass=null;glowEnabled=!1;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.glowBlurHorizSlot=this.textures.register("glowBlurHoriz"),this.glowBlurResultSlot=this.textures.register("glowBlurResult"),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=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;if(i){if(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.glowBlurHPass&&this.glowBlurVPass){const r=this.depthWidth,o=this.depthHeight;this.glowBlurHPass.resize(i,r,o),this.glowBlurVPass.resize(i,r,o),this.glowBlurHorizSlot.texture=this.glowBlurHPass.outputs[0].texture,this.glowBlurResultSlot.texture=this.glowBlurVPass.outputs[0].texture,i.useProgram(this.glowBlurHPass.program),i.uniform1i(this.glowBlurHPass.uniforms.uDepth,this.filteredDepthSlot.unit),i.uniform1i(this.glowBlurHPass.uniforms.uGlowCurve,this.glowLutSlot.unit),i.uniform2f(this.glowBlurHPass.uniforms.uBlurDir,1,0),i.uniform2f(this.glowBlurHPass.uniforms.uTexelSize,1/r,1/o),i.uniform1f(this.glowBlurHPass.uniforms.uGlowRadius,this.config.glowRadius),i.useProgram(this.glowBlurVPass.program),i.uniform1i(this.glowBlurVPass.uniforms.uHorizResult,this.glowBlurHorizSlot.unit),i.uniform2f(this.glowBlurVPass.uniforms.uBlurDir,0,1),i.uniform2f(this.glowBlurVPass.uniforms.uTexelSize,1/r,1/o),i.uniform1f(this.glowBlurVPass.uniforms.uGlowRadius,this.config.glowRadius)}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.glowRadius!==void 0&&(this.glowBlurHPass&&(e.useProgram(this.glowBlurHPass.program),e.uniform1f(this.glowBlurHPass.uniforms.uGlowRadius,this.config.glowRadius)),this.glowBlurVPass&&(e.useProgram(this.glowBlurVPass.program),e.uniform1f(this.glowBlurVPass.uniforms.uGlowRadius,this.config.glowRadius)),this.refreshGlowBlur()),(t.parallaxStrength!==void 0||t.overscanPadding!==void 0)&&this.recalculateViewportLayout()}updateCurveLUTs(t,e,n,i,r){const o=this.gl;if(!o||!this.effectPass)return;const l=!!(t||e),a=!!n,h=!!i;t&&this.uploadLUT(this.displacementLutSlot,t),e&&this.uploadLUT(this.blurLutSlot,e),n&&this.uploadLUT(this.glowLutSlot,n),i&&this.uploadLUT(this.colorShiftLutSlot,i),o.useProgram(this.effectPass.program),o.uniform1i(this.effectPass.uniforms.uCurvesEnabled,l?1:0),o.uniform1i(this.effectPass.uniforms.uGlowEnabled,a?1:0),o.uniform1i(this.effectPass.uniforms.uColorShiftEnabled,h?1:0);const c=this.glowEnabled!==a;if(this.glowEnabled=a,a&&(c||n)&&this.refreshGlowBlur(),h&&r){const f=this.effectPass.uniforms;o.uniform1f(f.uColorShiftHue,r.hueShift*(Math.PI/180)),o.uniform1f(f.uColorShiftSaturation,r.saturation),o.uniform1f(f.uColorShiftBrightness,r.brightness),o.uniform1f(f.uColorShiftTintStrength,r.tintStrength),o.uniform3f(f.uColorShiftTintColor,r.tintColor[0],r.tintColor[1],r.tintColor[2])}}initGPUResources(){const t=this.gl;if(!t)return;this.bilateralPass=Te(t,this.qualityParams.bilateralRadius),this.effectPass=Se(t);const e=Mt.replace("#version 300 es",`#version 300 es
|
|
511
|
+
#define PASS_HORIZONTAL`),n=["uDepth","uGlowCurve","uHorizResult","uTexelSize","uGlowRadius","uBlurDir"];this.glowBlurHPass=_t(t,"glow-blur-h",St,e,n,{internalFormat:t.R8,format:t.RED,type:t.UNSIGNED_BYTE,textureUnit:this.glowBlurHorizSlot.unit,width:0,height:0}),this.glowBlurVPass=_t(t,"glow-blur-v",St,Mt,n,{internalFormat:t.R8,format:t.RED,type:t.UNSIGNED_BYTE,textureUnit:this.glowBlurResultSlot.unit,width:0,height:0}),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),this.glowEnabled&&this.executeGlowBlur(e)}executeGlowBlur(t){if(!this.glowBlurHPass?.fbo||!this.glowBlurVPass?.fbo||!this.quadVao)return;const e=this.depthWidth,n=this.depthHeight;t.bindFramebuffer(t.FRAMEBUFFER,this.glowBlurHPass.fbo),t.viewport(0,0,e,n),t.useProgram(this.glowBlurHPass.program),t.bindVertexArray(this.quadVao),t.drawArrays(t.TRIANGLE_STRIP,0,4),t.bindFramebuffer(t.FRAMEBUFFER,this.glowBlurVPass.fbo),t.useProgram(this.glowBlurVPass.program),t.drawArrays(t.TRIANGLE_STRIP,0,4),t.bindFramebuffer(t.FRAMEBUFFER,null),t.viewport(0,0,this.canvas.width,this.canvas.height)}refreshGlowBlur(){const t=this.gl;!t||!this.glowEnabled||this.depthWidth===0||this.executeGlowBlur(t)}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),o=Math.round(n*i);(this.canvas.width!==r||this.canvas.height!==o)&&(this.canvas.width=r,this.canvas.height=o,t.viewport(0,0,r,o)),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.glowBlurHPass&&(this.glowBlurHPass.dispose(t),this.glowBlurHPass=null),this.glowBlurVPass&&(this.glowBlurVPass.dispose(t),this.glowBlurVPass=null),this.quadVao&&(t.deleteVertexArray(this.quadVao),this.quadVao=null))}}async function ht(s,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=s,e.appendChild(r),await Vt(r),new we(r)}class we{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 ft(s,t={}){const e=new Image;return e.crossOrigin="anonymous",e.src=s,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: ${s}`)),{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 Bt(s={video:!0},t={}){const{parent:e=document.body}=t,n=await navigator.mediaDevices.getUserMedia(s),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 Ae(i,n)}class Ae{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(s){s.readyState>=HTMLMediaElement.HAVE_METADATA||await new Promise((t,e)=>{const n=()=>{r(),t()},i=()=>{r(),e(new Error("Failed to load video metadata."))},r=()=>{s.removeEventListener("loadedmetadata",n),s.removeEventListener("error",i)};s.addEventListener("loadedmetadata",n),s.addEventListener("error",i),s.load()})}const Z=518;async function Pe(){return await import("onnxruntime-web/webgpu")}class De{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;preprocessWorker=null;disposed=!1;async init(t,e){const n=await Pe();if(this.ort=n,this.captureCanvas=document.createElement("canvas"),this.captureCanvas.width=Z,this.captureCanvas.height=Z,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 Fe(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(o){console.warn("[DepthEstimator] WebGPU EP unavailable, falling back to WASM:",o),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.preprocessWorker=new Worker(new URL("/assets/preprocess-worker-wra-uI6w.js",bt&&bt.tagName.toUpperCase()==="SCRIPT"&&bt.src||new URL("layershift.js",document.baseURI).href),{type:"module"}),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,this.preprocessWorker?.terminate(),this.preprocessWorker=null}async runInference(t){try{if(!this.session||!this.captureCtx||!this.ort||!this.preprocessWorker)return;this.captureCtx.drawImage(t,0,0,Z,Z);const e=this.captureCtx.getImageData(0,0,Z,Z),n=await this.workerPreprocess(e.data.buffer,e.width,e.height),i=new this.ort.Tensor("float32",new Float32Array(n),[1,3,e.height,e.width]),o=(await this.session.run({[this.inputName]:i}))[this.outputName],l=o.data,a=o.dims,h=a.length===3?a[1]:a[2],c=a.length===3?a[2]:a[3],f=await this.workerPostprocess(l.slice(0).buffer,c,h);this.backBuffer.set(new Uint8Array(f));const u=this.frontBuffer;this.frontBuffer=this.backBuffer,this.backBuffer=u}catch(e){console.error("[DepthEstimator] Inference failed:",e)}finally{this.inferenceInFlight=!1}}workerPreprocess(t,e,n){return new Promise((i,r)=>{if(!this.preprocessWorker){r(new Error("Worker not ready"));return}const o=a=>{this.preprocessWorker?.removeEventListener("message",o),a.data.type==="preprocessed"?i(a.data.float32):a.data.type==="error"&&r(new Error(a.data.message))};this.preprocessWorker.addEventListener("message",o);const l=t.slice(0);this.preprocessWorker.postMessage({type:"preprocess",pixels:l,width:e,height:n},[l])})}workerPostprocess(t,e,n){return new Promise((i,r)=>{if(!this.preprocessWorker){r(new Error("Worker not ready"));return}const o=a=>{this.preprocessWorker?.removeEventListener("message",o),a.data.type==="postprocessed"?i(a.data.depth):a.data.type==="error"&&r(new Error(a.data.message))};this.preprocessWorker.addEventListener("message",o);const l=t.slice(0);this.preprocessWorker.postMessage({type:"postprocess",depthFloat:l,srcW:e,srcH:n,dstW:this.depthWidth,dstH:this.depthHeight},[l])})}}async function dt(s,t,e,n){const i=new De(t,e);return await i.init(s,n),i}async function Fe(s,t){const e=await fetch(s);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 o=[];let l=0;const a=r.getReader();for(;;){const{done:f,value:u}=await a.read();if(f)break;u&&(o.push(u),l+=u.byteLength,t?.({receivedBytes:l,totalBytes:i,fraction:i?Math.min(l/i,1):0,label:"Downloading depth model…"}))}const h=new Uint8Array(l);let c=0;for(const f of o)h.set(f,c),c+=f.byteLength;return h.buffer}const Ot={sensitivityX:.4,sensitivityY:1,lerpFactor:.08};function yt(s,t){const e=s.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],o=(t-i.x)/(r.x-i.x);switch(s.interpolation){case"step":return i.y;case"linear":return i.y+(r.y-i.y)*o;case"smooth":{const l=o*o*(3-2*o);return i.y+(r.y-i.y)*l}default:return i.y+(r.y-i.y)*o}}function mt(s,t=256){const e=new Uint8Array(t);for(let n=0;n<t;n++){const i=n/(t-1);e[n]=Math.round(yt(s,i)*255)}return e}function q(s,t){return s.find(e=>e.channel===t&&e.enabled)}function kt(s,t){const e=q(s,"displacement"),n=q(s,"blur"),i=q(s,"glow"),r=e?.params;let o=.6,l=0;if(n){const a=n.curve;for(let h=0;h<=1;h+=.01)if(yt(a,h)>.01){o=h;break}l=yt(a,1)}return{parallaxStrength:r?.strength??.05,pomEnabled:r?.pomEnabled??!0,pomSteps:r?.pomSteps??16,contrastLow:t.contrastLow,contrastHigh:t.contrastHigh,verticalReduction:t.verticalReduction,dofStart:o,dofStrength:l,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 Ht(s){const t=q(s,"displacement"),e=q(s,"blur"),n=q(s,"glow"),i=q(s,"color-shift"),r=i?.params;return{displacementLUT:t?mt(t.curve):null,blurLUT:e?mt(e.curve):null,glowLUT:n?mt(n.curve):null,colorShiftLUT:i?mt(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 Xt{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 Y={parallaxX:.4,parallaxY:1,parallaxMax:30,overscan:.05,autoplay:!0,loop:!0,muted:!0},$=512,K=512;class pt extends HTMLElement{static TAG_NAME="layershift-effect";static get observedAttributes(){return["src","depth-src","depth-width","depth-height","depth-fps","depth-model","source-type","config","parallax-x","parallax-y","parallax-max","layers","overscan","quality","gpu-backend","autoplay","loop","muted"]}reinitAttributes=["src","depth-src","depth-width","depth-height","depth-fps","depth-model","source-type","config"];canInit(){if(this.sourceType==="camera")return!0;const t=!!this.getAttribute("src"),e=!!this.getAttribute("depth-src"),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 Xt(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",Y.parallaxX)}get parallaxY(){return this.getAttrFloat("parallax-y",Y.parallaxY)}get parallaxMax(){return this.getAttrFloat("parallax-max",Y.parallaxMax)}get overscan(){return this.getAttrFloat("overscan",Y.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",Y.autoplay)}get shouldLoop(){return this.getAttrBool("loop",Y.loop)}get shouldMute(){return this.getAttrBool("muted",Y.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
512
|
:host {
|
|
471
513
|
display: block;
|
|
472
514
|
width: 100%;
|
|
@@ -486,23 +528,23 @@ void main() {
|
|
|
486
528
|
width: 100%;
|
|
487
529
|
height: 100%;
|
|
488
530
|
}
|
|
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??
|
|
531
|
+
`,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??Ot,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,o=null;const l=m=>{this.emit("layershift-effect:model-progress",m)};if(e){if(i=await Bt({video:{facingMode:"user"}},{parent:this.shadow}),t.aborted){i.dispose();return}if(n){if(o=await dt(n,$,K,l),t.aborted){o.dispose(),i.dispose();return}r=N($,K)}else r=N(i.width,i.height)}else{const m=this.getAttribute("src"),T=this.getAttribute("depth-src"),R=!!T,A=this.sourceType==="image"||/\.(jpe?g|png|webp|gif|avif|bmp)(\?|$)/i.test(m);if(R){const[P,F]=await Promise.all([A?ft(m):ht(m,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),Ft(T,this.getAttrFloat("depth-width",512),this.getAttrFloat("depth-height",512),this.getAttrFloat("depth-fps",5))]);if(t.aborted){P.dispose();return}i=P,r=F}else if(n){const[P,F]=await Promise.all([A?ft(m):ht(m,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),dt(n,$,K,l)]);if(t.aborted){P.dispose(),F.dispose();return}if(i=P,o=F,A||!i.isLive){const _=i.getImageSource();if(_){const I=await o.submitFrameAndWait(_);r={width:$,height:K,fps:1,frameCount:1,frames:[I]}}else r=N($,K)}else r=N($,K)}else throw new Error("Either depth-src or depth-model must be provided.")}this.source=i,this.depthEstimator=o,this.loopCount=0,this.attachSourceEventListeners(i);const a=re(r.frames,r.width,r.height),h=se(a);this.depthFallback={contrastLow:h.contrastLow,contrastHigh:h.contrastHigh,verticalReduction:h.verticalReduction};let c;if(o)c=()=>o.getLatestDepth();else{const m=new Dt(r);c=T=>m.sample(T)}if(t.aborted)return;let f,u=null,x=Ot;const p=await this.fetchFilterConfig(t);if(t.aborted)return;if(p&&p.channels.length>0){const m=kt(p.channels,{contrastLow:h.contrastLow,contrastHigh:h.contrastHigh,verticalReduction:h.verticalReduction});f={parallaxStrength:m.parallaxStrength,pomEnabled:m.pomEnabled,pomSteps:m.pomSteps,overscanPadding:p.overscanPadding,quality:p.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},u=Ht(p.channels),x=p.motion}else f=this.buildLegacyConfig(h,i.width);this.renderer=new ye(this.container,f),this.renderer.initialize(i,r.width,r.height),u&&this.renderer.updateCurveLUTs(u.displacementLUT,u.blurLUT,u.glowLUT,u.colorShiftLUT,u.colorShiftParams??void 0);const d=x.tiltPlaneInput??!1,y=x.tiltPitchSensitivity??.35,b=x.tiltYawSensitivity??.15,g=p?.channels.find(m=>m.channel==="blur"&&m.enabled)?.params?.focalCenter??.5,v=o;if(this.renderer.start(i,c,()=>{const m=this._input;if(d){const A=m.y*y,P=m.x*b,F=Math.cos(A),_=Math.sin(A),I=Math.cos(P),S=Math.sin(P)*F,D=-_,U=I*F,M=.5+g*(5-.5);return{x:m.x*.3,y:m.y*.3,tiltPlaneNormal:[S,D,U],tiltPlaneD:U*M}}return{x:m.x,y:m.y}},(m,T)=>{if(v){const R=i.getImageSource();R&&v.submitFrame(R)}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:a,derivedParams:h,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=kt(t,e);this.renderer.updateConfig(n);const i=Ht(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)),o=Math.max(1,Math.round(e/n));this._width=r,this._height=o;const l=(h,c,f,u)=>{const x=i.createFramebuffer();return i.bindFramebuffer(i.FRAMEBUFFER,x),i.bindTexture(i.TEXTURE_2D,h),i.texStorage2D(i.TEXTURE_2D,1,c,f,u),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,h,0),i.bindFramebuffer(i.FRAMEBUFFER,null),x};this.maskTex=i.createTexture(),this.maskFbo=l(this.maskTex,i.R8,r,o);const a=this.hasColorBufferFloat?i.RG16F:i.RGBA8;this.pingTex=i.createTexture(),this.pingFbo=l(this.pingTex,a,r,o),this.pongTex=i.createTexture(),this.pongFbo=l(this.pongTex,a,r,o),this.distTex=i.createTexture(),this.distFbo=l(this.distTex,i.RGBA8,r,o),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 o=this.pingTex,l=this.pongFbo,a=this.pongTex;for(let h=0;h<r.length;h++){const c=r[h]/Math.max(n,i);e.bindFramebuffer(e.FRAMEBUFFER,l),e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,o),e.uniform1i(t.floodPass.uniforms.uSeedTex,5),e.uniform1f(t.floodPass.uniforms.uStepSize,c),e.bindVertexArray(t.quadVao),e.drawArrays(e.TRIANGLE_STRIP,0,4);const f=o,u=l;o=a,l=u===this.pongFbo?this.pingFbo:this.pongFbo,a=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,o),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 Ce=`#version 300 es
|
|
490
532
|
in vec2 aPosition;
|
|
491
533
|
uniform vec2 uMeshScale;
|
|
492
534
|
void main() {
|
|
493
535
|
gl_Position = vec4(aPosition * uMeshScale, 0.0, 1.0);
|
|
494
536
|
}
|
|
495
|
-
`,
|
|
537
|
+
`,Ue=`#version 300 es
|
|
496
538
|
precision lowp float;
|
|
497
539
|
out vec4 fragColor;
|
|
498
540
|
void main() { fragColor = vec4(0.0); }
|
|
499
|
-
`,
|
|
541
|
+
`,Le=`#version 300 es
|
|
500
542
|
in vec2 aPosition;
|
|
501
543
|
uniform vec2 uMeshScale;
|
|
502
544
|
void main() {
|
|
503
545
|
gl_Position = vec4(aPosition * uMeshScale, 0.0, 1.0);
|
|
504
546
|
}
|
|
505
|
-
`,
|
|
547
|
+
`,_e=`#version 300 es
|
|
506
548
|
precision lowp float;
|
|
507
549
|
out vec4 fragColor;
|
|
508
550
|
void main() { fragColor = vec4(1.0); }
|
|
@@ -513,7 +555,7 @@ void main() {
|
|
|
513
555
|
vUv = aPosition * 0.5 + 0.5;
|
|
514
556
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
515
557
|
}
|
|
516
|
-
`,
|
|
558
|
+
`,Me=`#version 300 es
|
|
517
559
|
precision highp float;
|
|
518
560
|
uniform sampler2D uMask;
|
|
519
561
|
uniform vec2 uTexelSize;
|
|
@@ -538,14 +580,14 @@ void main() {
|
|
|
538
580
|
fragSeed = vec2(-1.0);
|
|
539
581
|
}
|
|
540
582
|
}
|
|
541
|
-
`,
|
|
583
|
+
`,Be=`#version 300 es
|
|
542
584
|
in vec2 aPosition;
|
|
543
585
|
out vec2 vUv;
|
|
544
586
|
void main() {
|
|
545
587
|
vUv = aPosition * 0.5 + 0.5;
|
|
546
588
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
547
589
|
}
|
|
548
|
-
`,
|
|
590
|
+
`,Ve=`#version 300 es
|
|
549
591
|
precision highp float;
|
|
550
592
|
uniform sampler2D uSeedTex;
|
|
551
593
|
uniform float uStepSize;
|
|
@@ -574,14 +616,14 @@ void main() {
|
|
|
574
616
|
|
|
575
617
|
fragSeed = bestSeed;
|
|
576
618
|
}
|
|
577
|
-
`,
|
|
619
|
+
`,Oe=`#version 300 es
|
|
578
620
|
in vec2 aPosition;
|
|
579
621
|
out vec2 vUv;
|
|
580
622
|
void main() {
|
|
581
623
|
vUv = aPosition * 0.5 + 0.5;
|
|
582
624
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
583
625
|
}
|
|
584
|
-
`,
|
|
626
|
+
`,ke=`#version 300 es
|
|
585
627
|
precision highp float;
|
|
586
628
|
uniform sampler2D uSeedTex;
|
|
587
629
|
uniform sampler2D uMask;
|
|
@@ -606,7 +648,7 @@ void main() {
|
|
|
606
648
|
float normalized = clamp(d / max(uBevelWidth, 0.001), 0.0, 1.0);
|
|
607
649
|
fragDist = vec4(normalized, 0.0, 0.0, 1.0);
|
|
608
650
|
}
|
|
609
|
-
`,
|
|
651
|
+
`,He=`#version 300 es
|
|
610
652
|
in vec2 aPosition;
|
|
611
653
|
uniform vec2 uUvOffset;
|
|
612
654
|
uniform vec2 uUvScale;
|
|
@@ -618,7 +660,7 @@ void main() {
|
|
|
618
660
|
vScreenUv = baseUv;
|
|
619
661
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
620
662
|
}
|
|
621
|
-
`,
|
|
663
|
+
`,Xe=`#version 300 es
|
|
622
664
|
precision highp float;
|
|
623
665
|
|
|
624
666
|
#define MAX_POM_STEPS 32
|
|
@@ -749,14 +791,14 @@ void main() {
|
|
|
749
791
|
// Write lens-transformed depth to second attachment for boundary effects
|
|
750
792
|
fragDepth = vec4(lensD, 0.0, 0.0, 1.0);
|
|
751
793
|
}
|
|
752
|
-
`,
|
|
794
|
+
`,Ne=`#version 300 es
|
|
753
795
|
in vec2 aPosition;
|
|
754
796
|
out vec2 vUv;
|
|
755
797
|
void main() {
|
|
756
798
|
vUv = aPosition * 0.5 + 0.5;
|
|
757
799
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
758
800
|
}
|
|
759
|
-
`,
|
|
801
|
+
`,Ge=`#version 300 es
|
|
760
802
|
precision highp float;
|
|
761
803
|
uniform sampler2D uInteriorColor;
|
|
762
804
|
uniform sampler2D uDistField;
|
|
@@ -786,7 +828,7 @@ void main() {
|
|
|
786
828
|
|
|
787
829
|
fragColor = vec4(toSRGB(linear), color.a);
|
|
788
830
|
}
|
|
789
|
-
`,
|
|
831
|
+
`,We=`#version 300 es
|
|
790
832
|
in vec2 aPosition;
|
|
791
833
|
in vec2 aNormal;
|
|
792
834
|
uniform float uRimWidth;
|
|
@@ -809,7 +851,7 @@ void main() {
|
|
|
809
851
|
|
|
810
852
|
gl_Position = vec4(pos, 0.0, 1.0);
|
|
811
853
|
}
|
|
812
|
-
`,
|
|
854
|
+
`,ze=`#version 300 es
|
|
813
855
|
precision highp float;
|
|
814
856
|
|
|
815
857
|
uniform sampler2D uInteriorColor;
|
|
@@ -911,7 +953,7 @@ void main() {
|
|
|
911
953
|
|
|
912
954
|
fragColor = vec4(color * alpha, alpha);
|
|
913
955
|
}
|
|
914
|
-
`,
|
|
956
|
+
`,qe=`#version 300 es
|
|
915
957
|
in vec2 aPosition;
|
|
916
958
|
in vec3 aNormal3;
|
|
917
959
|
in float aLerpT; // 0 = inner (at silhouette), 1 = outer edge
|
|
@@ -927,7 +969,7 @@ void main() {
|
|
|
927
969
|
vLerpT = aLerpT;
|
|
928
970
|
gl_Position = vec4(sp, 0.0, 1.0);
|
|
929
971
|
}
|
|
930
|
-
`,
|
|
972
|
+
`,Ye=`#version 300 es
|
|
931
973
|
precision highp float;
|
|
932
974
|
uniform vec3 uLightDir3;
|
|
933
975
|
uniform vec3 uChamferColor;
|
|
@@ -994,7 +1036,7 @@ void main() {
|
|
|
994
1036
|
vec3 lit = base * (uChamferAmbient + (1.0 - uChamferAmbient) * diff) + vec3(spec);
|
|
995
1037
|
fragColor = vec4(toSRGB(lit), 1.0);
|
|
996
1038
|
}
|
|
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=`
|
|
1039
|
+
`;function je(s){const t=[];let e=0;for(let n=0;n<s.length-2;n+=2){const i=s[n],r=s[n+1],o=s[n+2],l=s[n+3],a=o-i,h=l-r,c=Math.sqrt(a*a+h*h);if(c<1e-6)continue;const f=-h/c,u=a/c;t.push(i,r,f,u,i,r,-f,-u,o,l,f,u,o,l,f,u,i,r,-f,-u,o,l,-f,-u),e+=6}return{vertices:new Float32Array(t),count:e}}function Ze(s,t,e,n,i){if(n<=0)return{vertices:new Float32Array(0),count:0};const r=i*Math.PI/180,o=-Math.cos(r),l=Math.sin(r),a=[];let h=0;for(let c=0;c<t.length;c++){const f=t[c],p=((c+1<t.length?t[c+1]:s.length)-f)/2;if(p<3)continue;const d=p-1;let y=0;for(let T=0;T<d;T++){const R=f+T*2,A=s[R],P=s[R+1],F=s[R+2],_=s[R+3];y+=A*_-F*P}const b=y>=0?1:-1,E=[],g=[];for(let T=0;T<d;T++){const R=f+T*2,A=s[R+2]-s[R],P=s[R+3]-s[R+1],F=Math.sqrt(A*A+P*P);F<1e-8?(E.push(T>0?E[T-1]:0),g.push(T>0?g[T-1]:0)):(E.push(-P/F*b),g.push(A/F*b))}const v=[],m=[];for(let T=0;T<d;T++){const R=(T-1+d)%d;let A=E[R]+E[T],P=g[R]+g[T];const F=Math.sqrt(A*A+P*P);F>1e-8?(A/=F,P/=F):(A=E[T],P=g[T]),v.push(A),m.push(P)}for(let T=0;T<d;T++){const R=T,A=(T+1)%d,P=f+T*2,F=f+(T+1)%d*2,_=s[P],I=s[P+1],C=s[F],S=s[F+1],D=v[R]*l,U=m[R]*l,M=o,O=v[A]*l,et=m[A]*l,at=o,Et=_+v[R]*n,Qt=I+m[R]*n,Fn=C+v[A]*n,Cn=S+m[A]*n;a.push(_,I,D,U,M,0),a.push(Et,Qt,D,U,M,1),a.push(C,S,O,et,at,0),a.push(C,S,O,et,at,0),a.push(Et,Qt,D,U,M,1),a.push(Fn,Cn,O,et,at,1),h+=6}}return{vertices:new Float32Array(a),count:h}}class $e extends ct{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 o=this.canvas.getContext("webgl2",{antialias:!0,alpha:!0,premultipliedAlpha:!0,stencil:!0,desynchronized:!0,powerPreference:"high-performance"});if(!o)throw new Error("WebGL 2 is not supported.");this.gl=o,this.qualityParams=It(o,e.quality),"drawingBufferColorSpace"in o&&(o.drawingBufferColorSpace="srgb"),this.hasColorBufferFloat=!!o.getExtension("EXT_color_buffer_float"),o.clearColor(0,0,0,0),o.pixelStorei(o.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,o=e.getAttribLocation(this.boundaryPass.program,"aPosition");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,2,e.FLOAT,!1,r,0);const l=e.getAttribLocation(this.boundaryPass.program,"aNormal");l>=0&&(e.enableVertexAttribArray(l),e.vertexAttribPointer(l,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=Ze(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,o=e.getAttribLocation(this.chamferPass.program,"aPosition");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,2,e.FLOAT,!1,r,0);const l=e.getAttribLocation(this.chamferPass.program,"aNormal3");l>=0&&(e.enableVertexAttribArray(l),e.vertexAttribPointer(l,3,e.FLOAT,!1,r,8));const a=e.getAttribLocation(this.chamferPass.program,"aLerpT");a>=0&&(e.enableVertexAttribArray(a),e.vertexAttribPointer(a,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=H(t,"stencil",Ce,Ue,["uMeshScale"]),this.maskPass=H(t,"mask",Le,_e,["uMeshScale"]),this.jfaSeedPass=H(t,"jfa-seed",Ie,Me,["uMask","uTexelSize"]),this.jfaFloodPass=H(t,"jfa-flood",Be,Ve,["uSeedTex","uStepSize"]),this.jfaDistPass=H(t,"jfa-dist",Oe,ke,["uSeedTex","uMask","uBevelWidth"]),this.interiorPass=H(t,"interior",He,Xe,["uImage","uDepth","uOffset","uStrength","uPomSteps","uDepthPower","uDepthScale","uDepthBias","uContrastLow","uContrastHigh","uVerticalReduction","uDofStart","uDofStrength","uImageTexelSize","uFogDensity","uFogColor","uColorShift","uBrightnessBias","uUvOffset","uUvScale"]),this.compositePass=H(t,"composite",Ne,Ge,["uInteriorColor","uDistField","uEdgeOcclusionWidth","uEdgeOcclusionStrength"]),this.boundaryPass=H(t,"boundary",We,ze,["uInteriorColor","uInteriorDepth","uDistField","uRimIntensity","uRimColor","uRimWidth","uMeshScale","uRefractionStrength","uChromaticStrength","uOcclusionIntensity","uTexelSize","uEdgeThickness","uEdgeSpecular","uEdgeColor","uLightDir","uBevelIntensity"]),this.chamferPass=H(t,"chamfer",qe,Ye,["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;if(this.jfa?.isDirty&&this.maskVao){const o=this.qualityParams.jfaDivisor,l=Math.max(1,Math.round(this.canvas.width/o)),a=Math.max(1,Math.round(this.canvas.height/o));(this.jfa.width!==l||this.jfa.height!==a)&&this.createJFAResources(this.canvas.width,this.canvas.height),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 o=this.readInput();i=-o.x,r=o.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),this.jfa&&this.jfa.markDirty()}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),o=Math.round(n*i);(this.canvas.width!==r||this.canvas.height!==o)&&(this.canvas.width=r,this.canvas.height=o,t.viewport(0,0,r,o)),(this.fboWidth!==r||this.fboHeight!==o)&&this.createFBO(r,o),this.jfa||this.createJFAResources(r,o),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 l=e/n,a=.65;this.meshScaleX=a,this.meshScaleY=a,l>this.meshAspect?this.meshScaleX=a*(this.meshAspect/l):this.meshScaleY=a*(l/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/o)),this.chamferPass&&(t.useProgram(this.chamferPass.program),t.uniform2f(this.chamferPass.uniforms.uMeshScale,this.meshScaleX,this.meshScaleY))}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(s){const t=await fetch(s);if(!t.ok)throw new Error(`Failed to fetch SVG: ${t.status} ${t.statusText}`);const e=await t.text();return Ke(e)}function Ke(s){const n=new DOMParser().parseFromString(s,"image/svg+xml").querySelector("svg");if(!n)throw new Error("No <svg> element found in document.");const i=Je(n);if(i.length===0)throw new Error("No path data found in SVG.");let r=1/0,o=1/0,l=-1/0,a=-1/0;for(const C of i)for(let S=0;S<C.length;S+=2)r=Math.min(r,C[S]),l=Math.max(l,C[S]),o=Math.min(o,C[S+1]),a=Math.max(a,C[S+1]);const h=l-r,c=a-o,f=(r+l)/2,u=(o+a)/2,x=2/Math.max(h,c),p=h/c,d=i.map(C=>{const S=[];for(let D=0;D<C.length;D+=2)S.push((C[D]-f)*x),S.push(-((C[D+1]-u)*x));return S}),y=an(d),b=[],E=[];for(const C of y){const{flatCoords:S,holeIndices:D}=on(C),U=ln(S,D),M=b.length/2;for(const O of U)E.push(O+M);for(const O of S)b.push(O)}const g=b,v=E,m=[],T=[],R=[],A=zt(d);for(let C=0;C<d.length;C++){const S=d[C];T.push(m.length),R.push(A[C]);for(let D=0;D<S.length;D++)m.push(S[D]);S.length>=2&&m.push(S[0],S[1])}let P=1/0,F=1/0,_=-1/0,I=-1/0;for(let C=0;C<g.length;C+=2)P=Math.min(P,g[C]),_=Math.max(_,g[C]),F=Math.min(F,g[C+1]),I=Math.max(I,g[C+1]);return{vertices:new Float32Array(g),indices:new Uint16Array(v),edgeVertices:new Float32Array(m),contourOffsets:T,contourIsHole:R,bounds:{minX:P,maxX:_,minY:F,maxY:I},aspect:p}}function Je(s){const t=[];return s.querySelectorAll("path").forEach(a=>{const h=a.getAttribute("d");if(!h)return;const c=en(h);t.push(...c)}),s.querySelectorAll("polygon").forEach(a=>{const h=a.getAttribute("points");if(!h)return;const c=Nt(h);c.length>=6&&t.push(c)}),s.querySelectorAll("polyline").forEach(a=>{const h=a.getAttribute("points");if(!h)return;const c=Nt(h);c.length>=6&&t.push(c)}),s.querySelectorAll("rect").forEach(a=>{const h=parseFloat(a.getAttribute("x")||"0"),c=parseFloat(a.getAttribute("y")||"0"),f=parseFloat(a.getAttribute("width")||"0"),u=parseFloat(a.getAttribute("height")||"0");f>0&&u>0&&t.push([h,c,h+f,c,h+f,c+u,h,c+u])}),s.querySelectorAll("circle").forEach(a=>{const h=parseFloat(a.getAttribute("cx")||"0"),c=parseFloat(a.getAttribute("cy")||"0"),f=parseFloat(a.getAttribute("r")||"0");f>0&&t.push(Qe(h,c,f))}),s.querySelectorAll("ellipse").forEach(a=>{const h=parseFloat(a.getAttribute("cx")||"0"),c=parseFloat(a.getAttribute("cy")||"0"),f=parseFloat(a.getAttribute("rx")||"0"),u=parseFloat(a.getAttribute("ry")||"0");f>0&&u>0&&t.push(tn(h,c,f,u))}),t}function Nt(s){const t=[],e=s.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 Qe(s,t,e,n=64){const i=[];for(let r=0;r<n;r++){const o=2*Math.PI*r/n;i.push(s+e*Math.cos(o),t+e*Math.sin(o))}return i}function tn(s,t,e,n,i=64){const r=[];for(let o=0;o<i;o++){const l=2*Math.PI*o/i;r.push(s+e*Math.cos(l),t+n*Math.sin(l))}return r}function en(s){const t=[];let e=[],n=0,i=0,r=0,o=0,l=0,a=0,h="";const c=nn(s);let f=0;function u(){return f>=c.length?0:parseFloat(c[f++])}for(;f<c.length;){const x=c[f];let p;/^[a-zA-Z]$/.test(x)?(p=x,f++):p=h==="M"?"L":h==="m"?"l":h;const d=p===p.toLowerCase();switch(p.toUpperCase()){case"M":{e.length>0&&t.push(e),e=[];const b=u()+(d?n:0),E=u()+(d?i:0);n=b,i=E,r=b,o=E,e.push(n,i),l=n,a=i;break}case"L":{n=u()+(d?n:0),i=u()+(d?i:0),e.push(n,i),l=n,a=i;break}case"H":{n=u()+(d?n:0),e.push(n,i),l=n,a=i;break}case"V":{i=u()+(d?i:0),e.push(n,i),l=n,a=i;break}case"C":{const b=u()+(d?n:0),E=u()+(d?i:0),g=u()+(d?n:0),v=u()+(d?i:0),m=u()+(d?n:0),T=u()+(d?i:0);it(e,n,i,b,E,g,v,m,T),n=m,i=T,l=g,a=v;break}case"S":{const b=2*n-l,E=2*i-a,g=u()+(d?n:0),v=u()+(d?i:0),m=u()+(d?n:0),T=u()+(d?i:0);it(e,n,i,b,E,g,v,m,T),n=m,i=T,l=g,a=v;break}case"Q":{const b=u()+(d?n:0),E=u()+(d?i:0),g=u()+(d?n:0),v=u()+(d?i:0);Gt(e,n,i,b,E,g,v),n=g,i=v,l=b,a=E;break}case"T":{const b=2*n-l,E=2*i-a,g=u()+(d?n:0),v=u()+(d?i:0);Gt(e,n,i,b,E,g,v),n=g,i=v,l=b,a=E;break}case"A":{const b=u(),E=u(),g=u(),v=u(),m=u(),T=u()+(d?n:0),R=u()+(d?i:0);sn(e,n,i,b,E,g,!!v,!!m,T,R),n=T,i=R,l=n,a=i;break}case"Z":{n=r,i=o,e.length>0&&t.push(e),e=[],l=n,a=i;break}default:f++;break}h=p}return e.length>=6&&t.push(e),t}function nn(s){const t=[],e=/([a-zA-Z])|([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)/g;let n;for(;(n=e.exec(s))!==null;)t.push(n[0]);return t}const rn=.5;function it(s,t,e,n,i,r,o,l,a,h=0){if(h>12){s.push(l,a);return}const c=l-t,f=a-e,u=Math.sqrt(c*c+f*f);if(u<1e-6){s.push(l,a);return}const x=Math.abs((n-l)*f-(i-a)*c)/u,p=Math.abs((r-l)*f-(o-a)*c)/u;if(x+p<rn){s.push(l,a);return}const d=(t+n)/2,y=(e+i)/2,b=(n+r)/2,E=(i+o)/2,g=(r+l)/2,v=(o+a)/2,m=(d+b)/2,T=(y+E)/2,R=(b+g)/2,A=(E+v)/2,P=(m+R)/2,F=(T+A)/2;it(s,t,e,d,y,m,T,P,F,h+1),it(s,P,F,R,A,g,v,l,a,h+1)}function Gt(s,t,e,n,i,r,o){const l=t+.6666666666666666*(n-t),a=e+2/3*(i-e),h=r+2/3*(n-r),c=o+2/3*(i-o);it(s,t,e,l,a,h,c,r,o)}function sn(s,t,e,n,i,r,o,l,a,h){if(n===0||i===0){s.push(a,h);return}let c=Math.abs(n),f=Math.abs(i);const u=r*Math.PI/180,x=Math.cos(u),p=Math.sin(u),d=(t-a)/2,y=(e-h)/2,b=x*d+p*y,E=-p*d+x*y;let g=b*b/(c*c)+E*E/(f*f);if(g>1){const U=Math.sqrt(g);c*=U,f*=U,g=1}const v=c*c,m=f*f,T=b*b,R=E*E;let A=Math.max(0,(v*m-v*R-m*T)/(v*R+m*T));A=Math.sqrt(A),o===l&&(A=-A);const P=A*(c*E)/f,F=A*-(f*b)/c,_=x*P-p*F+(t+a)/2,I=p*P+x*F+(e+h)/2,C=Wt(1,0,(b-P)/c,(E-F)/f);let S=Wt((b-P)/c,(E-F)/f,(-b-P)/c,(-E-F)/f);!l&&S>0&&(S-=2*Math.PI),l&&S<0&&(S+=2*Math.PI);const D=Math.max(4,Math.ceil(Math.abs(S)/(Math.PI/16)));for(let U=1;U<=D;U++){const M=C+U/D*S,O=Math.cos(M),et=Math.sin(M),at=x*c*O-p*f*et+_,Et=p*c*O+x*f*et+I;s.push(at,Et)}}function Wt(s,t,e,n){const i=s*n-t*e<0?-1:1,r=s*e+t*n,o=Math.sqrt(s*s+t*t),l=Math.sqrt(e*e+n*n),a=r/(o*l);return i*Math.acos(Math.max(-1,Math.min(1,a)))}function on(s){const t=[],e=[];for(let n=0;n<s.length;n++){n>0&&e.push(t.length/2);for(const i of s[n])t.push(i)}return{flatCoords:t,holeIndices:e}}function zt(s){const t=s.length,e=s.map(i=>Math.abs(qt(i))),n=new Array(t).fill(!1);for(let i=0;i<t;i++){let r=0;const o=s[i][0],l=s[i][1];for(let a=0;a<t;a++)i!==a&&e[a]>e[i]&&Yt(o,l,s[a])&&r++;n[i]=r%2===1}return n}function an(s){if(s.length<=1)return[s];const t=zt(s),e=s.map((o,l)=>{const a=qt(o);return{index:l,contour:o,area:a,isOuter:!t[l]}}),n=e.filter(o=>o.isOuter),i=e.filter(o=>!o.isOuter);if(n.length===0)return s.map(o=>[o]);const r=n.map(o=>({outer:o.contour,holes:[]}));for(const o of i){const l=o.contour[0],a=o.contour[1];let h=-1,c=1/0;for(let f=0;f<n.length;f++)if(Yt(l,a,n[f].contour)){const u=Math.abs(n[f].area);u<c&&(c=u,h=f)}h>=0?r[h].holes.push(o.contour):r.push({outer:o.contour,holes:[]})}return r.map(o=>[o.outer,...o.holes])}function qt(s){let t=0;const e=s.length;for(let n=0;n<e;n+=2){const i=s[n],r=s[n+1],o=s[(n+2)%e],l=s[(n+3)%e];t+=i*l-o*r}return t/2}function Yt(s,t,e){let n=!1;const i=e.length;for(let r=0,o=i-2;r<i;o=r,r+=2){const l=e[r],a=e[r+1],h=e[o],c=e[o+1];a>t!=c>t&&s<(h-l)*(t-a)/(c-a)+l&&(n=!n)}return n}function ln(s,t,e=2){const n=t&&t.length>0,i=n?t[0]*e:s.length;let r=jt(s,0,i,e,!0);const o=[];if(!r||r.next===r.prev)return o;n&&(r=dn(s,t,r,e));let l=1/0,a=1/0,h=-1/0,c=-1/0,f=0;if(s.length>80*e){for(let u=0;u<i;u+=e){const x=s[u],p=s[u+1];x<l&&(l=x),p<a&&(a=p),x>h&&(h=x),p>c&&(c=p)}f=Math.max(h-l,c-a),f=f!==0?32767/f:0}return rt(r,o,e,l,a,f,0),o}function jt(s,t,e,n,i){let r=null;if(i===yn(s,t,e,n)>0)for(let o=t;o<e;o+=n)r=Kt(o,s[o],s[o+1],r);else for(let o=e-n;o>=t;o-=n)r=Kt(o,s[o],s[o+1],r);return r&>(r,r.next)&&(ot(r),r=r.next),r?(r.next.prev=r,r.prev.next=r,r.next):null}function j(s,t){t||(t=s);let e=s,n;do if(n=!1,!e.steiner&&(gt(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 rt(s,t,e,n,i,r,o){if(!s)return;!o&&r&&vn(s,n,i,r);let l=s,a,h;for(;s.prev!==s.next;){if(a=s.prev,h=s.next,r?cn(s,n,i,r):un(s)){t.push(a.i/e,s.i/e,h.i/e),ot(s),s=h.next,l=h.next;continue}if(s=h,s===l){o?o===1?(s=hn(j(s),t,e),rt(s,t,e,n,i,r,2)):o===2&&fn(s,t,e,n,i,r):rt(j(s),t,e,n,i,r,1);break}}}function un(s){const t=s.prev,e=s,n=s.next;if(L(t,e,n)>=0)return!1;const i=t.x,r=e.x,o=n.x,l=t.y,a=e.y,h=n.y,c=i<r?i<o?i:o:r<o?r:o,f=l<a?l<h?l:h:a<h?a:h,u=i>r?i>o?i:o:r>o?r:o,x=l>a?l>h?l:h:a>h?a:h;let p=n.next;for(;p!==t;){if(p.x>=c&&p.x<=u&&p.y>=f&&p.y<=x&&J(i,l,r,a,o,h,p.x,p.y)&&L(p.prev,p,p.next)>=0)return!1;p=p.next}return!0}function cn(s,t,e,n){const i=s.prev,r=s,o=s.next;if(L(i,r,o)>=0)return!1;const l=i.x,a=r.x,h=o.x,c=i.y,f=r.y,u=o.y,x=l<a?l<h?l:h:a<h?a:h,p=c<f?c<u?c:u:f<u?f:u,d=l>a?l>h?l:h:a>h?a:h,y=c>f?c>u?c:u:f>u?f:u,b=At(x,p,t,e,n),E=At(d,y,t,e,n);let g=s.prevZ,v=s.nextZ;for(;g&&g.z>=b&&v&&v.z<=E;){if(g.x>=x&&g.x<=d&&g.y>=p&&g.y<=y&&g!==i&&g!==o&&J(l,c,a,f,h,u,g.x,g.y)&&L(g.prev,g,g.next)>=0||(g=g.prevZ,v.x>=x&&v.x<=d&&v.y>=p&&v.y<=y&&v!==i&&v!==o&&J(l,c,a,f,h,u,v.x,v.y)&&L(v.prev,v,v.next)>=0))return!1;v=v.nextZ}for(;g&&g.z>=b;){if(g.x>=x&&g.x<=d&&g.y>=p&&g.y<=y&&g!==i&&g!==o&&J(l,c,a,f,h,u,g.x,g.y)&&L(g.prev,g,g.next)>=0)return!1;g=g.prevZ}for(;v&&v.z<=E;){if(v.x>=x&&v.x<=d&&v.y>=p&&v.y<=y&&v!==i&&v!==o&&J(l,c,a,f,h,u,v.x,v.y)&&L(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function hn(s,t,e){let n=s;do{const i=n.prev,r=n.next.next;!gt(i,r)&&Zt(i,n,n.next,r)&&st(i,r)&&st(r,i)&&(t.push(i.i/e,n.i/e,r.i/e),ot(n),ot(n.next),n=s=r),n=n.next}while(n!==s);return j(n)}function fn(s,t,e,n,i,r){let o=s;do{let l=o.next.next;for(;l!==o.prev;){if(o.i!==l.i&&En(o,l)){let a=$t(o,l);o=j(o,o.next),a=j(a,a.next),rt(o,t,e,n,i,r,0),rt(a,t,e,n,i,r,0);return}l=l.next}o=o.next}while(o!==s)}function dn(s,t,e,n){const i=[];for(let r=0;r<t.length;r++){const o=t[r]*n,l=r<t.length-1?t[r+1]*n:s.length,a=jt(s,o,l,n,!1);a&&(a===a.next&&(a.steiner=!0),i.push(Tn(a)))}i.sort((r,o)=>r.x-o.x);for(const r of i)e=mn(r,e);return e}function mn(s,t){const e=pn(s,t);if(!e)return t;const n=$t(e,s);return j(n,n.next),j(e,e.next)}function pn(s,t){let e=t;const n=s.x,i=s.y;let r=-1/0,o=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,o=e.x<e.next.x?e:e.next,f===n))return o}e=e.next}while(e!==t);if(!o)return null;const l=o,a=o.x,h=o.y;let c=1/0;e=o;do{if(n>=e.x&&e.x>=a&&n!==e.x&&J(i<h?n:r,i,a,h,i<h?r:n,i,e.x,e.y)){const f=Math.abs(i-e.y)/(n-e.x);st(e,s)&&(f<c||f===c&&(e.x>o.x||gn(o,e)))&&(o=e,c=f)}e=e.next}while(e!==l);return o}function gn(s,t){return L(s.prev,s,t.prev)<0&&L(t.next,s,s.next)<0}function vn(s,t,e,n){let i=s;do i.z===0&&(i.z=At(i.x,i.y,t,e,n)),i.prevZ=i.prev,i.nextZ=i.next,i=i.next;while(i!==s);i.prevZ.nextZ=null,i.prevZ=null,xn(i)}function xn(s){let t=1,e;do{let n=s;s=null;let i=null;for(e=0;n;){e++;let r=n,o=0;for(let a=0;a<t&&(o++,r=r.nextZ,!!r);a++);let l=t;for(;o>0||l>0&&r;){let a;o!==0&&(l===0||!r||n.z<=r.z)?(a=n,n=n.nextZ,o--):(a=r,r=r.nextZ,l--),i?i.nextZ=a:s=a,a.prevZ=i,i=a}n=r}i.nextZ=null,t*=2}while(e>1);return s}function At(s,t,e,n,i){let r=(s-e)*i|0,o=(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,o=(o|o<<8)&16711935,o=(o|o<<4)&252645135,o=(o|o<<2)&858993459,o=(o|o<<1)&1431655765,r|o<<1}function Tn(s){let t=s,e=s;do(t.x<e.x||t.x===e.x&&t.y<e.y)&&(e=t),t=t.next;while(t!==s);return e}function J(s,t,e,n,i,r,o,l){return(i-o)*(t-l)-(s-o)*(r-l)>=0&&(s-o)*(n-l)-(e-o)*(t-l)>=0&&(e-o)*(r-l)-(i-o)*(n-l)>=0}function En(s,t){return s.next.i!==t.i&&s.prev.i!==t.i&&!bn(s,t)&&(st(s,t)&&st(t,s)&&Sn(s,t)&&(L(s.prev,s,t.prev)!==0||L(s,t.prev,t)!==0)||gt(s,t)&&L(s.prev,s,s.next)>0&&L(t.prev,t,t.next)>0)}function L(s,t,e){return(t.y-s.y)*(e.x-t.x)-(t.x-s.x)*(e.y-t.y)}function gt(s,t){return s.x===t.x&&s.y===t.y}function Zt(s,t,e,n){const i=xt(L(s,t,e)),r=xt(L(s,t,n)),o=xt(L(e,n,s)),l=xt(L(e,n,t));return!!(i!==r&&o!==l||i===0&&vt(s,e,t)||r===0&&vt(s,n,t)||o===0&&vt(e,s,n)||l===0&&vt(e,t,n))}function vt(s,t,e){return t.x<=Math.max(s.x,e.x)&&t.x>=Math.min(s.x,e.x)&&t.y<=Math.max(s.y,e.y)&&t.y>=Math.min(s.y,e.y)}function xt(s){return s>0?1:s<0?-1:0}function bn(s,t){let e=s;do{if(e.i!==s.i&&e.next.i!==s.i&&e.i!==t.i&&e.next.i!==t.i&&Zt(e,e.next,s,t))return!0;e=e.next}while(e!==s);return!1}function st(s,t){return L(s.prev,s,s.next)<0?L(s,t,s.next)>=0&&L(s,s.prev,t)>=0:L(s,t,s.prev)<0||L(s,s.next,t)<0}function Sn(s,t){let e=s,n=!1;const i=(s.x+t.x)/2,r=(s.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!==s);return n}function $t(s,t){const e=Pt(s.i,s.x,s.y),n=Pt(t.i,t.x,t.y),i=s.next,r=t.prev;return s.next=t,t.prev=s,e.next=i,i.prev=e,n.next=e,e.prev=n,r.next=n,n.prev=r,n}function Kt(s,t,e,n){const i=Pt(s,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(s){s.next.prev=s.prev,s.prev.next=s.next,s.prevZ&&(s.prevZ.nextZ=s.nextZ),s.nextZ&&(s.nextZ.prevZ=s.prevZ)}function Pt(s,t,e){return{i:s,x:t,y:e,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function yn(s,t,e,n){let i=0;for(let r=t,o=e-n;r<e;r+=n)i+=(s[o]-s[r])*(s[r+1]+s[o+1]),o=r;return i}const w={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},Q=512,tt=512;class Tt extends HTMLElement{static TAG_NAME="layershift-portal";static get observedAttributes(){return["src","depth-src","depth-width","depth-height","depth-fps","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-width","depth-height","depth-fps","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"),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 Xt(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 wn(n)}getAttrVec3(t,e){const i=(this.getAttribute(t)??e).split(",").map(o=>parseFloat(o.trim()));if(i.length>=3&&i.every(Number.isFinite))return[i[0],i[1],i[2]];const r=e.split(",").map(o=>parseFloat(o.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",w.parallaxX)}get parallaxY(){return this.getAttrFloat("parallax-y",w.parallaxY)}get parallaxMax(){return this.getAttrFloat("parallax-max",w.parallaxMax)}get overscan(){return this.getAttrFloat("overscan",w.overscan)}get pomSteps(){return this.getAttrFloat("pom-steps",w.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",w.rimIntensity)}get rimWidth(){return this.getAttrFloat("rim-width",w.rimWidth)}get rimColor(){return this.getAttrColor("rim-color",w.rimColor)}get refractionStrength(){return this.getAttrFloat("refraction-strength",w.refractionStrength)}get chromaticStrength(){return this.getAttrFloat("chromatic-strength",w.chromaticStrength)}get occlusionIntensity(){return this.getAttrFloat("occlusion-intensity",w.occlusionIntensity)}get depthPower(){return this.getAttrFloat("depth-power",w.depthPower)}get depthScale(){return this.getAttrFloat("depth-scale",w.depthScale)}get depthBias(){return this.getAttrFloat("depth-bias",w.depthBias)}get fogDensity(){return this.getAttrFloat("fog-density",w.fogDensity)}get fogColor(){return this.getAttrColor("fog-color",w.fogColor)}get colorShift(){return this.getAttrFloat("color-shift",w.colorShift)}get brightnessBias(){return this.getAttrFloat("brightness-bias",w.brightnessBias)}get contrastLow(){return this.getAttrFloat("contrast-low",w.contrastLow)}get contrastHigh(){return this.getAttrFloat("contrast-high",w.contrastHigh)}get verticalReduction(){return this.getAttrFloat("vertical-reduction",w.verticalReduction)}get dofStart(){return this.getAttrFloat("dof-start",w.dofStart)}get dofStrength(){return this.getAttrFloat("dof-strength",w.dofStrength)}get bevelIntensity(){return this.getAttrFloat("bevel-intensity",w.bevelIntensity)}get bevelWidth(){return this.getAttrFloat("bevel-width",w.bevelWidth)}get bevelDarkening(){return this.getAttrFloat("bevel-darkening",w.bevelDarkening)}get bevelDesaturation(){return this.getAttrFloat("bevel-desaturation",w.bevelDesaturation)}get bevelLightAngle(){return this.getAttrFloat("bevel-light-angle",w.bevelLightAngle)}get edgeThickness(){return this.getAttrFloat("edge-thickness",w.edgeThickness)}get edgeSpecular(){return this.getAttrFloat("edge-specular",w.edgeSpecular)}get edgeColor(){return this.getAttrColor("edge-color",w.edgeColor)}get chamferWidth(){return this.getAttrFloat("chamfer-width",w.chamferWidth)}get chamferAngle(){return this.getAttrFloat("chamfer-angle",w.chamferAngle)}get chamferColor(){return this.getAttrColor("chamfer-color",w.chamferColor)}get chamferAmbient(){return this.getAttrFloat("chamfer-ambient",w.chamferAmbient)}get chamferSpecular(){return this.getAttrFloat("chamfer-specular",w.chamferSpecular)}get chamferShininess(){return this.getAttrFloat("chamfer-shininess",w.chamferShininess)}get edgeOcclusionWidth(){return this.getAttrFloat("edge-occlusion-width",w.edgeOcclusionWidth)}get edgeOcclusionStrength(){return this.getAttrFloat("edge-occlusion-strength",w.edgeOcclusionStrength)}get lightDirection3(){return this.getAttrVec3("light-direction",w.lightDirection)}get depthModel(){return this.getAttribute("depth-model")}get shouldAutoplay(){return this.getAttrBool("autoplay",w.autoplay)}get shouldLoop(){return this.getAttrBool("loop",w.loop)}get shouldMute(){return this.getAttrBool("muted",w.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
1040
|
:host {
|
|
999
1041
|
display: block;
|
|
1000
1042
|
width: 100%;
|
|
@@ -1014,4 +1056,4 @@ void main() {
|
|
|
1014
1056
|
width: 100%;
|
|
1015
1057
|
height: 100%;
|
|
1016
1058
|
}
|
|
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,
|
|
1059
|
+
`,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,o,l,a=null;const h=d=>{this.emit("layershift-portal:model-progress",d)};if(n){const[d,y]=await Promise.all([Bt({video:{facingMode:"user"}},{parent:this.shadow}),Rt(e)]);if(t.aborted){d.dispose();return}if(r=d,l=y,i){if(a=await dt(i,Q,tt,h),t.aborted){a.dispose(),r.dispose();return}o=N(Q,tt)}else o=N(r.width,r.height)}else{const d=this.getAttribute("src"),y=this.getAttribute("depth-src"),b=!!y,E=this.sourceType==="image"||/\.(jpe?g|png|webp|gif|avif|bmp)(\?|$)/i.test(d);if(b){const[g,v,m]=await Promise.all([E?ft(d):ht(d,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),Ft(y,this.getAttrFloat("depth-width",512),this.getAttrFloat("depth-height",512),this.getAttrFloat("depth-fps",5)),Rt(e)]);if(t.aborted){g.dispose();return}r=g,o=v,l=m}else if(i){const[g,v,m]=await Promise.all([E?ft(d):ht(d,{parent:this.shadow,loop:this.shouldLoop,muted:this.shouldMute}),dt(i,Q,tt,h),Rt(e)]);if(t.aborted){g.dispose(),v.dispose();return}if(r=g,a=v,l=m,E||!r.isLive){const T=r.getImageSource();if(T){const R=await a.submitFrameAndWait(T);o={width:Q,height:tt,fps:1,frameCount:1,frames:[R]}}else o=N(Q,tt)}else o=N(Q,tt)}else throw new Error("Either depth-src or depth-model must be provided.")}this.source=r,this.depthEstimator=a,this.mesh=l,this.loopCount=0,this.attachSourceEventListeners(r);const c=this.container?.clientWidth||r.width,f=this.parallaxMax/Math.max(c,1);let u;if(a)u=()=>a.getLatestDepth();else{const d=new Dt(o);u=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 $e(this.container,x),this.renderer.initialize(r,o.width,o.height,l);const p=a;if(this.renderer.start(r,u,()=>({x:this._input.x,y:this._input.y}),(d,y)=>{if(p){const b=r.getImageSource();b&&p.submitFrame(b)}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 o=r instanceof Error?r.message:"Failed to initialize.";console.error("<layershift-portal>: Failed to initialize.",r),this.emit("layershift-portal:error",{message:o})}}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 wn(s){const t=s.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(s,t,e){return Math.min(e,Math.max(t,s))}function W(s,t,e){return s+(t-s)*e}const z=100,Jt=.06;function Rn(s,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??.08;let r=0,o=0,l=0,a=0,h=0,c=!0;const f=p=>{const d=s.getBoundingClientRect(),y=(p.clientX-d.left)/d.width*2-1,b=(p.clientY-d.top)/d.height*2-1;r=V(y,-1,1),o=V(b,-1,1)},u=()=>{r=0,o=0},x=()=>{c&&(l=W(l,r,i),a=W(a,o,i),s.input={x:l*e,y:a*n},h=requestAnimationFrame(x))};return s.addEventListener("mousemove",f),s.addEventListener("mouseleave",u),h=requestAnimationFrame(x),()=>{c=!1,cancelAnimationFrame(h),s.removeEventListener("mousemove",f),s.removeEventListener("mouseleave",u)}}function An(s,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??.08;let r=0,o=0,l=0,a=0,h=0,c=0,f=0,u=!0;const x=b=>{const E=b.touches[0];E&&(h=E.clientX-l*z,c=E.clientY-a*z,r=l,o=a)},p=b=>{const E=b.touches[0];if(!E)return;const g=E.clientX-h,v=E.clientY-c;r=V(g/z,-1,1),o=V(v/z,-1,1)},d=()=>{r=0,o=0},y=()=>{u&&(l=W(l,r,i),a=W(a,o,i),s.input={x:l*e,y:a*n},f=requestAnimationFrame(y))};return s.addEventListener("touchstart",x,{passive:!0}),s.addEventListener("touchmove",p,{passive:!0}),s.addEventListener("touchend",d,{passive:!0}),s.addEventListener("touchcancel",d,{passive:!0}),f=requestAnimationFrame(y),()=>{u=!1,cancelAnimationFrame(f),s.removeEventListener("touchstart",x),s.removeEventListener("touchmove",p),s.removeEventListener("touchend",d),s.removeEventListener("touchcancel",d)}}function Pn(s,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??Jt;let r=0,o=0,l=0,a=0,h=0,c=!0,f=!1;const u=y=>{r=V((y.gamma??0)/45,-1,1),o=V((y.beta??0)/45,-1,1)},x=()=>{c&&(l=W(l,r,i),a=W(a,o,i),s.input={x:l*e,y:a*n},h=requestAnimationFrame(x))},p=()=>{c&&!f&&(window.addEventListener("deviceorientation",u),f=!0)},d=DeviceOrientationEvent;return typeof d.requestPermission=="function"?d.requestPermission().then(y=>{y==="granted"&&p()}).catch(()=>{}):p(),h=requestAnimationFrame(x),()=>{c=!1,cancelAnimationFrame(h),f&&(window.removeEventListener("deviceorientation",u),f=!1)}}function Dn(s,t){const e=t?.sensitivityX??1,n=t?.sensitivityY??1,i=t?.lerpFactor??.08,r=t?.lerpFactor??Jt;let o=0,l=0,a=0,h=0,c=0,f=0,u=0,x=0,p=!1,d=!1,y=!1,b=0,E=0,g=0,v=!0;const m=S=>{const D=s.getBoundingClientRect(),U=(S.clientX-D.left)/D.width*2-1,M=(S.clientY-D.top)/D.height*2-1;o=V(U,-1,1),l=V(M,-1,1)},T=()=>{o=0,l=0},R=S=>{const D=S.touches[0];D&&(p=!0,b=D.clientX-u*z,E=D.clientY-x*z,a=u,h=x,!d&&!y&&I())},A=S=>{const D=S.touches[0];if(!D)return;const U=D.clientX-b,M=D.clientY-E;a=V(U/z,-1,1),h=V(M/z,-1,1)},P=()=>{p=!1,a=0,h=0},F=S=>{c=V((S.gamma??0)/45,-1,1),f=V((S.beta??0)/45,-1,1)},_=()=>{v&&!y&&(window.addEventListener("deviceorientation",F),y=!0,d=!0)},I=()=>{if(typeof DeviceOrientationEvent>"u")return;const S=DeviceOrientationEvent;typeof S.requestPermission=="function"?S.requestPermission().then(D=>{D==="granted"&&_()}).catch(()=>{}):_()},C=()=>{if(!v)return;let S,D,U;p?(S=a,D=h,U=i):d?(S=c,D=f,U=r):(S=o,D=l,U=i),u=W(u,S,U),x=W(x,D,U),s.input={x:u*e,y:x*n},g=requestAnimationFrame(C)};return s.addEventListener("mousemove",m),s.addEventListener("mouseleave",T),s.addEventListener("touchstart",R,{passive:!0}),s.addEventListener("touchmove",A,{passive:!0}),s.addEventListener("touchend",P,{passive:!0}),s.addEventListener("touchcancel",P,{passive:!0}),g=requestAnimationFrame(C),()=>{v=!1,cancelAnimationFrame(g),s.removeEventListener("mousemove",m),s.removeEventListener("mouseleave",T),s.removeEventListener("touchstart",R),s.removeEventListener("touchmove",A),s.removeEventListener("touchend",P),s.removeEventListener("touchcancel",P),y&&(window.removeEventListener("deviceorientation",F),y=!1)}}return customElements.get(pt.TAG_NAME)||customElements.define(pt.TAG_NAME,pt),customElements.get(Tt.TAG_NAME)||customElements.define(Tt.TAG_NAME,Tt),X.LayershiftElement=pt,X.LayershiftPortalElement=Tt,X.connectGyro=Pn,X.connectMouse=Rn,X.connectPointer=Dn,X.connectTouch=An,Object.defineProperty(X,Symbol.toStringTag,{value:"Module"}),X})({});
|