@joshtol/emotive-engine 3.2.1 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import*as e from"three";import{Vector2 as t,WebGLRenderTarget as i,HalfFloatType as n,RGBAFormat as a,LinearFilter as s,ShaderMaterial as o,Vector3 as r,AdditiveBlending as l,Color as h,MeshBasicMaterial as c}from"three";import{EffectComposer as u}from"three/examples/jsm/postprocessing/EffectComposer.js";import{RenderPass as d}from"three/examples/jsm/postprocessing/RenderPass.js";import{Pass as m,FullScreenQuad as p}from"three/examples/jsm/postprocessing/Pass.js";import{OrbitControls as g}from"three/examples/jsm/controls/OrbitControls.js";import{OBJLoader as f}from"three/examples/jsm/loaders/OBJLoader.js";new t(.5,.5),new t(.5,.5);class y extends m{constructor(e,u,d,m){super(),this.strength=void 0!==u?u:1,this.radius=d,this.threshold=m,this.resolution=void 0!==e?new t(e.x,e.y):new t(256,256);const g={minFilter:s,magFilter:s,format:a,type:n};this.renderTargetsHorizontal=[],this.renderTargetsVertical=[],this.nMips=5;let f=Math.round(.75*this.resolution.x),y=Math.round(.75*this.resolution.y);this.renderTargetBright=new i(f,y,g),this.renderTargetBright.texture.name="UnrealBloomPassAlpha.bright",this.renderTargetBright.texture.generateMipmaps=!1;for(let e=0;e<this.nMips;e++){const t=new i(f,y,g);t.texture.name=`UnrealBloomPassAlpha.h${e}`,t.texture.generateMipmaps=!1,this.renderTargetsHorizontal.push(t);const n=new i(f,y,g);n.texture.name=`UnrealBloomPassAlpha.v${e}`,n.texture.generateMipmaps=!1,this.renderTargetsVertical.push(n),f=Math.round(f/2),y=Math.round(y/2)}this.highPassUniforms={tDiffuse:{value:null},luminosityThreshold:{value:m},smoothWidth:{value:.01}},this.materialHighPassFilter=new o({uniforms:this.highPassUniforms,vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }",fragmentShader:"\n uniform sampler2D tDiffuse;\n uniform float luminosityThreshold;\n uniform float smoothWidth;\n varying vec2 vUv;\n\n void main() {\n vec4 texel = texture2D(tDiffuse, vUv);\n vec3 luma = vec3(0.299, 0.587, 0.114);\n float v = dot(texel.xyz, luma);\n float alpha = smoothstep(luminosityThreshold, luminosityThreshold + smoothWidth, v);\n\n // CRITICAL: Preserve original alpha, only filter by luminosity\n gl_FragColor = vec4(texel.rgb * alpha, texel.a);\n }"}),this.separableBlurMaterials=[];const v=[3,5,7,9,11];f=Math.round(.75*this.resolution.x),y=Math.round(.75*this.resolution.y);for(let e=0;e<this.nMips;e++)this.separableBlurMaterials.push(this.getSeperableBlurMaterial(v[e])),this.separableBlurMaterials[e].uniforms.texSize.value=new t(f,y),f=Math.round(f/2),y=Math.round(y/2);this.compositeMaterial=this.getCompositeMaterial(this.nMips),this.compositeMaterial.uniforms.blurTexture1.value=this.renderTargetsVertical[0].texture,this.compositeMaterial.uniforms.blurTexture2.value=this.renderTargetsVertical[1].texture,this.compositeMaterial.uniforms.blurTexture3.value=this.renderTargetsVertical[2].texture,this.compositeMaterial.uniforms.blurTexture4.value=this.renderTargetsVertical[3].texture,this.compositeMaterial.uniforms.blurTexture5.value=this.renderTargetsVertical[4].texture,this.compositeMaterial.uniforms.bloomStrength.value=u,this.compositeMaterial.uniforms.bloomRadius.value=.1,this.compositeMaterial.uniforms.bloomFactors.value=[1,.8,.6,.4,.2],this.bloomTintColors=[new r(1,1,1),new r(1,1,1),new r(1,1,1),new r(1,1,1),new r(1,1,1)],this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,this.materialCopy=new o({uniforms:{tDiffuse:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }",fragmentShader:"\n uniform sampler2D tDiffuse;\n varying vec2 vUv;\n void main() {\n gl_FragColor = texture2D(tDiffuse, vUv);\n }",blending:l,depthTest:!1,depthWrite:!1,transparent:!0}),this.enabled=!0,this.needsSwap=!1,this._oldClearColor=new h,this.oldClearAlpha=1,this.clearColor=new h(0,0,0),this.basic=new c({transparent:!0,depthTest:!1,depthWrite:!1}),this.fsQuad=new p(null)}dispose(){if(this.renderTargetsHorizontal)for(let e=0;e<this.renderTargetsHorizontal.length;e++)this.renderTargetsHorizontal[e]?.dispose();if(this.renderTargetsVertical)for(let e=0;e<this.renderTargetsVertical.length;e++)this.renderTargetsVertical[e]?.dispose();if(this.renderTargetBright?.dispose(),this.separableBlurMaterials)for(let e=0;e<this.separableBlurMaterials.length;e++)this.separableBlurMaterials[e]?.dispose();this.compositeMaterial?.dispose(),this.blendMaterial?.dispose(),this.basic?.dispose(),this.fsQuad?.dispose()}clearBloomBuffers(e){const t=e.getRenderTarget(),i=e.getClearColor(this._oldClearColor),n=e.getClearAlpha();e.setClearColor(0,0),e.setRenderTarget(this.renderTargetBright),e.clear();for(let t=0;t<this.renderTargetsHorizontal.length;t++)e.setRenderTarget(this.renderTargetsHorizontal[t]),e.clear();for(let t=0;t<this.renderTargetsVertical.length;t++)e.setRenderTarget(this.renderTargetsVertical[t]),e.clear();e.setRenderTarget(t),e.setClearColor(i,n)}setSize(e,i){let n=Math.round(.75*e),a=Math.round(.75*i);this.renderTargetBright.setSize(n,a);for(let e=0;e<this.nMips;e++)this.renderTargetsHorizontal[e].setSize(n,a),this.renderTargetsVertical[e].setSize(n,a),this.separableBlurMaterials[e].uniforms.texSize.value=new t(n,a),n=Math.round(n/2),a=Math.round(a/2)}render(e,t,i,n,a){e.getClearColor(this._oldClearColor),this.oldClearAlpha=e.getClearAlpha();const s=e.autoClear;e.autoClear=!1,e.setClearColor(this.clearColor,0),a&&e.state.buffers.stencil.setTest(!1),this.renderToScreen&&!this.skipBaseCopy&&(this.fsQuad.material=this.basic,this.basic.map=i.texture,e.setRenderTarget(null),this.fsQuad.render(e)),this.highPassUniforms.tDiffuse.value=i.texture,this.highPassUniforms.luminosityThreshold.value=this.threshold,this.fsQuad.material=this.materialHighPassFilter,e.setRenderTarget(this.renderTargetBright),e.clear(),this.fsQuad.render(e);let o=this.renderTargetBright;for(let t=0;t<this.nMips;t++)this.fsQuad.material=this.separableBlurMaterials[t],this.separableBlurMaterials[t].uniforms.colorTexture.value=o.texture,this.separableBlurMaterials[t].uniforms.direction.value=y.BlurDirectionX,e.setRenderTarget(this.renderTargetsHorizontal[t]),e.clear(),this.fsQuad.render(e),this.separableBlurMaterials[t].uniforms.colorTexture.value=this.renderTargetsHorizontal[t].texture,this.separableBlurMaterials[t].uniforms.direction.value=y.BlurDirectionY,e.setRenderTarget(this.renderTargetsVertical[t]),e.clear(),this.fsQuad.render(e),o=this.renderTargetsVertical[t];this.fsQuad.material=this.compositeMaterial,this.compositeMaterial.uniforms.bloomStrength.value=this.strength,this.compositeMaterial.uniforms.bloomRadius.value=this.radius,this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,e.setRenderTarget(this.renderTargetsHorizontal[0]),e.clear(),this.fsQuad.render(e),this.fsQuad.material=this.materialCopy,this.materialCopy.uniforms.tDiffuse.value=this.renderTargetsHorizontal[0].texture,a&&e.state.buffers.stencil.setTest(!0),this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(i),this.fsQuad.render(e)),e.setClearColor(this._oldClearColor,this.oldClearAlpha),e.autoClear=s}getSeperableBlurMaterial(e){return new o({defines:{MAX_RADIUS:e},uniforms:{colorTexture:{value:null},texSize:{value:new t(.5,.5)},direction:{value:new t(.5,.5)},kernelRadius:{value:1}},vertexShader:"\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n #include <common>\n varying vec2 vUv;\n uniform sampler2D colorTexture;\n uniform vec2 texSize;\n uniform vec2 direction;\n uniform float kernelRadius;\n\n float gaussianPdf(in float x, in float sigma) {\n return 0.39894 * exp( -0.5 * x * x / ( sigma * sigma ) ) / sigma;\n }\n\n void main() {\n vec2 invSize = 1.0 / texSize;\n float sigma = kernelRadius / 2.0;\n float weightSum = gaussianPdf(0.0, sigma);\n\n // CRITICAL: Accumulate RGB and alpha SEPARATELY\n // Include center pixel for BOTH RGB and alpha\n vec4 centerPixel = texture2D(colorTexture, vUv);\n vec3 diffuseSum = centerPixel.rgb * weightSum;\n float alphaSum = centerPixel.a * weightSum;\n\n vec2 delta = direction * invSize * kernelRadius / float(MAX_RADIUS);\n\n for( int i = 1; i < MAX_RADIUS; i ++ ) {\n float x = kernelRadius * float(i) / float(MAX_RADIUS);\n float w = gaussianPdf(x, sigma);\n\n vec2 uvOffset = delta * float(i);\n vec4 sample1 = texture2D(colorTexture, vUv + uvOffset);\n vec4 sample2 = texture2D(colorTexture, vUv - uvOffset);\n\n // Accumulate RGB and alpha separately\n diffuseSum += (sample1.rgb + sample2.rgb) * w;\n alphaSum += (sample1.a + sample2.a) * w;\n weightSum += 2.0 * w;\n }\n\n // Output with separately normalized alpha\n gl_FragColor = vec4(diffuseSum / weightSum, alphaSum / weightSum);\n }"})}getCompositeMaterial(e){return new o({uniforms:{blurTexture1:{value:null},blurTexture2:{value:null},blurTexture3:{value:null},blurTexture4:{value:null},blurTexture5:{value:null},bloomStrength:{value:1},bloomFactors:{value:null},bloomTintColors:{value:null},bloomRadius:{value:0}},vertexShader:"\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n varying vec2 vUv;\n uniform sampler2D blurTexture1;\n uniform sampler2D blurTexture2;\n uniform sampler2D blurTexture3;\n uniform sampler2D blurTexture4;\n uniform sampler2D blurTexture5;\n uniform float bloomStrength;\n uniform float bloomRadius;\n uniform float bloomFactors[5];\n uniform vec3 bloomTintColors[5];\n\n float lerpBloomFactor(const in float factor) {\n float mirrorFactor = 1.2 - factor;\n return mix(factor, mirrorFactor, bloomRadius);\n }\n\n void main() {\n // ALPHA PRESERVATION: Sample all textures and preserve their alpha\n vec4 sample1 = texture2D(blurTexture1, vUv);\n vec4 sample2 = texture2D(blurTexture2, vUv);\n vec4 sample3 = texture2D(blurTexture3, vUv);\n vec4 sample4 = texture2D(blurTexture4, vUv);\n vec4 sample5 = texture2D(blurTexture5, vUv);\n\n // Apply tint to RGB only, preserve alpha from samples\n vec4 color = bloomStrength * (\n lerpBloomFactor(bloomFactors[0]) * vec4(sample1.rgb * bloomTintColors[0], sample1.a) +\n lerpBloomFactor(bloomFactors[1]) * vec4(sample2.rgb * bloomTintColors[1], sample2.a) +\n lerpBloomFactor(bloomFactors[2]) * vec4(sample3.rgb * bloomTintColors[2], sample3.a) +\n lerpBloomFactor(bloomFactors[3]) * vec4(sample4.rgb * bloomTintColors[3], sample4.a) +\n lerpBloomFactor(bloomFactors[4]) * vec4(sample5.rgb * bloomTintColors[4], sample5.a)\n );\n\n gl_FragColor = color;\n }"})}}function v(e,t=.5){const[i,n,a]=e,s=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),o=s(i),r=s(n),l=s(a),h=.2126*o+.7152*r+.0722*l,c=t/Math.max(h,.001);let u=o*c,d=r*c,m=l*c;const p=Math.max(u,d,m);p>1&&(u/=p,d/=p,m/=p);const g=e=>e<=.0031308?12.92*e:1.055*Math.pow(e,1/2.4)-.055;return{r:Math.min(1,Math.max(0,g(u))),g:Math.min(1,Math.max(0,g(d))),b:Math.min(1,Math.max(0,g(m)))}}function b(e,t=0,i="glow"){const n=function(e){const t=parseInt(e.slice(1,3),16)/255,i=parseInt(e.slice(3,5),16)/255,n=parseInt(e.slice(5,7),16)/255,a=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);return.2126*a(t)+.7152*a(i)+.0722*a(n)}(e),a=(.5+t)/Math.max(n,.05);return Math.max(.3,Math.min(10,a))}y.BlurDirectionX=new t(1,0),y.BlurDirectionY=new t(0,1);class w{constructor(t){this.renderer=t,this.glowAmount=0,this.targetGlowAmount=0,this.glowColor=new e.Color(1,1,1),this.targetGlowColor=new e.Color(1,1,1),this.worldPosition=new e.Vector3(0,0,0),this.time=0,this.ringPhase=0,this.scene=new e.Scene,this.camera=new e.OrthographicCamera(-1,1,1,-1,.1,10),this.camera.position.z=1,this.createGlowMesh(),this._tempVector=new e.Vector3,this._tempColor=new e.Color}createGlowMesh(){const t=new e.PlaneGeometry(2,2),i=new e.ShaderMaterial({uniforms:{glowAmount:{value:0},glowColor:{value:new e.Color(1,1,1)},centerUV:{value:new e.Vector2(.5,.5)},time:{value:0},ringPhase:{value:0},aspectRatio:{value:1}},vertexShader:"\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = vec4(position.xy, 0.0, 1.0);\n }\n ",fragmentShader:"\n uniform float glowAmount;\n uniform vec3 glowColor;\n uniform vec2 centerUV;\n uniform float time;\n uniform float ringPhase;\n uniform float aspectRatio;\n\n varying vec2 vUv;\n\n void main() {\n // Aspect-correct UV coordinates - apply aspect to Y instead\n // This prevents horizontal clipping on wide screens\n vec2 centeredUV = vUv - centerUV;\n // Don't multiply by aspect - let glow be circular in screen space\n\n float dist = length(centeredUV);\n\n // Ring parameters that evolve with ringPhase\n // MUCH LARGER radii to prevent clipping - glow can extend to screen edges\n // At ringPhase=0: tight ring close to center\n // At ringPhase=1: expanded ring that can fill most of screen\n float innerRadius = mix(0.02, 0.08, ringPhase);\n float outerRadius = mix(0.15, 1.2, ringPhase); // Can extend beyond screen!\n float peakRadius = mix(0.06, 0.25, ringPhase);\n\n // Create soft ring falloff\n // Inner falloff: 0 at center, 1 at peak\n float innerFalloff = smoothstep(innerRadius * 0.3, peakRadius, dist);\n\n // Outer falloff: 1 at peak, 0 at outer edge (very gradual fade)\n float outerFalloff = 1.0 - smoothstep(peakRadius, outerRadius, dist);\n\n // Combine for ring shape\n float ringIntensity = innerFalloff * outerFalloff;\n\n // Add subtle shimmer/undulation\n float shimmer = 0.9 + 0.1 * sin(time * 3.0 + dist * 20.0);\n\n // Final intensity with glow amount control\n float intensity = ringIntensity * glowAmount * shimmer;\n\n // Soft glow color with intensity\n // Use HDR values (>1.0) for bloom pickup\n vec3 color = glowColor * intensity * 2.0;\n\n // Alpha for blending\n float alpha = intensity * 0.6;\n\n gl_FragColor = vec4(color, alpha);\n }\n ",transparent:!0,blending:e.AdditiveBlending,depthTest:!1,depthWrite:!1});this.glowMesh=new e.Mesh(t,i),this.scene.add(this.glowMesh)}setGlow(e,t,i){this.targetGlowAmount=Math.max(0,e),t&&(Array.isArray(t)?this.targetGlowColor.setRGB(t[0],t[1],t[2]):this.targetGlowColor.copy(t)),i&&this.worldPosition.copy(i)}update(e,t){const i=e/1e3;this.time+=i,this.glowAmount+=(this.targetGlowAmount-this.glowAmount)*Math.min(1,8*i),this.glowColor.lerp(this.targetGlowColor,Math.min(1,8*i));const n=Math.min(1,this.glowAmount);if(this.ringPhase+=(n-this.ringPhase)*Math.min(1,4*i),t){this._tempVector.copy(this.worldPosition),this._tempVector.project(t);const e=(this._tempVector.x+1)/2,i=(this._tempVector.y+1)/2;this.glowMesh.material.uniforms.centerUV.value.set(e,i)}this.glowMesh.material.uniforms.glowAmount.value=this.glowAmount,this.glowMesh.material.uniforms.glowColor.value.copy(this.glowColor),this.glowMesh.material.uniforms.time.value=this.time,this.glowMesh.material.uniforms.ringPhase.value=this.ringPhase;const a=this.renderer.domElement;this.glowMesh.material.uniforms.aspectRatio.value=a.width/a.height}render(e){if(this.glowAmount<.001)return;const{autoClear:t}=e;e.autoClear=!1,e.render(this.scene,this.camera),e.autoClear=t}isActive(){return this.glowAmount>.001||this.targetGlowAmount>0}dispose(){this.glowMesh&&(this.glowMesh.geometry.dispose(),this.glowMesh.material.dispose(),this.scene.remove(this.glowMesh),this.glowMesh=null),this.scene=null,this.camera=null,this._tempVector=null,this._tempColor=null}}class M{constructor(t,i={}){this.canvas=t,this.options=i,this._destroyed=!1,this.scene=new e.Scene,this.scene.background=null,this.renderer=new e.WebGLRenderer({canvas:t,alpha:!0,premultipliedAlpha:!1,antialias:!0,powerPreference:"high-performance",preserveDrawingBuffer:!1,precision:"highp",logarithmicDepthBuffer:!1,stencil:!1}),this.renderer.outputColorSpace=e.SRGBColorSpace,this.renderer.toneMapping=e.NoToneMapping,this.renderer.toneMappingExposure=1,this.renderer.setClearColor(0,0),this.renderer.autoClear=!1,this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,1.5)),this.renderer.setSize(t.width,t.height,!1),i.enableShadows&&(this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=e.PCFSoftShadowMap),this._contextLost=!1,this._boundHandleContextLost=this.handleContextLost.bind(this),this._boundHandleContextRestored=this.handleContextRestored.bind(this),t.addEventListener("webglcontextlost",this._boundHandleContextLost,!1),t.addEventListener("webglcontextrestored",this._boundHandleContextRestored,!1);const n=void 0!==i.fov?i.fov:45;this.camera=new e.PerspectiveCamera(n,t.width/t.height,.1,100),this.cameraDistance=void 0!==i.cameraDistance?i.cameraDistance:3,this.camera.position.set(0,0,this.cameraDistance),this.camera.lookAt(0,0,0),!1!==i.enableControls&&this.setupCameraControls(),this.setupLights(),!1!==i.enablePostProcessing&&this.setupPostProcessing(),this.coreMesh=null,this.materialMode="glow",this.glowMaterial=null,this.glassMaterial=null,this.mixer=null,this.clock=new e.Clock,this._tempColor=new e.Color,this._tempColor2=new e.Color,this._white=new e.Color(1,1,1),this._tempQuat=new e.Quaternion,this._tempEuler=new e.Euler,this._quatX=new e.Quaternion,this._quatY=new e.Quaternion,this._quatZ=new e.Quaternion,this._rollQuat=new e.Quaternion,this._meshQuat=new e.Quaternion,this._xAxis=new e.Vector3(1,0,0),this._yAxis=new e.Vector3(0,1,0),this._zAxis=new e.Vector3(0,0,1),this._cameraToMesh=new e.Vector3,this._cameraDir=new e.Vector3}setupCameraControls(){this.controls=new g(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.1;const e=void 0!==this.options.minZoom?this.options.minZoom:.5*this.cameraDistance,t=void 0!==this.options.maxZoom?this.options.maxZoom:2*this.cameraDistance;this.controls.minDistance=e,this.controls.maxDistance=t,this.controls.enablePan=!1,this.controls.autoRotate=!0===this.options.autoRotate,this.controls.autoRotateSpeed=void 0!==this.options.autoRotateSpeed?this.options.autoRotateSpeed:.5,this.controls.minPolarAngle=.2*Math.PI,this.controls.maxPolarAngle=.8*Math.PI,this.controls.rotateSpeed=.8,this.controls.zoomSpeed=1.5,("ontouchstart"in window||navigator.maxTouchPoints>0)&&(this.controls.rotateSpeed=1,this.controls.zoomSpeed=1.2),this.renderer.domElement.style.touchAction="none";const i=()=>{this.controls&&this.controls.update()};this.renderer.domElement.addEventListener("pointermove",i,{passive:!0}),this.renderer.domElement.addEventListener("pointerdown",i,{passive:!0})}setupLights(){this.ambientLight=new e.AmbientLight(16777215,.3),this.ambientLight.name="ambientLight",this.scene.add(this.ambientLight),this.keyLight=new e.DirectionalLight(16777215,.8),this.keyLight.position.set(2,2,2),this.keyLight.name="keyLight",this.options.enableShadows&&(this.keyLight.castShadow=!0,this.keyLight.shadow.mapSize.width=1024,this.keyLight.shadow.mapSize.height=1024,this.keyLight.shadow.camera.near=.5,this.keyLight.shadow.camera.far=10),this.scene.add(this.keyLight),this.fillLight=new e.DirectionalLight(16777215,.5),this.fillLight.position.set(-2,1,1),this.fillLight.name="fillLight",this.scene.add(this.fillLight),this.rimLight=new e.DirectionalLight(16777215,.7),this.rimLight.position.set(0,1,-2),this.rimLight.name="rimLight",this.scene.add(this.rimLight),this.accentLight1=new e.PointLight(54527,.3,10),this.accentLight1.position.set(-3,0,1),this.accentLight1.name="accentLight1",this.scene.add(this.accentLight1),this.accentLight2=new e.PointLight(16716947,.2,10),this.accentLight2.position.set(3,0,1),this.accentLight2.name="accentLight2",this.scene.add(this.accentLight2),this.accentLight3=new e.PointLight(16739125,.2,10),this.accentLight3.position.set(0,3,-1),this.accentLight3.name="accentLight3",this.scene.add(this.accentLight3),this.createEnvironmentMap()}async createEnvironmentMap(){if(this._destroyed)return;try{const{RGBELoader:t}=await import("three/examples/jsm/loaders/RGBELoader.js");if(this._destroyed)return;const i=new e.PMREMGenerator(this.renderer);i.compileEquirectangularShader();try{const n=new t,a=(this.options.assetBasePath||"/assets").replace("/assets",""),s=await n.loadAsync(`${a}/hdri/studio_1k.hdr`);if(!s||!s.image)throw new Error("HDR texture loaded but image data is missing");return this._destroyed?(s.dispose(),void i.dispose()):(s.mapping=e.EquirectangularReflectionMapping,this.envMap=i.fromEquirectangular(s).texture,s.dispose(),i.dispose(),void console.log("[Emotive] HDRI environment map loaded"))}catch(e){i.dispose()}}catch(e){}if(this._destroyed)return;const t=new e.WebGLCubeRenderTarget(512),i=new e.Scene,n=new e.Color(5609983),a=new e.Color(16739229),s=new e.Color(1710638),o=new e.HemisphereLight(n,s,1.5);i.add(o);const r=new e.PointLight(54527,2,20);r.position.set(-5,2,-5),i.add(r);const l=new e.PointLight(16716947,2,20);l.position.set(5,2,-5),i.add(l);const h=new e.PointLight(16755200,1.5,20);h.position.set(0,5,0),i.add(h),i.background=a;const c=new e.CubeCamera(.1,100,t);c.update(this.renderer,i),this.envMap=t.texture,this._envCubeRenderTarget=t,this._envScene=i,this._envCubeCamera=c}setupPostProcessing(){const t=new e.Vector2;this.renderer.getDrawingBufferSize(t);const i=new e.WebGLRenderTarget(t.x,t.y,{format:e.RGBAFormat,type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,stencilBuffer:!1,depthBuffer:!0});this.composer=new u(this.renderer,i);const n=new d(this.scene,this.camera);n.clearColor=new e.Color(0),n.clearAlpha=0,this.composer.addPass(n);const a="ontouchstart"in window||navigator.maxTouchPoints>0?.5:1,s=new e.Vector2(Math.floor(t.x*a),Math.floor(t.y*a));this.bloomPass=new y(s,1.2,.8,.3),this.bloomPass.name="bloomPass",this.bloomPass.enabled=!0,this.bloomPass.renderToScreen=!0,this.composer.addPass(this.bloomPass),this.particleRenderTarget=new e.WebGLRenderTarget(t.x,t.y,{format:e.RGBAFormat,type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,stencilBuffer:!1,depthBuffer:!0}),this.particleBloomPass=new y(s,.5,.4,.3),this.particleBloomPass.name="particleBloomPass",this.particleBloomPass.enabled=!0,this.particleBloomPass.clearColor=new e.Color(1,1,1),this.particleBloomPass.skipBaseCopy=!0,this.soulRenderTarget=new e.WebGLRenderTarget(t.x,t.y,{format:e.RGBAFormat,type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,stencilBuffer:!1,depthBuffer:!0}),this.particleCompositeShader={uniforms:{tDiffuse:{value:null},tParticles:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",fragmentShader:"\n uniform sampler2D tDiffuse;\n uniform sampler2D tParticles;\n varying vec2 vUv;\n\n void main() {\n vec4 base = texture2D(tDiffuse, vUv);\n vec4 particles = texture2D(tParticles, vUv);\n\n // Alpha-preserving composite: particles over base\n // Use particle alpha to blend\n vec3 blended = mix(base.rgb, particles.rgb, particles.a);\n float alpha = base.a + particles.a * (1.0 - base.a);\n\n gl_FragColor = vec4(blended, alpha);\n }\n "},this.glowLayer=new w(this.renderer)}handleContextLost(e){e.preventDefault(),this._contextLost=!0,console.warn("⚠️ WebGL context lost - rendering paused"),this.cameraAnimationId&&(cancelAnimationFrame(this.cameraAnimationId),this.cameraAnimationId=null)}handleContextRestored(){this._contextLost=!1,this.recreateResources()}recreateResources(){this.createEnvironmentMap(),"glow"===this.materialMode?(this.glowMaterial=this.createGlowMaterial(),this.coreMesh&&(this.coreMesh.material=this.glowMaterial)):"glass"===this.materialMode&&(this.glassMaterial=this.createGlassMaterial(),this.coreMesh&&(this.coreMesh.material=this.glassMaterial),this.coreMesh&&this.createInnerCore())}createCoreMesh(t,i=null){if(this.coreMesh&&(this.scene.remove(this.coreMesh),this.coreMesh.isGroup?this.coreMesh.traverse(e=>{e.geometry&&e.geometry.dispose(),e.material&&this.disposeMaterial(e.material)}):(this.coreMesh.geometry&&this.coreMesh.geometry.dispose(),this.coreMesh.material&&this.disposeMaterial(this.coreMesh.material)),this.coreMesh=null),t.isGroup)return this.coreMesh=t,this.coreMesh.name="coreMascot",this.options.enableShadows&&this.coreMesh.traverse(e=>{e.isMesh&&(e.castShadow=!0,e.receiveShadow=!0)}),this.scene.add(this.coreMesh),this.coreMesh;let n;return i?n=i:(this.glowMaterial||(this.glowMaterial=this.createGlowMaterial()),n="glass"===this.materialMode?this.glassMaterial||this.createGlassMaterial():this.glowMaterial),this.coreMesh=new e.Mesh(t,n),this.coreMesh.name="coreMascot",this.options.enableShadows&&(this.coreMesh.castShadow=!0,this.coreMesh.receiveShadow=!0),this.scene.add(this.coreMesh),"glass"===this.materialMode&&this.createInnerCore(),this.coreMesh}swapGeometry(t,i=null){if(!this.coreMesh)return;this.bloomPass&&this.bloomPass.clearBloomBuffers(this.renderer),this.particleBloomPass&&this.particleBloomPass.clearBloomBuffers(this.renderer);const n=this.coreMesh.geometry;if(n&&n.dispose(),this.coreMesh.geometry=t,i){if(this.coreMesh.material&&this.coreMesh.material!==this.glowMaterial&&this.coreMesh.material!==this.glassMaterial&&this.disposeMaterial(this.coreMesh.material),this.coreMesh.material=i,i.uniforms?.resolution){const t=this.renderer.getDrawingBufferSize(new e.Vector2);i.uniforms.resolution.value.set(t.x,t.y)}}else{const e="glass"===this.materialMode?this.glassMaterial||this.createGlassMaterial():this.glowMaterial;this.coreMesh.material!==e&&(this.coreMesh.material&&this.coreMesh.material!==this.glowMaterial&&this.coreMesh.material!==this.glassMaterial&&this.disposeMaterial(this.coreMesh.material),this.coreMesh.material=e)}"glass"!==this.materialMode||i||this.createInnerCore()}createGlowMaterial(){return new e.ShaderMaterial({uniforms:{glowColor:{value:new e.Color(1,1,1)},glowIntensity:{value:1},coreColor:{value:new e.Color(1,1,1)},fresnelPower:{value:3}},vertexShader:"\n varying vec3 vNormal;\n varying vec3 vViewPosition;\n\n void main() {\n // Transform normal to view space\n vNormal = normalize(normalMatrix * normal);\n\n // Calculate view space position\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = -mvPosition.xyz;\n\n // Output clip space position\n gl_Position = projectionMatrix * mvPosition;\n }\n ",fragmentShader:"\n uniform vec3 glowColor;\n uniform vec3 coreColor;\n uniform float glowIntensity;\n uniform float fresnelPower;\n\n varying vec3 vNormal;\n varying vec3 vViewPosition;\n\n void main() {\n // Fresnel effect: edges glow more than center\n vec3 viewDir = normalize(vViewPosition);\n float fresnel = pow(1.0 - abs(dot(vNormal, viewDir)), fresnelPower);\n\n // Combine white core with colored glow\n // Both core and glow respect glowIntensity for proper on/off toggle\n vec3 finalColor = (coreColor * glowIntensity) + (glowColor * glowIntensity * fresnel);\n\n gl_FragColor = vec4(finalColor, 1.0);\n }\n ",transparent:!1,side:e.FrontSide})}createGlassMaterial(){this.glassEmissiveMultiplier=.6;const t=new e.MeshPhysicalMaterial({transmission:1,thickness:2.7,roughness:.37,metalness:0,ior:1.5,reflectivity:.5,envMapIntensity:1.2,side:e.DoubleSide,transparent:!0,opacity:1,color:16777215,emissive:16777215,emissiveIntensity:.6,clearcoat:.8,clearcoatRoughness:.05,iridescence:.4,iridescenceIOR:1.3,iridescenceThicknessRange:[100,400]});return this.envMap&&(t.envMap=this.envMap),t}createInnerCore(){if(this.innerCore&&(this.coreMesh&&this.coreMesh.remove(this.innerCore),this.innerCore.geometry.dispose(),this.disposeMaterial(this.innerCore.material),this.innerCore=null,this.innerCoreMaterial=null),!this.coreMesh||!this.coreMesh.geometry)return;const t=this.coreMesh.geometry;let i;if("TorusGeometry"===t.type||void 0!==t.parameters?.tube){const n=t.parameters,a=n.radius||1,s=.25*(n.tube||.4),o=n.radialSegments||16,r=n.tubularSegments||100;i=new e.TorusGeometry(a,s,o,r)}else if("SphereGeometry"===t.type){const n=.2*(t.parameters.radius||1);i=new e.SphereGeometry(n,32,32)}else if("BoxGeometry"===t.type){const n=t.parameters,a=.2*(n.width||1),s=.2*(n.height||1),o=.2*(n.depth||1);i=new e.BoxGeometry(a,s,o)}else if("IcosahedronGeometry"===t.type||"OctahedronGeometry"===t.type){const n=t.parameters,a=.2*(n.radius||1),s=n.detail||2;i="IcosahedronGeometry"===t.type?new e.IcosahedronGeometry(a,s):new e.OctahedronGeometry(a,s)}else i=new e.IcosahedronGeometry(.2,2);const n=t.userData?.geometryType,a="IcosahedronGeometry"===t.type||"OctahedronGeometry"===t.type||"crystal"===n||"diamond"===n,s=new e.MeshStandardMaterial({emissive:16777215,emissiveIntensity:a?3.5:2,color:16777215,transparent:!1,opacity:1});this.innerCoreMaterial=s,this.innerCore=new e.Mesh(i,s),this.innerCore.name="innerCore",this.coreMesh.add(this.innerCore)}setMaterialMode(e){if(!this.coreMesh)return console.warn("Cannot set material mode: core mesh not created yet"),void(this.materialMode=e);if(e===this.materialMode)return;this.materialMode=e,"glass"!==e||this.glassMaterial?"glow"!==e||this.glowMaterial||(this.glowMaterial=this.createGlowMaterial()):this.glassMaterial=this.createGlassMaterial();const t="glass"===e?this.glassMaterial:this.glowMaterial;this.coreMesh.material=t,"glass"===e?this.createInnerCore():this.innerCore&&(this.coreMesh.remove(this.innerCore),this.innerCore.geometry.dispose(),this.disposeMaterial(this.innerCore.material),this.innerCore=null,this.innerCoreMaterial=null)}updateGlassProperties(e){this.glassMaterial&&(void 0!==e.transmission&&(this.glassMaterial.transmission=e.transmission,this.glassMaterial.needsUpdate=!0),void 0!==e.thickness&&(this.glassMaterial.thickness=e.thickness,this.glassMaterial.needsUpdate=!0),void 0!==e.roughness&&(this.glassMaterial.roughness=e.roughness,this.glassMaterial.needsUpdate=!0),void 0!==e.emissiveMultiplier&&(this.glassEmissiveMultiplier=e.emissiveMultiplier))}updateLighting(e,t,i=.15){if(!t||!t.visual)return;const n=t.visual.glowColor||"#FFFFFF";this._tempColor.set(n);const a=t.visual.glowIntensity||1;if(this.keyLight&&(this.keyLight.color.lerp(this._tempColor,i),this.keyLight.intensity+=(.8*a-this.keyLight.intensity)*i),this.fillLight&&(this._tempColor2.copy(this._tempColor).lerp(this._white,.7),this.fillLight.color.lerp(this._tempColor2,.5*i),this.fillLight.intensity+=(.3*a-this.fillLight.intensity)*i),this.ambientLight){const e=.4*a;this.ambientLight.intensity+=(e-this.ambientLight.intensity)*i}}normalizeIntensity(e){return.8+Math.log(e+1)/Math.log(11)*.4}calculateColorLuminance(e,t,i){const n=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);return.2126*n(e)+.7152*n(t)+.0722*n(i)}updateBloom(e,t=.1,i=null){if(this.bloomPass){const n=this.normalizeIntensity(e);let a,s,o;"sun"===i?(s=1.5,o=.4,a=.3):"crystal"===i||"rough"===i||"heart"===i?(s=1.8,o=.7,a=.35):"glass"===this.materialMode?(s=.3,o=.2,a=.85):(s=1+.8*n,o=.4,a=.85),this.bloomPass.strength+=(s-this.bloomPass.strength)*t,this.bloomPass.threshold+=(a-this.bloomPass.threshold)*t,this.bloomPass.radius=o}}setCameraPreset(t,i=1e3,n=!1){if(!this.controls)return;const a=this.cameraDistance,s={front:{x:0,y:0,z:a},side:{x:a,y:0,z:0},top:{x:0,y:a,z:0},angle:{x:.67*a,y:.5*a,z:.67*a},back:{x:0,y:0,z:-a},bottom:{x:0,y:-a,z:0}}[t];if(!s)return void console.warn(`Unknown camera preset: ${t}`);const o=n?this.controls.target.clone():null;if(0===i)return this.controls.reset(),this.camera.position.set(s.x,s.y,s.z),o?(this.controls.target.copy(o),this.camera.lookAt(o)):(this.controls.target.set(0,0,0),this.camera.lookAt(0,0,0)),void this.controls.update();n||this.controls.target.set(0,0,0);const r=this.camera.position.clone(),l=new e.Vector3(s.x,s.y,s.z),h=performance.now(),c=e=>{const t=e-h,n=Math.min(t/i,1),a=1-Math.pow(1-n,3);this.camera.position.lerpVectors(r,l,a),this.camera.lookAt(0,0,0),this.controls.update(),this.cameraAnimationId=n<1?requestAnimationFrame(c):null};this.cameraAnimationId=requestAnimationFrame(c)}resetCamera(){this.setCameraPreset("front",1e3)}toggleAutoRotate(e){this.controls&&(this.controls.autoRotate=void 0!==e?e:!this.controls.autoRotate)}isAutoRotateEnabled(){return!!this.controls&&this.controls.autoRotate}render(t={}){if(this._destroyed)return void console.log("[ThreeRenderer] render() BLOCKED - destroyed");if(!this.scene||!this.camera||!this.renderer)return void console.log(`[ThreeRenderer] render() BLOCKED - scene=${!!this.scene}, camera=${!!this.camera}, renderer=${!!this.renderer}`);const i=(e,t)=>{if(!e||!e.children)return!0;for(let n=0;n<e.children.length;n++){const a=e.children[n];null!=a?null!==a.visible&&void 0!==a.visible?i(a,`${t}.children[${n}]`):(console.error(`[ThreeRenderer] child.visible is NULL at ${t}.children[${n}] name=${a.name} - REMOVING!`),e.children.splice(n,1),n--):(console.error(`[ThreeRenderer] NULL CHILD at ${t}.children[${n}] - REMOVING!`),e.children.splice(n,1),n--)}return!0};i(this.scene,"scene");const{position:n=[0,0,0],rotation:a=[0,0,0],scale:s=1,glowColor:o=[1,1,1],glowIntensity:r=1,glowColorHex:l=null,hasActiveGesture:h=!1,calibrationRotation:c=[0,0,0],cameraRoll:u=0,solarEclipse:d=null,deltaTime:m=0,morphProgress:p=null}=t;if(this.controls&&this.controls.update(),this.coreMesh){if(this.coreMesh.position.set(...n),this._tempEuler.set(a[0],a[1],a[2],"XYZ"),this._tempQuat.setFromEuler(this._tempEuler),this._quatX.setFromAxisAngle(this._xAxis,c[0]),this._quatY.setFromAxisAngle(this._yAxis,c[1]),this._cameraToMesh.subVectors(this.coreMesh.position,this.camera.position).normalize(),this._quatZ.setFromAxisAngle(this._cameraToMesh,c[2]),this._tempQuat.multiply(this._quatX),this._tempQuat.multiply(this._quatY),this._tempQuat.multiply(this._quatZ),this.coreMesh.rotation.setFromQuaternion(this._tempQuat),0!==u&&(this._cameraDir.subVectors(this.coreMesh.position,this.camera.position).normalize(),this._rollQuat.setFromAxisAngle(this._cameraDir,u),this._meshQuat.setFromEuler(this.coreMesh.rotation),this._meshQuat.premultiply(this._rollQuat),this.coreMesh.rotation.setFromQuaternion(this._meshQuat)),this.coreMesh.scale.setScalar(s),d&&d.update(this.camera,this.coreMesh,m,p),this.coreMesh.material&&this.coreMesh.material.uniforms){if(this.coreMesh.material.uniforms.glowColor&&(this._tempColor.setRGB(...o),this.coreMesh.material.uniforms.glowColor.value.lerp(this._tempColor,.15)),this.coreMesh.material.uniforms.glowIntensity){let e;e=0===r?0:h?r:this.normalizeIntensity(r);const t=this.coreMesh.material.uniforms.glowIntensity.value,i=h?.5:.15;this.coreMesh.material.uniforms.glowIntensity.value+=(e-t)*i}}else if(this.coreMesh.material&&this.coreMesh.material.emissive){this._tempColor.setRGB(...o),this.coreMesh.material.emissive.lerp(this._tempColor,.15);const e=.15*r,t=this.coreMesh.material.emissiveIntensity,i=h?.5:.15;this.coreMesh.material.emissiveIntensity+=(e-t)*i,this.coreMesh.material.color.lerp(this._white,.15)}this.innerCore&&(this.innerCore.visible=r>0,this.innerCoreMaterial&&(this._tempColor.setRGB(...o),this.innerCoreMaterial.emissive.lerp(this._tempColor,.15)))}if(this.mixer){const e=this.clock.getDelta();this.mixer.update(e)}if(this.renderer.clear(),this.composer){if(this.soulRenderTarget){let e=null;if(this.scene.traverse(t=>{"crystalSoul"===t.name&&(e=t)}),this.renderer.setRenderTarget(this.soulRenderTarget),this.renderer.setClearColor(0,0),this.renderer.clear(),this.camera.layers.set(2),this.renderer.render(this.scene,this.camera),this.coreMesh?.material?.uniforms?.soulTexture&&(this.coreMesh.material.uniforms.soulTexture.value=this.soulRenderTarget.texture,this.coreMesh.material.uniforms.soulTextureSize&&this.coreMesh.material.uniforms.soulTextureSize.value.set(this.soulRenderTarget.width,this.soulRenderTarget.height),this.coreMesh.material.uniforms.soulScreenCenter&&e)){const t=e.position.clone().project(this.camera),i=.5*(t.x+1),n=.5*(t.y+1);this.coreMesh.material.uniforms.soulScreenCenter.value.set(i,n)}this.renderer.setRenderTarget(null),this.renderer.setClearColor(0,0)}if(this.camera.layers.set(0),this.composer.render(),this.particleRenderTarget&&this.particleBloomPass){this.renderer.setRenderTarget(this.particleRenderTarget),this.renderer.setClearColor(16777215,0),this.renderer.clear(),this.camera.layers.set(0);const t=this._depthOnlyMaterial||(this._depthOnlyMaterial=new e.MeshBasicMaterial({colorWrite:!1,depthWrite:!0}));this.scene.overrideMaterial=t,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(1),this.renderer.render(this.scene,this.camera);const i=this.particleRenderTarget;this.particleBloomPass.renderToScreen=!0,this.particleBloomPass.render(this.renderer,null,i,0,!1),this.renderer.setClearColor(0,0),this.renderer.setRenderTarget(null)}else this.camera.layers.set(1),this.renderer.render(this.scene,this.camera);this.camera.layers.enableAll(),this.glowLayer&&this.glowLayer.isActive()&&this.glowLayer.render(this.renderer)}else this.renderer.render(this.scene,this.camera),this.glowLayer&&this.glowLayer.isActive()&&this.glowLayer.render(this.renderer)}updateGlowLayer(e,t,i,n){this.glowLayer&&(this.glowLayer.setGlow(e,t,i),this.glowLayer.update(n,this.camera))}resize(t,i){if(this.camera.aspect=t/i,this.camera.updateProjectionMatrix(),this.renderer.setSize(t,i,!1),this.composer){const t=new e.Vector2;this.renderer.getDrawingBufferSize(t),this.composer.setSize(t.x,t.y),this.bloomPass&&this.bloomPass.resolution&&this.bloomPass.resolution.set(t.x,t.y),this.particleRenderTarget&&this.particleRenderTarget.setSize(t.x,t.y),this.particleBloomPass&&this.particleBloomPass.setSize(t.x,t.y),this.soulRenderTarget&&this.soulRenderTarget.setSize(t.x,t.y),this.coreMesh?.material?.uniforms?.resolution&&this.coreMesh.material.uniforms.resolution.value.set(t.x,t.y)}}disposeMaterial(e){e&&(["map","lightMap","bumpMap","normalMap","specularMap","envMap","alphaMap","aoMap","displacementMap","emissiveMap","gradientMap","metalnessMap","roughnessMap"].forEach(t=>{e[t]&&e[t].dispose()}),e.uniforms&&Object.values(e.uniforms).forEach(e=>{e.value&&(e.value.isTexture?(e.value.dispose(),e.value=null):(e.value.isColor||e.value.isVector2||e.value.isVector3||e.value.isVector4)&&(e.value=null))}),e.dispose())}destroy(){console.log(`[ThreeRenderer] destroy() CALLED, scene children=${this.scene?.children?.length}`),this._destroyed=!0,this.canvas&&(this.canvas.removeEventListener("webglcontextlost",this._boundHandleContextLost,!1),this.canvas.removeEventListener("webglcontextrestored",this._boundHandleContextRestored,!1)),this.cameraAnimationId&&(cancelAnimationFrame(this.cameraAnimationId),this.cameraAnimationId=null),this.innerCore&&(this.coreMesh&&this.coreMesh.remove(this.innerCore),this.innerCore.geometry.dispose(),this.disposeMaterial(this.innerCore.material),this.innerCore=null,this.innerCoreMaterial=null),this.coreMesh&&(this.scene.remove(this.coreMesh),this.coreMesh.geometry.dispose(),this.disposeMaterial(this.coreMesh.material),this.coreMesh=null),this.glowMaterial&&(this.disposeMaterial(this.glowMaterial),this.glowMaterial=null),this.glassMaterial&&(this.disposeMaterial(this.glassMaterial),this.glassMaterial=null),this.composer&&(this.composer.dispose(),this.composer=null),this.particleRenderTarget&&(this.particleRenderTarget.dispose(),this.particleRenderTarget=null),this.particleBloomPass&&(this.particleBloomPass.dispose(),this.particleBloomPass=null),this.soulRenderTarget&&(this.soulRenderTarget.dispose(),this.soulRenderTarget=null),this.glowLayer&&(this.glowLayer.dispose(),this.glowLayer=null),this.controls&&(this.controls.dispose(),this.controls=null),this.keyLight?.shadow?.map&&this.keyLight.shadow.map.dispose(),this.fillLight?.shadow?.map&&this.fillLight.shadow.map.dispose(),this.rimLight?.shadow?.map&&this.rimLight.shadow.map.dispose(),this.keyLight=null,this.fillLight=null,this.rimLight=null,this.ambientLight=null,this.accentLight1=null,this.accentLight2=null,this.accentLight3=null,this.envMap&&(this.envMap.dispose(),this.envMap=null),this._envCubeRenderTarget&&(this._envCubeRenderTarget.dispose(),this._envCubeRenderTarget=null),this._envScene&&(this._envScene.traverse(e=>{e.geometry&&e.geometry.dispose(),e.material&&this.disposeMaterial(e.material)}),this._envScene.clear(),this._envScene=null),this._envCubeCamera&&(this._envCubeCamera=null),this.renderer&&(this.renderer.dispose(),this.renderer=null),this.scene.clear(),this.mixer&&(this.mixer.stopAllAction(),this.mixer=null),this.clock=null,this.camera=null,this._tempColor=null,this._tempColor2=null,this._white=null,this._tempQuat=null,this._tempEuler=null,this._quatX=null,this._quatY=null,this._quatZ=null,this._rollQuat=null,this._meshQuat=null,this._xAxis=null,this._yAxis=null,this._zAxis=null,this._cameraToMesh=null,this._cameraDir=null}}const S="\n/**\n * Apply a single blend mode to two colors\n * @param base - Base color (RGB, 0.0-1.0 range)\n * @param blend - Blend color (RGB, 0.0-1.0 range)\n * @param mode - Blend mode index (0-17)\n * @return Blended color (RGB, 0.0-1.0 range)\n *\n * Blend Mode Reference:\n * 0 = Multiply (darkening)\n * 1 = Linear Burn (darkening, linear)\n * 2 = Color Burn (darkening, intense)\n * 3 = Color Dodge (brightening, intense)\n * 4 = Screen (brightening)\n * 5 = Overlay (contrast, screen/multiply hybrid)\n * 6 = Add (brightening, additive glow)\n * 7 = Soft Light (contrast, gentle)\n * 8 = Hard Light (contrast, strong)\n * 9 = Vivid Light (contrast, saturation boost)\n * 10 = Linear Light (contrast, linear)\n * 11 = Difference (inversion)\n * 12 = Exclusion (soft inversion)\n * 13 = Darken (comparison, darker)\n * 14 = Lighten (comparison, lighter)\n * 15 = Subtract (darkening, deep shadows)\n * 16 = Divide (brightening, ethereal glow)\n * 17 = Pin Light (posterization)\n */\nvec3 applyBlendMode(vec3 base, vec3 blend, int mode) {\n if (mode == 0) {\n // MULTIPLY: base * blend\n return base * blend;\n } else if (mode == 1) {\n // LINEAR BURN: base + blend - 1\n return max(base + blend - vec3(1.0), vec3(0.0));\n } else if (mode == 2) {\n // COLOR BURN: (blend==0.0) ? 0.0 : max((1.0-((1.0-base)/blend)), 0.0)\n return vec3(\n blend.r == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.r) / blend.r), 0.0),\n blend.g == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.g) / blend.g), 0.0),\n blend.b == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.b) / blend.b), 0.0)\n );\n } else if (mode == 3) {\n // COLOR DODGE: (blend==1.0) ? 1.0 : min(base/(1.0-blend), 1.0)\n return vec3(\n blend.r == 1.0 ? 1.0 : min(base.r / (1.0 - blend.r), 1.0),\n blend.g == 1.0 ? 1.0 : min(base.g / (1.0 - blend.g), 1.0),\n blend.b == 1.0 ? 1.0 : min(base.b / (1.0 - blend.b), 1.0)\n );\n } else if (mode == 4) {\n // SCREEN: 1 - (1 - base) * (1 - blend)\n return vec3(1.0) - (vec3(1.0) - base) * (vec3(1.0) - blend);\n } else if (mode == 5) {\n // OVERLAY: base < 0.5 ? (2 * base * blend) : (1 - 2 * (1 - base) * (1 - blend))\n return vec3(\n base.r < 0.5 ? (2.0 * base.r * blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r)),\n base.g < 0.5 ? (2.0 * base.g * blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g)),\n base.b < 0.5 ? (2.0 * base.b * blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b))\n );\n } else if (mode == 6) {\n // ADD (LINEAR DODGE): base + blend\n return min(base + blend, vec3(1.0));\n } else if (mode == 7) {\n // SOFT LIGHT: blend < 0.5 ? (2*base*blend + base^2*(1-2*blend)) : (sqrt(base)*(2*blend-1) + 2*base*(1-blend))\n return vec3(\n blend.r < 0.5 ? (2.0 * base.r * blend.r + base.r * base.r * (1.0 - 2.0 * blend.r)) : (sqrt(base.r) * (2.0 * blend.r - 1.0) + 2.0 * base.r * (1.0 - blend.r)),\n blend.g < 0.5 ? (2.0 * base.g * blend.g + base.g * base.g * (1.0 - 2.0 * blend.g)) : (sqrt(base.g) * (2.0 * blend.g - 1.0) + 2.0 * base.g * (1.0 - blend.g)),\n blend.b < 0.5 ? (2.0 * base.b * blend.b + base.b * base.b * (1.0 - 2.0 * blend.b)) : (sqrt(base.b) * (2.0 * blend.b - 1.0) + 2.0 * base.b * (1.0 - blend.b))\n );\n } else if (mode == 8) {\n // HARD LIGHT: blend < 0.5 ? (2 * base * blend) : (1 - 2 * (1 - base) * (1 - blend))\n return vec3(\n blend.r < 0.5 ? (2.0 * base.r * blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r)),\n blend.g < 0.5 ? (2.0 * base.g * blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g)),\n blend.b < 0.5 ? (2.0 * base.b * blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b))\n );\n } else if (mode == 9) {\n // VIVID LIGHT: blend < 0.5 ? ColorBurn(base, 2*blend) : ColorDodge(base, 2*(blend-0.5))\n return vec3(\n blend.r < 0.5 ? (blend.r == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.r) / (2.0 * blend.r)), 0.0)) : (blend.r == 1.0 ? 1.0 : min(base.r / (2.0 * (1.0 - blend.r)), 1.0)),\n blend.g < 0.5 ? (blend.g == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.g) / (2.0 * blend.g)), 0.0)) : (blend.g == 1.0 ? 1.0 : min(base.g / (2.0 * (1.0 - blend.g)), 1.0)),\n blend.b < 0.5 ? (blend.b == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.b) / (2.0 * blend.b)), 0.0)) : (blend.b == 1.0 ? 1.0 : min(base.b / (2.0 * (1.0 - blend.b)), 1.0))\n );\n } else if (mode == 10) {\n // LINEAR LIGHT: blend < 0.5 ? LinearBurn(base, 2*blend) : LinearDodge(base, 2*(blend-0.5))\n return vec3(\n blend.r < 0.5 ? max(base.r + 2.0 * blend.r - 1.0, 0.0) : min(base.r + 2.0 * (blend.r - 0.5), 1.0),\n blend.g < 0.5 ? max(base.g + 2.0 * blend.g - 1.0, 0.0) : min(base.g + 2.0 * (blend.g - 0.5), 1.0),\n blend.b < 0.5 ? max(base.b + 2.0 * blend.b - 1.0, 0.0) : min(base.b + 2.0 * (blend.b - 0.5), 1.0)\n );\n } else if (mode == 11) {\n // DIFFERENCE: abs(base - blend)\n return abs(base - blend);\n } else if (mode == 12) {\n // EXCLUSION: base + blend - 2 * base * blend\n return base + blend - 2.0 * base * blend;\n } else if (mode == 13) {\n // DARKEN: min(base, blend)\n return min(base, blend);\n } else if (mode == 14) {\n // LIGHTEN: max(base, blend)\n return max(base, blend);\n } else if (mode == 15) {\n // SUBTRACT: max(base - blend, 0)\n return max(base - blend, vec3(0.0));\n } else if (mode == 16) {\n // DIVIDE: base / (blend + epsilon)\n return min(base / (blend + vec3(0.001)), vec3(1.0));\n } else {\n // PIN LIGHT (mode 17): Replaces colors based on blend brightness\n float blendLum = (blend.r + blend.g + blend.b) / 3.0;\n if (blendLum > 0.5) {\n // Lighten: replace pixels darker than blend\n return max(base, 2.0 * blend - vec3(1.0));\n } else {\n // Darken: replace pixels lighter than blend\n return min(base, 2.0 * blend);\n }\n }\n}\n",x=["Multiply","Linear Burn","Color Burn","Color Dodge","Screen","Overlay","Add","Soft Light","Hard Light","Vivid Light","Linear Light","Difference","Exclusion","Darken","Lighten","Subtract","Divide","Pin Light"];function C(e){return x[e]||"Unknown"}function D(e){const t=x.indexOf(e);return-1!==t?t:0}const P=`\n/**\n * Moon Fragment Shader with Blend Layers\n *\n * Supports up to 4 sequential blend mode layers for complex color grading\n * using universal Photoshop-style blend modes\n */\n\nuniform sampler2D colorMap;\nuniform sampler2D normalMap;\nuniform vec2 shadowOffset;\nuniform float shadowCoverage;\nuniform float shadowSoftness;\nuniform vec3 glowColor;\nuniform float glowIntensity;\nuniform float opacity;\n\n// Lunar Eclipse (Blood Moon) uniforms\nuniform float eclipseProgress;\nuniform float eclipseIntensity;\nuniform vec3 bloodMoonColor;\nuniform float emissiveStrength;\nuniform vec2 eclipseShadowPos; // Shadow center position (-2 to 1)\nuniform float eclipseShadowRadius; // Shadow radius\n\n// Eclipse Color Grading (from color pickers)\nuniform vec3 eclipseShadowColor;\nuniform vec3 eclipseMidtoneColor;\nuniform vec3 eclipseHighlightColor;\nuniform vec3 eclipseGlowColor;\n\n// Brightness model toggle (0 = centeredness-based, 1 = edge-based)\nuniform float eclipseBrightnessModel;\n\n// Shadow darkness control (0.0 = no darkening, 1.0 = maximum darkening)\nuniform float shadowDarkness;\n\n// Blend Layer Uniforms (up to 4 layers)\nuniform float layer1Mode;\nuniform float layer1Strength;\nuniform float layer1Enabled;\n\nuniform float layer2Mode;\nuniform float layer2Strength;\nuniform float layer2Enabled;\n\nuniform float layer3Mode;\nuniform float layer3Strength;\nuniform float layer3Enabled;\n\nuniform float layer4Mode;\nuniform float layer4Strength;\nuniform float layer4Enabled;\n\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewNormal;\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// UNIVERSAL BLEND MODES (injected from utils/blendModes.js)\n// ═══════════════════════════════════════════════════════════════════════════\n${S}\n\nvoid main() {\n // DIRECTIONAL SHADOW in VIEW SPACE - camera-relative moon phase\n // Shadow stays fixed relative to screen; rotating moon doesn't change which side is lit\n vec3 viewNormal = normalize(vViewNormal);\n\n float lightX = shadowOffset.x;\n float lightY = shadowOffset.y;\n float offsetMagnitude = length(vec2(lightX, lightY));\n float lightZ = 1.0 - pow(offsetMagnitude, 1.5);\n vec3 lightDir = normalize(vec3(lightX, lightY, lightZ));\n\n // Light direction is in view space (camera-relative)\n float facing = dot(viewNormal, lightDir);\n float edgeWidth = max(fwidth(facing) * 4.0, shadowSoftness * 3.0);\n float shadowFactor = smoothstep(-edgeWidth, edgeWidth, facing);\n\n // Sample moon surface texture\n vec4 texColor = texture2D(colorMap, vUv);\n float brightness = texColor.r + texColor.g + texColor.b;\n if (brightness < 0.03) {\n texColor = vec4(0.5, 0.5, 0.5, 1.0);\n }\n\n // VIEW DIRECTION (for eclipse rim effects only, NOT for general lighting)\n vec3 viewDir = normalize(-vViewPosition);\n float rimFactor = dot(viewNormal, viewDir);\n\n // EARTHSHINE - faint blue glow on shadowed side\n vec3 earthshine = texColor.rgb * 0.01 * vec3(0.35, 0.4, 0.6);\n\n // Apply shadow transition (moon phase only - NOT camera-based)\n // The moon texture is uniformly visible; only the phase shadow creates darkness\n float litFactor = pow(shadowFactor, 2.0);\n vec3 detailEnhanced = texColor.rgb * 1.08;\n float textureLuminance = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));\n detailEnhanced = mix(texColor.rgb * 0.95, texColor.rgb * 1.12, smoothstep(0.3, 0.7, textureLuminance));\n\n // Lit areas show texture; shadowed areas show earthshine\n // NO camera-based limb darkening - moon rotates, texture stays uniformly lit\n vec3 shadowedColor = mix(earthshine, detailEnhanced, litFactor);\n\n vec3 emissive = vec3(0.02, 0.02, 0.02) * shadowFactor;\n vec3 emotionGlow = glowColor * glowIntensity * 0.02 * shadowFactor;\n vec3 finalColor = shadowedColor + emissive + emotionGlow;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LUNAR ECLIPSE EFFECT (Earth's Shadow Sweep)\n // Shadow position drives everything - automatically transitions from dark sharp shadow to red glow\n // ═══════════════════════════════════════════════════════════════════════════\n // Only apply eclipse if shadow is actually near the moon (shadowX > -1.5)\n if (eclipseProgress > 0.001 && eclipseShadowPos.x > -1.5) {\n // Eclipse progress is now pre-modulated by UI based on shadow position\n // No need for shader-side modulation\n float effectiveProgress = eclipseProgress;\n\n // Calculate distance from shadow center using VIEW-SPACE position (3D spherical)\n // This creates a proper circular shadow on the sphere, not a flat UV-based cutoff\n // viewNormal.xy ranges -1 to 1, scale to match UV range (0 to 0.5 from center)\n vec2 shadowCenter = vec2(eclipseShadowPos.x, eclipseShadowPos.y);\n vec2 spherePos = viewNormal.xy * 0.5; // Scale to UV-equivalent range\n float distFromShadow = length(spherePos - shadowCenter);\n\n // TOTALITY FACTOR: Based on how centered the shadow is on the moon\n // When shadowX near 0.0 (centered), we're at totality - brightens and reddens\n // When shadowX far from 0.0 (off to side), we're partial - stays dark and diffuse\n float shadowCenteredness = 1.0 - smoothstep(0.0, 0.6, abs(eclipseShadowPos.x));\n float totalityFactor = shadowCenteredness;\n\n // Earth's umbra (full shadow) - DIFFUSE at partials, sharper at totality\n float umbraRadius = eclipseShadowRadius * 0.7;\n // Edge softness: very diffuse at partials (0.25), sharp at totality (0.05)\n float umbraEdge = mix(0.25, 0.05, totalityFactor);\n float umbra = 1.0 - smoothstep(umbraRadius - umbraEdge, umbraRadius + umbraEdge, distFromShadow);\n\n // Earth's penumbra (partial shadow) - wider and softer\n // Penumbra extends further at partials, tighter at totality\n float penumbraRadius = eclipseShadowRadius * mix(1.4, 1.1, totalityFactor);\n float penumbraEdge = mix(0.3, 0.15, totalityFactor);\n float penumbra = 1.0 - smoothstep(penumbraRadius - penumbraEdge, penumbraRadius + penumbraEdge, distFromShadow);\n\n // UMBRA DARKENING: Much darker at partials, lighter at totality\n // Partials: 85% darkening (very dark shadow)\n // Totality: 30% darkening (blood moon glow visible)\n float baseDarkening = mix(0.85, 0.30, totalityFactor);\n float umbraDarkeningAmount = baseDarkening * shadowDarkness;\n float umbraDarkening = umbra * effectiveProgress;\n\n // Apply base darkening first\n finalColor *= (1.0 - umbraDarkening * umbraDarkeningAmount);\n\n // PENUMBRA: Darker gradient at partials, lighter at totality\n float penumbraDarkening = (penumbra - umbra) * effectiveProgress;\n float penumbraDarkenAmount = mix(0.50, 0.20, totalityFactor); // 50% at partials, 20% at totality\n finalColor *= (1.0 - penumbraDarkening * penumbraDarkenAmount);\n\n // BLOOD MOON COLOR: Applied throughout entire eclipse, not just totality\n // Matches real lunar eclipse behavior - color present at all phases\n // Use totality factor to control BRIGHTNESS, not color presence\n float colorStrength = umbra; // Color appears wherever umbra shadow is present\n vec3 bloodMoonTint = mix(vec3(1.0), eclipseMidtoneColor, colorStrength);\n finalColor *= bloodMoonTint;\n\n // REALISTIC ECLIPSE PROGRESSION (corrected):\n // Shadow sweeps LEFT → RIGHT but NEVER fully covers moon during partials\n // A bright crescent ALWAYS remains visible (shadow stops before covering moon)\n // Just before totality: shadow nearly covers moon, blood moon glow appears\n // The glow spreads FROM the visible bright crescent INTO the shadowed area\n // During totality: shadow finally covers entire moon, full blood moon\n\n // Use view-space normal for spherical position (not UV)\n // Scale to match UV range\n float pixelX = viewNormal.x * 0.5;\n\n // THE LIT CRESCENT: Always visible during partial phases\n // During partials, the moon is partially lit (outside umbra)\n // Only during totality does the shadow fully cover the moon\n\n // Where is the bright crescent? Opposite side from shadow\n // Approaching (shadowX < 0): crescent on RIGHT (positive X)\n // Leaving (shadowX > 0): crescent on LEFT (negative X)\n float crescentSide = -sign(eclipseShadowPos.x);\n\n // CRESCENT EDGE: Where shadow meets lit surface\n // This is always VISIBLE during partials - never goes to zero\n float umbraEdgeX = eclipseShadowPos.x + (umbraRadius * crescentSide);\n\n // Distance from this pixel to the lit crescent edge\n // Positive = inside shadow, negative = in lit crescent\n float distFromLitEdge = (pixelX - umbraEdgeX) * crescentSide;\n\n // GRADIENT: Blood moon glow spreads from the LIT CRESCENT\n // Only pixels INSIDE the shadow get the gradient\n // Gradient is strongest at the umbra edge (where crescent is)\n float crescentGradient = smoothstep(0.5, 0.0, distFromLitEdge);\n\n // BRIGHTNESS CONTROL: Glow only appears near totality\n // When shadow is far from center: stays dark\n // When shadow approaches center: glow spreads from crescent\n float brightnessControl = umbra * crescentGradient * totalityFactor;\n\n // During full totality (shadowX ≈ 0), switch to uniform brightness\n brightnessControl = mix(brightnessControl, umbra * totalityFactor, totalityFactor);\n\n // EMISSIVE GLOW: Blood moon color spreading from crescent\n float glowStrength = mix(0.0, 1.0, brightnessControl);\n vec3 atmosphereGlow = eclipseMidtoneColor * emissiveStrength * glowStrength * umbra;\n finalColor += atmosphereGlow;\n\n // RIM GLOW: Atmospheric limb brightening\n float limbGlowStrength = mix(0.0, 1.5, brightnessControl);\n float limbGlow = pow(1.0 - rimFactor, 3.0) * umbra;\n vec3 rimColor = mix(eclipseGlowColor, eclipseHighlightColor, 0.5);\n finalColor += rimColor * limbGlow * emissiveStrength * limbGlowStrength;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ECLIPSE BLEND LAYERS (Applied AFTER blood moon color)\n // Applied throughout eclipse wherever umbra is present\n // Strength modulated by totality factor for smooth brightness transitions\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Layer 1: Linear Burn @ 0.634\n if (layer1Enabled > 0.5 && effectiveProgress > 0.1) {\n vec3 blendColor1 = vec3(min(layer1Strength, 1.0));\n int mode1 = int(layer1Mode + 0.5);\n vec3 blended1 = clamp(applyBlendMode(finalColor, blendColor1, mode1), 0.0, 1.0);\n // Apply at FULL strength wherever umbra exists\n finalColor = clamp(mix(finalColor, blended1, umbra), 0.0, 1.0);\n }\n\n // Layer 2: Multiply @ 3.086 - Brightness enhancement\n if (layer2Enabled > 0.5 && effectiveProgress > 0.1) {\n // Apply full brightness boost wherever umbra exists\n vec3 brightened = clamp(finalColor * min(layer2Strength, 5.0), 0.0, 1.0);\n finalColor = mix(finalColor, brightened, umbra);\n }\n\n // Layer 3: Hard Light @ 0.351\n if (layer3Enabled > 0.5 && effectiveProgress > 0.1) {\n vec3 blendColor3 = vec3(min(layer3Strength, 1.0));\n int mode3 = int(layer3Mode + 0.5);\n vec3 blended3 = clamp(applyBlendMode(finalColor, blendColor3, mode3), 0.0, 1.0);\n // Apply at FULL strength wherever umbra exists\n finalColor = clamp(mix(finalColor, blended3, umbra), 0.0, 1.0);\n }\n\n // Layer 4: Manual UI layer\n if (layer4Enabled > 0.5 && effectiveProgress > 0.1) {\n vec3 blendColor4 = vec3(min(layer4Strength, 1.0));\n int mode4 = int(layer4Mode + 0.5);\n vec3 blended4 = clamp(applyBlendMode(finalColor, blendColor4, mode4), 0.0, 1.0);\n finalColor = clamp(mix(finalColor, blended4, umbra), 0.0, 1.0);\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // UNIVERSAL BLEND MODE LAYERS (Only applied when eclipse is OFF)\n // These are manual UI-driven color grading tools\n // NOTE: These are DISABLED by default - they're NEVER used since the multiplexer\n // demo doesn't enable them. This section exists for potential future manual control.\n // ═══════════════════════════════════════════════════════════════════════════\n // INTENTIONALLY COMMENTED OUT - these would interfere with eclipse blend layers\n // if (eclipseProgress < 0.001) {\n // // Layer 1 - manual UI control only\n // if (layer1Enabled > 0.5) {\n // vec3 blendColor1 = vec3(layer1Strength);\n // int mode1 = int(layer1Mode + 0.5);\n // finalColor = applyBlendMode(finalColor, blendColor1, mode1);\n // }\n // }\n\n gl_FragColor = vec4(finalColor, opacity);\n}\n`,B=55.5,k=-85,T=-60.5,E={enabled:!0,strength:1,lockedFace:[0,0,1],lerpSpeed:10},I={new:{x:200,y:0,coverage:0},"waxing-crescent":{x:1.5,y:0,coverage:.25},"first-quarter":{x:1,y:0,coverage:.5},"waxing-gibbous":{x:.7,y:0,coverage:.75},full:{x:0,y:0,coverage:1},"waning-gibbous":{x:-.7,y:0,coverage:.75},"last-quarter":{x:-1,y:0,coverage:.5},"waning-crescent":{x:-1.5,y:0,coverage:.25}};function A(){return Object.keys(I)}function R(e){const t=(e%1+1)%1;let i;if(t<=.5){const e=2*t;i=10*Math.pow(1-e,2.5)}else{const e=2*(t-.5);if(e<=.25)i=e/.25*-.3;else if(e<=.5)i=-.3-(e-.25)/.25*.7;else if(e<=.75)i=-1-(e-.5)/.25*2;else{const t=(e-.75)/.25;i=13*Math.pow(t,.4)-3}}return{x:i,y:0,coverage:1-2*Math.abs(t-.5)}}function z(t=64,i=64){const n=new e.SphereGeometry(.5,t,i);return n.userData.tracked=!0,n}function _(e){if(e&&(e.geometry&&e.geometry.dispose(),e.material)){const{material:t}=e;t.userData&&t.userData.pendingTextures&&(t.userData.pendingTextures.forEach(({texture:e})=>{e&&e.dispose()}),t.userData.pendingTextures.clear()),t.map&&t.map.dispose(),t.normalMap&&t.normalMap.dispose(),t.uniforms&&(t.uniforms.colorMap&&t.uniforms.colorMap.value&&t.uniforms.colorMap.value.dispose(),t.uniforms.normalMap&&t.uniforms.normalMap.value&&t.uniforms.normalMap.value.dispose()),t.dispose()}}function O(t,i={}){const n=i.resolution||"2k",a=i.assetBasePath||"/assets",s=`${a}/textures/Moon/moon-color-${n}.jpg`,o=`${a}/textures/Moon/moon-normal-${n}.jpg`,r=new Map;r.set(s,{texture:null});const l=t.load(s,e=>{const t=r.get(s);t&&(t.texture=e),r.delete(s)},void 0,e=>{console.error(`❌ Failed to load moon color texture (${n}):`,e),r.delete(s)});r.set(o,{texture:null});const h=t.load(o,e=>{const t=r.get(o);t&&(t.texture=e),r.delete(o)},void 0,e=>{console.error(`❌ Failed to load moon normal map (${n}):`,e),r.delete(o)});l.wrapS=l.wrapT=e.RepeatWrapping,h.wrapS=h.wrapT=e.RepeatWrapping,l.anisotropy=16,h.anisotropy=16;const c=new e.MeshStandardMaterial({map:l,normalMap:h,normalScale:new e.Vector2(1.5,1.5),roughness:.7,metalness:0,emissive:new e.Color(.3,.3,.3),emissiveIntensity:.5,transparent:!1,side:e.FrontSide});return c.userData.pendingTextures=r,c}function F(t=new e.Color(16777215),i=0){return new e.MeshStandardMaterial({color:15263976,roughness:.9,metalness:0,emissive:t,emissiveIntensity:i})}function L(t,i={}){const n=i.resolution||"2k",a=i.glowColor||new e.Color(1,1,1),s=i.glowIntensity||1,o=i.shadowType||"crescent",r=i.assetBasePath||"/assets";let l,h;if(void 0!==i.shadowOffsetX)({shadowOffsetX:l}=i),h=void 0!==i.shadowOffsetY?i.shadowOffsetY:0;else if(void 0!==i.moonPhase){let e;"string"==typeof i.moonPhase?([e]=[I[i.moonPhase]],e||(console.warn(`Unknown moon phase: ${i.moonPhase}, using waxing-crescent`),e=I["waxing-crescent"])):e="number"==typeof i.moonPhase?R(i.moonPhase):I["waxing-crescent"],l=e.x,h=e.y}else{const e=I["waxing-crescent"];l=e.x,h=e.y}const c=void 0!==i.shadowCoverage?i.shadowCoverage:.85,u=`${r}/textures/Moon/moon-color-${n}.jpg`,d=`${r}/textures/Moon/moon-normal-${n}.jpg`,{vertexShader:m,fragmentShader:p}=function(e){return"crescent"===e||console.warn(`Unknown shadow type: ${e}, defaulting to crescent`),{vertexShader:"\n/**\n * Moon Crescent Vertex Shader\n * Passes world-space normal to fragment shader for realistic lighting\n */\n\nvarying vec3 vPosition; // LOCAL position\nvarying vec3 vWorldPosition;\nvarying vec3 vWorldNormal; // WORLD SPACE normal (rotates with moon)\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n vPosition = position;\n\n // Transform normal to WORLD space (not view space)\n // This makes the shadow rotate with the moon geometry\n vWorldNormal = normalize(mat3(modelMatrix) * normal);\n\n vec4 worldPosition = modelMatrix * vec4(position, 1.0);\n vWorldPosition = worldPosition.xyz;\n vec4 viewPosition = viewMatrix * worldPosition;\n vViewPosition = viewPosition.xyz;\n gl_Position = projectionMatrix * viewPosition;\n}\n",fragmentShader:"\n/**\n * Moon Crescent Fragment Shader\n *\n * Uses directional half-space test in WORLD SPACE to create realistic terminator:\n * - Light direction fixed in world space (like the sun)\n * - Normals rotate with moon geometry (in world space)\n * - dot(normal, lightDir) < 0 = shadow side\n * - dot(normal, lightDir) > 0 = lit side\n * - Smooth terminator with earthshine on dark side\n */\n\nuniform sampler2D colorMap;\nuniform sampler2D normalMap;\nuniform vec2 shadowOffset; // Controls light direction (x=horizontal, y=vertical)\nuniform float shadowCoverage; // Unused for directional shadow\nuniform float shadowSoftness; // Terminator edge softness (default: 0.05)\nuniform vec3 glowColor;\nuniform float glowIntensity;\nuniform float opacity; // Fade in opacity (0-1) to prevent gray flash during texture load\n\n// Lunar Eclipse (Blood Moon) uniforms\nuniform float eclipseProgress; // 0.0 = no eclipse, 1.0 = totality\nuniform float eclipseIntensity; // Darkening strength (0.0-1.0)\nuniform vec3 bloodMoonColor; // Deep reddish-orange for total eclipse\nuniform float blendMode; // 0=Multiply, 1=LinearBurn, 2=ColorBurn, 3=ColorDodge, 4=Screen, 5=Overlay\nuniform float blendStrength; // Blend strength multiplier (0.0-5.0)\nuniform float emissiveStrength; // Emissive glow strength (0.0-1.0)\n\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vWorldNormal; // WORLD SPACE normal (rotates with moon)\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n // DIRECTIONAL SHADOW in WORLD SPACE - realistic moon phase lighting\n // Light direction is fixed in world space, shadow rotates with moon\n\n // Use world-space normal (rotates with moon geometry)\n vec3 worldNormal = normalize(vWorldNormal);\n\n // Light direction in WORLD SPACE\n // shadowOffset.x controls horizontal angle (left/right)\n // shadowOffset.y controls vertical angle (up/down)\n // For thin crescents, we need extreme angles (light from the side or behind)\n\n float lightX = shadowOffset.x;\n float lightY = shadowOffset.y;\n\n // Adaptive Z component with LOGARITHMIC scaling for wider angular range\n // Goal: Spread phases across full 0° to 180° instead of plateauing at 135°\n //\n // Target angles after normalization:\n // - Full moon (x=0): 0° (light from front)\n // - Quarter moon (x=1): 90° (light from side)\n // - Crescent (x=3): 120° (thin crescent)\n // - New moon (x=10): 170° (nearly behind)\n\n float offsetMagnitude = length(vec2(lightX, lightY));\n\n // Use exponential decay for Z to spread angular range\n // Formula: Z = 1.0 - offsetMagnitude^1.5 for better distribution\n float lightZ = 1.0 - pow(offsetMagnitude, 1.5);\n\n // Normalize the light direction vector\n vec3 lightDir = normalize(vec3(lightX, lightY, lightZ));\n\n // Calculate how much this fragment faces the light source\n float facing = dot(worldNormal, lightDir);\n\n // Smooth transition at terminator (shadow boundary)\n // Softer edge for realistic lunar terminator (like real moon photography)\n // Use fwidth() for automatic screen-space anti-aliasing\n float edgeWidth = max(fwidth(facing) * 4.0, shadowSoftness * 3.0);\n float shadowFactor = smoothstep(-edgeWidth, edgeWidth, facing);\n\n // Sample moon surface texture\n vec4 texColor = texture2D(colorMap, vUv);\n\n // Fallback to gray if texture not loaded yet\n float brightness = texColor.r + texColor.g + texColor.b;\n if (brightness < 0.03) {\n texColor = vec4(0.5, 0.5, 0.5, 1.0);\n }\n\n // LIMB DARKENING: Moon gets darker at edges (spherical falloff)\n vec3 viewDir = normalize(-vViewPosition);\n float rimFactor = dot(worldNormal, viewDir);\n float limbDarkening = smoothstep(0.0, 0.6, rimFactor); // Subtle edge darkening\n\n // DIFFUSE LIGHTING: Vary brightness across lit surface (not uniform)\n // More realistic Lambertian diffuse reflection\n float diffuse = max(facing, 0.0);\n float diffuseLighting = mix(0.7, 1.0, diffuse); // Subtle variation\n\n // EARTHSHINE: Almost invisible (~1% for ultimate realism)\n vec3 earthshine = texColor.rgb * 0.01 * vec3(0.35, 0.4, 0.6);\n\n // Apply dramatic shadow transition with maximum contrast\n float litFactor = pow(shadowFactor, 2.0); // Maximum contrast\n\n // TEXTURE ENHANCEMENT: Boost surface detail contrast\n // Slightly darken dark areas, brighten bright areas of texture\n vec3 detailEnhanced = texColor.rgb * 1.08; // Subtle boost\n float textureLuminance = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));\n detailEnhanced = mix(texColor.rgb * 0.95, texColor.rgb * 1.12, smoothstep(0.3, 0.7, textureLuminance));\n\n // Combine enhanced texture with diffuse lighting\n vec3 litColor = detailEnhanced * diffuseLighting;\n vec3 shadowedColor = mix(earthshine, litColor, litFactor);\n\n // Apply limb darkening (slightly stronger for more depth)\n shadowedColor *= mix(0.6, 1.0, limbDarkening);\n\n // Nearly zero emissive for pure realism\n vec3 emissive = vec3(0.02, 0.02, 0.02) * shadowFactor;\n\n // Emotion glow (almost invisible)\n vec3 emotionGlow = glowColor * glowIntensity * 0.02 * shadowFactor;\n\n // Combine all lighting components\n vec3 finalColor = shadowedColor + emissive + emotionGlow;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LUNAR ECLIPSE (BLOOD MOON) EFFECT\n // ═══════════════════════════════════════════════════════════════════════════\n // Simulates Earth's umbral shadow with Rayleigh scattering (reddish glow)\n if (eclipseProgress > 0.001) {\n // Calculate gradient from lit edge to dark center\n // Use rim factor (view angle) to create radial gradient\n float gradientFactor = rimFactor; // 1.0 at edges, 0.0 at center\n\n // Darken the moon (Earth's shadow)\n float darkeningFactor = 1.0 - eclipseIntensity;\n finalColor *= darkeningFactor;\n\n // ═══════════════════════════════════════════════════════════════════\n // PHOTOSHOP-STYLE BLEND MODES: Multiple modes for deep saturation control\n // ═══════════════════════════════════════════════════════════════════\n\n // Define blood moon gradient colors\n vec3 deepRed = vec3(0.6, 0.2, 0.12); // Dark burnt red-orange (center)\n vec3 brightOrange = vec3(0.95, 0.45, 0.22); // Bright burnt orange (edges)\n\n // Create radial gradient from center (dark) to edge (bright)\n vec3 bloodGradient = mix(deepRed, brightOrange, pow(gradientFactor, 1.8));\n\n // Apply blend strength multiplier\n vec3 blendColor = bloodGradient * blendStrength;\n\n // Calculate all blend modes\n vec3 finalBlend;\n int mode = int(blendMode + 0.5); // Round to nearest int\n\n if (mode == 0) {\n // MULTIPLY: base * blend\n finalBlend = finalColor * blendColor;\n } else if (mode == 1) {\n // LINEAR BURN: base + blend - 1\n finalBlend = max(finalColor + blendColor - vec3(1.0), vec3(0.0));\n } else if (mode == 2) {\n // COLOR BURN: (blend==0.0) ? 0.0 : max((1.0-((1.0-base)/blend)), 0.0)\n finalBlend = vec3(\n blendColor.r == 0.0 ? 0.0 : max(1.0 - ((1.0 - finalColor.r) / blendColor.r), 0.0),\n blendColor.g == 0.0 ? 0.0 : max(1.0 - ((1.0 - finalColor.g) / blendColor.g), 0.0),\n blendColor.b == 0.0 ? 0.0 : max(1.0 - ((1.0 - finalColor.b) / blendColor.b), 0.0)\n );\n } else if (mode == 3) {\n // COLOR DODGE: (blend==1.0) ? 1.0 : min(base/(1.0-blend), 1.0)\n finalBlend = vec3(\n blendColor.r == 1.0 ? 1.0 : min(finalColor.r / (1.0 - blendColor.r), 1.0),\n blendColor.g == 1.0 ? 1.0 : min(finalColor.g / (1.0 - blendColor.g), 1.0),\n blendColor.b == 1.0 ? 1.0 : min(finalColor.b / (1.0 - blendColor.b), 1.0)\n );\n } else if (mode == 4) {\n // SCREEN: 1 - (1 - base) * (1 - blend)\n finalBlend = vec3(1.0) - (vec3(1.0) - finalColor) * (vec3(1.0) - blendColor);\n } else {\n // OVERLAY: base < 0.5 ? (2 * base * blend) : (1 - 2 * (1 - base) * (1 - blend))\n finalBlend = vec3(\n finalColor.r < 0.5 ? (2.0 * finalColor.r * blendColor.r) : (1.0 - 2.0 * (1.0 - finalColor.r) * (1.0 - blendColor.r)),\n finalColor.g < 0.5 ? (2.0 * finalColor.g * blendColor.g) : (1.0 - 2.0 * (1.0 - finalColor.g) * (1.0 - blendColor.g)),\n finalColor.b < 0.5 ? (2.0 * finalColor.b * blendColor.b) : (1.0 - 2.0 * (1.0 - finalColor.b) * (1.0 - blendColor.b))\n );\n }\n\n // Apply blood moon effect\n finalColor = mix(finalColor, finalBlend, eclipseProgress);\n\n // Add emissive glow for visibility\n finalColor += bloodGradient * emissiveStrength * eclipseProgress;\n\n // Add bright rim glow during totality (refracted atmosphere light)\n if (eclipseProgress > 0.7) {\n float rimIntensity = pow(gradientFactor, 2.5); // Sharp falloff from edge\n vec3 rimGlow = brightOrange * rimIntensity * (eclipseProgress - 0.7) * 2.5;\n finalColor += rimGlow;\n }\n }\n\n // Apply fade-in opacity to prevent gray flash during texture load\n gl_FragColor = vec4(finalColor, opacity);\n}\n"}}(o),g=new e.ShaderMaterial({uniforms:{colorMap:{value:null},normalMap:{value:null},shadowOffset:{value:new e.Vector2(l,h)},shadowCoverage:{value:c},shadowSoftness:{value:.05},glowColor:{value:a},glowIntensity:{value:s},opacity:{value:0},eclipseProgress:{value:0},eclipseIntensity:{value:0},bloodMoonColor:{value:[.85,.18,.08]},blendMode:{value:0},blendStrength:{value:2},emissiveStrength:{value:.39},eclipseShadowPos:{value:[-2,0]},eclipseShadowRadius:{value:1.2},eclipseShadowColor:{value:[.85,.08,.02]},eclipseMidtoneColor:{value:[1,.12,.03]},eclipseHighlightColor:{value:[1,.35,.08]},eclipseGlowColor:{value:[1,.4,.1]}},vertexShader:m,fragmentShader:p,transparent:!0,side:e.FrontSide}),f=new Map;f.set(u,{texture:null});const y=t.load(u,e=>{g.uniforms.colorMap.value=e;const t=performance.now(),i=()=>{const e=performance.now()-t,n=Math.min(e/300,1);g.uniforms.opacity.value=n,g.needsUpdate=!0,n<1&&requestAnimationFrame(i)};i();const n=f.get(u);n&&(n.texture=e),f.delete(u)},void 0,e=>{console.error("❌ Failed to load moon crescent color texture:",e),f.delete(u)});f.set(d,{texture:null});const v=t.load(d,e=>{g.uniforms.normalMap.value=e,g.needsUpdate=!0;const t=f.get(d);t&&(t.texture=e),f.delete(d)},void 0,e=>{console.error("❌ Failed to load moon crescent normal map:",e),f.delete(d)});return y.wrapS=y.wrapT=e.RepeatWrapping,v.wrapS=v.wrapT=e.RepeatWrapping,y.anisotropy=16,v.anisotropy=16,g.userData.pendingTextures=f,g}function G(e,t={}){return L(e,{...t,shadowType:"crescent"})}function V(e,t){if(!e.uniforms||!e.uniforms.shadowOffset)return console.warn("Material does not have shadowOffset uniform"),!1;let i;if("string"==typeof t){if(i=I[t],!i)return console.warn(`Unknown moon phase: ${t}`),!1}else{if("number"!=typeof t)return console.warn("Phase must be a string or number"),!1;i=R(t)}return e.uniforms.shadowOffset.value.set(i.x,i.y),!0}function q(e,t,i=2e3){let n=null,a=!1;const s=new Promise((s,o)=>{if(!e.uniforms||!e.uniforms.shadowOffset)return void o(new Error("Material does not have shadowOffset uniform"));let r;if("string"==typeof t){if(r=I[t],!r)return void o(new Error(`Unknown moon phase: ${t}`))}else{if("number"!=typeof t)return void o(new Error("Phase must be a string or number"));r=R(t)}const l=e.uniforms.shadowOffset.value.x,h=e.uniforms.shadowOffset.value.y,c=r.x,u=r.y,d=Date.now(),m=()=>{if(a)return void s({cancelled:!0});const t=Date.now()-d,o=Math.min(t/i,1),r=o<.5?4*o*o*o:1-Math.pow(-2*o+2,3)/2,p=l+(c-l)*r,g=h+(u-h)*r;e.uniforms.shadowOffset.value.set(p,g),o<1?n=requestAnimationFrame(m):s({cancelled:!1})};m()});return{promise:s,cancel:()=>{a=!0,null!==n&&(cancelAnimationFrame(n),n=null)}}}function N(e,t,i){e.emissive&&(e.emissive.copy(t),e.emissiveIntensity=i),e.uniforms&&e.uniforms.glowColor&&(e.uniforms.glowColor.value.copy(t),e.uniforms.glowIntensity.value=i)}function j(e,t,i,n){e.uniforms&&e.uniforms.shadowOffset&&(e.uniforms.shadowOffset.value.set(t,i),e.uniforms.shadowCoverage.value=n)}function U(t,i={}){const{resolution:n="2k",glowColor:a=new e.Color(16777215),glowIntensity:s=1,assetBasePath:o="/assets"}=i,{vertexShader:r,fragmentShader:l}={vertexShader:"\n/**\n * Moon Vertex Shader\n * Passes view-space normal for camera-relative moon phase shadows\n */\n\nvarying vec3 vPosition; // LOCAL position (object space)\nvarying vec3 vWorldPosition;\nvarying vec3 vViewNormal; // VIEW SPACE normal (fixed relative to camera)\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n vPosition = position;\n\n // Transform normal to VIEW space (camera-relative)\n // This keeps the moon phase shadow fixed relative to camera view\n // When you rotate the moon, the texture rotates but the phase shadow stays put\n vViewNormal = normalize(normalMatrix * normal);\n\n vec4 worldPosition = modelMatrix * vec4(position, 1.0);\n vWorldPosition = worldPosition.xyz;\n vec4 viewPosition = viewMatrix * worldPosition;\n vViewPosition = viewPosition.xyz;\n gl_Position = projectionMatrix * viewPosition;\n}\n",fragmentShader:P},h=new e.ShaderMaterial({uniforms:{colorMap:{value:null},normalMap:{value:null},shadowOffset:{value:new e.Vector2(0,0)},shadowCoverage:{value:.5},shadowSoftness:{value:.05},glowColor:{value:a},glowIntensity:{value:s},opacity:{value:0},eclipseProgress:{value:0},eclipseIntensity:{value:0},bloodMoonColor:{value:[.85,.18,.08]},emissiveStrength:{value:.39},eclipseShadowPos:{value:[-2,0]},eclipseShadowRadius:{value:1.2},eclipseShadowColor:{value:[1,.58,0]},eclipseMidtoneColor:{value:[.71,.43,.03]},eclipseHighlightColor:{value:[1,.28,.1]},eclipseGlowColor:{value:[.09,.09,.09]},eclipseBrightnessModel:{value:0},shadowDarkness:{value:.53},layer1Mode:{value:9},layer1Strength:{value:.322},layer1Enabled:{value:1},layer2Mode:{value:0},layer2Strength:{value:2.785},layer2Enabled:{value:1},layer3Mode:{value:7},layer3Strength:{value:.199},layer3Enabled:{value:1},layer4Mode:{value:0},layer4Strength:{value:0},layer4Enabled:{value:0}},vertexShader:r,fragmentShader:l,transparent:!0,depthWrite:!0,side:e.FrontSide}),c=`${o}/textures/Moon/moon-color-${n}.jpg`,u=`${o}/textures/Moon/moon-normal-${n}.jpg`;return t.load(c,e=>{h.uniforms.colorMap.value=e;const t=performance.now(),i=()=>{const e=performance.now()-t,n=Math.min(e/300,1);h.uniforms.opacity.value=n,h.needsUpdate=!0,n<1&&requestAnimationFrame(i)};i()}),t.load(u,e=>{h.uniforms.normalMap.value=e}),h}const H=`\n/**\n * Sun Fragment Shader with Blend Layers and Solar Eclipse\n *\n * Supports solar eclipse effects with moon's shadow darkening the sun\n * and up to 4 sequential blend mode layers for eclipse appearance adjustment\n */\n\nuniform float time;\nuniform sampler2D colorMap;\nuniform sampler2D normalMap;\nuniform vec3 baseColor;\nuniform float emissiveIntensity;\nuniform vec2 shadowOffset;\nuniform float shadowCoverage;\nuniform float shadowSoftness;\nuniform float opacity;\n\n// Solar Eclipse uniforms (moon's shadow covering sun)\nuniform float eclipseProgress; // Eclipse progress (0 = no eclipse, 1 = totality)\nuniform vec2 eclipseShadowPos; // Shadow center position in UV space\nuniform float eclipseShadowRadius; // Moon's shadow radius\nuniform float shadowDarkness; // How much to darken the sun (0-1)\n\n// Blend Layer Uniforms (up to 4 layers)\nuniform float layer1Mode;\nuniform float layer1Strength;\nuniform float layer1Enabled;\n\nuniform float layer2Mode;\nuniform float layer2Strength;\nuniform float layer2Enabled;\n\nuniform float layer3Mode;\nuniform float layer3Strength;\nuniform float layer3Enabled;\n\nuniform float layer4Mode;\nuniform float layer4Strength;\nuniform float layer4Enabled;\n\nvarying vec2 vUv;\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition; // View-space position (camera-relative)\n\n// ═══════════════════════════════════════════════════════════════════════════\n// UNIVERSAL BLEND MODES (injected from utils/blendModes.js)\n// ═══════════════════════════════════════════════════════════════════════════\n${S}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// SIMPLEX NOISE (for fire animation - from original sun shader)\n// ═══════════════════════════════════════════════════════════════════════════\nvec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }\nvec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\nfloat snoise(vec3 v) {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n vec3 i = floor(v + dot(v, C.yyy));\n vec3 x0 = v - i + dot(i, C.xxx);\n\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min(g.xyz, l.zxy);\n vec3 i2 = max(g.xyz, l.zxy);\n\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy;\n vec3 x3 = x0 - D.yyy;\n\n i = mod289(i);\n vec4 p = permute(permute(permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0));\n\n float n_ = 0.142857142857;\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_);\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4(x.xy, y.xy);\n vec4 b1 = vec4(x.zw, y.zw);\n\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;\n vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;\n\n vec3 p0 = vec3(a0.xy, h.x);\n vec3 p1 = vec3(a0.zw, h.y);\n vec3 p2 = vec3(a1.xy, h.z);\n vec3 p3 = vec3(a1.zw, h.w);\n\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));\n}\n\nvoid main() {\n // ═══════════════════════════════════════════════════════════════════════════\n // BASE SUN RENDERING (photosphere texture + fire animation)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Sample base photosphere texture\n vec4 texColor = texture2D(colorMap, vUv);\n\n // Optimized single-octave noise for subtle fire\n vec3 noiseCoord = vPosition * 30.0 + vec3(0.0, time * 0.025, 0.0);\n float fireNoise = snoise(noiseCoord);\n\n // Simple threshold - fire appears only in specific noise ranges\n float fireMask = fireNoise * 0.5 + 0.5; // Remap -1..1 to 0..1\n fireMask = step(0.45, fireMask) * (1.0 - step(0.55, fireMask)); // Only 0.45-0.55 range\n\n // Almost imperceptible warmth shift\n vec3 fireColor = vec3(1.01, 1.0, 0.99);\n\n // Microscopic blending\n vec3 finalColor = mix(texColor.rgb, fireColor, fireMask * 0.008);\n\n // Apply base color tinting\n finalColor *= baseColor;\n\n // Apply emissive intensity for HDR bloom\n finalColor *= emissiveIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LIMB DARKENING (realistic solar effect - edges appear darker than center)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Calculate distance from center (0 at center, 1 at edge)\n float distFromCenterLimb = length(vWorldPosition.xy) / 0.5; // normalize by sun radius (0.5)\n distFromCenterLimb = clamp(distFromCenterLimb, 0.0, 1.0);\n\n // Limb darkening formula: I(μ) = 1 - u*(1-μ) where μ = cos(viewing angle)\n // Simplified using distance: darker at edges, brighter at center\n float mu = sqrt(1.0 - distFromCenterLimb * distFromCenterLimb); // cos approximation\n // EXTREME limb darkening for visibility\n float limbDarkeningCoeff = 0.98; // 98% darkening at edges\n float limbBrightness = 1.0 - limbDarkeningCoeff * (1.0 - mu);\n limbBrightness = pow(limbBrightness, 0.4); // Very aggressive power curve\n\n // Clamp to prevent over-darkening\n limbBrightness = max(limbBrightness, 0.02); // Edges at least 2% brightness\n\n // Apply limb darkening (BEFORE bloom processing)\n finalColor *= limbBrightness;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // SOLAR ECLIPSE EFFECT (Moon Occulting Sun)\n // ═══════════════════════════════════════════════════════════════════════════\n // Solar eclipse: Moon passes BETWEEN viewer and sun, blocking our view\n // The moon appears as a dark circular disk that covers parts of the sun\n // From Earth, moon and sun appear same angular size (0.5°)\n\n // Only apply eclipse if there's a moon to occlude (radius > 0)\n if (eclipseShadowRadius > 0.01) {\n // Only occlude FRONT-FACING parts of the sun (vViewPosition.z < 0 faces camera in view space)\n // Back of sun should not be affected by moon\n if (vViewPosition.z < 0.1) {\n // Project to screen space - camera-relative, independent of sun rotation\n // vViewPosition.xy is already in camera space, just normalize to sun radius\n // Sun radius in view space is approximately 0.5 at typical camera distance\n vec2 screenPos = vViewPosition.xy;\n\n // Moon center position in screen space (same coordinate system)\n vec2 moonCenter = eclipseShadowPos;\n\n // Distance from this sun point to moon center (2D screen space)\n float distToMoon = length(screenPos - moonCenter);\n\n // Moon's angular size (appears same size as sun from Earth)\n // In normalized screen space, sun radius = 1.0, moon radius = 1.0 for total eclipse\n float moonRadius = eclipseShadowRadius;\n float moonEdge = 0.01; // Sharp edge for moon silhouette\n\n // Check if moon blocks this point (moon is in front of sun)\n float moonOcclusion = 1.0 - smoothstep(moonRadius - moonEdge, moonRadius + moonEdge, distToMoon);\n\n // Only apply if moon is actually occluding something\n if (moonOcclusion > 0.001) {\n // Moon completely blocks sun where it overlaps (no light gets through)\n finalColor *= (1.0 - moonOcclusion);\n\n // Subtle penumbra around moon edge (diffraction)\n float penumbraRadius = moonRadius * 1.02;\n float penumbraEdge = 0.03;\n float penumbra = 1.0 - smoothstep(penumbraRadius - penumbraEdge, penumbraRadius + penumbraEdge, distToMoon);\n float penumbraBlocking = (penumbra - moonOcclusion) * 0.2;\n finalColor *= (1.0 - penumbraBlocking);\n }\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // BLEND LAYERS (Applied globally to entire sun)\n // These allow adjusting the appearance of the sun\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Layer 1\n if (layer1Enabled > 0.5) {\n vec3 blendColor1 = vec3(min(layer1Strength, 1.0));\n int mode1 = int(layer1Mode + 0.5);\n vec3 blended1 = clamp(applyBlendMode(finalColor, blendColor1, mode1), 0.0, 1.0);\n finalColor = clamp(blended1, 0.0, 1.0);\n }\n\n // Layer 2\n if (layer2Enabled > 0.5) {\n vec3 blendColor2 = vec3(min(layer2Strength, 1.0));\n int mode2 = int(layer2Mode + 0.5);\n vec3 blended2 = clamp(applyBlendMode(finalColor, blendColor2, mode2), 0.0, 1.0);\n finalColor = clamp(blended2, 0.0, 1.0);\n }\n\n // Layer 3\n if (layer3Enabled > 0.5) {\n vec3 blendColor3 = vec3(min(layer3Strength, 1.0));\n int mode3 = int(layer3Mode + 0.5);\n vec3 blended3 = clamp(applyBlendMode(finalColor, blendColor3, mode3), 0.0, 1.0);\n finalColor = clamp(blended3, 0.0, 1.0);\n }\n\n // Layer 4\n if (layer4Enabled > 0.5) {\n vec3 blendColor4 = vec3(min(layer4Strength, 1.0));\n int mode4 = int(layer4Mode + 0.5);\n vec3 blended4 = clamp(applyBlendMode(finalColor, blendColor4, mode4), 0.0, 1.0);\n finalColor = clamp(blended4, 0.0, 1.0);\n }\n\n // Apply fade-in opacity to prevent texture flash during load\n gl_FragColor = vec4(finalColor, opacity);\n}\n`,W={baseSpeed:.01,axes:[0,1,0]};function X(t,i={}){const n=i.resolution||"4k",a=i.glowColor||[1,1,1],s=i.glowIntensity||1,o=i.materialVariant||null,r=i.assetBasePath||"/assets",l=`${r}/textures/Sun/sun-photosphere-${n}.jpg`,h=`${r}/textures/Sun/sun-photosphere-normal-${n}.jpg`,c=1+2*s,u=new e.Color(c*a[0],c*a[1],c*a[2]*.95),d=new Map;d.set(l,{texture:null});const m=t.load(l,e=>{v.uniforms?.opacity&&(v.uniforms.opacity.value=1);const t=d.get(l);t&&(t.texture=e),d.delete(l)},void 0,e=>{console.warn(`⚠️ Failed to load sun texture (${n}), using color fallback:`,e),d.delete(l)});d.set(h,{texture:null});const p=t.load(h,e=>{const t=d.get(h);t&&(t.texture=e),d.delete(h)},void 0,e=>{console.warn(`⚠️ Sun normal map not found (${n}), continuing without surface detail:`,e),d.delete(h)});let g,f;m.wrapS=m.wrapT=e.RepeatWrapping,p.wrapS=p.wrapT=e.RepeatWrapping,m.anisotropy=16,p.anisotropy=16;let y={};if("multiplexer"===o){const{vertexShader:e,fragmentShader:t}={vertexShader:"\n/**\n * Sun Vertex Shader\n * Passes view-space position for camera-relative eclipse shadow calculations\n */\n\nvarying vec2 vUv;\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition; // View-space position (camera-relative)\n\nvoid main() {\n vUv = uv;\n vNormal = normalize(normalMatrix * normal);\n vPosition = position;\n vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n\n // Calculate view-space position (camera-relative, always faces camera)\n vec4 viewPos = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = viewPos.xyz;\n\n gl_Position = projectionMatrix * viewPos;\n}\n",fragmentShader:H};g=e,f=t,y={eclipseProgress:{value:0},eclipseShadowPos:{value:[-2,0]},eclipseShadowRadius:{value:.882},shadowDarkness:{value:1},layer1Mode:{value:0},layer1Strength:{value:.23},layer1Enabled:{value:1},layer2Mode:{value:0},layer2Strength:{value:0},layer2Enabled:{value:0},layer3Mode:{value:0},layer3Strength:{value:0},layer3Enabled:{value:0},layer4Mode:{value:0},layer4Strength:{value:0},layer4Enabled:{value:0}}}else g="\n varying vec2 vUv;\n varying vec3 vNormal;\n varying vec3 vPosition;\n varying vec3 vWorldPosition;\n\n void main() {\n vUv = uv;\n vNormal = normalize(normalMatrix * normal);\n vPosition = position;\n vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",f="\n uniform float time;\n uniform sampler2D colorMap;\n uniform sampler2D normalMap;\n uniform vec3 baseColor;\n uniform float emissiveIntensity;\n uniform vec2 shadowOffset;\n uniform float shadowCoverage;\n uniform float shadowSoftness;\n uniform float opacity; // Fade in opacity (0-1) to prevent texture flash\n\n varying vec2 vUv;\n varying vec3 vNormal;\n varying vec3 vPosition;\n varying vec3 vWorldPosition;\n\n // Simplex noise for fire animation (Ashima Arts)\n vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }\n vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\n float snoise(vec3 v) {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n vec3 i = floor(v + dot(v, C.yyy));\n vec3 x0 = v - i + dot(i, C.xxx);\n\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min(g.xyz, l.zxy);\n vec3 i2 = max(g.xyz, l.zxy);\n\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy;\n vec3 x3 = x0 - D.yyy;\n\n i = mod289(i);\n vec4 p = permute(permute(permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0));\n\n float n_ = 0.142857142857;\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_);\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4(x.xy, y.xy);\n vec4 b1 = vec4(x.zw, y.zw);\n\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;\n vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;\n\n vec3 p0 = vec3(a0.xy, h.x);\n vec3 p1 = vec3(a0.zw, h.y);\n vec3 p2 = vec3(a1.xy, h.z);\n vec3 p3 = vec3(a1.zw, h.w);\n\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));\n }\n\n void main() {\n // Sample base photosphere texture\n vec4 texColor = texture2D(colorMap, vUv);\n\n // Optimized single-octave noise for subtle fire (was 2 FBM calls with 3 octaves each)\n // Using position-based noise with time offset for animation\n vec3 noiseCoord = vPosition * 30.0 + vec3(0.0, time * 0.025, 0.0);\n float fireNoise = snoise(noiseCoord);\n\n // Simple threshold - fire appears only in specific noise ranges\n // Using step functions instead of smoothstep for performance\n float fireMask = fireNoise * 0.5 + 0.5; // Remap -1..1 to 0..1\n fireMask = step(0.45, fireMask) * (1.0 - step(0.55, fireMask)); // Only 0.45-0.55 range\n\n // Almost imperceptible warmth shift (same visual as before)\n vec3 fireColor = vec3(1.01, 1.0, 0.99);\n\n // Microscopic blending - nearly invisible (same blend factor)\n vec3 finalColor = mix(texColor.rgb, fireColor, fireMask * 0.008);\n\n // Apply base color tinting\n finalColor *= baseColor;\n\n // Apply emissive intensity for HDR bloom\n finalColor *= emissiveIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LIMB DARKENING (realistic solar effect - edges appear darker than center)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Calculate distance from center (0 at center, 1 at edge)\n float distFromCenterLimb = length(vWorldPosition.xy) / 0.5; // normalize by sun radius (0.5)\n distFromCenterLimb = clamp(distFromCenterLimb, 0.0, 1.0);\n\n // Limb darkening formula: I(μ) = 1 - u*(1-μ) where μ = cos(viewing angle)\n // Simplified using distance: darker at edges, brighter at center\n float mu = sqrt(1.0 - distFromCenterLimb * distFromCenterLimb); // cos approximation\n float limbDarkeningCoeff = 0.6; // NASA solar data: ~60% darkening at limb\n float limbBrightness = 1.0 - limbDarkeningCoeff * (1.0 - mu);\n\n // Apply limb darkening (preserves bright core for bloom)\n finalColor *= limbBrightness;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // SHADOW DARKENING (applied AFTER bloom intensity so it doesn't affect bloom)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Sun sphere center (world space origin)\n float sunRadius = 0.5; // Matches geometry radius\n\n // Shadow sphere center (offset from sun center)\n vec3 shadowCenter = vec3(shadowOffset.x, shadowOffset.y, 0.0);\n\n // Calculate distance from fragment to shadow sphere center\n float distToShadow = distance(vWorldPosition, shadowCenter);\n\n // Shadow threshold (shadow sphere radius adjusted by coverage)\n float shadowRadius = sunRadius * shadowCoverage;\n\n // Calculate shadow factor (0 = full shadow, 1 = no shadow)\n float shadowFactor = smoothstep(shadowRadius - shadowSoftness, shadowRadius + shadowSoftness, distToShadow);\n\n // Darken ONLY the final color output (not the bloom calculation)\n float shadowDarkness = 0.05; // How dark the shadow gets (5% brightness)\n finalColor *= mix(shadowDarkness, 1.0, shadowFactor);\n\n // ═══════════════════════════════════════════════════════════════════════════\n // RADIAL CORONA WAVES (applied AFTER shadow, visible around eclipse edge)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Calculate angle from sun center in world space XY plane\n float angle = atan(vWorldPosition.y, vWorldPosition.x);\n\n // Create radial wave pattern (16 petals for finer detail, rotating slowly)\n float wave = sin(angle * 16.0 + time * 0.3) * 0.5 + 0.5;\n\n // Apply waves to visible (non-shadowed) edges\n float distFromCenter = length(vWorldPosition.xy);\n\n // Edge factor: strong at sun's edge where bloom will amplify it\n float edgeFactor = smoothstep(0.35, 0.5, distFromCenter);\n\n // Only apply waves to non-shadowed areas (visible during eclipse)\n // Combine with shadow factor so waves appear around shadow edge\n float waveStrength = edgeFactor * shadowFactor;\n\n // Very strong modulation (2x variation) for dramatic eclipse corona\n float coronaModulation = 1.0 + (wave * 2.0 - 1.0) * waveStrength;\n finalColor *= coronaModulation;\n\n // Apply fade-in opacity to prevent texture flash during load\n gl_FragColor = vec4(finalColor, opacity);\n }\n ";const v=new e.ShaderMaterial({uniforms:{time:{value:0},colorMap:{value:m},normalMap:{value:p},baseColor:{value:u},emissiveIntensity:{value:1.2},glowColor:{value:new e.Color(1,1,1)},glowIntensity:{value:1},shadowOffset:{value:new e.Vector2(200,0)},shadowCoverage:{value:.5},shadowSoftness:{value:.1},opacity:{value:0},...y},vertexShader:g,fragmentShader:f,transparent:!0,toneMapped:!1});return v.userData.uniforms=v.uniforms,v.userData.pendingTextures=d,v}function Y(t=null,i={}){const n=i.glowColor||[1,1,1],a=i.glowIntensity||1,s=i.resolution||"4k",o=i.materialVariant||null,r=new e.SphereGeometry(.5,128,128);let l;if(r.userData.tracked=!0,t)l=X(t,{glowColor:n,glowIntensity:a,resolution:s,materialVariant:o});else{const t=1+2*a,i=new e.Color(t*n[0],t*n[1],t*n[2]*.95);l=new e.MeshBasicMaterial({color:i,toneMapped:!1})}const h=new e.Mesh(r,l);return h.castShadow=!1,h.receiveShadow=!1,h}function $(e,t,i=1,n=0){if(!e||!e.material)return;const{material:a}=e;if(a.uniforms&&a.uniforms.baseColor){const{uniforms:e}=a;n>0&&(e.time.value=(e.time.value+n)%(2*Math.PI));const t=1+2*i;e.baseColor.value.setRGB(t,t,.95*t),e.emissiveIntensity.value=1.2}else if(a.color){const e=1+2*i;a.color.setRGB(e,e,.95*e)}}function Q(e){if(e&&(e.geometry&&e.geometry.dispose(),e.material)){const{material:t}=e;t.userData&&t.userData.pendingTextures&&(t.userData.pendingTextures.forEach(({texture:e})=>{e&&e.dispose()}),t.userData.pendingTextures.clear()),t.uniforms&&(t.uniforms.colorMap&&t.uniforms.colorMap.value&&t.uniforms.colorMap.value.dispose(),t.uniforms.normalMap&&t.uniforms.normalMap.value&&t.uniforms.normalMap.value.dispose()),t.map&&t.map.dispose(),t.normalMap&&t.normalMap.dispose(),t.dispose()}}function Z(){const t=new e.SphereGeometry(.5,32,32),i=t.attributes.position;for(let e=0;e<i.count;e++){let t=i.getX(e);const n=i.getY(e);let a=i.getZ(e);const s=1+.3*Math.max(0,n);if(t*=s,a*=.8*s,n<-.3){const e=(-n-.3)/.2;t*=1-.8*e,a*=1-.8*e}i.setXYZ(e,t,n,a)}return t.computeVertexNormals(),t}function J(){const t=new e.DodecahedronGeometry(.5,0);return t.computeVertexNormals(),t}function K(){const t=new e.BufferGeometry,i=[],n=[];i.push(0,2.3,0);for(let e=0;e<6;e++){const t=e/6*Math.PI*2;i.push(1*Math.cos(t),1.5,1*Math.sin(t))}for(let e=0;e<6;e++){const t=e/6*Math.PI*2;i.push(1*Math.cos(t),-1.5,1*Math.sin(t))}i.push(0,-2.3,0);for(let e=0;e<6;e++){const t=(e+1)%6;n.push(0,1+e,1+t)}for(let e=0;e<6;e++){const t=(e+1)%6;n.push(1+e,7+e,1+t),n.push(1+t,7+e,7+t)}for(let e=0;e<6;e++){const t=(e+1)%6;n.push(13,7+t,7+e)}t.setAttribute("position",new e.Float32BufferAttribute(i,3)),t.setIndex(n);const a=1.6/4.6;return t.scale(a,a,a),t.computeVertexNormals(),t}function ee(t=.4,i=.15,n=32,a=64){return new e.TorusGeometry(t,i,n,a)}function te(t=.5,i=1){return new e.IcosahedronGeometry(t,i)}const ie={sphere:{geometry:function(t=64,i=64){return new e.SphereGeometry(.5,t,i)}(64,64),blink:{type:"vertical-squish",duration:150,scaleAxis:[1,.3,1],curve:"sine",playful:{anticipation:.03,overshoot:.05}}},torus:{geometry:ee(),blink:{type:"vertical-squish",duration:150,scaleAxis:[1,.4,1],rotation:[0,0,Math.PI/8],curve:"sine"}},icosahedron:{geometry:te(.5,1),blink:{type:"geometric-pulse",duration:130,scaleAxis:[.7,.7,.7],curve:"sine"}},octahedron:{geometry:function(t=.5,i=0){return new e.OctahedronGeometry(t,i)}(.5,0),blink:{type:"geometric-pulse",duration:130,scaleAxis:[.7,.7,.7],curve:"sine"}},tetrahedron:{geometry:function(t=.5,i=0){return new e.TetrahedronGeometry(t,i)}(.5,0),blink:{type:"geometric-pulse",duration:110,scaleAxis:[.75,.75,.75],rotation:[Math.PI/6,0,0],curve:"sine"}},dodecahedron:{geometry:function(t=.5,i=0){return new e.DodecahedronGeometry(t,i)}(.5,0),blink:{type:"facet-flash",duration:140,scaleAxis:[.75,.75,.75],glowBoost:.4,curve:"sine"}},"smooth-icosahedron":{geometry:te(.5,2),blink:{type:"geometric-pulse",duration:140,scaleAxis:[.75,.75,.75],curve:"sine"}},"faceted-icosahedron":{geometry:te(.5,0),blink:{type:"facet-flash",duration:120,scaleAxis:[.7,.7,.7],glowBoost:.3,curve:"sine"}},ring:{geometry:ee(.4,.1,16,64),blink:{type:"vertical-squish",duration:140,scaleAxis:[1,.5,1],curve:"sine"}},moon:{geometry:z(64,64),material:"custom",blink:{type:"gentle-pulse",duration:180,scaleAxis:[.95,.95,.95],glowBoost:.2,curve:"sine"},particleRadiusMultiplier:1.4},sun:{geometry:new e.SphereGeometry(.5,64,64),material:"emissive",blink:{type:"radial-pulse",duration:200,scaleAxis:[1.05,1.05,1.05],glowBoost:.5,curve:"sine"},particleRadiusMultiplier:1.5},crystal:{geometry:null,geometryLoader:function(t="/assets"){return new Promise((i,n)=>{(new f).load(`${t}/models/Crystal/crystal.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.6/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.attributes.normal||n.computeVertexNormals(),n.computeBoundingBox();const o=new e.Vector3;n.boundingBox.getSize(o);let r=n;r.computeVertexNormals(),i(r)}else{console.warn("💎 [CRYSTAL] No mesh in OBJ, using fallback");const e=K();i(e)}},e=>{},e=>{console.warn("💎 [CRYSTAL] OBJ load FAILED:",e);const t=K();i(t)})})},material:"custom",blink:{type:"facet-flash",duration:160,scaleAxis:[.95,.95,.95],glowBoost:.4,curve:"sine"},particleRadiusMultiplier:1.4},rough:{geometry:null,geometryLoader:function(t="/assets"){return new Promise(i=>{(new f).load(`${t}/models/Crystal/rough.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.6/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),n.computeBoundingBox(),i(n)}else console.warn("💎 [ROUGH] No mesh in OBJ, using fallback sphere"),i(new e.SphereGeometry(.5,32,32))},void 0,t=>{console.warn("💎 [ROUGH] OBJ load failed:",t),i(new e.SphereGeometry(.5,32,32))})})},material:"custom",blink:{type:"facet-flash",duration:150,scaleAxis:[.95,.95,.95],glowBoost:.5,curve:"sine"},particleRadiusMultiplier:1.3},heart:{geometry:null,geometryLoader:function(t="/assets"){return new Promise(i=>{(new f).load(`${t}/models/Crystal/heart.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.2/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),n.computeBoundingBox(),n.attributes.uv||function(t){t.computeBoundingBox();const i=t.boundingBox,n=t.attributes.position,a=new Float32Array(2*n.count),s=i.max.x-i.min.x,o=i.max.y-i.min.y;for(let e=0;e<n.count;e++){const t=n.getX(e),r=n.getY(e);a[2*e]=(t-i.min.x)/s,a[2*e+1]=(r-i.min.y)/o}t.setAttribute("uv",new e.BufferAttribute(a,2))}(n),i(n)}else console.warn("💗 [HEART] No mesh in OBJ, using fallback"),i(Z())},void 0,e=>{console.warn("💗 [HEART] OBJ load failed:",e),i(Z())})})},material:"custom",blink:{type:"gentle-pulse",duration:180,scaleAxis:[.92,.92,.92],glowBoost:.6,curve:"sine"},particleRadiusMultiplier:1.3},star:{geometry:null,geometryLoader:function(t="/assets"){return new Promise(i=>{(new f).load(`${t}/models/Crystal/star.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.4/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),n.computeBoundingBox(),n.attributes.uv||function(t){t.computeBoundingBox();const i=t.boundingBox,n=t.attributes.position,a=new Float32Array(2*n.count),s=i.max.x-i.min.x,o=i.max.y-i.min.y;for(let e=0;e<n.count;e++){const t=n.getX(e),r=n.getY(e);a[2*e]=(t-i.min.x)/s,a[2*e+1]=(r-i.min.y)/o}t.setAttribute("uv",new e.BufferAttribute(a,2))}(n),i(n)}else console.warn("⭐ [STAR] No mesh in OBJ, using fallback"),i(J())},void 0,e=>{console.warn("⭐ [STAR] OBJ load failed:",e),i(J())})})},material:"custom",blink:{type:"facet-flash",duration:150,scaleAxis:[.93,.93,.93],glowBoost:.5,curve:"sine"},particleRadiusMultiplier:1.4}};class ne{constructor(){this.currentAnimation=null,this.animations=[],this.time=0}playEmotion(e,t={}){const i=this.createEmotionAnimation(e);this.startAnimation(i,t)}playGesture(e,t={}){const i=this.createGestureAnimation(e);this.startAnimation(i,t)}playMorph(e,t,i={}){const n=this.createMorphAnimation(e,t);this.startAnimation(n,i)}update(e){this.time+=e;for(let e=this.animations.length-1;e>=0;e--){const t=this.animations[e],i=t.duration;Math.min((this.time-t.startTime)/i,1)>=1&&(t.callbacks&&t.callbacks.onComplete&&t.callbacks.onComplete(),this.animations.splice(e,1))}}createEmotionAnimation(e){const t={joy:{duration:.6,evaluate:e=>({scale:1+.15*Math.sin(e*Math.PI),glowIntensity:1+.15*Math.sin(e*Math.PI)})},love:{duration:1.2,evaluate:e=>({scale:1+.08*Math.sin(e*Math.PI*2),glowIntensity:1+.1*Math.sin(e*Math.PI*2)})},curiosity:{duration:.8,evaluate:e=>({rotation:[0,.1*Math.sin(e*Math.PI*4),0],scale:1+.05*Math.sin(e*Math.PI),glowIntensity:1})},sadness:{duration:1.5,evaluate:e=>({scale:1-.1*e,glowIntensity:1-.15*Math.sin(e*Math.PI)})},anger:{duration:.4,evaluate:e=>{const t=.15*Math.sin(e*Math.PI*8);return{rotation:[t,t,0],scale:1.1+.1*Math.sin(e*Math.PI),glowIntensity:1+.15*Math.sin(e*Math.PI*8)}}},fear:{duration:.5,evaluate:e=>{const t=.08*Math.sin(e*Math.PI*10);return{scale:.9+t,rotation:[t,0,t],glowIntensity:1+.1*Math.sin(e*Math.PI*10)}}},surprise:{duration:.4,evaluate:e=>({scale:1+.25*(1-Math.cos(e*Math.PI)),glowIntensity:1+.2*(1-Math.cos(e*Math.PI))})},neutral:{duration:.5,evaluate:e=>({scale:1,glowIntensity:1})}};return t[e]||t.neutral}createGestureAnimation(e){const t={bounce:{duration:.8,evaluate:e=>{const t=Math.abs(Math.sin(e*Math.PI));return{position:[0,.5*t,0],scale:1+.1*t}}},pulse:{duration:.6,evaluate:e=>{const t=Math.sin(e*Math.PI);return{scale:1+.2*t,glowIntensity:1+.5*t}}},spin:{duration:1,evaluate:e=>({rotation:[0,e*Math.PI*2,0]})},wobble:{duration:1,evaluate:e=>{const t=Math.sin(e*Math.PI*3);return{rotation:[.3*t,0,.2*t]}}},float:{duration:2,evaluate:e=>({position:[0,.3*Math.sin(e*Math.PI),0]})},shake:{duration:.5,evaluate:e=>{const t=Math.sin(e*Math.PI*6)*(1-e);return{position:[.2*t,0,0],rotation:[0,0,.1*t]}}},nod:{duration:.8,evaluate:e=>({rotation:[.3*Math.sin(e*Math.PI*2),0,0]})}};return t[e]||t.pulse}createMorphAnimation(e,t){return{duration:1,fromShape:e,toShape:t,evaluate:e=>({morphProgress:e,scale:1+.1*Math.sin(e*Math.PI),rotation:[0,e*Math.PI*.5,0]})}}startAnimation(e,t){this.animations.push({...e,startTime:this.time,callbacks:t||{}}),this.currentAnimation=e}stopAll(){this.animations=[],this.currentAnimation=null}destroy(){this.stopAll(),this.animations=null,this.currentAnimation=null,this.time=0}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}getIdleAnimation(){return{duration:3,loop:!0,evaluate:e=>{const t=Math.sin(e*Math.PI*2),i=Math.sin(e*Math.PI);return{scale:1+.02*t,position:[.05*i,.03*t,0],rotation:[0,.05*i,0],glowIntensity:1+.1*t}}}}isPlaying(){return this.animations.length>0}}class ae{constructor(){this.breathingSpeed=1,this.breathingDepth=.03,this.breathingPhase=0,this.breathRate=1,this.breathDepth=.03,this.breathRateMult=1,this.breathDepthMult=1,this.emotionBreathPatterns={happy:{rate:1.1,depth:1.2},sad:{rate:.8,depth:.7},angry:{rate:1.4,depth:1.3},calm:{rate:.7,depth:.9},excited:{rate:1.5,depth:1.4},focused:{rate:.9,depth:.6},neutral:{rate:1,depth:1},love:{rate:1.2,depth:1.3},surprised:{rate:1.3,depth:1.1},confused:{rate:1.1,depth:.9},amused:{rate:1.2,depth:1.1},bored:{rate:.6,depth:.8},tired:{rate:.5,depth:1.2},anxious:{rate:1.6,depth:.9},determined:{rate:1.1,depth:1},proud:{rate:.9,depth:1.3},content:{rate:.8,depth:1},hopeful:{rate:1,depth:1.1},zen:{rate:.4,depth:1.5},intrigued:{rate:1.1,depth:.8},embarrassed:{rate:1.3,depth:.7},grateful:{rate:.9,depth:1.1},inspired:{rate:1,depth:1.3},silly:{rate:1.4,depth:1.2},sleepy:{rate:.3,depth:1.4}}}update(e,t,i=null){const n=this.emotionBreathPatterns[t]||{rate:1,depth:1};i&&i["3d"]&&i["3d"].scale?(this.breathRateMult=i["3d"].scale.breathRateMultiplier||1,this.breathDepthMult=i["3d"].scale.breathDepthMultiplier||1):(this.breathRateMult=1,this.breathDepthMult=1),this.breathRate=n.rate*this.breathRateMult,this.breathDepth=this.breathingDepth*n.depth*this.breathDepthMult;const a=this.breathingSpeed*this.breathRate*(e/1e3);this.breathingPhase+=a,this.breathingPhase>2*Math.PI&&(this.breathingPhase-=2*Math.PI)}getBreathingScale(){return 1+Math.sin(this.breathingPhase)*this.breathDepth}setEmotion(e,t=null){const i=this.emotionBreathPatterns[e]||{rate:1,depth:1};t&&t["3d"]&&t["3d"].scale?(this.breathRateMult=t["3d"].scale.breathRateMultiplier||1,this.breathDepthMult=t["3d"].scale.breathDepthMultiplier||1):(this.breathRateMult=1,this.breathDepthMult=1),this.breathRate=i.rate*this.breathRateMult,this.breathDepth=this.breathingDepth*i.depth*this.breathDepthMult}reset(){this.breathingPhase=0,this.breathRate=1,this.breathDepth=this.breathingDepth,this.breathRateMult=1,this.breathDepthMult=1}getBreathingInfo(){return{phase:this.breathingPhase,rate:this.breathRate,depth:this.breathDepth,scale:this.getBreathingScale(),rateMult:this.breathRateMult,depthMult:this.breathDepthMult}}destroy(){this.emotionBreathPatterns=null}}class se{constructor(){this.tempEuler=new e.Euler,this.tempQuat=new e.Quaternion,this.accumulatedRotationQuat=new e.Quaternion,this.finalQuaternion=new e.Quaternion}blend(e,t,i,n,a){this.accumulatedRotationQuat.identity();const s={position:[0,0,0],rotationQuat:this.accumulatedRotationQuat,scale:1,glowIntensity:1,glowBoost:0};for(const i of e)if(i.evaluate){const e=t-i.startTime,n=i.duration,a=Math.min(e/n,1),o=i.evaluate(a);o&&(o.position&&(s.position[0]+=o.position[0],s.position[1]+=o.position[1],s.position[2]+=o.position[2]),o.rotation&&(this.tempEuler.set(o.rotation[0],o.rotation[1],o.rotation[2],"XYZ"),this.tempQuat.setFromEuler(this.tempEuler),s.rotationQuat.multiply(this.tempQuat)),void 0!==o.scale&&(s.scale*=o.scale),void 0!==o.glowIntensity&&(s.glowIntensity*=o.glowIntensity),void 0!==o.glowBoost&&(s.glowBoost+=o.glowBoost))}this.finalQuaternion.copy(i).multiply(s.rotationQuat),this.tempEuler.setFromQuaternion(this.finalQuaternion,"XYZ");const o=[this.tempEuler.x,this.tempEuler.y,this.tempEuler.z],r=n*s.scale,l=a*s.glowIntensity;return{position:s.position,rotation:o,scale:r,glowIntensity:l,glowBoost:s.glowBoost,gestureQuaternion:s.rotationQuat}}destroy(){this.tempEuler=null,this.tempQuat=null,this.accumulatedRotationQuat=null,this.finalQuaternion=null}}const oe=new Map;var re=function(e){return oe.get(e)||null},le=function(){return Array.from(oe.keys())},he={name:"suspicion",emoji:"🤨",description:"Paranoid watchfulness with surveillance scanning",visual:{glowColor:"#6B46C1",particleRate:4,minParticles:6,maxParticles:12,particleBehavior:"surveillance",particleSpeed:.2,breathRate:.6,breathDepth:.04,coreJitter:.02,blinkRate:1.1,blinkSpeed:1,particleColors:[{color:"#6B46C1",weight:30},{color:"#4A5568",weight:25},{color:"#8B4789",weight:20},{color:"#9F7AEA",weight:15},{color:"#2D3748",weight:10}],threatLevel:0,getGlowIntensity(){return.3+.7*this.threatLevel},getParticleSpeed(){return.2+.8*this.threatLevel},getGlowColor(){const e=this.threatLevel||0,t=Math.round(107+113*e),i=Math.round(70+-32*e),n=Math.round(193+-66*e),a=e=>e.toString(16).padStart(2,"0");return`#${a(t)}${a(i)}${a(n)}`}},modifiers:{speed:.4,amplitude:.6,intensity:1.2,smoothness:.3,regularity:.2,focus:1.5,addWobble:!0},typicalGestures:["scan","twitch","peek","tilt","hold"],transitions:{duration:500,easing:"linear",priority:4},special:{coreSquint:.6,scanInterval:2e3,scanDuration:1200,scanAngle:60,twitchChance:.02,peekInterval:4e3,maxThreatDistance:300,alertThreshold:.7},"3d":{rotation:{type:"suspicious",speed:1,axes:[0,0,0],musicSync:!1},glow:{color:"#6B46C1",intensity:.85,pulse:{speed:.6,range:[.7,1]}},scale:{base:1,breathe:{enabled:!0,depth:.04,rate:.6}}},soulAnimation:{driftSpeed:.9,shimmerSpeed:1.8,turbulence:.4}},ce={name:"calm",emoji:"😌",description:"Serene, peaceful state with gentle movements",visual:{glowColor:"#66D9CC",particleRate:6,minParticles:10,maxParticles:50,particleBehavior:"zen",breathRate:.4,breathDepth:.12,coreJitter:!1,blinkRate:.8,blinkSpeed:1,particleColors:[{color:"#66D9CC",weight:35},{color:"#99E6D9",weight:25},{color:"#40BFB3",weight:20},{color:"#B3F2E6",weight:15},{color:"#339980",weight:5}]},modifiers:{speed:.5,amplitude:.3,intensity:.4,smoothness:2,regularity:1.5,addWeight:!1,floatHeight:.2,swayAmount:.15,duration:1.5},typicalGestures:["breathe","float","drift","idle"],transitions:{duration:800,easing:"easeInOutSine",priority:1},movement:{floatPattern:"sine_slow",floatPeriod:6e3,floatAmplitude:8,swayPattern:"gentle",swayPeriod:8e3,swayAmplitude:5,microMovements:!1},getCoreParams(e){const t=e.time||Date.now(),i=.5*Math.sin(6e-4*t)+.5;return{scaleX:1-.02*i,scaleY:1-.02*i,eyeOpenness:.85,eyeExpression:"serene",pupilOffset:{x:2*Math.sin(3e-4*t),y:1*Math.cos(4e-4*t)},glowPulse:.95+.05*i}},updateParticle(e,t){e.x+=.1*Math.sin(.001*e.life),e.y-=.02*t,e.opacity=.3*Math.sin(.002*e.life)+.2,e.size=e.baseSize*(1+.2*Math.sin(.001*e.life))},renderCore:(e,t,i,n)=>!1,"3d":{rotation:{type:"gentle",speed:.5,axes:[0,.3,0],musicSync:!0},glow:{color:"#66D9CC",intensity:.6,pulse:{speed:.4,range:[.5,.7]}},scale:{base:1,breathe:{enabled:!0,depth:.12,rate:.4}}},soulAnimation:{driftSpeed:.3,shimmerSpeed:.4,turbulence:.1}};const ue=new Map,de={happy:"joy",peaceful:"calm",curious:"surprise",frustrated:"anger",sad:"sadness",excitement:"excited"};function me(e){const t=de[e]||e,i=ue.get(t);if(i)return i;return re(t)||null}function pe(e){const t=me(e);if(!t)return me("neutral").visual;if(!t.visual)return{};const{visual:i}=t,n={};for(const e in i)"function"!=typeof i[e]&&(n[e]=i[e]);return"function"==typeof i.getGlowIntensity&&(n.glowIntensity=i.getGlowIntensity()),"function"==typeof i.getParticleSpeed&&(n.particleSpeed=i.getParticleSpeed()),"function"==typeof i.getParticleRate&&(n.particleRate=i.getParticleRate()),"function"==typeof i.getGlowColor&&(n.glowColor=i.getGlowColor()),n}function ge(e){const t=me(e);return t?t.modifiers:me("neutral").modifiers}function fe(e,t){const i=me(e),n=me(t);return i&&n?n.transitions&&n.transitions[e]?n.transitions[e]:{duration:1e3,easing:"ease-in-out",gesture:n.transitions?.defaultGesture||null}:{duration:1e3,easing:"ease-in-out"}}[{name:"neutral",emoji:"😐",description:"Calm, balanced emotional state",visual:{glowColor:"#00BCD4",particleRate:2,minParticles:8,maxParticles:10,particleBehavior:"ambient",breathRate:1,breathDepth:.08,coreJitter:!1,blinkRate:1,blinkSpeed:1,particleColors:[{color:"#00BCD4",weight:25},{color:"#00ACC1",weight:20},{color:"#26C6DA",weight:15},{color:"#B2EBF2",weight:15},{color:"#0097A7",weight:10},{color:"#80DEEA",weight:10},{color:"#E0F7FA",weight:5}]},modifiers:{speed:1,amplitude:1,intensity:1,smoothness:1,regularity:1},typicalGestures:["breathe","float","idle","blink"],transitions:{duration:500,easing:"easeInOut",priority:0},getCoreParams:e=>({scaleX:1,scaleY:1,eyeOpenness:1,eyeExpression:"neutral",pupilOffset:{x:0,y:0}}),renderCore:(e,t,i,n)=>!1,"3d":{rotation:{type:"gentle",speed:1,axes:[0,.3,0],musicSync:!1},glow:{color:"#00BCD4",intensity:.9,pulse:{speed:1,range:[.8,1]}},scale:{base:1,breathe:{enabled:!0,depth:.08,rate:1}}},soulAnimation:{driftSpeed:.5,shimmerSpeed:.5,turbulence:.2}},{name:"joy",emoji:"😊",description:"Playful happiness and celebration",visual:{glowColor:"#FFEB3B",particleRate:8,minParticles:0,maxParticles:50,particleBehavior:"popcorn",breathRate:1.5,breathDepth:.1,coreJitter:!1,blinkRate:1.3,blinkSpeed:1.1,particleColors:[{color:"#FFEB3B",weight:25},{color:"#FFC107",weight:20},{color:"#FFFF00",weight:15},{color:"#FFD700",weight:15},{color:"#FFF59D",weight:10},{color:"#FF9800",weight:10},{color:"#FFFDE7",weight:5}]},modifiers:{speed:1.8,amplitude:1.9,intensity:1.1,smoothness:1,regularity:.9,addBounce:!0},typicalGestures:["bounce","spin","wave","expand","shake","float"],transitions:{duration:400,easing:"easeOutBack",priority:5,burstOnEntry:!0},getCoreParams:e=>({scaleX:1,scaleY:1,eyeOpenness:1,eyeExpression:"happy",pupilOffset:{x:0,y:-.1},sparkle:!0}),"3d":{rotation:{type:"rhythmic",speed:1.8,axes:[0,.3,0],musicSync:!0},glow:{color:"#FFEB3B",intensity:1.6,pulse:{speed:1.5,range:[1.2,1.8]}},scale:{base:1,breathe:{enabled:!0,depth:.1,rate:1.5}}},soulAnimation:{driftSpeed:1.2,shimmerSpeed:1.5,turbulence:.3}},{name:"sadness",emoji:"😢",description:"Deep melancholic sorrow",visual:{glowColor:"#4169E1",particleRate:6,minParticles:0,maxParticles:50,particleBehavior:"falling",breathRate:.6,breathDepth:.12,coreJitter:!1,blinkRate:.6,blinkSpeed:.8,particleColors:[{color:"#4169E1",weight:25},{color:"#1E90FF",weight:20},{color:"#6495ED",weight:15},{color:"#B0C4DE",weight:15},{color:"#191970",weight:10},{color:"#87CEEB",weight:10},{color:"#2F4F4F",weight:5}]},modifiers:{speed:.7,amplitude:.6,intensity:.8,smoothness:1.3,regularity:1.1,addGravity:!0},typicalGestures:["droop","sway","contract","drift","sink"],transitions:{duration:800,easing:"easeInOut",priority:3},"3d":{rotation:{type:"gentle",speed:.7,axes:[0,.2,0],musicSync:!1},glow:{color:"#4169E1",intensity:.65,pulse:{speed:.6,range:[.5,.8]}},scale:{base:1,breathe:{enabled:!0,depth:.12,rate:.6}}},soulAnimation:{driftSpeed:.2,shimmerSpeed:.3,turbulence:.1}},{name:"anger",emoji:"😠",description:"Intense rage and aggression",visual:{glowColor:"#DC143C",particleRate:8,minParticles:8,maxParticles:50,particleBehavior:"aggressive",breathRate:2.2,breathDepth:.15,coreJitter:!0,blinkRate:1.6,blinkSpeed:1.3,particleColors:[{color:"#DC143C",weight:25},{color:"#FF0000",weight:20},{color:"#B22222",weight:15},{color:"#FF4500",weight:15},{color:"#8B0000",weight:10},{color:"#FF6347",weight:10},{color:"#660000",weight:5}]},modifiers:{speed:1.5,amplitude:1.4,intensity:1.3,smoothness:.3,regularity:.7,addShake:!0},typicalGestures:["shake","vibrate","expand","pulse","flicker","strike"],transitions:{duration:300,easing:"easeOutExpo",priority:8,shakeOnEntry:!0},special:{screenShake:!0,particleTrails:"fire",glowPulse:!0,temperatureEffect:"hot"},"3d":{rotation:{type:"unstable",speed:1.5,axes:[0,.3,0],shake:{amplitude:.02,frequency:7},eruption:{enabled:!0,interval:3e3,speedMultiplier:3.5,duration:400},musicSync:!1},glow:{color:"#DC143C",intensity:1.8,pulse:{speed:2.2,range:[.8,2]}},scale:{base:1,breathe:{enabled:!0,depth:.15,rate:2.2}}},soulAnimation:{driftSpeed:2,shimmerSpeed:.8,turbulence:.8}},{name:"fear",emoji:"😨",description:"Anxious state with fleeing particles",visual:{glowColor:"#8A2BE2",particleRate:8,minParticles:8,maxParticles:50,particleBehavior:"scattering",breathRate:2.5,breathDepth:.06,coreJitter:!0,blinkRate:1.7,blinkSpeed:1.4,particleColors:[{color:"#8A2BE2",weight:25},{color:"#4B0082",weight:20},{color:"#9400D3",weight:15},{color:"#6B46C1",weight:15},{color:"#9932CC",weight:10},{color:"#E6E6FA",weight:8},{color:"#301934",weight:7}]},modifiers:{speed:1.4,amplitude:.8,intensity:1.2,smoothness:.5,regularity:.5,addJitter:!0},typicalGestures:["shake","vibrate","contract","flicker","retreat"],transitions:{duration:400,easing:"easeOut",priority:7},"3d":{rotation:{type:"unstable",speed:1.4,axes:[0,.3,0],shake:{amplitude:.015,frequency:3.5},musicSync:!1},glow:{color:"#8A2BE2",intensity:.9,pulse:{speed:2.5,range:[.6,1.2]}},scale:{base:1,breathe:{enabled:!0,depth:.06,rate:2.5}}},soulAnimation:{driftSpeed:1.8,shimmerSpeed:2.5,turbulence:.6}},{name:"surprise",emoji:"😲",description:"Sudden shock with explosive particles",visual:{glowColor:"#FFD700",particleRate:5,minParticles:0,maxParticles:15,particleBehavior:"burst",breathRate:.3,breathDepth:.18,coreJitter:!1,blinkRate:1.4,blinkSpeed:1.2,particleColors:[{color:"#FFD700",weight:25},{color:"#FFA500",weight:20},{color:"#FFFF00",weight:15},{color:"#FF6347",weight:15},{color:"#FFE4B5",weight:10},{color:"#FF4500",weight:10},{color:"#FFFACD",weight:5}]},modifiers:{speed:1.6,amplitude:1.5,intensity:1.4,smoothness:.7,regularity:.8,addPop:!0},typicalGestures:["expand","bounce","flash","pulse","pop"],transitions:{duration:200,easing:"easeOutBack",priority:6},"3d":{rotation:{type:"unstable",speed:1.6,axes:[0,.45,0],shake:{amplitude:.01,frequency:3},musicSync:!1},glow:{color:"#FFD700",intensity:1.8,pulse:{speed:.3,range:[1,2.2]}},scale:{base:1,breathe:{enabled:!0,depth:.18,rate:.3}}},soulAnimation:{driftSpeed:1.5,shimmerSpeed:2,turbulence:.5}},{name:"disgust",emoji:"🤢",description:"Revulsion with repelling particles",visual:{glowColor:"#9ACD32",particleRate:4,minParticles:5,maxParticles:12,particleBehavior:"repelling",breathRate:.7,breathDepth:.04,coreJitter:!1,blinkRate:.9,blinkSpeed:.9,particleColors:[{color:"#9ACD32",weight:25},{color:"#ADFF2F",weight:20},{color:"#7FFF00",weight:15},{color:"#BDB76B",weight:15},{color:"#6B8E23",weight:10},{color:"#CCFF00",weight:8},{color:"#556B2F",weight:7}]},modifiers:{speed:.9,amplitude:.7,intensity:.9,smoothness:.8,regularity:1,addRecoil:!0},typicalGestures:["contract","shake","recoil","wobble"],transitions:{duration:600,easing:"easeIn",priority:4},"3d":{rotation:{type:"gentle",speed:.9,axes:[0,.25,0],musicSync:!1},glow:{color:"#9ACD32",intensity:1,pulse:{speed:.7,range:[.7,1.2]}},scale:{base:1,breathe:{enabled:!0,depth:.04,rate:.7}}},soulAnimation:{driftSpeed:.4,shimmerSpeed:.6,turbulence:.35}},{name:"love",emoji:"💕",description:"Warm affection with orbiting particles",visual:{glowColor:"#FF1493",particleRate:6,minParticles:15,maxParticles:50,particleBehavior:"orbiting",breathRate:.75,breathDepth:.15,coreJitter:!1,blinkRate:1.2,blinkSpeed:1,particleColors:[{color:"#FF1493",weight:30},{color:"#FF69B4",weight:25},{color:"#FF007F",weight:15},{color:"#FFB6C1",weight:10},{color:"#FF45A0",weight:10},{color:"#E91E63",weight:5},{color:"#FFC0CB",weight:5}]},modifiers:{speed:.9,amplitude:1.1,intensity:1.2,smoothness:1.4,regularity:1.2,addWarmth:!0},typicalGestures:["pulse","sway","orbit","glow","breathe","float"],transitions:{duration:700,easing:"easeInOut",priority:5},"3d":{rotation:{type:"gentle",speed:.9,axes:[0,.28,0],musicSync:!0},glow:{color:"#FF1493",intensity:1.8,pulse:{speed:.75,range:[1.3,2]}},scale:{base:1,breathe:{enabled:!0,depth:.15,rate:.75}}},soulAnimation:{driftSpeed:.8,shimmerSpeed:1.2,turbulence:.2}},he,{name:"excited",emoji:"🤩",description:"High energy with rapid particles",visual:{glowColor:"#FF6B35",particleRate:8,minParticles:10,maxParticles:50,particleBehavior:"burst",breathRate:2,breathDepth:.14,coreJitter:!0,blinkRate:1.5,blinkSpeed:1.2,particleColors:[{color:"#FF6B35",weight:25},{color:"#FF1744",weight:20},{color:"#FFC107",weight:15},{color:"#FF9100",weight:15},{color:"#FFEB3B",weight:10},{color:"#FF5722",weight:10},{color:"#FFF59D",weight:5}]},modifiers:{speed:1.4,amplitude:1.3,intensity:1.3,smoothness:.8,regularity:.7,addVibration:!0},typicalGestures:["bounce","spin","vibrate","expand","shake","pulse"],transitions:{duration:300,easing:"easeOutElastic",priority:6},"3d":{rotation:{type:"unstable",speed:1.4,axes:[0,.4,0],shake:{amplitude:.01,frequency:4},musicSync:!1},glow:{color:"#FF6B35",intensity:1.5,pulse:{speed:2,range:[1,1.8]}},scale:{base:1,breathe:{enabled:!0,depth:.14,rate:2}}},soulAnimation:{driftSpeed:1.5,shimmerSpeed:2,turbulence:.5}},{name:"resting",emoji:"😴",description:"Deep relaxation with slow drift",visual:{glowColor:"#9370DB",particleRate:1,minParticles:3,maxParticles:5,particleBehavior:"resting",breathRate:.8,breathDepth:.12,coreJitter:!1,blinkRate:.4,blinkSpeed:.7,particleColors:[{color:"#9370DB",weight:30},{color:"#A591C4",weight:20},{color:"#B366FF",weight:20},{color:"#B8A1E6",weight:15},{color:"#674D9B",weight:15}]},modifiers:{speed:.5,amplitude:.4,intensity:.5,smoothness:1.4,regularity:.9,addWeight:!0},typicalGestures:["breathe","drift","sway","float"],transitions:{duration:1e3,easing:"easeInOut",priority:2},"3d":{rotation:{type:"gentle",speed:.5,axes:[0,.15,0],musicSync:!1},glow:{color:"#9370DB",intensity:.8,pulse:{speed:.8,range:[.6,1]}},scale:{base:1,breathe:{enabled:!0,depth:.12,rate:.8}}},soulAnimation:{driftSpeed:.15,shimmerSpeed:.1,turbulence:.05}},{name:"euphoria",emoji:"🌟",description:"Radiant hope and new beginnings",visual:{glowColor:"#FFB6C1",particleRate:6,minParticles:15,maxParticles:30,particleBehavior:"radiant",breathRate:1.3,breathDepth:.25,coreJitter:!1,blinkRate:1.4,blinkSpeed:1.1,particleColors:[{color:"#FFB6C1",weight:20},{color:"#FFD700",weight:18},{color:"#87CEEB",weight:15},{color:"#DDA0DD",weight:15},{color:"#98FB98",weight:12},{color:"#FFA07A",weight:10},{color:"#E6E6FA",weight:8},{color:"#FFFFFF",weight:2}]},modifiers:{speed:1.4,amplitude:1.5,intensity:1.6,smoothness:1.3,regularity:.8,addWarmth:!0,addLift:!0},typicalGestures:["expand","radiate","pulse","glow","float","bloom"],transitions:{duration:600,easing:"easeOutExpo",priority:8},"3d":{rotation:{type:"rhythmic",speed:1.4,axes:[0,.35,0],musicSync:!0},glow:{color:"#FFB6C1",intensity:1.2,pulse:{speed:1.3,range:[.9,1.5]}},scale:{base:1,breathe:{enabled:!0,depth:.25,rate:1.3}}},soulAnimation:{driftSpeed:1.8,shimmerSpeed:2.5,turbulence:.7}},{name:"focused",emoji:"🎯",description:"Intense concentration with directed flow",visual:{glowColor:"#00CED1",particleRate:4,minParticles:5,maxParticles:12,particleBehavior:"directed",breathRate:1.2,breathDepth:.08,coreJitter:!0,blinkRate:.7,blinkSpeed:1,particleColors:[{color:"#00CED1",weight:30},{color:"#4A9FA0",weight:20},{color:"#00FFFF",weight:20},{color:"#5FE5E7",weight:15},{color:"#006B6D",weight:15}],eyeOpenness:.7,microAdjustments:!0},modifiers:{speed:1,amplitude:.9,intensity:1.1,smoothness:1.1,regularity:1.2,addPrecision:!0},typicalGestures:["track","lock","scan","pulse","vibrate"],transitions:{duration:400,easing:"easeIn",priority:5},getCoreParams:e=>({scaleX:1.1,scaleY:.7,eyeOpenness:.7,eyeExpression:"focused",pupilOffset:{x:0,y:0},microAdjustments:!0}),"3d":{rotation:{type:"still",speed:.5,axes:[0,.1,0],musicSync:!1},glow:{color:"#00CED1",intensity:1.2,pulse:{speed:1.2,range:[1,1.3]}},scale:{base:1,breathe:{enabled:!0,depth:.08,rate:1.2}}},soulAnimation:{driftSpeed:.6,shimmerSpeed:.2,turbulence:.1}},{name:"glitch",emoji:"🌈",description:"Surprised sadness with rainbow colors and glitch wiggle",visual:{primaryColor:"#FF6B9D",glowColor:"#4169E1",glowIntensity:1.2,particleRate:5,minParticles:5,maxParticles:15,particleBehavior:"burst",particleSpeed:1,breathRate:.4,breathDepth:.15,coreJitter:!1,coreSize:1,eyeOpenness:.8,blinkRate:1.3,blinkSpeed:1.2,particleColors:[{color:"#FF0080",weight:18},{color:"#00FF80",weight:18},{color:"#8000FF",weight:18},{color:"#FF8000",weight:15},{color:"#0080FF",weight:15},{color:"#FFFF00",weight:10},{color:"#FF6B9D",weight:6}],particleGlitchWiggle:!0,glitchWiggleIntensity:.3,glitchWiggleFrequency:.1},modifiers:{speed:1.1,amplitude:1,intensity:1.1,smoothness:.8,regularity:.7,focus:.6},typicalGestures:["bounce","sway","pulse","drift","flash"],transitions:{duration:300,easing:"easeInOut",priority:5},"3d":{rotation:{type:"unstable",speed:1.1,axes:[0,.35,0],shake:{amplitude:.02,frequency:5},musicSync:!1},glow:{color:"#FF6B9D",intensity:1.2,pulse:{speed:.4,range:[.8,1.6]}},scale:{base:1,breathe:{enabled:!0,depth:.15,rate:.4}}}},ce].forEach(e=>{e&&e.name&&ue.set(e.name,e)});class ye{constructor(e,t={}){this.blinkConfig=e.blink||this.getDefaultBlinkConfig(),this.currentGeometryType=null,this.baseDuration=this.blinkConfig.duration||150,this.baseMinInterval=3e3,this.baseMaxInterval=7e3,this.emotionBlinkRate=1,this.emotionBlinkSpeed=1,this.isBlinking=!1,this.blinkTimer=0,this.nextBlinkTime=this.getRandomBlinkTime(),this.enabled=!0,this.blinkProgress=0}setEmotion(e){const t=me(e);this.emotionBlinkRate=t?.visual?.blinkRate||1,this.emotionBlinkSpeed=t?.visual?.blinkSpeed||1}setGeometry(e){this.blinkConfig=e.blink||this.getDefaultBlinkConfig(),this.baseDuration=this.blinkConfig.duration||150}update(e){if(!this.enabled)return this.getIdleState();if(this.isBlinking){this.blinkTimer+=e;const t=this.baseDuration/this.emotionBlinkSpeed;if(this.blinkTimer>=t)return this.completeBlink(),this.getIdleState();const i=this.blinkTimer/t;return this.blinkProgress=i,this.getBlinkState()}return Date.now()>=this.nextBlinkTime?(this.startBlink(),this.getBlinkState()):this.getIdleState()}startBlink(){this.enabled&&(this.isBlinking=!0,this.blinkTimer=0,this.blinkProgress=0)}completeBlink(){this.isBlinking=!1,this.blinkTimer=0,this.blinkProgress=0,this.nextBlinkTime=Date.now()+this.getRandomBlinkTime()}getRandomBlinkTime(){const e=this.baseMinInterval/this.emotionBlinkRate,t=this.baseMaxInterval/this.emotionBlinkRate;return e+Math.random()*(t-e)}getBlinkState(){const e=this.blinkConfig,t=Math.sin(this.blinkProgress*Math.PI);let i=1;if(e.playful)if(this.blinkProgress<.1){const t=this.blinkProgress/.1;i-=Math.sin(t*Math.PI)*e.playful.anticipation}else if(this.blinkProgress>.8){const t=(this.blinkProgress-.8)/.2;i+=Math.sin(t*Math.PI)*e.playful.overshoot}const n=t*i,a=[1-(1-e.scaleAxis[0])*n,1-(1-e.scaleAxis[1])*n,1-(1-e.scaleAxis[2])*n];let s=null;e.rotation&&(s=[e.rotation[0]*n,e.rotation[1]*n,e.rotation[2]*n]);let o=0;return e.glowBoost&&(o=e.glowBoost*n),{isBlinking:!0,progress:this.blinkProgress,scale:a,rotation:s,glowBoost:o}}getIdleState(){return{isBlinking:!1,progress:0,scale:[1,1,1],rotation:null,glowBoost:0}}getDefaultBlinkConfig(){return{type:"vertical-squish",duration:150,scaleAxis:[1,.3,1],curve:"sine"}}pause(){this.enabled=!1,this.isBlinking&&this.completeBlink()}resume(){this.enabled=!0,this.nextBlinkTime=Date.now()+this.getRandomBlinkTime()}getState(){return{isBlinking:this.isBlinking,enabled:this.enabled,blinkProgress:this.blinkProgress,emotionBlinkRate:this.emotionBlinkRate,emotionBlinkSpeed:this.emotionBlinkSpeed,nextBlinkTime:this.nextBlinkTime}}destroy(){this.blinkConfig=null,this.enabled=!1,this.isBlinking=!1}}let ve;"undefined"!=typeof window&&window.__emotiveRhythmEngine?ve=window.__emotiveRhythmEngine:(ve=new class{constructor(){this.bpm=120,this.timeSignature=[4,4],this.isPlaying=!1,this.startTime=0,this.currentBeat=0,this.currentBar=0,this.beatProgress=0,this.barProgress=0,this.beatDuration=6e4/this.bpm,this.barDuration=this.beatDuration*this.timeSignature[0],this.lastBeatTime=0,this.nextBeatTime=0,this.listeners=new Map,this.beatCallbacks=new Set,this.barCallbacks=new Set,this.subdivisions={sixteenth:0,eighth:0,triplet:0,swing:0},this.audioSync=null,this.syncOffset=0,this.autoSync=!1,this.intensity=1,this.groove=0,this.humanize=.05,this.patterns=new Map,this.currentPattern=null,this.initializePatterns()}initializePatterns(){this.patterns.set("4/4",{name:"4/4",description:"Common time - 4 beats per bar",timeSignature:[4,4],groove:0,accents:[1,.5,.7,.5]}),this.patterns.set("straight",{name:"straight",description:"Straight, even timing",groove:0,accents:[1,.5,.7,.5]}),this.patterns.set("swing",{name:"swing",description:"Swing/shuffle timing",groove:.67,accents:[1,.3,.8,.3]}),this.patterns.set("3/4",{name:"3/4",description:"Waltz time - 3 beats per bar",timeSignature:[3,4],accents:[1,.5,.5]}),this.patterns.set("waltz",{name:"waltz",description:"3/4 waltz timing",timeSignature:[3,4],accents:[1,.5,.5]}),this.patterns.set("6/8",{name:"6/8",description:"Compound duple time",timeSignature:[6,8],accents:[1,.3,.3,.7,.3,.3]}),this.patterns.set("5/4",{name:"5/4",description:"Complex meter - 5 beats per bar",timeSignature:[5,4],accents:[1,.5,.6,.5,.7]}),this.patterns.set("7/8",{name:"7/8",description:"Irregular meter",timeSignature:[7,8],accents:[1,.5,.5,.7,.5,.5,.6]}),this.patterns.set("dubstep",{name:"dubstep",description:"Dubstep half-time feel",accents:[.2,.2,1,.2],subdivisions:{wobble:!0}}),this.patterns.set("breakbeat",{name:"breakbeat",description:"Broken beat pattern",accents:[1,.2,.7,.9,.2,.8,.4,.2]})}start(){this.isPlaying||(this.isPlaying=!0,this.isRunning=!0,this.startTime=performance.now(),this.lastBeatTime=this.startTime,this.nextBeatTime=this.startTime+this.beatDuration,this.currentBeat=0,this.currentBar=0,this.emit("start",{bpm:this.bpm,timeSignature:this.timeSignature,pattern:this.currentPattern}),this.update())}stop(){this.isPlaying&&(this.isPlaying=!1,this.emit("stop",{totalBeats:this.currentBeat,totalBars:this.currentBar}))}update(){if(!this.isPlaying)return;const e=(performance.now()-this.startTime)/this.beatDuration,t=Math.floor(e);this.beatProgress=e%1,t>this.currentBeat&&this.onBeat(t);const i=Math.floor(t/this.timeSignature[0]);i>this.currentBar&&this.onBar(i),this.currentBeat=t,this.currentBar=i,this.barProgress=t%this.timeSignature[0]/this.timeSignature[0],this.updateSubdivisions(),this.emit("update",this.getTimeInfo()),this.isPlaying&&requestAnimationFrame(()=>this.update())}onBeat(e){const t=e%this.timeSignature[0],i=this.getAccent(t),n=this.humanize*(Math.random()-.5)*this.beatDuration,a={beat:e,beatInBar:t,bar:this.currentBar,accent:i,intensity:this.intensity*i,humanTiming:n,timestamp:performance.now()};this.emit("beat",a),this.beatCallbacks.forEach(e=>e(a)),this.lastBeatTime=performance.now(),this.nextBeatTime=this.lastBeatTime+this.beatDuration}onBar(e){const t={bar:e,timeSignature:this.timeSignature,pattern:this.currentPattern,timestamp:performance.now()};this.emit("bar",t),this.barCallbacks.forEach(e=>e(t))}updateSubdivisions(){if(this.subdivisions.sixteenth=4*this.beatProgress%1,this.subdivisions.eighth=2*this.beatProgress%1,this.subdivisions.triplet=3*this.beatProgress%1,this.groove>0){const e=.5+.17*this.groove;this.subdivisions.eighth<.5?this.subdivisions.swing=this.subdivisions.eighth/e:this.subdivisions.swing=.5+(this.subdivisions.eighth-.5)/(1-e)}else this.subdivisions.swing=this.subdivisions.eighth}getAccent(e){if(this.currentPattern&&this.patterns.has(this.currentPattern)){const t=this.patterns.get(this.currentPattern);if(t.accents&&void 0!==t.accents[e])return t.accents[e]}return 0===e?1:2===e&&4===this.timeSignature[0]?.7:.5}getTimeInfo(){return{elapsed:performance.now()-this.startTime,beat:this.currentBeat,bar:this.currentBar,beatInBar:this.currentBeat%this.timeSignature[0],beatProgress:this.beatProgress,barProgress:this.barProgress,subdivisions:{...this.subdivisions},bpm:this.bpm,beatDuration:this.beatDuration,timeSignature:[...this.timeSignature],intensity:this.intensity,groove:this.groove,pattern:this.currentPattern,nextBeatIn:this.nextBeatTime-performance.now(),accent:this.getAccent(this.currentBeat%this.timeSignature[0])}}setBPM(e){this.bpm=Math.max(20,Math.min(360,e)),this.beatDuration=6e4/this.bpm,this.barDuration=this.beatDuration*this.timeSignature[0],this.emit("tempoChange",{bpm:this.bpm})}setTimeSignature(e,t){this.timeSignature=[e,t],this.barDuration=this.beatDuration*e,this.emit("timeSignatureChange",{timeSignature:this.timeSignature})}setPattern(e){if(!this.patterns.has(e))return;const t=this.patterns.get(e);this.currentPattern=e,t.timeSignature&&this.setTimeSignature(...t.timeSignature),void 0!==t.groove&&(this.groove=t.groove),this.emit("patternChange",{pattern:e})}onBeatCallback(e){return this.beatCallbacks.add(e),()=>this.beatCallbacks.delete(e)}onBarCallback(e){return this.barCallbacks.add(e),()=>this.barCallbacks.delete(e)}emit(e,t){this.listeners.has(e)&&this.listeners.get(e).forEach(e=>e(t))}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.has(e)&&this.listeners.get(e).delete(t)}}syncToAudio(e,t){this.audioSync={context:e,source:t}}getAdapter(){return{getTimeInfo:()=>this.getTimeInfo(),isOnBeat:(e=.1)=>this.beatProgress<e||this.beatProgress>1-e,isOnSubdivision:(e,t=.1)=>{const i=this.subdivisions[e]||0;return i<t||i>1-t},getBeatSync:(e=0,t=1,i="linear")=>{let n=this.beatProgress;switch(i){case"ease":n=.5-Math.cos(n*Math.PI)/2;break;case"bounce":n=Math.abs(Math.sin(n*Math.PI));break;case"pulse":n=Math.pow(Math.sin(n*Math.PI),2)}return e+(t-e)*n},getAccentedValue:(e,t=2)=>e*(1+(this.getAccent(this.currentBeat%this.timeSignature[0])-.5)*t),onBeat:e=>this.onBeatCallback(e),onBar:e=>this.onBarCallback(e),beatsToMs:e=>e*this.beatDuration,msToBeats:e=>e/this.beatDuration,isPlaying:()=>this.isPlaying,getBPM:()=>this.bpm,getPattern:()=>this.currentPattern}}},"undefined"!=typeof window&&(window.__emotiveRhythmEngine=ve));class be{constructor(){this.enabled=!1,this.adapter=null,this.beatProgress=0,this.barProgress=0,this.accent=.5,this.intensity=1,this.bpm=120,this.isOnBeat=!1,this.pattern=null,this.grooveEnabled=!0,this.grooveTime=0,this._lastBeatProgress=0,this._staleFrameCount=0,this.modulation={scaleMultiplier:1,glowMultiplier:1,positionMultiplier:1,rotationMultiplier:1,accentBoost:0,grooveOffset:[0,0,0],grooveScale:1,grooveRotation:[0,0,0]},this._target={scaleMultiplier:1,glowMultiplier:1,positionMultiplier:1,rotationMultiplier:1,accentBoost:0,grooveOffset:[0,0,0],grooveScale:1,grooveRotation:[0,0,0]},this.config={beatSyncStrength:.3,accentMultiplier:1.5,grooveBounceAmount:.02,grooveSwayAmount:.015,groovePulseAmount:.03,grooveRotationAmount:.02,smoothingSpeed:8,grooveSmoothingSpeed:6}}_lerp(e,t,i,n){return e+(t-e)*(1-Math.exp(-i*n))}_lerpArray(e,t,i,n){const a=1-Math.exp(-i*n);return e.map((e,i)=>e+(t[i]-e)*a)}initialize(){this.adapter=ve.getAdapter(),this.enabled=!0,this.adapter.onBeat(e=>{this.accent=e.accent,this.isOnBeat=!0,setTimeout(()=>{this.isOnBeat=!1},100)})}start(e=120,t="straight"){this.enabled||this.initialize(),e&&ve.setBPM(e),t&&ve.setPattern(t),ve.start()}stop(){ve.stop()}setBPM(e){ve.setBPM(e),this.bpm=e}setPattern(e){ve.setPattern(e),this.pattern=e}update(e){const t=e/1e3;if(this.adapter||(this.adapter=ve.getAdapter()),!this.adapter)return void this.resetModulation(t);if(!this.adapter.isPlaying())return void this.resetModulation(t);this.enabled=!0;const i=this.adapter.getTimeInfo();if(Math.abs(i.beatProgress-this._lastBeatProgress)<.001?this._staleFrameCount++:(this._staleFrameCount=0,this._lastBeatProgress=i.beatProgress),this._staleFrameCount>10){const e=(i.bpm||this.bpm||120)/60;this.grooveTime+=t,this.beatProgress=this.grooveTime*e%1,this.barProgress=this.grooveTime*e/4%1}else this.beatProgress=i.beatProgress,this.barProgress=i.barProgress,this.grooveTime+=t;this.intensity=i.intensity,this.bpm=i.bpm||this.bpm,this.pattern=i.pattern,this.computeModulation(),this.applySmoothing(t)}computeModulation(){const{beatSyncStrength:e,accentMultiplier:t}=this.config,i=this.beatProgress*Math.PI*2,n=.5*(Math.cos(i)+1);this._target.scaleMultiplier=1+n*e*.4,this._target.glowMultiplier=1+n*e*.8,this._target.positionMultiplier=1+n*e*.2,this._target.rotationMultiplier=1+n*e*.15,this._target.accentBoost=this.isOnBeat?(this.accent-.5)*t:0,this.grooveEnabled?this.computeGroove():(this._target.grooveOffset=[0,0,0],this._target.grooveScale=1,this._target.grooveRotation=[0,0,0])}computeGroove(){const{grooveBounceAmount:e,grooveSwayAmount:t,groovePulseAmount:i,grooveRotationAmount:n}=this.config,a=this.beatProgress*Math.PI*2,s=Math.sin(a)*e,o=this.barProgress*Math.PI*2,r=Math.sin(o)*t,l=1+Math.sin(a)*i,h=Math.sin(o)*n;this._target.grooveOffset=[r,s,0],this._target.grooveScale=l,this._target.grooveRotation=[0,0,h]}applySmoothing(e){const{smoothingSpeed:t,grooveSmoothingSpeed:i}=this.config;this.modulation.scaleMultiplier=this._lerp(this.modulation.scaleMultiplier,this._target.scaleMultiplier,t,e),this.modulation.glowMultiplier=this._lerp(this.modulation.glowMultiplier,this._target.glowMultiplier,t,e),this.modulation.positionMultiplier=this._lerp(this.modulation.positionMultiplier,this._target.positionMultiplier,t,e),this.modulation.rotationMultiplier=this._lerp(this.modulation.rotationMultiplier,this._target.rotationMultiplier,t,e),this.modulation.accentBoost=this._lerp(this.modulation.accentBoost,this._target.accentBoost,.5*t,e),this.modulation.grooveOffset=this._lerpArray(this.modulation.grooveOffset,this._target.grooveOffset,i,e),this.modulation.grooveScale=this._lerp(this.modulation.grooveScale,this._target.grooveScale,i,e),this.modulation.grooveRotation=this._lerpArray(this.modulation.grooveRotation,this._target.grooveRotation,i,e)}resetModulation(e=.016){this._target.scaleMultiplier=1,this._target.glowMultiplier=1,this._target.positionMultiplier=1,this._target.rotationMultiplier=1,this._target.accentBoost=0,this._target.grooveOffset=[0,0,0],this._target.grooveScale=1,this._target.grooveRotation=[0,0,0],this.modulation.scaleMultiplier=this._lerp(this.modulation.scaleMultiplier,1,4,e),this.modulation.glowMultiplier=this._lerp(this.modulation.glowMultiplier,1,4,e),this.modulation.positionMultiplier=this._lerp(this.modulation.positionMultiplier,1,4,e),this.modulation.rotationMultiplier=this._lerp(this.modulation.rotationMultiplier,1,4,e),this.modulation.accentBoost=this._lerp(this.modulation.accentBoost,0,4,e),this.modulation.grooveOffset=this._lerpArray(this.modulation.grooveOffset,[0,0,0],4,e),this.modulation.grooveScale=this._lerp(this.modulation.grooveScale,1,4,e),this.modulation.grooveRotation=this._lerpArray(this.modulation.grooveRotation,[0,0,0],4,e)}getModulation(){return this.modulation}getMusicalDuration(e,t=null){if(!this.enabled||!this.adapter||!this.adapter.isPlaying())return e;if(t?.durationSync){const e=t.durationSync;if("beats"===e.mode&&e.beats)return this.adapter.beatsToMs(e.beats);if("bars"===e.mode&&e.bars)return this.adapter.beatsToMs(4*e.bars)}return e}isOnBeatNow(e=.1){return!(!this.enabled||!this.adapter)&&this.adapter.isOnBeat(e)}isOnAccent(e=.7){return this.isOnBeat&&this.accent>=e}getBeatSync(e,t,i="pulse"){return this.enabled&&this.adapter?this.adapter.getBeatSync(e,t,i):e}getAccentedValue(e,t=2){return this.enabled&&this.adapter?this.adapter.getAccentedValue(e,t):e}setGrooveEnabled(e){this.grooveEnabled=e,e||(this._target.grooveOffset=[0,0,0],this._target.grooveScale=1,this._target.grooveRotation=[0,0,0])}setGrooveConfig(e){Object.assign(this.config,e)}setBeatSyncStrength(e){this.config.beatSyncStrength=Math.max(0,Math.min(1,e))}isPlaying(){return this.enabled&&this.adapter&&this.adapter.isPlaying()}getBPM(){return this.bpm}getPattern(){return this.pattern}destroy(){this.enabled=!1,this.adapter=null,this.resetModulation()}}const we=new be;class Me{constructor(){this.isTransitioning=!1,this.currentGeometryType=null,this.targetGeometryType=null,this.morphStartTime=0,this.morphDuration=1e3,this.morphProgress=0,this.visualProgress=0,this.hasSwappedGeometry=!1,this.isPausedAtSwap=!1,this.pausedAtTime=0,this.easing="easeInOutCubic"}startMorph(e,t,i=1e3){if(e===t&&!this.isTransitioning)return!1;if(this.isTransitioning&&this.targetGeometryType===t)return!1;if(this.isTransitioning){const e=this.calculateScaleMultiplier(this.visualProgress);if(this.hasSwappedGeometry){this.morphStartTime=Date.now(),this.morphDuration=i;const n=e>0?Math.sqrt(1-Math.min(e,1))/2:.5;this.morphProgress=n,this.visualProgress=n,this.hasSwappedGeometry=!1,this.targetGeometryType=t,this._interruptedTarget=t,this.isPausedAtSwap=!1,this.isGrowIn=!1;const a=n*i;return this.morphStartTime=Date.now()-a,!0}return this.targetGeometryType=t,this._interruptedTarget=t,!0}return this.currentGeometryType=e,this.targetGeometryType=t,this.morphStartTime=Date.now(),this.morphDuration=i,this.morphProgress=0,this.visualProgress=0,this.isTransitioning=!0,this.hasSwappedGeometry=!1,this.isPausedAtSwap=!1,this.pausedAtTime=0,this.isGrowIn=!1,this._interruptedTarget=null,!0}getInterruptedTarget(){const e=this._interruptedTarget;return this._interruptedTarget=null,e}growIn(e,t=500){return!this.isTransitioning&&(this.currentGeometryType=e,this.targetGeometryType=e,this.morphStartTime=Date.now(),this.morphDuration=t,this.morphProgress=0,this.visualProgress=0,this.isTransitioning=!0,this.hasSwappedGeometry=!0,this.isPausedAtSwap=!1,this.pausedAtTime=0,this.isGrowIn=!0,!0)}pauseAtSwap(){this.isTransitioning&&!this.isPausedAtSwap&&(this.isPausedAtSwap=!0,this.pausedAtTime=Date.now())}resumeFromSwap(){if(this.isPausedAtSwap){const e=Date.now()-this.pausedAtTime;this.morphStartTime+=e,this.isPausedAtSwap=!1,this.pausedAtTime=0}}update(e){if(!this.isTransitioning)return{isTransitioning:!1,progress:0,visualProgress:0,scaleMultiplier:1};if(this.isPausedAtSwap)return{isTransitioning:!0,progress:.5,visualProgress:.5,scaleMultiplier:0,waitingForGeometry:!0};const t=Date.now()-this.morphStartTime,i=Math.min(t/this.morphDuration,1);this.morphProgress=this.applyEasing(i),this.visualProgress=.6*this.visualProgress+.4*this.morphProgress,Math.abs(this.visualProgress-this.morphProgress)<.01&&(this.visualProgress=this.morphProgress);const n=this.calculateScaleMultiplier(this.visualProgress);let a=!1;return!this.hasSwappedGeometry&&this.morphProgress>=.5&&(this.hasSwappedGeometry=!0,a=!0),this.morphProgress>=1?(this.completeMorph(),{isTransitioning:!1,progress:1,visualProgress:1,scaleMultiplier:1,completed:!0}):{isTransitioning:!0,progress:this.morphProgress,visualProgress:this.visualProgress,scaleMultiplier:n,shouldSwapGeometry:a}}calculateScaleMultiplier(e){if(this.isGrowIn){const t=1.70158,i=1+(t+1)*Math.pow(e-1,3)+t*Math.pow(e-1,2);return Math.max(0,i)}if(e<=.5){const t=2*e;return 1-t*t}{const t=2*(e-.5);return t*(2-t)}}completeMorph(){this.currentGeometryType=this.targetGeometryType,this.targetGeometryType=null,this.isTransitioning=!1,this.morphProgress=0,this.visualProgress=0}applyEasing(e){switch(this.easing){case"linear":return e;case"easeInQuad":return e*e;case"easeOutQuad":return e*(2-e);case"easeInOutQuad":return e<.5?2*e*e:(4-2*e)*e-1;case"easeInOutSine":return-(Math.cos(Math.PI*e)-1)/2;default:return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}}getState(){return{isTransitioning:this.isTransitioning,currentGeometryType:this.currentGeometryType,targetGeometryType:this.targetGeometryType,progress:this.morphProgress,visualProgress:this.visualProgress}}cancel(){this.isTransitioning=!1,this.targetGeometryType=null,this.morphProgress=0,this.visualProgress=0}}class Se{constructor(e={},t=null,i=null){if(this.config=e,this.rhythmEngine=t,this.geometryRotation=i,this.type=e.type||"gentle",this.speed=e.speed||1,i&&void 0!==i.baseSpeed){const e=i.baseSpeed,t=i.axes||[0,1,0];this.axes=[t[0]*e*this.speed,t[1]*e*this.speed,t[2]*e*this.speed]}else this.axes=e.axes||[0,.01,0];this.shake=e.shake||{amplitude:0,frequency:0},this.wobbleEnabled=!0,this.eruption=e.eruption||{enabled:!1},this.eruption.enabled&&(this.eruption.interval=this.eruption.interval||3e3,this.eruption.speedMultiplier=this.eruption.speedMultiplier||3,this.eruption.duration=this.eruption.duration||400,this.eruption.nextEruptionTime=this.eruption.interval,this.eruption.eruptionStartTime=-1),this.musicSync=void 0!==e.musicSync&&e.musicSync,this.time=0,this.episodicWobble={enabled:!1,minInterval:2e3,maxInterval:5e3,amplitude:.05,duration:200,nextWobbleTime:0,wobbleStartTime:-1,wobbleTarget:[0,0,0]}}update(e,t){switch(this.time+=e,this.episodicWobble.enabled&&this.wobbleEnabled&&this._applyEpisodicWobble(e,t),this.type){case"gentle":default:return this._evaluateGentle(e,t);case"unstable":return this._evaluateUnstable(e,t);case"rhythmic":return this._evaluateRhythmic(e,t);case"orbital":return this._evaluateOrbital(e,t);case"still":return this._evaluateStill(e,t);case"suspicious":return this._evaluateSuspicious(e,t)}}_evaluateGentle(e,t){const i=.001*e;return t[0]+=this.axes[0]*this.speed*i,t[1]+=this.axes[1]*this.speed*i,t[2]+=this.axes[2]*this.speed*i,t}_evaluateUnstable(e,t){const i=.001*e;let n=1;if(this.eruption.enabled&&(this.eruption.eruptionStartTime<0&&this.time>=this.eruption.nextEruptionTime&&(this.eruption.eruptionStartTime=this.time),this.eruption.eruptionStartTime>=0)){const e=this.time-this.eruption.eruptionStartTime;if(e<this.eruption.duration){const t=e/this.eruption.duration,i=Math.sin(t*Math.PI);n=1+(this.eruption.speedMultiplier-1)*i}else this.eruption.eruptionStartTime=-1,this.eruption.nextEruptionTime=this.time+this.eruption.interval}const a=this.speed*n;if(t[0]+=this.axes[0]*a*i,t[1]+=this.axes[1]*a*i,t[2]+=this.axes[2]*a*i,this.wobbleEnabled){const e=.001*this.time,i=this.shake.frequency||8,n=this.shake.amplitude||.02,a=.02,s=Math.min(n,a),o=Math.sin(e*i*Math.PI*2)*s*.7,r=Math.sin(e*i*Math.PI*2*1.3)*s*.5,l=Math.sin(e*i*Math.PI*2*.9)*s*.8;t[0]+=o,t[1]+=r,t[2]+=l}return t}_evaluateRhythmic(e,t){const i=.001*e;if(!this.musicSync||!this.rhythmEngine)return this._evaluateGentle(e,t);{const e=60/(this.rhythmEngine.bpm||120),n=.001*this.time%e,a=1+.3*Math.sin(n/e*Math.PI*2);t[0]+=this.axes[0]*this.speed*a*i,t[1]+=this.axes[1]*this.speed*a*i,t[2]+=this.axes[2]*this.speed*a*i}return t}_evaluateOrbital(e,t){const i=.001*e,n=.001*this.time,a=.5*this.speed,s=.1*Math.sin(n*a*Math.PI*2),o=.05*Math.sin(n*a*Math.PI*2*.5);return t[0]+=s*i,t[1]+=this.axes[1]*this.speed*i,t[2]+=o*i,t}_evaluateStill(e,t){const i=.001*e;return t[0]+=.1*this.axes[0]*i,t[1]+=.1*this.axes[1]*i,t[2]+=.1*this.axes[2]*i,t}_evaluateSuspicious(e,t){const i=.001*e,n=.001*this.time,a=4/this.speed,s=n%a/a;let o;if(s<.85)o=s/.85*Math.PI;else{const e=(s-.85)/.15;o=Math.PI*(1-e)}const r=o-t[1];return t[1]+=3*r*i,t}reset(){this.time=0}_applyEpisodicWobble(e,t){const i=this.episodicWobble;if(-1===i.wobbleStartTime&&this.time>=i.nextWobbleTime){i.wobbleStartTime=this.time,i.wobbleTarget=[(Math.random()-.5)*i.amplitude,(Math.random()-.5)*i.amplitude,(Math.random()-.5)*i.amplitude];const e=i.minInterval+Math.random()*(i.maxInterval-i.minInterval);i.nextWobbleTime=this.time+e}if(-1!==i.wobbleStartTime){const e=this.time-i.wobbleStartTime,n=Math.min(e/i.duration,1);if(n<1){const e=Math.sin(n*Math.PI);t[0]+=i.wobbleTarget[0]*e,t[1]+=i.wobbleTarget[1]*e,t[2]+=i.wobbleTarget[2]*e}else i.wobbleStartTime=-1}}updateConfig(e){if(this.config=e,this.type=e.type||"gentle",this.speed=e.speed||1,this.geometryRotation&&void 0!==this.geometryRotation.baseSpeed){const e=this.geometryRotation.baseSpeed,t=this.geometryRotation.axes||[0,1,0];this.axes=[t[0]*e*this.speed,t[1]*e*this.speed,t[2]*e*this.speed]}else this.axes=e.axes||[0,.01,0];this.shake=e.shake||{amplitude:0,frequency:0},this.musicSync=void 0!==e.musicSync&&e.musicSync}applyUndertoneMultipliers(e){if(void 0!==e.speedMultiplier&&(this.speed*=e.speedMultiplier),void 0!==e.shakeMultiplier&&this.shake.amplitude&&(this.shake.amplitude*=e.shakeMultiplier),void 0!==e.enableEpisodicWobble&&(this.episodicWobble.enabled=e.enableEpisodicWobble,this.episodicWobble.enabled&&0===this.episodicWobble.nextWobbleTime)){const e=this.episodicWobble.minInterval+Math.random()*(this.episodicWobble.maxInterval-this.episodicWobble.minInterval);this.episodicWobble.nextWobbleTime=this.time+e}}setWobbleEnabled(e){this.wobbleEnabled=e}}class xe{constructor(e={}){this.config=e,this.strength=void 0!==e.strength?e.strength:.5,this.damping=void 0!==e.damping?e.damping:.8,this.centerOfMass=e.centerOfMass||[0,-.3,0],this.axes=e.axes||{pitch:!0,roll:!0,yaw:!1},this.angularVelocity={x:0,y:0,z:0}}update(e,t){if(0===this.strength)return t;const i=.001*e,n=t[0],a=t[1],s=t[2];if(this.axes.pitch){const e=-n*this.strength;this.angularVelocity.x+=e*i,this.angularVelocity.x*=1-this.damping,t[0]+=this.angularVelocity.x*i}if(this.axes.roll){const e=-s*this.strength;this.angularVelocity.z+=e*i,this.angularVelocity.z*=1-this.damping,t[2]+=this.angularVelocity.z*i}if(this.axes.yaw){const e=-a*this.strength;this.angularVelocity.y+=e*i,this.angularVelocity.y*=1-this.damping,t[1]+=this.angularVelocity.y*i}return t}reset(){this.angularVelocity={x:0,y:0,z:0}}updateConfig(e){this.config=e,this.strength=void 0!==e.strength?e.strength:this.strength,this.damping=void 0!==e.damping?e.damping:this.damping,this.centerOfMass=e.centerOfMass||this.centerOfMass,this.axes=e.axes||this.axes}applyUndertoneMultipliers(e){void 0!==e.strengthMultiplier&&(this.strength*=e.strengthMultiplier)}}class Ce{constructor(t={},i=null){this.config=t,this.camera=i,this.strength=void 0!==t.strength?t.strength:1,this.lockedFace=t.lockedFace||[0,0,1],this.calibrationRotation=t.calibrationRotation||[0,0,0],this.lerpSpeed=void 0!==t.lerpSpeed?t.lerpSpeed:1,this.tempVector=new e.Vector3,this.tempQuaternion=new e.Quaternion,this.targetQuaternion=new e.Quaternion,this.calibrationQuaternion=new e.Quaternion,this.currentQuaternion=new e.Quaternion,this._lockedFaceVec=new e.Vector3,this._targetMatrix=new e.Matrix4,this._lookAtOrigin=new e.Vector3(0,0,0),this._upVector=new e.Vector3(0,1,0),this._tempEuler=new e.Euler(0,0,0,"XYZ"),this._defaultPosition=new e.Vector3(0,0,0)}update(e,t,i){if(0===this.strength||!this.camera)return t;const n=i||this._defaultPosition,a=.001*e;this.tempVector.copy(this.camera.position).sub(n),this.tempVector.lengthSq()<1e-4&&this.tempVector.set(0,0,1),this.tempVector.normalize(),this._lockedFaceVec.set(this.lockedFace[0],this.lockedFace[1],this.lockedFace[2]).normalize(),this._targetMatrix.lookAt(this.tempVector,this._lookAtOrigin,this._upVector),this.targetQuaternion.setFromRotationMatrix(this._targetMatrix),0===this.calibrationRotation[0]&&0===this.calibrationRotation[1]&&0===this.calibrationRotation[2]||(this._tempEuler.set(this.calibrationRotation[0],this.calibrationRotation[1],this.calibrationRotation[2],"XYZ"),this.calibrationQuaternion.setFromEuler(this._tempEuler),this.targetQuaternion.multiply(this.calibrationQuaternion)),this._tempEuler.set(t[0],t[1],t[2],"XYZ"),this.currentQuaternion.setFromEuler(this._tempEuler);const s=Math.min(1,this.strength*this.lerpSpeed*a*60);return this.currentQuaternion.slerp(this.targetQuaternion,s),this._tempEuler.setFromQuaternion(this.currentQuaternion,"XYZ"),t[0]=this._tempEuler.x,t[1]=this._tempEuler.y,t[2]=this._tempEuler.z,t}setCamera(e){this.camera=e}setCalibrationRotation(e){this.calibrationRotation=e}updateConfig(e){this.config=e,this.strength=void 0!==e.strength?e.strength:this.strength,this.lockedFace=e.lockedFace||this.lockedFace,this.calibrationRotation=e.calibrationRotation||this.calibrationRotation,this.lerpSpeed=void 0!==e.lerpSpeed?e.lerpSpeed:this.lerpSpeed}dispose(){this.camera=null,this.tempVector=null,this.tempQuaternion=null,this.targetQuaternion=null,this.calibrationQuaternion=null,this.currentQuaternion=null}}const De=new Map;var Pe=function(e){return De.get(e)||null},Be={name:"bounce",emoji:"⬆️",type:"blending",description:"Vertical oscillation with smooth easing",config:{duration:800,musicalDuration:{musical:!0,beats:2},amplitude:30,frequency:2,axis:"vertical",damping:!0,easing:"sine",strength:.6,particleMotion:{type:"bounce",axis:"vertical",strength:.6,frequency:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:3,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.8,offBeat:.6,curve:"bounce"},frequencySync:{mode:"tempo",multiplier:1},durationSync:{mode:"beats",beats:4},accentResponse:{enabled:!0,multiplier:1.5},patternOverrides:{waltz:{frequencySync:{multiplier:.75},durationSync:{beats:3}},swing:{amplitudeSync:{onBeat:2,offBeat:.4,curve:"ease"}},dubstep:{amplitudeSync:{onBeat:1.5,dropBeat:3,curve:"pulse"}},breakbeat:{frequencySync:{multiplier:1.5},amplitudeSync:{onBeat:2.2,offBeat:.3}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.bounce={startY:e.y,startX:e.x,startVx:e.vx,startVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.bounce?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=this.easeInOutCubic(t);let{frequency:h}=o;const c=i.phase||0;let u=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(u*=i.rhythmModulation.amplitudeMultiplier||1,u*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(h*=i.rhythmModulation.frequencyMultiplier));const d=Math.sin((l+c)*Math.PI*2*h);if(o.damping&&t>.7&&(u*=1-(t-.7)/.3*.8),"vertical"===o.axis?(e.vy+=d*u*.01*n,t>.9&&(e.vx*=.98)):"horizontal"===o.axis&&(e.vx+=d*u*.01*n,t>.9&&(e.vy*=.98)),t>.9){const i=1-10*(t-.9);e.vx=e.vx*(.95+.05*i),e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.bounce&&delete e.gestureData.bounce},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||30,a=i.frequency||2,s=.003*n*(i.strength||.6),o=(e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2)*Math.PI*a,r=Math.abs(Math.sin(o));let l=s;return e>.7&&(l*=1-(e-.7)/.3*.8),{position:[0,r*l,0],rotation:[0,0,0],scale:1+.08*r}}}},ke={name:"pulse",emoji:"💗",type:"blending",description:"Radial expansion and contraction from center",config:{duration:600,amplitude:30,frequency:1,holdPeak:.1,easing:"sine",scaleAmount:.2,glowAmount:.3,strength:.15,direction:"outward",particleMotion:{type:"pulse",strength:.15,direction:"outward",frequency:1}},rhythm:{enabled:!0,syncMode:"beat",amplitudeSync:{onBeat:1.6,offBeat:.8,curve:"pulse"},frequencySync:{mode:"locked",subdivision:"quarter"},durationSync:{mode:"beats",beats:1},accentResponse:{enabled:!0,multiplier:2},patternOverrides:{waltz:{amplitudeSync:{onBeat:2,offBeat:.5},durationSync:{beats:3}},swing:{amplitudeSync:{onBeat:1.8,offBeat:.6,curve:"ease"},frequencySync:{subdivision:"swing"}},dubstep:{amplitudeSync:{onBeat:1.2,dropBeat:4,curve:"pulse"}},breakbeat:{frequencySync:{mode:"random",range:[.5,2]},amplitudeSync:{onBeat:2.5,offBeat:.3}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.sqrt(a*a+s*s),r=Math.atan2(s,a);e.gestureData.pulse={baseDistance:o,angle:r,startX:e.x,startY:e.y,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.pulse?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.pulse,r={...this.config,...i},l=i.strength||1,h=this.easeInOutSine(t);let c,{frequency:u}=r,{amplitude:d}=r;i.rhythmModulation&&(d*=i.rhythmModulation.amplitudeMultiplier||1,d*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(u*=i.rhythmModulation.frequencyMultiplier));const m=h*u*2%2;c=r.holdPeak>0&&m>1-r.holdPeak&&m<1+r.holdPeak?1:Math.sin(h*Math.PI*2*u);const p=c*d*l*e.scaleFactor,g=o.baseDistance+p,f=a+Math.cos(o.angle)*g,y=s+Math.sin(o.angle)*g,v=.15*n;if(e.vx+=(f-e.x)*v*.1,e.vy+=(y-e.y)*v*.1,t>.9){const i=1-10*(t-.9);e.vx*=.9+.1*i,e.vy*=.9+.1*i}},cleanup(e){e.gestureData?.pulse&&delete e.gestureData.pulse},easeInOutSine:e=>-(Math.cos(Math.PI*e)-1)/2,"3d":{evaluate(e,t){const i=t||{},n=i.frequency||1,a=i.strength||.15,s=i.scaleAmount||.2,o=i.glowAmount||.3,r=-(Math.cos(Math.PI*e)-1)/2,l=Math.sin(r*Math.PI*2*n);return{position:[0,0,0],rotation:[0,0,0],scale:1+l*s*a,glowIntensity:1+Math.max(-.3,Math.min(.3,l*o*a*2)),glowBoost:Math.max(0,.8*l)}}}},Te={name:"shake",emoji:"🫨",type:"blending",description:"Random jitter movement for vibration effects",config:{duration:400,amplitude:15,frequency:15,decay:.9,smoothing:.1,axes:"both",easing:"linear",strength:3,particleMotion:{type:"shake",strength:3,frequency:15,decay:!1}},rhythm:{enabled:!0,syncMode:"subdivision",amplitudeSync:{subdivision:"sixteenth",onBeat:2.5,offBeat:.7,curve:"pulse"},frequencySync:{mode:"tempo",baseFrequency:15,scaling:"linear"},durationSync:{mode:"beats",beats:2},patternOverrides:{breakbeat:{amplitudeSync:{onBeat:3,offBeat:.2},frequencySync:{mode:"random",range:[8,20]}},dubstep:{amplitudeSync:{subdivision:"eighth",onBeat:4,dropBeat:6,curve:"pulse"}},swing:{amplitudeSync:{onBeat:1.8,offBeat:1,curve:"ease"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.shake={originalX:e.x,originalY:e.y,randomAngle:Math.random()*Math.PI*2,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.shake?.initialized||this.initialize(e,i);const o=e.gestureData.shake,r={...this.config,...i},l=r.strength||this.config.strength||1;let{amplitude:h}=r,{frequency:c}=r;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(c*=i.rhythmModulation.frequencyMultiplier));const u=r.decay?1-t:1,d=Math.sin(t*Math.PI*c)*h*u*l*e.scaleFactor,m=d*Math.cos(o.randomAngle),p=d*Math.sin(o.randomAngle);e.x=o.originalX+m,e.y=o.originalY+p},pseudoRandom(e){const t=1e4*Math.sin(e);return t-Math.floor(t)},cleanup(e){e.gestureData?.shake&&(e.x=e.gestureData.shake.originalX,e.y=e.gestureData.shake.originalY,delete e.gestureData.shake)},"3d":{evaluate(e,t){const i=t||{},n=.015*(i.amplitude||15),a=i.frequency||15,s=i.strength||1,o=i.decay?1-e:1,r=Math.sin(e*Math.PI*a)*n*o*s,l=Math.floor(e*a);return{position:[r*(1e4*Math.sin(l)%1-.5)*2,0,r*(1e4*Math.sin(1.3*l)%1-.5)*2],rotation:[0,0,r*(1e4*Math.sin(1.7*l)%1-.5)*.5],scale:1}}}},Ee={name:"nod",emoji:"🙂",type:"blending",description:"Vertical nodding motion",config:{duration:500,amplitude:15,frequency:2,easing:"sine",strength:.4,particleMotion:{type:"bounce",axis:"vertical",strength:.4,frequency:2,phase:0}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!1,priority:5,blendable:!1,minDuration:"halfBar",frequencySync:{mode:"subdivision",subdivision:"half",multiplier:1},amplitudeSync:{onBeat:1.4,offBeat:.8,curve:"ease"},durationSync:{mode:"beats",beats:2},patternOverrides:{waltz:{frequencySync:{subdivision:"quarter"},amplitudeSync:{onBeat:1.6,curve:"ease"}},swing:{amplitudeSync:{onBeat:1.5,offBeat:.9}},dubstep:{amplitudeSync:{onBeat:1.2,dropBeat:3,curve:"pulse"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.nod={startY:e.y,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.nod?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1;let{frequency:l}=o,{amplitude:h}=o;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(l*=i.rhythmModulation.frequencyMultiplier));const c=Math.sin(t*Math.PI*2*l);h=h*r*e.scaleFactor,e.vy+=c*h*.01*n,t>.9&&(e.vy*=.95)},cleanup(e){e.gestureData?.nod&&delete e.gestureData.nod},"3d":{evaluate(e,t){const i={...this.config,...t};let{frequency:n}=i,{amplitude:a}=i;t.rhythmModulation&&(a*=t.rhythmModulation.amplitudeMultiplier||1,a*=t.rhythmModulation.accentMultiplier||1,t.rhythmModulation.frequencyMultiplier&&(n*=t.rhythmModulation.frequencyMultiplier));const s=Math.sin(e*Math.PI),o=e>.9?.95:1;return{position:[0,0,s*(.1*a)*.015*o],rotation:[s*(.08*a)*o,0,0],scale:1}}}},Ie={name:"vibrate",emoji:"📳",type:"blending",description:"High frequency vibration",config:{duration:500,frequency:20,amplitude:8,easing:"linear",strength:2,particleMotion:{type:"shake",strength:2,frequency:20,amplitude:8}},rhythm:{enabled:!0,syncMode:"subdivision",frequencySync:{subdivision:"thirty-second",baseFrequency:20,tempoScaling:!0},amplitudeSync:{onBeat:1.5,offBeat:.8,curve:"pulse"},durationSync:{mode:"beats",beats:1},patternOverrides:{dubstep:{frequencySync:{subdivision:"sixteenth"},amplitudeSync:{onBeat:2,dropBeat:3}},breakbeat:{frequencySync:{mode:"random",range:[15,30]}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.vibrate={timer:0,seed:1e3*Math.random(),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.vibrate?.initialized||this.initialize(e,i);const o=e.gestureData.vibrate,r={...this.config,...i},l=r.strength||this.config.strength||1;let{amplitude:h}=r,{frequency:c}=r;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(c*=i.rhythmModulation.frequencyMultiplier)),o.timer+=n*c;const u=(Math.random()-.5)*h*l,d=(Math.random()-.5)*h*l;if(e.vx+=.5*u*n,e.vy+=.5*d*n,e.vx*=.9,e.vy*=.9,t>.8){const i=1-5*(t-.8);e.vx*=i,e.vy*=i}},cleanup(e){e.gestureData?.vibrate&&delete e.gestureData.vibrate},"3d":{evaluate(e,t){const i={...this.config,...t};let{amplitude:n}=i;const a=i.strength||this.config.strength||1;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const s=Math.sin(e*Math.PI),o=n*a*.003*s;return{position:[(Math.random()-.5)*o,(Math.random()-.5)*o,(Math.random()-.5)*o],rotation:[.01*(Math.random()-.5)*s,.01*(Math.random()-.5)*s,.01*(Math.random()-.5)*s],scale:1+.01*(Math.random()-.5)*s}}}},Ae={name:"orbit",emoji:"🪐",description:"3D orbital motion around center",type:"override",config:{speed:1,rotations:1,zRotations:1,smoothness:.15,verticalOscillation:0,centripetal:!1},rhythm:{enabled:!0,syncMode:"bar",speedSync:{mode:"tempo",baseSpeed:1,scaling:"linear"},rotationSync:{mode:"bars",rotationsPerBar:1,zSync:!0},radiusSync:{subdivision:"quarter",pulsAmount:.1,curve:"ease"},patternOverrides:{waltz:{rotationSync:{rotationsPerBar:.75},radiusSync:{pulsAmount:.15}},swing:{speedSync:{mode:"swing",ratio:.67},verticalOscillation:.2},dubstep:{radiusSync:{subdivision:"eighth",pulsAmount:.3,dropMultiplier:2}},breakbeat:{speedSync:{mode:"random",range:[.5,2]},centripetal:!0}}},apply:function(e,t,i,n,a,s){e.gestureData||(e.gestureData={});const o=e.gestureData,r=i,l=i.amplitude||1;if(!o.initialized){o.originalX=e.x,o.originalY=e.y,o.originalZ=e.z||0,o.originalVx=e.vx||0,o.originalVy=e.vy||0;const t=e.x-a,i=e.y-s;o.radius=Math.sqrt(t*t+i*i),o.radius<50&&(o.radius=50+100*Math.random()),o.initialAngle=Math.atan2(i,t),o.orbitSpeed=r.speed*(.8+.4*Math.random()),o.orbitTilt=.3*Math.random(),o.initialized=!0}let{rotations:h}=r,c=.05;r.rhythmModulation&&(r.rhythmModulation.speedMultiplier&&(o.orbitSpeed*=r.rhythmModulation.speedMultiplier),r.rhythmModulation.rotationMultiplier&&(h*=r.rhythmModulation.rotationMultiplier),r.rhythmModulation.radiusPulse&&(c=r.rhythmModulation.radiusPulse));let u=1,d=1;t<.15?(u=t/.15,u=u*u*(3-2*u),d=u):t>.85&&(u=(1-t)/.15,u=u*u*(3-2*u),d=u);const m=o.initialAngle+t*Math.PI*2*h*u,p=1+Math.sin(t*Math.PI*4)*c*u,g=o.radius*l*p*u,f=a+Math.cos(m)*g,y=s+Math.sin(m)*g,v=m*r.zRotations;if(e.z=.8*Math.sin(v)*u+o.originalZ*(1-u),t<.15){const t=.3*u;e.x=o.originalX+(f-o.originalX)*t,e.y=o.originalY+(y-o.originalY)*t;const i=-Math.sin(m)*g*o.orbitSpeed,n=Math.cos(m)*g*o.orbitSpeed;e.vx=o.originalVx+(i-o.originalVx)*d,e.vy=o.originalVy+(n-o.originalVy)*d}else if(t>.85){e.x=f+(o.originalX-f)*(1-u),e.y=y+(o.originalY-y)*(1-u);const t=-Math.sin(m)*g*o.orbitSpeed,i=Math.cos(m)*g*o.orbitSpeed;e.vx=t*d+o.originalVx*(1-d),e.vy=i*d+o.originalVy*(1-d)}else{if(r.verticalOscillation>0){const t=Math.sin(2*m)*r.verticalOscillation*l;e.y=y+t,e.x=f}else{const t=r.smoothness||.1;e.x+=(f-e.x)*t,e.y+=(y-e.y)*t}e.vx=-Math.sin(m)*g*o.orbitSpeed,e.vy=Math.cos(m)*g*o.orbitSpeed}if(r.centripetal){const i=1+.3*(1-Math.abs(e.z)),n=o.initialAngle+t*Math.PI*2*r.rotations*i;e.x=a+Math.cos(n)*g,e.y=s+Math.sin(n)*g}},emotions:["zen","love","excited","surprise"],features:{uses3D:!0,smooth:!0,looping:!0,dramatic:!0},"3d":{evaluate(e,t){const i={...this.config,...t};let{rotations:n}=i;const{zRotations:a}=i;t.rhythmModulation&&t.rhythmModulation.rotationMultiplier&&(n*=t.rhythmModulation.rotationMultiplier);let s=1;e<.15?(s=e/.15,s=s*s*(3-2*s)):e>.85&&(s=(1-e)/.15,s=s*s*(3-2*s));const o=e*Math.PI*2*n*s,r=o*a,l=.1*Math.sin(o)*s,h=.05*Math.cos(o)*s,c=.05*Math.sin(r)*s;return{position:[0,0,.2*Math.sin(r)*s],rotation:[h,l,c],scale:1+.03*Math.sin(2*o)*s}}}},Re={name:"twitch",emoji:"⚡",type:"blending",description:"Nervous, paranoid twitching",config:{intensity:8,frequency:.08,duration:100,recovery:200,maxOffset:15,sharpness:.9},rhythm:{enabled:!0,syncMode:"subdivision",probabilitySync:{subdivision:"sixteenth",onBeat:.3,offBeat:.05,accentBoost:2},intensitySync:{onBeat:2,offBeat:.8,curve:"pulse"},patternOverrides:{breakbeat:{probabilitySync:{onBeat:.5,offBeat:.1},intensitySync:{onBeat:3,offBeat:.5}},dubstep:{intensitySync:{onBeat:1.5,dropBeat:5,curve:"pulse"}}}},apply(e,t,i,n,a,s){e.gestureData||(e.gestureData={}),e.gestureData.twitch||(e.gestureData.twitch={twitchOffset:{x:0,y:0},targetOffset:{x:0,y:0},isTwitching:!1,twitchTimer:0,cooldownTimer:0,lastTwitch:0});const o=e.gestureData.twitch,{config:r}=this;let l=i.intensity||r.intensity;i.rhythmModulation&&(l*=i.rhythmModulation.amplitudeMultiplier||1,l*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.probabilityMultiplier);const h=Date.now();if(!o.isTwitching&&o.cooldownTimer<=0&&Math.random()<(i.frequency||r.frequency)){o.isTwitching=!0,o.twitchTimer=r.duration,o.cooldownTimer=r.recovery;const e=Math.random()*Math.PI*2,t=.5*r.maxOffset+Math.random()*(.5*r.maxOffset);o.targetOffset={x:Math.cos(e)*t*l/8,y:Math.sin(e)*t*l/8},o.lastTwitch=h}if(o.cooldownTimer>0&&(o.cooldownTimer-=16*n),o.isTwitching)if(o.twitchTimer-=16*n,o.twitchTimer>0){const{sharpness:e}=r;o.twitchOffset.x+=(o.targetOffset.x-o.twitchOffset.x)*e,o.twitchOffset.y+=(o.targetOffset.y-o.twitchOffset.y)*e}else o.isTwitching=!1;else o.twitchOffset.x*=.85,o.twitchOffset.y*=.85;e.vx+=o.twitchOffset.x*n*.5,e.vy+=o.twitchOffset.y*n*.5,Math.random()<.1&&(e.vx+=(Math.random()-.5)*l*.3,e.vy+=(Math.random()-.5)*l*.3)},cleanup(e){e.gestureData?.twitch&&delete e.gestureData.twitch},"3d":{evaluate(e,t){const i=t.config||{};let n=i.intensity||8;const a=i.maxOffset||15,s=i.frequency||.08;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const o=9999*Math.floor(10*e),r=e=>{const t=1e4*Math.sin(o+e);return t-Math.floor(t)};if(r(0)<3*s){const e=r(1)*Math.PI*2,t=a*n/8*.005;return{position:[Math.cos(e)*t*r(2),Math.sin(e)*t*r(3),(r(4)-.5)*t],rotation:[.2*(r(5)-.5),.2*(r(6)-.5),.2*(r(7)-.5)],scale:1+.1*(r(8)-.5)}}{const e=.5;return{position:[(r(10)-.5)*e,(r(11)-.5)*e,(r(12)-.5)*e],rotation:[.01*(r(13)-.5),.01*(r(14)-.5),.01*(r(15)-.5)],scale:1}}}}},ze={name:"sway",type:"blending",emoji:"🌊",description:"Gentle side-to-side swaying motion",config:{duration:2e3,amplitude:20,frequency:1,strength:.5},rhythm:{enabled:!0,syncMode:"bar",amplitudeSync:{onBeat:1.2,offBeat:.9,curve:"ease"},durationSync:{mode:"bars",bars:1},patternOverrides:{waltz:{durationSync:{bars:1},amplitudeSync:{onBeat:1.5,curve:"ease"}},swing:{amplitudeSync:{onBeat:1.3,offBeat:.7,curve:"bounce"}}}},apply(e,t,i,n,a,s){const o={...this.config,...i},r=o.amplitude||this.config.amplitude,l=o.frequency||this.config.frequency,h=o.strength||this.config.strength,c=Math.sin(t*Math.PI*2*l)*r;e.vx+=.01*c*n*h,e.vy+=.5*Math.cos(t*Math.PI*4)*n*h},cleanup(e){},"3d":{evaluate(e,t){const i={...this.config,...t};let n=i.amplitude||this.config.amplitude;const a=i.frequency||this.config.frequency,s=i.strength||this.config.strength;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const o=Math.sin(e*Math.PI*2*a),r=n*s*.3*.01,l=.15*o*s,h=.08*o*s;return{position:[o*r,.3*Math.cos(e*Math.PI*4)*r,Math.sin(e*Math.PI*a)*r*.5],rotation:[0,h,l],scale:1}}}},_e={name:"float",type:"blending",emoji:"🎈",description:"Gentle floating upward motion",config:{duration:2e3,amplitude:80,wobbleAmount:20,strength:1},rhythm:{enabled:!0,syncMode:"beat",amplitudeSync:{onBeat:1.5,offBeat:.8,curve:"bounce"},wobbleSync:{subdivision:"eighth",intensity:.7},durationSync:{mode:"bars",bars:2},accentResponse:{enabled:!0,multiplier:1.3},patternOverrides:{waltz:{wobbleSync:{subdivision:"quarter",intensity:.9}},dubstep:{amplitudeSync:{onBeat:2,curve:"pulse"}}}},apply(e,t,i,n,a,s){e.gestureData||(e.gestureData={}),e.gestureData.float||(e.gestureData.float={originalSize:e.size,originalOpacity:e.opacity||1});const o={...this.config,...i};let r=o.amplitude||this.config.amplitude,l=o.wobbleAmount||this.config.wobbleAmount;const h=o.strength||this.config.strength;i.rhythmModulation&&(r*=i.rhythmModulation.amplitudeMultiplier||1,r*=i.rhythmModulation.accentMultiplier||1,l*=i.rhythmModulation.wobbleMultiplier||1);const c=Math.sin(t*Math.PI*4)*l;e.vy-=.01*r*n*h*(1-.5*t),e.vx+=.01*c*n*h,e.size=e.baseSize*(1+.1*t),e.opacity=1-.3*t},cleanup(e){e.gestureData?.float?(e.opacity=e.gestureData.float.originalOpacity,e.size=e.gestureData.float.originalSize,delete e.gestureData.float):(e.opacity=1,e.size=e.baseSize),e.vx*=.5,e.vy*=.5},"3d":{evaluate(e,t){const i={...this.config,...t};let n=i.amplitude||this.config.amplitude,a=i.wobbleAmount||this.config.wobbleAmount;const s=i.strength||this.config.strength;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1,a*=t.rhythmModulation.wobbleMultiplier||1);const o=Math.sin(e*Math.PI),r=n*o*s*.005,l=Math.sin(e*Math.PI*4)*a*.3*.005,h=Math.sin(e*Math.PI)*Math.PI*.5*s,c=Math.sin(e*Math.PI);return{position:[l,r,0],rotation:[c*Math.sin(e*Math.PI*2)*.1,h,c*Math.cos(e*Math.PI*3)*.08],scale:1+.1*o}}}},Oe={name:"jitter",type:"blending",emoji:"🫨",description:"Nervous jittery movement",config:{duration:1e3,intensity:15,frequency:30,strength:1},rhythm:{enabled:!0,syncMode:"beat",amplitudeSync:{onBeat:2,offBeat:.5,curve:"pulse"},patternOverrides:{breakbeat:{amplitudeSync:{onBeat:3,offBeat:.3}},dubstep:{amplitudeSync:{onBeat:5,offBeat:.1,curve:"pulse"}}}},apply(e,t,i,n,a,s){e.gestureData||(e.gestureData={}),e.gestureData.jitter||(e.gestureData.jitter={originalSize:e.size});const o={...this.config,...i};let r=o.intensity||this.config.intensity;const l=o.strength||this.config.strength;i.rhythmModulation&&(r*=i.rhythmModulation.amplitudeMultiplier||1,r*=i.rhythmModulation.accentMultiplier||1);const h=(Math.random()-.5)*r*l,c=(Math.random()-.5)*r*l,u=1-.5*t;e.vx+=.1*h*n*u,e.vy+=.1*c*n*u,e.size=e.baseSize*(1+.1*(Math.random()-.5))},cleanup(e){e.gestureData?.jitter?(e.size=e.gestureData.jitter.originalSize,delete e.gestureData.jitter):e.size=e.baseSize,e.vx*=.7,e.vy*=.7},"3d":{evaluate(e,t){const i={...this.config,...t};let n=i.intensity||this.config.intensity;const a=i.strength||this.config.strength;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const s=Math.sin(e*Math.PI),o=n*a*.002*s;return{position:[(Math.random()-.5)*o,(Math.random()-.5)*o,(Math.random()-.5)*o],rotation:[.005*(Math.random()-.5)*s,.005*(Math.random()-.5)*s,.005*(Math.random()-.5)*s],scale:1+.02*(Math.random()-.5)*s}}}},Fe={name:"wiggle",emoji:"〰️",type:"additive",description:"Rapid side-to-side oscillation",config:{duration:600,musicalDuration:{musical:!0,beats:1},amplitude:15,frequency:6,strength:1,damping:.3,easing:"linear",particleMotion:{type:"wiggle",strength:1,amplitude:15,frequency:6}},rhythm:{enabled:!0,syncMode:"beat",frequencySync:{subdivision:"sixteenth",wigglePerBeat:4},amplitudeSync:{onBeat:1.5,offBeat:.8,curve:"bounce"},durationSync:{mode:"beats",beats:1}},apply(e,t,i,n,a,s,o){const r=(i.amplitude||this.config.amplitude)*a,l=i.frequency||this.config.frequency,h=1-n*(i.damping||this.config.damping),c=Math.sin(n*Math.PI*l)*r*h;e.vx+=.5*c;const u=Math.cos(n*Math.PI*l*2)*r*.1*h;e.vy+=.3*u},"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||1,a=i.amplitude||15,s=i.frequency||6,o=i.damping||.3,r=Math.sin(e*Math.PI*s),l=1-e*o;return{position:[r*a*.008*n*l,0,0],rotation:[0,.25*r*n*l,0],scale:1}}}},Le={name:"headBob",emoji:"🎧",type:"additive",description:"Rhythmic vertical bobbing to music",config:{duration:600,musicalDuration:{musical:!0,beats:1},amplitude:12,frequency:2,strength:1,damping:.1,easing:"linear",particleMotion:{type:"headBob",strength:1,amplitude:12,frequency:2}},rhythm:{enabled:!0,syncMode:"beat",frequencySync:{subdivision:"eighth",bobsPerBeat:2},amplitudeSync:{onBeat:1.3,offBeat:1,curve:"pulse"},durationSync:{mode:"beats",beats:1}},apply(e,t,i,n,a,s,o){const r=(i.amplitude||this.config.amplitude)*a,l=i.frequency||this.config.frequency,h=1-n*(i.damping||this.config.damping),c=Math.sin(n*Math.PI*2*l)*r*h;e.vy+=.5*c;const u=Math.cos(n*Math.PI*2*l*1.5)*r*.05*h;e.vx+=.2*u},"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||1,a=i.amplitude||12,s=i.frequency||2,o=i.damping||.1,r=Math.sin(e*Math.PI*2*s),l=1-e*o;return{position:[0,-r*a*.008*n*l,0],rotation:[r*(.045*a)*n*l,0,0],scale:1}}}},Ge={name:"lean",emoji:"↗️",type:"blending",description:"Diagonal tilting motion with smooth return",config:{duration:1200,musicalDuration:{musical:!0,beats:2},amplitude:10,frequency:1,direction:"right",strength:.7,particleMotion:{type:"lean",direction:"right",strength:.7,frequency:1}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:3,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.3,offBeat:.8,curve:"ease"},durationSync:{mode:"beats",beats:2},accentResponse:{enabled:!0,multiplier:1.4},patternOverrides:{waltz:{durationSync:{beats:3},amplitudeSync:{onBeat:1.5,offBeat:.6}},swing:{amplitudeSync:{onBeat:1.6,offBeat:.5,curve:"bounce"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.lean={startX:e.x,startY:e.y,startVx:e.vx,startVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.lean?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=this.easeInOutCubic(t),h=o.frequency||this.config.frequency;let c=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(c*=i.rhythmModulation.amplitudeMultiplier||1,c*=i.rhythmModulation.accentMultiplier||1);const u=Math.sin(l*Math.PI*h),d="left"===o.direction?-1:1;if(e.vx+=u*c*.015*n*d,e.vy+=u*c*.01*n*d*.5,t>.9){const i=1-10*(t-.9);e.vx=e.vx*(.95+.05*i),e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.lean&&delete e.gestureData.lean},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||10,a=i.frequency||1,s=i.strength||.7,o=i.direction||"right",r=.003*n*s,l=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,h=Math.sin(l*Math.PI*a),c="left"===o?-1:1;return{position:[h*r*c,0,0],rotation:[0,0,.35*h*c],scale:1}}}},Ve={name:"point",emoji:"👉",type:"blending",description:"Directional pointing motion with forward momentum",config:{duration:1e3,musicalDuration:{musical:!0,beats:2},amplitude:15,direction:"right",strength:.8,particleMotion:{type:"point",direction:"right",strength:.8}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:4,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.5,offBeat:.7,curve:"ease"},durationSync:{mode:"beats",beats:2},accentResponse:{enabled:!0,multiplier:1.6},patternOverrides:{march:{amplitudeSync:{onBeat:2,offBeat:.5,curve:"pulse"}},swing:{amplitudeSync:{onBeat:1.4,offBeat:.8,curve:"bounce"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.point={startX:e.x,startY:e.y,startVx:e.vx,startVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.point?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=this.easeInOutCubic(t);let h=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1);const c=Math.sin(l*Math.PI);let u=0,d=0;switch(o.direction||"right"){case"right":u=1;break;case"left":u=-1;break;case"up":d=-1;break;case"down":d=1}if(e.vx+=c*h*.02*n*u,e.vy+=c*h*.02*n*d,t>.9){const i=1-10*(t-.9);e.vx=e.vx*(.95+.05*i),e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.point&&delete e.gestureData.point},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||15,a=i.strength||.8,s=i.direction||"right",o=.005*n*a,r=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,l=Math.sin(r*Math.PI);let h=0,c=0;switch(s){case"right":h=l*o,c=.25*l;break;case"left":h=-l*o,c=.25*-l;break;case"up":case"down":c=0}return{position:[h,0,0],rotation:[0,c,0],scale:1}}}},qe={name:"reach",emoji:"🙌",type:"blending",description:"Upward reaching motion with scale increase",config:{duration:1400,musicalDuration:{musical:!0,beats:2},amplitude:25,strength:.9,scaleMax:1.05,particleMotion:{type:"reach",strength:.9,scaleMax:1.05}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:4,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.4,offBeat:.9,curve:"ease"},durationSync:{mode:"beats",beats:2},accentResponse:{enabled:!0,multiplier:1.5},patternOverrides:{uplifting:{amplitudeSync:{onBeat:1.8,offBeat:.7,curve:"ease"},durationSync:{beats:3}},ambient:{amplitudeSync:{onBeat:1.2,offBeat:1,curve:"linear"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.reach={startY:e.y,startVy:e.vy,originalSize:e.size,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.reach?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=o.scaleMax||this.config.scaleMax||1.05,h=this.easeInOutCubic(t);let c=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(c*=i.rhythmModulation.amplitudeMultiplier||1,c*=i.rhythmModulation.accentMultiplier||1);const u=Math.sin(h*Math.PI);e.vy-=u*c*.015*n;const d=1+u*(l-1);if(e.size=e.baseSize*d,t>.9){const i=1-10*(t-.9);e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.reach&&(e.gestureData.reach.originalSize?e.size=e.gestureData.reach.originalSize:e.size=e.baseSize,delete e.gestureData.reach)},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||25,a=i.strength||.9,s=i.scaleMax||1.05,o=.004*n*a,r=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,l=Math.sin(r*Math.PI);return{position:[0,l*o,0],rotation:[.1*l,0,0],scale:1+l*(s-1)}}}},Ne={name:"spin",emoji:"🌀",type:"override",description:"Orbital rotation around center point",config:{duration:600,musicalDuration:{musical:!0,beats:1},rotations:1,direction:"random",radiusMultiplier:1,spiralOut:!1,accelerate:!0,maintainDistance:!0,scaleAmount:.1,easing:"linear",strength:.7,particleMotion:{type:"spin",strength:.7,rotations:1,radius:1}},rhythm:{enabled:!0,syncMode:"bar",rotationSync:{mode:"bars",rotationsPerBar:1,accelerateOnBeat:!0},radiusSync:{subdivision:"quarter",expandOnBeat:1.2,contractOffBeat:.9,curve:"bounce"},durationSync:{mode:"beats",beats:4},patternOverrides:{waltz:{rotationSync:{rotationsPerBar:.75},radiusSync:{curve:"ease"}},swing:{rotationSync:{accelerateOnBeat:!1},direction:"alternating"},dubstep:{radiusSync:{subdivision:"eighth",expandOnBeat:1.5,dropMultiplier:2},spiralOut:!0},breakbeat:{rotationSync:{mode:"random",range:[.5,2]},direction:"random"}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;let o=t.direction||this.config.direction;"random"===o&&(o=Math.random()<.5?"clockwise":"counter-clockwise"),e.gestureData.spin={startAngle:Math.atan2(s,a),startRadius:Math.sqrt(a*a+s*s)||30,originalX:e.x,originalY:e.y,originalVx:e.vx,originalVy:e.vy,direction:o,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.spin?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.spin,r={...this.config,...i},l=i.strength||1;let{rotations:h}=r,{radiusMultiplier:c}=r;i.rhythmModulation&&(i.rhythmModulation.rotationMultiplier&&(h*=i.rhythmModulation.rotationMultiplier),i.rhythmModulation.radiusMultiplier&&(c*=i.rhythmModulation.radiusMultiplier));let u=t;r.accelerate&&(u=t<.5?.5*this.easeInQuad(2*t):.5+.5*this.easeOutQuad(2*(t-.5)));const d=h*Math.PI*2*l,m="counter-clockwise"===o.direction?-1:1,p=o.startAngle+d*u*m;let g=o.startRadius;r.spiralOut&&(g*=1+.5*t),1!==c&&(g*=1+(c-1)*Math.sin(t*Math.PI));const f=a+Math.cos(p)*g,y=s+Math.sin(p)*g;if(e.x+=.25*(f-e.x),e.y+=.25*(y-e.y),e.vx=.5*(f-e.x),e.vy=.5*(y-e.y),t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.spin){const t=e.gestureData.spin;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.spin}},easeInQuad:e=>e*e,easeOutQuad:e=>e*(2-e),"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.spin)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.spin,a=t.config||{},s=t.strength||1;let o=e;a.accelerate&&(o=e<.5?e*e*4*.5:.5+(e-.5)*(2-(e-.5))*.5);const r=(a.rotations||1)*Math.PI*2*s,l="counter-clockwise"===n.direction?-1:1;return{position:[0,0,0],rotation:[0,r*Math.sin(o*Math.PI)*l,0],scale:1+(a.scaleAmount||.1)*Math.sin(e*Math.PI)*s}}}},je={name:"jump",emoji:"🦘",type:"override",description:"Squash, leap, and land with classic animation principles",config:{duration:800,jumpHeight:60,squashAmount:.8,stretchAmount:1.2,anticipation:.2,hangTime:.1,landingImpact:!0,driftOutward:!0,easing:"quad",particleMotion:{type:"jump",strength:.9,jumpHeight:60,squash:.8,stretch:1.2}},rhythm:{enabled:!0,syncMode:"beat",phaseSync:{anticipation:"eighth",jump:"beat",landing:"sixteenth"},heightSync:{onBeat:1.5,offBeat:.8,accent:2,curve:"exponential"},deformationSync:{squashOnBeat:.6,stretchOnBeat:1.4,timing:"anticipatory"},hangTimeSync:{mode:"tempo",baseDuration:.1,scaling:"inverse"},dynamics:{forte:{jumpHeight:80,stretch:1.3},piano:{jumpHeight:30,stretch:1.1}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={}),e.gestureData.jump={startX:e.x,startY:e.y,startSize:e.size,originalVx:e.vx,originalVy:e.vy,driftDirection:.1*(e.x-i),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.jump?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.jump,r={...this.config,...i},l=i.strength||1,h=r.jumpHeight*l*e.scaleFactor,c=r.squashAmount,u=r.stretchAmount,d=r.anticipation,m=1-.5*r.anticipation;if(t<d){const i=t/d,n=this.easeOutQuad(i);e.size=o.startSize*(1-(1-c)*n),e.y=o.startY+5*n*e.scaleFactor,e.vx=0,e.vy=0}else if(t<m){const i=(t-d)/(m-d);let n=Math.sin(i*Math.PI);if(r.hangTime>0&&i>.4&&i<.6){const e=(i-.4)/.2;n=.95+.05*this.easeInOutCubic(e)}if(e.y=o.startY-n*h,r.driftOutward&&(e.x=o.startX+n*o.driftDirection),i<.5){const t=2*i;e.size=o.startSize*(c+(u-c)*t)}else{const t=2*(i-.5);e.size=o.startSize*(u-(u-1)*t*.8)}e.vx=.5*o.driftDirection,e.vy=-Math.cos(i*Math.PI)*h*.1}else{const i=(t-m)/(1-m),n=this.easeOutBounce(i);if(e.y=o.startY,r.landingImpact)if(i<.3){const t=i/.3;e.size=o.startSize*(1-(1-.8*c)*(1-t))}else{const t=(i-.3)/.7;e.size=o.startSize*(.8*c+(1-.8*c)*t)}else e.size=o.startSize*(c+(1-c)*n);e.vx=o.originalVx*n,e.vy=o.originalVy*n}},cleanup(e){if(e.gestureData?.jump){const t=e.gestureData.jump;e.size=t.startSize,e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.jump}},easeOutQuad:e=>e*(2-e),easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutBounce(e){const t=7.5625,i=2.75;return e<1/i?t*e*e:e<2/i?t*(e-=1.5/i)*e+.75:e<2.5/i?t*(e-=2.25/i)*e+.9375:t*(e-=2.625/i)*e+.984375},"3d":{evaluate(e,t){const i=t.config||t||{},n=t.strength||1,a=.004*(i.jumpHeight||60)*n,s=i.squashAmount||.8,o=i.stretchAmount||1.2,r=i.anticipation||.2,l=1-.5*r;let h=0,c=1,u=0;if(e<r){const t=e/r,i=t*(2-t);c=1-(1-s)*i,h=.02*-i}else if(e<l){const t=(e-r)/(l-r);h=Math.sin(t*Math.PI)*a,c=t<.5?s+2*t*(o-s):o-2*(t-.5)*(o-1)*.8,u=.05*Math.sin(t*Math.PI)}else{const t=(e-l)/(1-l);if(t<.5){const e=2*t;h=-Math.sin(e*Math.PI)*a*.15}else h=0;c=!1!==i.landingImpact?t<.3?1-(1-.8*s)*(1-t/.3):.8*s+(t-.3)/.7*(1-.8*s):s+(1-s)*t}return{position:[0,h,0],rotation:[u,0,0],scale:c}}}},Ue={name:"morph",emoji:"✨",type:"override",description:"Form geometric patterns and shapes",config:{musicalDuration:{musical:!0,beats:2,minBeats:1,maxBeats:8},phases:[{name:"gather",beats:.25},{name:"form",beats:.75},{name:"hold",beats:.5},{name:"dissolve",beats:.5}],morphType:"fluid",pattern:"star",points:5,innerRadius:.4,size:80,amplitude:20,rotation:0,smooth:!0,randomizeOrder:!1,easing:"sine",strength:1.2,particleMotion:{type:"morph",pattern:"star",strength:1.2,smooth:!0,points:5}},rhythm:{enabled:!0,syncMode:"phrase",patternSync:{verse:"circle",chorus:"star",bridge:"heart",drop:"explosion"},timingSync:{formationBeat:1,holdBeats:2,dissolveBeat:4,curve:"anticipatory"},sizeSync:{onBeat:1.2,offBeat:.95,subdivision:"quarter",curve:"elastic"},rotationSync:{mode:"continuous",degreesPerBar:90,direction:"clockwise"},dynamics:{forte:{points:8,size:100},piano:{points:3,size:60}}},initialize(e,t,i,n,a){e.gestureData||(e.gestureData={});const s={...this.config,...t},o=e.x,r=e.y,l=Math.atan2(e.y-n,e.x-i),h=Math.random()<.5?1:-1;let c,u;const d=s.size*e.scaleFactor,m=(s.rotation||0)*Math.PI/180*h;switch(s.pattern){case"star":c=i,u=n,this.calculateStarPosition(e,l,d,s.points,s.innerRadius,m,i,n);break;case"heart":this.calculateHeartPosition(e,l,d,m,i,n);break;case"square":this.calculateSquarePosition(e,l,d,m,i,n);break;case"triangle":this.calculateTrianglePosition(e,l,d,m,i,n);break;default:{const e=d;c=i+Math.cos(l+m)*e,u=n+Math.sin(l+m)*e;break}}e.gestureData.morph={startX:o,startY:r,targetX:e.gestureData.morphTargetX||c,targetY:e.gestureData.morphTargetY||u,originalVx:e.vx,originalVy:e.vy,rotationDirection:h,initialized:!0}},calculateStarPosition(e,t,i,n,a,s,o,r){const l=((t+Math.PI)%(2*Math.PI)+2*Math.PI)%(2*Math.PI),h=Math.floor(l/(2*Math.PI)*10),c=h%2==0,u=Math.floor(h/2);let d;d=c?72*u*Math.PI/180:(72*u+36)*Math.PI/180,d+=s;const m=c?i:i*a;e.gestureData.morphTargetX=o+Math.cos(d)*m,e.gestureData.morphTargetY=r+Math.sin(d)*m},calculateHeartPosition(e,t,i,n,a,s){const o=(t+Math.PI)/(2*Math.PI),r=.05*i,l=16*Math.pow(Math.sin(o*Math.PI*2),3),h=-(13*Math.cos(o*Math.PI*2)-5*Math.cos(2*o*Math.PI*2)-2*Math.cos(3*o*Math.PI*2)-Math.cos(4*o*Math.PI*2)),c=Math.cos(n),u=Math.sin(n),d=l*c-h*u,m=l*u+h*c;e.gestureData.morphTargetX=a+d*r,e.gestureData.morphTargetY=s+m*r},calculateSquarePosition(e,t,i,n,a,s){const o=((t+n)%(2*Math.PI)+2*Math.PI)%(2*Math.PI);let r,l;const h=i;o<Math.PI/4||o>=7*Math.PI/4?(r=h,l=h*Math.tan(o)):o<3*Math.PI/4?(r=h/Math.tan(o),l=h):o<5*Math.PI/4?(r=-h,l=-h*Math.tan(o)):(r=-h/Math.tan(o),l=-h);const c=Math.cos(n),u=Math.sin(n),d=r*c-l*u,m=r*u+l*c;e.gestureData.morphTargetX=a+d,e.gestureData.morphTargetY=s+m},calculateTrianglePosition(e,t,i,n,a,s){const o=[{x:0,y:-i},{x:.866*-i,y:.5*i},{x:.866*i,y:.5*i}],r=Math.floor((t+Math.PI)/(2*Math.PI)*3)%3,l=(r+1)%3,h=Math.random(),c=o[r].x+(o[l].x-o[r].x)*h,u=o[r].y+(o[l].y-o[r].y)*h,d=Math.cos(n),m=Math.sin(n),p=c*d-u*m,g=c*m+u*d;e.gestureData.morphTargetX=a+p,e.gestureData.morphTargetY=s+g},apply(e,t,i,n,a,s){e.gestureData?.morph?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.morph,r={...this.config,...i};let l,h,c=t;if(r.holdTime>0){const e=.5-r.holdTime/2,i=.5+r.holdTime/2;c=t<e?t/e*.5:t<i?.5:.5+(t-i)/(1-i)*.5}if(c<=.5){const e=2*c;l=o.startX+(o.targetX-o.startX)*this.easeOutQuad(e),h=o.startY+(o.targetY-o.startY)*this.easeOutQuad(e)}else{const e=2*(c-.5);l=o.targetX+(o.startX-o.targetX)*this.easeInQuad(e),h=o.targetY+(o.startY-o.targetY)*this.easeInQuad(e)}if(r.smooth){const t=.2;e.x+=(l-e.x)*t,e.y+=(h-e.y)*t}else e.x=l,e.y=h;if(e.vx=.5*(l-e.x),e.vy=.5*(h-e.y),t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.morph){const t=e.gestureData.morph;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.morph,delete e.gestureData.morphTargetX,delete e.gestureData.morphTargetY}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutQuad:e=>e*(2-e),easeInQuad:e=>e*e,"3d":{evaluate(e,t){const i=t?.strength||1,n=Math.sin(e*Math.PI);let a;if(e<=.5){const t=2*e;a=1+t*(2-t)*.25*i}else{const t=2*(e-.5);a=1.25*i+t*t*(1-1.25*i),a=Math.max(1,a)}return{position:[0,0,0],rotation:[0,n*Math.PI*.3*i,.1*Math.sin(e*Math.PI*2)*i],scale:a,glowIntensity:1+.4*n*i,glowBoost:1.5*n*i}}}},He={name:"stretch",emoji:"↔️",type:"override",description:"Scale particles along X and Y axes",config:{duration:2e3,scaleX:1.3,scaleY:.9,alternate:!1,elastic:!0,overshoot:.1,frequency:1,easing:"sine",strength:1,particleMotion:{type:"stretch",scaleX:1.8,scaleY:.6,strength:1},centerBased:!0,preserveArea:!1},rhythm:{enabled:!0,syncMode:"beat",scaleSync:{onBeat:{x:1.5,y:.7},offBeat:{x:.8,y:1.3},subdivision:"eighth",curve:"elastic"},alternateSync:{pattern:"XYXY",beatsPerChange:1,overlap:.1},overshootSync:{normal:.1,accent:.3,downbeat:.2,curve:"spring"},preservationSync:{verse:!0,chorus:!1,bridge:!0},dynamics:{forte:{scaleX:2,scaleY:.5,overshoot:.4},piano:{scaleX:1.1,scaleY:.95,overshoot:.05}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.stretch={offsetX:a,offsetY:s,startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.stretch?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.stretch,r={...this.config,...i},l=i.strength||1;let h,c,{scaleX:u}=r,{scaleY:d}=r;if(r.preserveArea&&1!==u&&1!==d){const e=u*d,t=Math.sqrt(1/e);u*=t,d*=t}if(r.alternate)if(t<.5){const e=2*t;u=1+(u-1)*this.getElasticProgress(e,r),d=1+(1/u-1)*(r.preserveArea?1:0)}else{const e=2*(t-.5);u+=(1-u)*this.getElasticProgress(e,r),d=1+(d-1)*this.getElasticProgress(e,r)}else{const e=this.getElasticProgress(t,r);u=1+(u-1)*e*l,d=1+(d-1)*e*l}if(r.centerBased?(h=a+o.offsetX*u,c=s+o.offsetY*d):(h=o.startX*u,c=o.startY*d),e.x=h,e.y=c,e.vx=o.offsetX*(u-1)*l*.1,e.vy=o.offsetY*(d-1)*l*.1,t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},getElasticProgress(e,t){if(!t.elastic)return this.easeInOutCubic(e);if(0===e)return 0;if(1===e)return 1;const i=t.overshoot||.1;if(e<.5){const t=2*e;return.5*this.easeInElastic(t,i)}{const t=2*(e-.5);return.5+.5*this.easeOutElastic(t,i)}},cleanup(e){if(e.gestureData?.stretch){const t=e.gestureData.stretch;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.stretch}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeInElastic:(e,t)=>0===e?0:1===e?1:-Math.pow(2,10*(e-1))*Math.sin((e-1-.075)*(2*Math.PI)/.3)*(1+t),easeOutElastic:(e,t)=>0===e?0:1===e?1:Math.pow(2,-10*e)*Math.sin((e-.075)*(2*Math.PI)/.3)*(1+t)+1,"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.stretch)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=t.config||{},a=t.strength||1;let s,o=n.scaleX||1.3,r=n.scaleY||.9;if(n.preserveArea&&1!==o&&1!==r){const e=o*r,t=Math.sqrt(1/e);o*=t,r*=t}if(n.elastic){const t=n.overshoot||.1;if(e<.5){const i=2*e,n=.3,a=n/4;s=-Math.pow(2,10*(i-1))*Math.sin((i-1-a)*(2*Math.PI)/n)*(1+t)*.5}else{const i=2*(e-.5),n=.3,a=n/4;s=.5+.5*(Math.pow(2,-10*i)*Math.sin((i-a)*(2*Math.PI)/n)*(1+t)+1)}}else s=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2;let l,h=1;if(e>.8){const t=(e-.8)/(1-.8);h=1-t*t*t}l=n.alternate?e<.5?2*e*.8:.8-2*(e-.5)*1.4:1*s*a;const c=1+l*h;return{position:[0,0,0],rotation:[0,0,.1*Math.sin(e*Math.PI*4)*s*h],scale:c}}}},We={name:"tilt",emoji:"🤔",type:"override",description:"Gather particles then tilt as unified group",config:{duration:500,gatherPhase:.2,tiltAngle:45,swayAmount:80,liftAmount:60,frequency:3,homeRadius:20,easing:"sine",strength:2.5,particleMotion:{type:"tilt",strength:2.5,frequency:3,swayAmount:80,liftAmount:60},smoothness:.25},rhythm:{enabled:!0,syncMode:"swing",angleSync:{onBeat:45,offBeat:-30,swing:15,subdivision:"triplet",curve:"ease-in-out"},gatherSync:{beatsBefore:.5,releaseAfter:.25,intensity:"dynamic"},swaySync:{verse:60,chorus:100,bridge:80,syncopated:!0},liftSync:{upOnTilt:!0,heightOnAccent:80,normalHeight:40,curve:"bounce"},dynamics:{forte:{tiltAngle:60,swayAmount:120,frequency:4},piano:{tiltAngle:20,swayAmount:40,frequency:2}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.atan2(s,a),r=Math.sqrt(a*a+s*s),l=Math.random(),h=({...this.config,...t}.homeRadius+20*Math.random())*e.scaleFactor;e.gestureData.tilt={startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,angle:o,distance:r,homeRadius:h,homeX:i+Math.cos(o)*h,homeY:n+Math.sin(o)*h,role:l,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.tilt?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.tilt,r={...this.config,...i},l=i.strength||1;let h,c;if(t<r.gatherPhase){const i=t/r.gatherPhase,n=this.easeInOutCubic(i);h=o.startX+(o.homeX-o.startX)*n,c=o.startY+(o.homeY-o.startY)*n;const a=.6;e.x+=(h-e.x)*a,e.y+=(c-e.y)*a}else{const i=(t-r.gatherPhase)/(1-r.gatherPhase)*Math.PI*r.frequency,n=Math.sin(i),u=r.tiltAngle*Math.PI/180*l,d=o.angle+n*u,m=Math.abs(n)*r.liftAmount*e.scaleFactor,p=o.homeRadius+m;h=a+Math.cos(d)*p,c=s+Math.sin(d)*p-.3*m;const g=r.smoothness+.1*o.role;e.x+=(h-e.x)*g,e.y+=(c-e.y)*g;const f=-Math.sin(d),y=Math.cos(d);e.vx=f*n*2,e.vy=y*n*2}if(t<r.gatherPhase&&(e.vx=.25*(h-e.x),e.vy=.25*(c-e.y)),t>.9){const i=10*(1-t),n=o.startX+(e.x-o.startX)*i,a=o.startY+(e.y-o.startY)*i;e.x=n,e.y=a,e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.tilt){const t=e.gestureData.tilt;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.tilt}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||1,a=i.gatherPhase||.2,s=i.frequency||3,o=i.tiltAngle||45;let r=0;if(e>=a){const t=(e-a)/(1-a)*Math.PI*s;r=Math.sin(t)*(o*Math.PI/180*n*.4)}return{position:[0,0,0],rotation:[0,0,r],scale:1}}}},Xe={name:"orbital",emoji:"🪐",type:"override",description:"Orbital motion around center",config:{speed:.02,maintainRadius:!0,elliptical:!1,use3D:!0,zPhaseOffset:0,verticalOscillation:0,duration:3e3,particleMotion:{type:"orbital",strength:1}},rhythm:{enabled:!0,syncMode:"harmonic",speedSync:{tonic:.02,fifth:.03,octave:.04,third:.025,curve:"smooth"},radiusSync:{bass:150,mid:100,treble:50,scaling:"logarithmic"},depthSync:{major:{z:1,phase:0},minor:{z:-1,phase:Math.PI},diminished:{z:.5,phase:Math.PI/2},augmented:{z:.8,phase:-Math.PI/2}},phaseSync:{mode:"harmonic",intervals:[1,1.5,2],drift:.05},dynamics:{forte:{speed:.04,maintainRadius:!1},piano:{speed:.01,maintainRadius:!0}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.sqrt(a*a+s*s),r=Math.random()<.5?1:-1,l=Math.max(o,100+180*Math.random()),h=o<5?Math.random()*Math.PI*2:Math.atan2(s,a);e.gestureData.orbital={radius:l,targetRadius:l,angle:h,initialAngle:h,originalVx:e.vx,originalVy:e.vy,originalZ:e.z||0,zPhase:Math.random()*Math.PI*2,direction:r}},apply(e,t,i,n,a,s){e.gestureData?.orbital||this.initialize(e,i,a,s);const o=e.gestureData.orbital,r=(i.speed||this.config.speed)*(i.strength||1);o.angle+=r*n*o.direction;let{radius:l}=o;if(i.maintainRadius||(l=o.radius*(1+.1*Math.sin(t*Math.PI*2))),e.x=a+Math.cos(o.angle)*l,e.y=s+Math.sin(o.angle)*l,!1!==i.use3D){const t=o.angle+o.zPhase+(i.zPhaseOffset||0);if(e.z=.8*Math.sin(t),i.verticalOscillation){const n=Math.cos(t)*i.verticalOscillation*l*.1;e.y+=n}}if(e.vx=-Math.sin(o.angle)*l*r,e.vy=Math.cos(o.angle)*l*r,t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.orbital){const t=e.gestureData.orbital;e.vx=t.originalVx,e.vy=t.originalVy,e.z=t.originalZ,delete e.gestureData.orbital}},"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.orbital)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.orbital;t.config;let a=1;e<.15?(a=e/.15,a=Math.sin(a*Math.PI*.5)):e>.85&&(a=(1-e)/.15,a=Math.sin(a*Math.PI*.5));const s=n.initialAngle+e*Math.PI*2*n.direction,o=.3*Math.cos(s)*a,r=.3*Math.sin(s)*a,l=(s+Math.PI/2-(n.initialAngle+Math.PI/2))*a,h=i.z||0;return{position:[o,0,r+.1*h*a],rotation:[0,l,0],scale:1+.15*h*a}}}},Ye={name:"hula",emoji:"🌀",type:"override",description:"Hula-hoop motion with vertical waves",config:{speed:.015,maintainRadius:!1,elliptical:!0,use3D:!0,zPhaseOffset:Math.PI/4,verticalOscillation:.3,wobbleAmount:.15,duration:2500,particleMotion:{type:"hula",strength:1,verticalOscillation:.3}},rhythm:{enabled:!0,syncMode:"bar",speedSync:{mode:"tempo",baseSpeed:.015,scaling:"proportional"},wobbleSync:{onBeat:.25,offBeat:.1,curve:"sine"},verticalSync:{subdivision:"quarter",amplitude:.4,phase:"sequential"},dynamics:{forte:{wobbleAmount:.3,speed:1.2},piano:{wobbleAmount:.05,speed:.8}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.sqrt(a*a+s*s),r=Math.random()<.5?1:-1,l=Math.max(o,100+180*Math.random()),h=o<5?Math.random()*Math.PI*2:Math.atan2(s,a);e.gestureData.hula={radius:l,angle:h,initialAngle:h,originalVx:e.vx,originalVy:e.vy,originalZ:e.z||0,zPhase:Math.random()*Math.PI*2,wobblePhase:Math.random()*Math.PI*2,direction:r}},apply(e,t,i,n,a,s){e.gestureData?.hula||this.initialize(e,i,a,s);const o=e.gestureData.hula,r=(i.speed||this.config.speed)*(i.strength||1);let l=1;t<.1?(l=t/.1,l=Math.sin(l*Math.PI*.5)):t>.9&&(l=(1-t)/.1,l=Math.sin(l*Math.PI*.5)),o.angle+=r*n*o.direction*l;const h=Math.sin(2*o.angle+o.wobblePhase)*(i.wobbleAmount||this.config.wobbleAmount)*l,c=o.radius*(1+h)*l,u=o.radius*(.7+h)*l,d=a+Math.cos(o.angle)*c,m=s+Math.sin(o.angle)*u;if(t<.1){const t=e.x-a,i=e.y-s;Math.sqrt(t*t+i*i)<50?(e.x=a+Math.cos(o.angle)*c,e.y=s+Math.sin(o.angle)*u):(e.x=e.x+(d-e.x)*l*.5,e.y=e.y+(m-e.y)*l*.5)}else e.x=d,e.y=m;const p=o.angle+o.zPhase+(i.zPhaseOffset||this.config.zPhaseOffset);e.z=.9*Math.sin(p)*l;const g=i.verticalOscillation||this.config.verticalOscillation,f=Math.cos(2*p)*g*o.radius*.2*l;e.y+=f;const y=e.z*o.radius*.1;e.y-=y;const v=-Math.sin(o.angle)*c*r,b=Math.cos(o.angle)*u*r;t<.1?(e.vx=o.originalVx+(v-o.originalVx)*l,e.vy=o.originalVy+(b-o.originalVy)*l):t>.9?(e.vx=v*l+o.originalVx*(1-l),e.vy=b*l+o.originalVy*(1-l),e.z=e.z*l+o.originalZ*(1-l)):(e.vx=v,e.vy=b)},cleanup(e){if(e.gestureData?.hula){const t=e.gestureData.hula;e.vx=t.originalVx,e.vy=t.originalVy,e.z=t.originalZ,delete e.gestureData.hula}},"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.hula)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.hula,a=t.config||{};let s=1;e<.15?(s=e/.15,s=Math.sin(s*Math.PI*.5)):e>.85&&(s=(1-e)/.15,s=Math.sin(s*Math.PI*.5));const o=n.initialAngle+e*Math.PI*2*n.direction,r=.25*Math.cos(o)*s,l=.25*Math.sin(o)*s,h=a.verticalOscillation||.3;return{position:[r,Math.sin(2*o+n.wobblePhase)*h*s,l],rotation:[0,(o-n.initialAngle)*s,0],scale:1+.15*Math.abs(Math.sin(o))*s}}}},$e={name:"twist",emoji:"🌀",type:"override",description:"Twisting dance motion with alternating rotation",config:{duration:1200,rotationAngle:45,contractionFactor:.8,twistFrequency:2,easing:"smooth",strength:.8,particleMotion:{type:"twist",rotationAngle:45,contractionFactor:.8,twistFrequency:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:4,blendable:!1,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.5,offBeat:.7,curve:"elastic"},patternOverrides:{funk:{rotationAngle:60,contractionFactor:.7},disco:{twistFrequency:3,rotationAngle:50},latin:{rotationAngle:35,contractionFactor:.85,twistFrequency:2.5}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.twist={startX:e.x,startY:e.y,startAngle:Math.atan2(e.y-t.centerY,e.x-t.centerX),startDistance:Math.sqrt(Math.pow(e.x-t.centerX,2)+Math.pow(e.y-t.centerY,2)),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.twist?.initialized||this.initialize(e,{...i,centerX:a,centerY:s});const o={...this.config,...i},r=e.gestureData.twist,l=o.strength||this.config.strength||1,h=t*o.twistFrequency*Math.PI*2,c=Math.sin(h)*l;let{rotationAngle:u}=o,{contractionFactor:d}=o;i.rhythmModulation&&(u*=i.rhythmModulation.amplitudeMultiplier||1,d=1-(1-d)*(i.rhythmModulation.amplitudeMultiplier||1));const m=u*Math.PI/180*c,p=1-(1-d)*Math.abs(c),g=r.startAngle+m,f=r.startDistance*p,y=a+Math.cos(g)*f,v=s+Math.sin(g)*f,b=.15*l;e.x+=(y-e.x)*b,e.y+=(v-e.y)*b,e.vx=.05*(y-e.x),e.vy=.05*(v-e.y);const w=5*Math.sin(t*Math.PI*4)*l;if(e.y+=.1*w,t>.9){const i=1-10*(t-.9);e.vx*=i,e.vy*=i}},cleanup(e){e.gestureData?.twist&&delete e.gestureData.twist},"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.twist)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.twist,a=t.config||{},s=a.strength||1,o=e>.85?(1-e)/.15:1,r=e*(a.twistFrequency||2)*Math.PI*2,l=Math.sin(r)*s*o,h=l*((a.rotationAngle||45)*Math.PI/180),c=n.startAngle+h,u=(a.contractionFactor||.8)*n.startDistance;return{position:[Math.cos(c)*u*.1*o*.01,0,Math.sin(c)*u*.1*o*.01],rotation:[.1*Math.cos(r)*s*o,h,.15*Math.sin(.5*r)*s*o],scale:1-(1-(a.contractionFactor||.8))*Math.abs(l)}}}},Qe={name:"wave",emoji:"🌊",type:"override",description:"Infinity pattern flow with phasing",config:{musicalDuration:{musical:!0,bars:1,minBeats:4,maxBeats:16},phases:[{name:"gather",beats:.5},{name:"rise",beats:.5},{name:"waveLeft",beats:1},{name:"waveRight",beats:1},{name:"settle",beats:1}],amplitude:40,frequency:1,phaseShift:.3,liftHeight:20,fadeInOut:!0,smoothness:.1,easing:"sine",strength:1,particleMotion:{type:"wave",strength:1,amplitude:50}},rhythm:{enabled:!0,syncMode:"wave",amplitudeSync:{onWave:65,onStatic:25,curve:"flowing"},frequencySync:{mode:"phrase",slow:.7,fast:1.8,curve:"melodic"},durationSync:{mode:"bars",adaptToPhrase:!0,sustain:!0},phaseSync:{enabled:!0,multiplier:.5,type:"ensemble"},melodicResponse:{enabled:!0,multiplier:1.4,type:"amplitude"},patternOverrides:{ambient:{amplitudeSync:{onWave:80,onStatic:40,curve:"hypnotic"},frequencySync:{slow:.5,fast:1.2},durationSync:{minBeats:16,maxBeats:64}},ocean:{amplitudeSync:{onWave:90,onStatic:20,curve:"natural"},phaseSync:{multiplier:.8},melodicResponse:{multiplier:1.8}},electronic:{amplitudeSync:{onWave:70,onStatic:30,curve:"digital"},frequencySync:{slow:.8,fast:2.5,curve:"precise"}},orchestral:{amplitudeSync:{onWave:75,onStatic:35},phaseSync:{multiplier:.7},melodicResponse:{multiplier:2}}},dynamics:{forte:{amplitudeSync:{onWave:{multiplier:1.8},onStatic:{multiplier:1.4}},frequencySync:{multiplier:1.3},melodicResponse:{multiplier:2.2}},piano:{amplitudeSync:{onWave:{multiplier:.6},onStatic:{multiplier:.4}},frequencySync:{multiplier:.7},melodicResponse:{multiplier:1.1}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.atan2(s,a),r=Math.sqrt(a*a+s*s),l=Math.random()<.5?1:-1;e.gestureData.wave={startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,baseOpacity:e.opacity||e.life||1,angle:o,radius:r,offset:Math.random()*Math.PI*2,role:Math.random(),direction:l,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.wave?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.wave,r={...this.config,...i},l=i.strength||1,h=this.easeInOutSine(t),c=o.role*r.phaseShift,u=Math.max(0,h-c),d=u*Math.PI*2*r.frequency*o.direction+o.offset,m=.5+o.radius/100*.5,p=r.amplitude*m*l*e.scaleFactor,g=a+Math.sin(d)*p,f=s+Math.sin(2*d)*p*.3+-Math.abs(Math.sin(h*Math.PI))*r.liftHeight*e.scaleFactor,y=r.smoothness+.12*o.role;if(e.x+=(g-e.x)*y,e.y+=(f-e.y)*y,e.vx=.3*(g-e.x),e.vy=.3*(f-e.y),r.fadeInOut){let t;t=u<.1?u/.1:u>.9?(1-u)/.1:.5+.5*Math.sin(u*Math.PI),e.opacity=o.baseOpacity*(.3+.7*t),void 0!==e.life&&(e.life=e.opacity)}if(t>=.95){const i=20*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i),r.fadeInOut&&(e.opacity=o.baseOpacity*i,void 0!==e.life&&(e.life=e.opacity))}},cleanup(e){if(e.gestureData?.wave){const t=e.gestureData.wave;e.vx=t.originalVx,e.vy=t.originalVy,e.opacity=t.baseOpacity,void 0!==e.life&&(e.life=t.baseOpacity),delete e.gestureData.wave}},easeInOutSine:e=>-(Math.cos(Math.PI*e)-1)/2,"3d":{evaluate(e,t){const i=t?.strength||1,n=t?.frequency||1,a=-(Math.cos(Math.PI*e)-1)/2,s=a*Math.PI*2*n,o=.12*Math.sin(s)*i,r=.06*Math.sin(2*s)*i,l=.03*Math.sin(s)*i,h=.08*Math.sin(2*s)*i,c=.05*Math.sin(s)*i,u=1+.08*Math.abs(Math.sin(a*Math.PI))*i,d=Math.abs(Math.sin(s));return{position:[o,r,l],rotation:[h,0,c],scale:u,glowIntensity:1+.3*d*i,glowBoost:.6*d*i}}}},Ze={name:"drift",emoji:"☁️",type:"override",description:"Controlled floating with fade effects",config:{duration:800,distance:50,angle:45,returnToOrigin:!0,fadeOut:!1,holdTime:.2,turbulence:.1,angleSpread:45,smoothness:.08,easing:"ease",strength:1,particleMotion:{type:"drift",strength:1,distance:60}},rhythm:{enabled:!0,syncMode:"ambient",distanceSync:{quiet:30,loud:80,crescendo:"expand",diminuendo:"contract"},angleSync:{major:45,minor:225,modulation:"smooth",cadence:"return"},holdSync:{shortPhrase:.1,longPhrase:.4,fermata:"sustain"},accentResponse:{enabled:!0,multiplier:1.3,type:"distance"},patternOverrides:{ambient:{distanceSync:{quiet:40,loud:100},holdSync:{shortPhrase:.3,longPhrase:.6}},classical:{angleSync:{major:30,minor:210},distanceSync:{quiet:25,loud:60}},jazz:{angleSync:{major:60,minor:240,swing:!0,syncopated:!0}},new_age:{distanceSync:{quiet:35,loud:70},holdSync:{shortPhrase:.4,longPhrase:.8},angleSync:{modulation:"gradual"}}},dynamics:{forte:{distanceSync:{quiet:{multiplier:1.5},loud:{multiplier:1.8}},holdSync:{multiplier:1.2},accentResponse:{multiplier:1.6}},piano:{distanceSync:{quiet:{multiplier:.6},loud:{multiplier:.8}},holdSync:{multiplier:.8},accentResponse:{multiplier:1.1}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;let o=Math.atan2(s,a);const r={...this.config,...t}.angleSpread*Math.PI/180,l=(Math.random()-.5)*r;o+=l;const h=30+30*Math.random();e.gestureData.drift={startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,baseOpacity:e.opacity||e.life||1,driftAngle:o,angleOffset:l,homeRadius:h*e.scaleFactor,homeX:i+Math.cos(o)*h,homeY:n+Math.sin(o)*h,role:Math.random(),turbulencePhase:Math.random()*Math.PI*2,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.drift?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.drift,r={...this.config,...i},l=i.strength||1,h=this.easeInOutCubic(t),c=Math.max(0,h-.1*o.role);let u,d,m;if(r.returnToOrigin)if(c<.4){const e=c/.4,t=this.easeOutQuad(e);u=o.startX+(o.homeX-o.startX)*t,d=o.startY+(o.homeY-o.startY)*t}else if(c<.6+r.holdTime){const t=(c-.4)/(.2+r.holdTime);m=o.homeRadius+Math.sin(t*Math.PI*.5)*r.distance*l*e.scaleFactor}else{const t=(c-.6-r.holdTime)/(.4-r.holdTime);m=o.homeRadius+Math.cos(t*Math.PI*.5)*r.distance*l*e.scaleFactor}else{const t=c;m=o.homeRadius+t*r.distance*l*e.scaleFactor}if(void 0!==m){o.turbulencePhase+=r.turbulence*n;const e=Math.sin(o.turbulencePhase)*r.turbulence*10,t=Math.cos(1.3*o.turbulencePhase)*r.turbulence*10,i=o.driftAngle+o.angleOffset;u=a+Math.cos(i)*m+e,d=s+Math.sin(i)*m+t}const p=r.smoothness+.08*o.role;if(e.x+=(u-e.x)*p,e.y+=(d-e.y)*p,e.vx=.25*(u-e.x),e.vy=.25*(d-e.y),r.fadeOut){let i;i=t<.25?.3+t/.25*.7:t<.75?.7+.3*Math.sin((t-.25)*Math.PI/.5):4*(1-t),e.opacity=o.baseOpacity*i,void 0!==e.life&&(e.life=e.opacity)}t>=.99&&(e.vx=.1*o.originalVx,e.vy=.1*o.originalVy,r.fadeOut&&(e.opacity=o.baseOpacity,void 0!==e.life&&(e.life=o.baseOpacity)))},cleanup(e){if(e.gestureData?.drift){const t=e.gestureData.drift;e.vx=t.originalVx,e.vy=t.originalVy,e.opacity=t.baseOpacity,void 0!==e.life&&(e.life=t.baseOpacity),delete e.gestureData.drift}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutQuad:e=>e*(2-e),"3d":{evaluate(e,t){const i={...this.config,...t},n=t.strength||1,a=(i.angle||45)*Math.PI/180,s=i.returnToOrigin?e<.5?2*e:2*(1-e):e;return{position:[Math.cos(a)*s*.3*n,Math.sin(a)*s*.3*n,.15*Math.sin(e*Math.PI)*n],rotation:[0,10*s*n,0],scale:1+.03*Math.sin(e*Math.PI),glowIntensity:1-.1*s}}}},Je={name:"flicker",emoji:"⚡",type:"blending",description:"Rapid opacity changes with motion jitter",config:{duration:800,flickerRate:15,frequency:6,minOpacity:.3,maxOpacity:1,jitterAmount:2,colorShift:!1,strobe:!1,pulseMode:!1,groupFlicker:.3,easing:"linear",strength:.7,particleMotion:{type:"flicker",strength:.7,frequency:6}},rhythm:{enabled:!0,syncMode:"subdivision",rateSync:{subdivision:"sixteenth",onBeat:30,offBeat:10,triplet:20,curve:"step"},opacitySync:{pattern:"HLMH",subdivision:"eighth",onAccent:.1,regular:.5},jitterSync:{onBeat:5,offBeat:1,accent:10,curve:"random"},strobeSync:{verse:!1,chorus:!0,drop:"intense",pattern:"XOXO"},dynamics:{forte:{flickerRate:25,jitterAmount:5,minOpacity:.1},piano:{flickerRate:8,jitterAmount:1,minOpacity:.5}}},initialize(e,t){e.gestureData||(e.gestureData={});const i={...this.config,...t},n=Math.random()<i.groupFlicker;e.gestureData.flicker={baseOpacity:e.opacity||e.life||1,baseColor:e.color,baseX:e.x,baseY:e.y,flickerTimer:0,lastFlicker:0,flickerState:!0,isGrouped:n,groupId:n?Math.floor(3*Math.random()):-1,phase:Math.random()*Math.PI*2,colorHue:0,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.flicker?.initialized||this.initialize(e,i);const o=e.gestureData.flicker,r={...this.config,...i},l=i.strength||1;let h;if(o.flickerTimer+=n*r.flickerRate,r.strobe)h=(o.flickerTimer+o.phase)%1<.5?1:r.minOpacity;else if(r.pulseMode){const e=o.flickerTimer+o.phase;h=r.minOpacity+(r.maxOpacity-r.minOpacity)*(.5*Math.sin(e)+.5)}else{if(o.flickerTimer-o.lastFlicker>1)if(o.lastFlicker=o.flickerTimer,o.isGrouped){const e=Math.floor(o.flickerTimer)%3;o.flickerState=e===o.groupId}else o.flickerState=Math.random()>.3;const t=o.flickerState?r.maxOpacity:r.minOpacity+.3*Math.random(),i=e.opacity/o.baseOpacity;h=i+.3*(t-i)}const c=o.baseOpacity*(1+(h-1)*l);if(e.opacity=Math.max(0,Math.min(1,c)),void 0!==e.life&&(e.life=e.opacity),r.jitterAmount>0&&h>r.minOpacity){const t=r.jitterAmount*l*e.scaleFactor,i=(Math.random()-.5)*t*h,a=(Math.random()-.5)*t*h;e.vx+=.1*i*n,e.vy+=.1*a*n}if(r.colorShift&&e.color){o.colorHue+=.01*n;const t=30*Math.sin(o.colorHue);e.color=this.shiftHue(o.baseColor,t*l)}let u=1;t<.1?u=t/.1:t>.9&&(u=(1-t)/.1),e.opacity*=u,void 0!==e.life&&(e.life=e.opacity),t>.8&&(e.vx*=.95,e.vy*=.95)},shiftHue(e,t){if(!e||!e.startsWith("#"))return e;const i=e.slice(1),n=parseInt(i.substr(0,2),16)/255,a=parseInt(i.substr(2,2),16)/255,s=parseInt(i.substr(4,2),16)/255,o=t*Math.PI/180,r=Math.cos(o),l=Math.sin(o),h=n*l+a*r,c=s,u=e=>Math.max(0,Math.min(255,Math.round(255*e))).toString(16).padStart(2,"0");return`#${u(n*r-a*l)}${u(h)}${u(c)}`},cleanup(e){if(e.gestureData?.flicker){const t=e.gestureData.flicker;e.opacity=t.baseOpacity,e.color=t.baseColor,void 0!==e.life&&(e.life=t.baseOpacity),delete e.gestureData.flicker}},"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||.7,a=i.flickerRate||15;i.minOpacity;const s=e*a,o=Math.sin(s*Math.PI*2),r=Math.floor(10*s),l=.3*o+.5*(Math.sin(123.456*r)+1)*.7,h=.6+.8*l,c=i.jitterAmount||2,u=.003*n*h,d=(Math.random()-.5)*c*u,m=(Math.random()-.5)*c*u,p=.03*(Math.random()-.5)*n*h;return{position:[d,m,0],rotation:[.5*p,0,p],scale:1+.08*(h-1),glowIntensity:h,glowBoost:1.2*l}}}},Ke={name:"burst",emoji:"💥",type:"blending",description:"Explosive outward burst from center",config:{decay:.5,strength:2},rhythm:{enabled:!0,syncMode:"beat",strengthSync:{onBeat:3.5,offBeat:1,curve:"explosion"},decaySync:{mode:"tempo",fast:.8,slow:.3,curve:"exponential"},durationSync:{mode:"beats",beats:.5,sustain:!1},accentResponse:{enabled:!0,multiplier:2.5,type:"strength"},patternOverrides:{rock:{strengthSync:{onBeat:4,offBeat:1.5},decaySync:{fast:.6,slow:.4}},electronic:{strengthSync:{onBeat:3.8,offBeat:.8,curve:"sharp"},decaySync:{fast:.9,slow:.7}},jazz:{strengthSync:{onBeat:2.8,offBeat:1.8,swing:!0},decaySync:{fast:.5,slow:.2}},orchestral:{strengthSync:{onBeat:3.2,offBeat:.5},accentResponse:{multiplier:3}}},dynamics:{forte:{strengthSync:{onBeat:{multiplier:2},offBeat:{multiplier:1.5}},decaySync:{multiplier:.7},accentResponse:{multiplier:3.5}},piano:{strengthSync:{onBeat:{multiplier:.6},offBeat:{multiplier:.3}},decaySync:{multiplier:1.3},accentResponse:{multiplier:1.8}}}},apply(e,t,i,n,a,s){const o=i.decay||this.config.decay,r=(i.strength||this.config.strength)*(1-t*o),l=e.x-a,h=e.y-s,c=Math.sqrt(l*l+h*h);c>1&&(e.vx+=l/c*r*2*n,e.vy+=h/c*r*2*n)},"3d":{evaluate(e,t){const i={...this.config,...t}.decay||.5,n=e<.3?.3-e:0;return{position:[0,0,0],rotation:[0,0,0],scale:1+(e<.2?5*e:1.5*(1-e))*((t.strength||2)*(1-e*i)),glowIntensity:1+Math.min(1*n,.3),glowBoost:2.5*n}}}},et={name:"directional",emoji:"➡️",type:"blending",description:"Move particles in a specific direction",config:{angle:0,returnToOrigin:!1,strength:1},rhythm:{enabled:!0,syncMode:"flow",angleSync:{verse:0,chorus:90,bridge:180,outro:270,transition:"smooth"},strengthSync:{onBeat:1.8,offBeat:.6,curve:"wave"},returnSync:{enabled:!0,onSectionChange:!0,duration:"transition",strength:1.2},accentResponse:{enabled:!0,multiplier:2,type:"strength"},patternOverrides:{march:{angleSync:{verse:0,chorus:0},strengthSync:{onBeat:2.5,offBeat:1}},waltz:{angleSync:{verse:45,chorus:135,bridge:225,outro:315,transition:"circular"}},swing:{strengthSync:{onBeat:1.6,offBeat:1.4,swing:!0}},electronic:{angleSync:{transition:"instant"},strengthSync:{onBeat:2.2,offBeat:.4,curve:"sharp"}}},dynamics:{forte:{strengthSync:{onBeat:{multiplier:1.6},offBeat:{multiplier:1.2}},angleSync:{transition:"sharp"},accentResponse:{multiplier:2.5}},piano:{strengthSync:{onBeat:{multiplier:.7},offBeat:{multiplier:.8}},angleSync:{transition:"gradual"},accentResponse:{multiplier:1.4}}}},initialize(e){e.gestureData||(e.gestureData={}),e.gestureData.directional={initialX:e.x,initialY:e.y}},apply(e,t,i,n,a,s){e.gestureData?.directional||this.initialize(e);const o=(i.angle||this.config.angle)*Math.PI/180,r=i.strength||this.config.strength;if(e.vx+=Math.cos(o)*r*.3*n,e.vy+=Math.sin(o)*r*.3*n,i.returnToOrigin&&t>.5){const i=2*(t-.5),a=e.gestureData.directional,s=a.initialX-e.x,o=a.initialY-e.y;e.vx+=s*i*.02*n,e.vy+=o*i*.02*n}},"3d":{evaluate(e,t){const i={...this.config,...t},n=(i.angle||0)*Math.PI/180,a=t.strength||1,s=i.returnToOrigin?e<.5?2*e:2*(1-e):e;return{position:[Math.cos(n)*s*.4*a,Math.sin(n)*s*.4*a,0],rotation:[0,0,0],scale:1,glowIntensity:1}}}},tt={name:"settle",emoji:"🍃",type:"blending",description:"Gradually settle particles to rest",config:{damping:.02,threshold:.01},rhythm:{enabled:!0,syncMode:"resolution",dampingSync:{onResolution:.035,onTension:.015,curve:"gradual"},thresholdSync:{mode:"dynamics",forte:.02,piano:.005,curve:"exponential"},durationSync:{mode:"phrase",minBeats:2,maxBeats:12,sustain:!0},cadenceResponse:{enabled:!0,multiplier:1.6,type:"damping"},patternOverrides:{ambient:{dampingSync:{onResolution:.025,onTension:.008,curve:"atmospheric"},durationSync:{minBeats:8,maxBeats:32}},jazz:{dampingSync:{onResolution:.04,onTension:.02},cadenceResponse:{multiplier:1.8}},classical:{dampingSync:{onResolution:.045,onTension:.012,curve:"expressive"},cadenceResponse:{multiplier:2}},minimalist:{dampingSync:{onResolution:.02,onTension:.005},durationSync:{minBeats:16,maxBeats:64}}},dynamics:{forte:{dampingSync:{onResolution:{multiplier:1.4},onTension:{multiplier:.8}},thresholdSync:{multiplier:2},cadenceResponse:{multiplier:2.2}},piano:{dampingSync:{onResolution:{multiplier:.7},onTension:{multiplier:1.2}},thresholdSync:{multiplier:.5},cadenceResponse:{multiplier:1.3}}}},apply(e,t,i,n,a,s){const o=i.damping||this.config.damping,r=i.threshold||this.config.threshold;e.vx*=Math.max(0,1-o*n*60),e.vy*=Math.max(0,1-o*n*60),Math.abs(e.vx)<r&&(e.vx=0),Math.abs(e.vy)<r&&(e.vy=0)},"3d":{evaluate(e,t){const i=1-Math.pow(1-e,2),n=.01*(1-i);return{position:[Math.sin(e*Math.PI*2)*n,Math.cos(e*Math.PI*3)*n*.5,0],rotation:[0,0,0],scale:1-.03*i,glowIntensity:1-.15*i}}}},it={name:"fade",emoji:"👻",type:"blending",description:"Fade particle opacity",config:{duration:2e3,fadeIn:!0,fadeOut:!0,minOpacity:0,maxOpacity:1},rhythm:{enabled:!0,syncMode:"dynamic",opacitySync:{onBeat:.9,offBeat:.3,subdivision:"eighth",curve:"exponential"},fadePhaseSync:{verse:{fadeIn:!0,fadeOut:!1},chorus:{fadeIn:!1,fadeOut:!1},bridge:{fadeIn:!0,fadeOut:!0},outro:{fadeIn:!1,fadeOut:!0}},pulseSync:{enabled:!0,frequency:"quarter",intensity:.2,onAccent:.4},dynamics:{forte:{minOpacity:.5,maxOpacity:1},piano:{minOpacity:0,maxOpacity:.4}}},initialize(e){e.gestureData||(e.gestureData={}),e.gestureData.fade={baseOpacity:e.opacity||e.life||1}},apply(e,t,i,n,a,s){e.gestureData?.fade||this.initialize(e);const o=e.gestureData.fade,r={...this.config,...i};let l;l=r.fadeIn&&!r.fadeOut?r.minOpacity+(r.maxOpacity-r.minOpacity)*t:r.fadeOut&&!r.fadeIn?r.maxOpacity-(r.maxOpacity-r.minOpacity)*t:t<.5?r.minOpacity+(r.maxOpacity-r.minOpacity)*(2*t):r.maxOpacity-(r.maxOpacity-r.minOpacity)*(2*(t-.5)),e.opacity=o.baseOpacity*l,void 0!==e.life&&(e.life=e.opacity)},cleanup(e){e.gestureData?.fade&&(e.opacity=e.gestureData.fade.baseOpacity,void 0!==e.life&&(e.life=e.opacity),delete e.gestureData.fade)},"3d":{evaluate(e,t){const i={...this.config,...t};let n;const a=i.minOpacity??0,s=i.maxOpacity??1;return n=i.fadeIn&&!i.fadeOut?a+(s-a)*e:i.fadeOut&&!i.fadeIn?s-(s-a)*e:e<.5?s-2*e*(s-a):a+2*(e-.5)*(s-a),{position:[0,0,0],rotation:[0,0,0],scale:1,glowIntensity:n}}}},nt={name:"hold",emoji:"⏸️",type:"override",description:"Hold particles in current position",config:{holdStrength:.95,allowDrift:!1},rhythm:{enabled:!0,syncMode:"rest",holdSync:{onRest:.98,onSound:.8,curve:"immediate"},durationSync:{mode:"rests",minBeats:.5,maxBeats:8,sustain:!0},pauseResponse:{enabled:!0,multiplier:1.5,type:"strength"},patternOverrides:{classical:{holdSync:{onRest:.99,onSound:.75,curve:"dramatic"},pauseResponse:{multiplier:2}},minimal:{holdSync:{onRest:.95,onSound:.85},durationSync:{minBeats:2,maxBeats:16}},jazz:{holdSync:{onRest:.9,onSound:.7},allowDrift:!0},electronic:{holdSync:{onRest:.99,onSound:.6,curve:"digital"},pauseResponse:{multiplier:1.2}}},dynamics:{forte:{holdSync:{onRest:{multiplier:1.02},onSound:{multiplier:.9}},pauseResponse:{multiplier:2.2}},piano:{holdSync:{onRest:{multiplier:.97},onSound:{multiplier:.85}},pauseResponse:{multiplier:1.3}}}},initialize(e){e.gestureData||(e.gestureData={}),e.gestureData.hold={holdX:e.x,holdY:e.y,originalVx:e.vx,originalVy:e.vy}},apply(e,t,i,n,a,s){e.gestureData?.hold||this.initialize(e);const o=e.gestureData.hold,r=i.holdStrength||this.config.holdStrength;if(i.allowDrift?(e.vx*=r,e.vy*=r):(e.x+=(o.holdX-e.x)*(1-r),e.y+=(o.holdY-e.y)*(1-r),e.vx=0,e.vy=0),t>.9){const i=10*(t-.9);e.vx=e.vx*(1-i)+o.originalVx*i,e.vy=e.vy*(1-i)+o.originalVy*i}},cleanup(e){if(e.gestureData?.hold){const t=e.gestureData.hold;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.hold}},"3d":{evaluate:(e,t)=>({position:[0,0,0],rotation:[0,0,0],scale:1,glowIntensity:1})}},at={name:"breathe",emoji:"🫁",type:"blending",description:"Breathing rhythm with inhale and exhale",config:{musicalDuration:{musical:!0,bars:1,minBeats:2,maxBeats:16},phases:[{name:"inhale",beats:1.5},{name:"hold_in",beats:.5},{name:"exhale",beats:1.5},{name:"hold_out",beats:.5}],inhaleRadius:1.5,exhaleRadius:.3,breathRate:.3,spiralStrength:.002,scaleAmount:.25,glowAmount:.4,frequency:1,easing:"sine",strength:.8,particleMotion:{type:"breathe",strength:.8,inhaleRadius:1.5,exhaleRadius:.3}},rhythm:{enabled:!0,syncMode:"phrase",breathRateSync:{mode:"tempo",bpm:"auto",subdivision:"whole",curve:"sine"},radiusSync:{inhale:{onUpbeat:1.8,onDownbeat:1.4,curve:"ease-in"},exhale:{onUpbeat:.2,onDownbeat:.4,curve:"ease-out"}},durationSync:{mode:"phrases",phrases:2,hold:"fermata"},accentResponse:{enabled:!0,multiplier:1.5,type:"expansion"},patternOverrides:{ballad:{breathRateSync:{subdivision:"double-whole"},radiusSync:{inhale:{onUpbeat:2.2,onDownbeat:1.8},exhale:{onUpbeat:.1,onDownbeat:.2}}},uptempo:{breathRateSync:{subdivision:"half"},radiusSync:{inhale:{onUpbeat:1.4,onDownbeat:1.2},exhale:{onUpbeat:.3,onDownbeat:.4}}},ambient:{breathRateSync:{subdivision:"whole",curve:"ease"},radiusSync:{inhale:{onUpbeat:1.6,onDownbeat:1.6},exhale:{onUpbeat:.2,onDownbeat:.2}}}},dynamics:{forte:{radiusSync:{inhale:{multiplier:1.8},exhale:{multiplier:.5}},spiralStrength:.004,scaleAmount:.4},piano:{radiusSync:{inhale:{multiplier:1.2},exhale:{multiplier:.8}},spiralStrength:.001,scaleAmount:.1}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.breathe={startX:e.x,startY:e.y,angle:Math.atan2(s,a),baseRadius:Math.sqrt(a*a+s*s),phaseOffset:.2*Math.random()-.1}},apply(e,t,i,n,a,s){e.gestureData?.breathe||this.initialize(e,i,a,s);const o={...this.config,...i},r=(Math.sin(t*Math.PI*2*o.breathRate)+1)/2,l=100*(e.scaleFactor||1),h=o.inhaleRadius*l,c=o.exhaleRadius*l,u=c+(h-c)*r,d=e.x-a,m=e.y-s,p=Math.sqrt(d*d+m*m),g=u-p,f=.05*(i.strength||.8)*n;if(p>0){const t=d/p*g*f,a=m/p*g*f;e.vx+=t,e.vy+=a;const s=o.spiralStrength*n*(i.strength||1),l=-m/p,h=d/p;e.vx+=l*s*r,e.vy+=h*s*r}e.vx*=.98,e.vy*=.98},cleanup(e){e.gestureData?.breathe&&delete e.gestureData.breathe},"3d":{evaluate(e,t){const i=(t.config||{}).breathRate||.3,n=Math.sin(e*Math.PI*2*i);let a=1;if(e>.8){const t=(e-.8)/(1-.8);a=1-t*t*t}const s=.2*n*a;return{position:[0,.05*n*a,0],rotation:[0,0,0],scale:1+.35*n*a,glowIntensity:1+s,glowBoost:Math.max(0,2*s)}}}},st={name:"expand",emoji:"💫",type:"blending",description:"Radial expansion from center",config:{duration:600,scaleAmount:3,scaleTarget:3,glowAmount:.5,easing:"back",strength:3,particleMotion:{type:"pulse",strength:3,direction:"outward",persist:!0}},rhythm:{enabled:!0,syncMode:"crescendo",strengthSync:{pianissimo:1.5,fortissimo:5,crescendo:"build",sforzando:"burst"},scaleTargetSync:{verse:2,chorus:4.5,climax:6,curve:"exponential"},durationSync:{mode:"phrases",build:1.2,release:.8,sustain:"hold"},accentResponse:{enabled:!0,multiplier:2.8,type:"strength"},patternOverrides:{orchestral:{strengthSync:{pianissimo:2,fortissimo:6.5,crescendo:"dramatic"},scaleTargetSync:{climax:8}},rock:{strengthSync:{pianissimo:1.8,fortissimo:5.5,curve:"power"},accentResponse:{multiplier:3.2}},ambient:{strengthSync:{pianissimo:1.2,fortissimo:3.5,crescendo:"organic"},durationSync:{build:1.8,release:1.2}},electronic:{strengthSync:{pianissimo:1.6,fortissimo:4.8,curve:"digital"},scaleTargetSync:{curve:"linear"}}},dynamics:{forte:{strengthSync:{pianissimo:{multiplier:1.4},fortissimo:{multiplier:1.8}},scaleTargetSync:{multiplier:1.6},accentResponse:{multiplier:3.5}},piano:{strengthSync:{pianissimo:{multiplier:.8},fortissimo:{multiplier:1.2}},scaleTargetSync:{multiplier:.7},accentResponse:{multiplier:2}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.expand={startX:e.x,startY:e.y,angle:Math.atan2(s,a),baseRadius:Math.sqrt(a*a+s*s),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.expand?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.expand,r={...this.config,...i},l=r.strength||1,h=1+(r.scaleTarget-1)*t*l,c=o.baseRadius*h,u=a+Math.cos(o.angle)*c,d=s+Math.sin(o.angle)*c,m=u-e.x,p=d-e.y;e.vx+=.8*m*n,e.vy+=.8*p*n,e.vx*=.95,e.vy*=.95},cleanup(e){e.gestureData?.expand&&delete e.gestureData.expand},"3d":{evaluate(e,t){const i={...this.config,...t},n=i.strength||3;return{position:[0,0,0],rotation:[0,0,0],scale:1+e*(i.scaleAmount||3)*(n/3),glowIntensity:1+.25*e,glowBoost:.8*e}}}},ot={name:"contract",emoji:"🌀",type:"blending",description:"Radial contraction toward center",config:{duration:600,scaleAmount:.2,scaleTarget:.2,glowAmount:-.2,easing:"cubic",strength:2.5,particleMotion:{type:"pulse",strength:2.5,direction:"inward",persist:!0}},rhythm:{enabled:!0,syncMode:"tension",strengthSync:{onTension:4,onRelease:1.5,curve:"magnetic"},scaleTargetSync:{forte:.1,piano:.4,crescendo:"gradual",diminuendo:"ease"},durationSync:{mode:"phrases",shortPhrase:.8,longPhrase:1.5,hold:"sustain"},accentResponse:{enabled:!0,multiplier:2.2,type:"strength"},patternOverrides:{classical:{strengthSync:{onTension:3.5,onRelease:1.8},scaleTargetSync:{forte:.15,piano:.35}},metal:{strengthSync:{onTension:5,onRelease:2,curve:"sharp"},scaleTargetSync:{forte:.05,piano:.25}},ambient:{strengthSync:{onTension:2.8,onRelease:1.2,curve:"ease"},durationSync:{shortPhrase:1.2,longPhrase:2}},trap:{strengthSync:{onTension:4.5,onRelease:1,dropBeat:6},scaleTargetSync:{forte:.08,piano:.3}}},dynamics:{forte:{strengthSync:{onTension:{multiplier:1.8},onRelease:{multiplier:1.4}},scaleTargetSync:{multiplier:.6},accentResponse:{multiplier:2.8}},piano:{strengthSync:{onTension:{multiplier:.7},onRelease:{multiplier:.8}},scaleTargetSync:{multiplier:1.4},accentResponse:{multiplier:1.6}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.contract={startX:e.x,startY:e.y,angle:Math.atan2(s,a),baseRadius:Math.sqrt(a*a+s*s),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.contract?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.contract,r={...this.config,...i},l=r.strength||1,h=1-(1-r.scaleTarget)*t*l,c=o.baseRadius*h,u=a+Math.cos(o.angle)*c,d=s+Math.sin(o.angle)*c,m=u-e.x,p=d-e.y;e.vx+=.5*m*n,e.vy+=.5*p*n,e.vx*=.95,e.vy*=.95},cleanup(e){e.gestureData?.contract&&delete e.gestureData.contract},"3d":{evaluate(e,t){const i={...this.config,...t},n=i.strength||2.5,a=i.scaleTarget||.2,s=1-e*(1-a)*(n/2.5),o=1-.15*e;return{position:[0,0,0],rotation:[0,0,0],scale:Math.max(a,s),glowIntensity:o}}}},rt={name:"flash",emoji:"⚡",type:"blending",description:"Bright flash burst effect",config:{duration:400,glowAmount:2.5,glowPeak:3,scalePeak:1.1,easing:"cubic",strength:1,particleMotion:{type:"burst",strength:1,decay:.3}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"immediate",interruptible:!0,priority:8,blendable:!0,intensitySync:{onBeat:3.5,offBeat:1,accent:5,subdivision:"quarter",curve:"exponential"},durationSync:{mode:"tempo",baseDuration:400,scaling:"inverse"},scaleSync:{onBeat:1.2,offBeat:1,accent:1.4,curve:"elastic"},strobeSync:{enabled:!1,pattern:"XXOX",subdivision:"sixteenth"},dynamics:{forte:{glowPeak:4,scalePeak:1.3,duration:300},piano:{glowPeak:2,scalePeak:1.05,duration:500}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.flash={originalOpacity:e.opacity,originalSize:e.size,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.flash?.initialized||this.initialize(e,i);const o=e.gestureData.flash,r={...this.config,...i},l=r.strength||1;let h;if(h=t<.3?t/.3*r.glowPeak:r.glowPeak*(1-(t-.3)/.7),e.opacity=Math.min(1,o.originalOpacity*(1+h*l)),e.size=o.originalSize*(1+(r.scalePeak-1)*h*l*.1),t<.2){const i=(1-t/.2)*l,o=Math.atan2(e.y-s,e.x-a);e.vx+=Math.cos(o)*i*2*n,e.vy+=Math.sin(o)*i*2*n}e.vx*=1-.1*r.particleMotion.decay,e.vy*=1-.1*r.particleMotion.decay},cleanup(e){e.gestureData?.flash&&(e.opacity=e.gestureData.flash.originalOpacity,e.size=e.gestureData.flash.originalSize,delete e.gestureData.flash)},"3d":{evaluate(e,t){const i={...this.config,...t};let n;t.strength,n=e<.3?e/.3:1-(e-.3)/.7;const a=1+.4*n;return{position:[0,0,0],rotation:[0,0,0],scale:1+n*((i.scalePeak||1.1)-1),glowIntensity:a,glowBoost:2*n}}}},lt={name:"glow",emoji:"✨",type:"blending",description:"Pure luminous glow without movement",config:{duration:1500,amplitude:0,frequency:1,holdPeak:.3,easing:"sine",scaleAmount:.1,glowAmount:.8,strength:0,direction:"none",particleMotion:{type:"glow",strength:0,direction:"none",frequency:1}},rhythm:{enabled:!0,syncMode:"phrase",amplitudeSync:{onBeat:2,offBeat:1.2,curve:"smooth"},frequencySync:{mode:"phrase",subdivision:"bar"},durationSync:{mode:"bars",bars:2},accentResponse:{enabled:!0,multiplier:2.5},patternOverrides:{ambient:{amplitudeSync:{onBeat:2.5,offBeat:1.8},durationSync:{bars:4}},electronic:{amplitudeSync:{onBeat:3,offBeat:.5,curve:"sharp"},frequencySync:{subdivision:"quarter"}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={}),e.gestureData.glow={startOpacity:e.opacity,startGlow:e.glowSizeMultiplier||0,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.glow?.initialized||this.initialize(e,i,a,s);const o={...this.config,...i},r=this.easeInOutSine(t);let l,{frequency:h}=o,{glowAmount:c}=o;i.rhythmModulation&&(c*=i.rhythmModulation.amplitudeMultiplier||1,c*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(h*=i.rhythmModulation.frequencyMultiplier));const u=r*h*2%2;l=o.holdPeak>0&&u>1-o.holdPeak&&u<1+o.holdPeak?1:Math.sin(r*Math.PI*2*h);let d=1;t>.9&&(d=.5+.5*(1-10*(t-.9))),e.glowIntensity=1+l*c*d},cleanup(e){e.gestureData?.glow&&(e.glowIntensity=1,delete e.gestureData.glow)},easeInOutSine:e=>-(Math.cos(Math.PI*e)-1)/2,"3d":{evaluate(e,t){const i={...this.config,...t},n=-(Math.cos(Math.PI*e)-1)/2,a=Math.sin(n*Math.PI);let s=i.glowAmount||.8;t.rhythmModulation&&(s*=t.rhythmModulation.amplitudeMultiplier||1,s*=t.rhythmModulation.accentMultiplier||1);const o=1+a*s;return{position:[0,0,0],rotation:[0,0,0],scale:1+a*(i.scaleAmount||.1)*.5,glowIntensity:o,glowBoost:1.5*a}}}},ht={name:"peek",emoji:"👀",type:"effect",description:"Quick peek and hide motion",config:{peekDistance:40,peekSpeed:.15,holdDuration:200,hideSpeed:.25,stagger:!0,duration:1500},rhythm:{enabled:!0,syncMode:"accent",distanceSync:{onAccent:60,offAccent:25,curve:"quick"},speedSync:{mode:"tempo",fast:.25,slow:.1,hideMultiplier:1.8},durationSync:{mode:"subdivision",beats:.25,staggerBeats:.125,sustain:!1},syncopationResponse:{enabled:!0,multiplier:1.8,type:"distance"},patternOverrides:{funk:{distanceSync:{onAccent:70,offAccent:35,curve:"funky"},syncopationResponse:{multiplier:2.2}},latin:{speedSync:{fast:.3,slow:.12},durationSync:{beats:.5,staggerBeats:.25}},breakbeat:{distanceSync:{onAccent:55,offAccent:40},syncopationResponse:{multiplier:2.5}},classical:{distanceSync:{onAccent:45,offAccent:20,curve:"elegant"},speedSync:{fast:.18,slow:.08}}},dynamics:{forte:{distanceSync:{onAccent:{multiplier:1.6},offAccent:{multiplier:1.3}},speedSync:{multiplier:1.4},syncopationResponse:{multiplier:2.8}},piano:{distanceSync:{onAccent:{multiplier:.6},offAccent:{multiplier:.4}},speedSync:{multiplier:.7},syncopationResponse:{multiplier:1.2}}}},apply(e,t,i,n,a,s){if(e.gestureData||(e.gestureData={}),!e.gestureData.peek){const t=e.x-a,i=e.y-s,n=Math.atan2(i,t),o=Math.sqrt(t*t+i*i);e.gestureData.peek={originalX:e.x,originalY:e.y,peekAngle:n,originalDistance:o,staggerDelay:this.config.stagger?.3*Math.random():0,phase:"waiting",phaseTimer:0,peekOffset:{x:0,y:0}}}const o=e.gestureData.peek,{config:r}=this,l=Math.max(0,Math.min(1,(t-o.staggerDelay)/(1-o.staggerDelay)));0===l?o.phase="waiting":l<.3?o.phase="peeking":l<.6?o.phase="holding":l<1&&(o.phase="hiding");let h=0;switch(o.phase){case"peeking":{const e=l/.3;h=this.easeOutCubic(e)*r.peekDistance;break}case"holding":h=r.peekDistance,Math.random()<.1&&(o.peekOffset.x+=2*(Math.random()-.5),o.peekOffset.y+=2*(Math.random()-.5));break;case"hiding":{const e=(l-.6)/.4;h=(1-this.easeInCubic(e))*r.peekDistance;break}}if("waiting"!==o.phase){const t=Math.cos(o.peekAngle)*h,i=Math.sin(o.peekAngle)*h;o.peekOffset.x+=(t-o.peekOffset.x)*r.peekSpeed,o.peekOffset.y+=(i-o.peekOffset.y)*r.peekSpeed,e.x=o.originalX+o.peekOffset.x,e.y=o.originalY+o.peekOffset.y}void 0!==e.alpha&&("peeking"===o.phase||"holding"===o.phase?e.alpha=.7+.3*Math.random():e.alpha=1)},easeOutCubic:e=>1-Math.pow(1-e,3),easeInCubic:e=>e*e*e,cleanup(e){e.gestureData?.peek&&(e.x=e.gestureData.peek.originalX,e.y=e.gestureData.peek.originalY,void 0!==e.alpha&&(e.alpha=1),delete e.gestureData.peek)},"3d":{evaluate(e,t){const i=.01*({...this.config,...t}.peekDistance||40);let n=0,a=1;if(e<.3){const t=e/.3;n=(1-Math.pow(1-t,3))*i}else if(e<.6)n=i,a=.7+.3*Math.random();else{const t=(e-.6)/.4;n=(1-Math.pow(t,3))*i}return{position:[n,0,0],rotation:[0,0,0],scale:1,glowIntensity:a}}}},ct={name:"runningman",emoji:"🏃",type:"effect",description:"Hip-hop running man shuffle",config:{duration:2e3,slideDistance:30,stepHeight:15,speed:1.2,strength:.8,particleMotion:{type:"runningman",strength:.7}},rhythm:{enabled:!0,syncToBeat:!0,beatMultiplier:1,accentBeats:[1,3]},apply:(e,t,i,n,a,s)=>!1,blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i={...this.config,...t}.strength||.8;return{position:[.1*Math.sin(e*Math.PI*4)*i,.05*Math.abs(Math.sin(e*Math.PI*8))*i,0],rotation:[0,0,.035*Math.sin(e*Math.PI*4)*i],scale:1-.035*Math.abs(Math.sin(e*Math.PI*8))*i,glowIntensity:1+.25*Math.abs(Math.sin(e*Math.PI*8)),glowBoost:.35*Math.max(0,Math.abs(Math.sin(e*Math.PI*8)))}}}},ut={name:"charleston",emoji:"🕺",type:"effect",description:"Hip-hop Charleston shuffle with crisscross",config:{duration:2500,kickDistance:35,swivelRange:40,bounceHeight:12,strength:.9,particleMotion:{type:"charleston",strength:.8}},rhythm:{enabled:!0,syncToBeat:!0,beatMultiplier:2,accentBeats:[1,2.5,3,4.5]},apply:(e,t,i,n,a,s)=>!1,blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i={...this.config,...t}.strength||.9;return{position:[.12*Math.sin(e*Math.PI*8)*i,.05*Math.abs(Math.sin(e*Math.PI*8))*i,0],rotation:[0,0,.05*Math.sin(e*Math.PI*8)*i],scale:1-.04*Math.abs(Math.sin(e*Math.PI*8))*i,glowIntensity:1+.3*Math.abs(Math.sin(e*Math.PI*8)),glowBoost:.4*Math.max(0,Math.abs(Math.sin(e*Math.PI*8)))}}}};const dt=[Be,ke,Te,Ee,Ie,Ae,Re,ze,_e,Oe,{name:"sparkle",emoji:"✨",type:"blending",description:"Bright twinkling sparkle bursts",config:{duration:800,musicalDuration:{musical:!0,beats:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",durationSync:{mode:"beats",beats:2},interruptible:!0,priority:5,blendable:!0},apply:(e,t,i)=>!1,blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i=t?.strength||1,n=Math.pow(Math.max(0,Math.sin(e*Math.PI*6)),3),a=Math.pow(Math.max(0,Math.sin(e*Math.PI*8+1)),3),s=Math.pow(Math.max(0,Math.sin(e*Math.PI*10+2)),3),o=Math.max(n,a,s)*Math.sin(e*Math.PI);return{position:[0,0,0],rotation:[0,0,0],scale:1+.08*o*i,glowIntensity:1+.5*o*i,glowBoost:2*o*i}}}},{name:"shimmer",emoji:"🌟",type:"particle",description:"Shimmer effect with sparkling particles",config:{duration:2e3,musicalDuration:{musical:!0,bars:1},particleMotion:"radiant"},rhythm:{enabled:!0,syncType:"beat",durationSync:{mode:"bars",bars:1},intensity:.8},override:(e,t,i)=>(e.shimmerEffect=!0,e.shimmerProgress=t,!0),blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i=t?.strength||1,n=(.4*Math.sin(e*Math.PI*4)+.35*Math.sin(e*Math.PI*6+.5)+.25*Math.sin(e*Math.PI*10+1)+1)/2;return{position:[0,0,0],rotation:[0,0,0],scale:1+.05*n*i,glowIntensity:1+.3*n*i,glowBoost:1*n*i}}}},Fe,((e,t="✨")=>({name:e,emoji:t,type:"blending",description:`${e} animation`,config:{duration:1e3,musicalDuration:{musical:!0,beats:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",durationSync:{mode:"beats",beats:2},interruptible:!0,priority:3,blendable:!0,crossfadePoint:"anyBeat",maxQueue:3},apply:(e,t,i)=>!1,blend:(e,t,i)=>!1}))("groove","🎵"),Ve,Ge,qe,Le,{name:"rain",emoji:"🌧️",type:"particle",description:"Rain effect with falling particles",config:{duration:3e3,musicalDuration:{musical:!0,bars:2},particleMotion:"falling"},rhythm:{enabled:!0,syncType:"off-beat",durationSync:{mode:"bars",bars:2},intensity:.8},apply:(e,t,i)=>(e.rainEffect=!0,e.rainProgress=t,!0),blend:(e,t,i)=>!1}],mt=[Ne,je,Ue,He,We,Xe,Ye,$e],pt=[Qe,Ze,Je,Ke,et,tt,it,nt,at,st,ot,rt,lt,ht,ct,ut],gt={};function ft(e){if(gt[e])return gt[e];return Pe(e)||null}[...dt,...mt,...pt].forEach(e=>{gt[e.name]=e}),dt.map(e=>e.name),mt.map(e=>e.name),pt.map(e=>e.name);const yt={none:{speed:1,amplitude:1,intensity:1,smoothness:1,regularity:1,"3d":{rotation:{speedMultiplier:1,shakeMultiplier:1},glow:{intensityMultiplier:1,pulseSpeedMultiplier:1},scale:{breathDepthMultiplier:1,breathRateMultiplier:1},righting:{strengthMultiplier:1}}},clear:{speed:1,amplitude:1,intensity:1,smoothness:1,regularity:1,"3d":{rotation:{speedMultiplier:1,shakeMultiplier:1},glow:{intensityMultiplier:1,pulseSpeedMultiplier:1},scale:{breathDepthMultiplier:1,breathRateMultiplier:1},righting:{strengthMultiplier:1}}},nervous:{speed:1.2,amplitude:.9,intensity:1.1,smoothness:.7,regularity:.6,addFlutter:!0,addMicroShake:!0,"3d":{rotation:{speedMultiplier:1.5,shakeMultiplier:3.5,enableEpisodicWobble:!0},glow:{intensityMultiplier:1.25,pulseSpeedMultiplier:2},scale:{breathDepthMultiplier:.5,breathRateMultiplier:1.8},righting:{strengthMultiplier:.7}}},confident:{speed:.9,amplitude:1.3,intensity:1.2,smoothness:1.1,regularity:1.2,addPower:!0,addHold:!0,"3d":{rotation:{speedMultiplier:.7,shakeMultiplier:.2},glow:{intensityMultiplier:1.4,pulseSpeedMultiplier:.7},scale:{breathDepthMultiplier:1.5,breathRateMultiplier:.7},righting:{strengthMultiplier:1.6}}},tired:{speed:.7,amplitude:.7,intensity:.8,smoothness:1.3,regularity:.8,addDroop:!0,addPause:!0,"3d":{rotation:{speedMultiplier:.4,shakeMultiplier:.15},glow:{intensityMultiplier:.5,pulseSpeedMultiplier:.5},scale:{breathDepthMultiplier:1.3,breathRateMultiplier:.5},righting:{strengthMultiplier:.6}}},intense:{speed:1.3,amplitude:1.2,intensity:1.4,smoothness:.6,regularity:.9,addPulse:!0,addFocus:!0,"3d":{rotation:{speedMultiplier:1.6,shakeMultiplier:2.5},glow:{intensityMultiplier:1.8,pulseSpeedMultiplier:2.2},scale:{breathDepthMultiplier:1.6,breathRateMultiplier:1.8},righting:{strengthMultiplier:1.3}}},subdued:{speed:.8,amplitude:.8,intensity:.7,smoothness:1.2,regularity:1.1,addSoftness:!0,addFade:!0,"3d":{rotation:{speedMultiplier:.5,shakeMultiplier:.1},glow:{intensityMultiplier:.55,pulseSpeedMultiplier:.6},scale:{breathDepthMultiplier:.7,breathRateMultiplier:.6},righting:{strengthMultiplier:1.4}}}};function vt(e){return e&&""!==e&&"clear"!==e&&yt[e]||yt.clear}function bt(e){return 3===(e=e.replace("#","")).length&&(e=e.split("").map(e=>e+e).join("")),{r:parseInt(e.substr(0,2),16),g:parseInt(e.substr(2,2),16),b:parseInt(e.substr(4,2),16)}}const wt={intense:1.6,confident:1.3,nervous:1.15,clear:1,tired:.8,subdued:.5};function Mt(e,t){if(!t||"clear"===t)return e;const i=wt[t.toLowerCase()];return i&&1!==i?function(e,t){const i=bt(e),n=function(e,t,i){e/=255,t/=255,i/=255;const n=Math.max(e,t,i),a=Math.min(e,t,i),s=(n+a)/2;let o,r;if(n===a)o=r=0;else{const l=n-a;switch(r=s>.5?l/(2-n-a):l/(n+a),n){case e:o=(t-i)/l+(t<i?6:0);break;case t:o=(i-e)/l+2;break;case i:o=(e-t)/l+4}o/=6}return{h:360*o,s:100*r,l:100*s}}(i.r,i.g,i.b);n.s=Math.max(0,Math.min(100,n.s*t));const a=function(e,t,i){e/=360,i/=100;const n=(e,t,i)=>(i<0&&(i+=1),i>1&&(i-=1),i<1/6?e+6*(t-e)*i:i<.5?t:i<2/3?e+(t-e)*(2/3-i)*6:e);let a,s,o;if(0==(t/=100))a=s=o=i;else{const r=i<.5?i*(1+t):i+t-i*t,l=2*i-r;a=n(l,r,e+1/3),s=n(l,r,e),o=n(l,r,e-1/3)}return{r:Math.round(255*a),g:Math.round(255*s),b:Math.round(255*o)}}(n.h,n.s,n.l);return function(e,t,i){const n=e=>{const t=Math.round(Math.max(0,Math.min(255,e))).toString(16);return 1===t.length?`0${t}`:t};return`#${n(e)}${n(t)}${n(i)}`}(a.r,a.g,a.b)}(e,i):e}Object.fromEntries(Object.entries({neutral:"#B0B0B0",joy:"#FFD700",sadness:"#4169E1",anger:"#DC143C",fear:"#8B008B",surprise:"#FF8C00",disgust:"#9ACD32",love:"#FF69B4"}).map(([e,t])=>{const i=bt(t);return[e,`${i.r}, ${i.g}, ${i.b}`]}));const St=new class{constructor(){this.enabled=!1,this.adapter=null,this.subsystemConfigs=new Map,this.activeModulations=new Map}initialize(){this.adapter=ve.getAdapter(),this.enabled=!0,this.adapter.onBeat(this.handleBeat.bind(this)),this.adapter.onBar(this.handleBar.bind(this))}updateBPM(e){if(e>=60&&e<=220){if(window.rhythmManuallyStoppedForCurrentAudio)return;if(!ve.isRunning)return this.start(e,"straight"),void(window.rhythmSyncVisualizer&&!window.rhythmSyncVisualizer.state.active&&window.rhythmSyncVisualizer.start());ve.setBPM(e)}}registerConfig(e,t,i){if(!i.rhythm||!i.rhythm.enabled)return;const n=`${e}:${t}`;this.subsystemConfigs.set(n,{type:e,name:t,rhythmConfig:i.rhythm,originalConfig:i})}applyGestureRhythm(e,t,i,n){if(!this.enabled||!e.rhythm?.enabled)return{};const a=e.rhythm,s={};if(a.amplitudeSync){const e=a.amplitudeSync,t=this.adapter.getBeatSync(e.offBeat||.8,e.onBeat||1.5,e.curve||"linear");s.amplitudeMultiplier=t}if(a.wobbleSync){const e=a.wobbleSync;this.adapter.isOnSubdivision(e.subdivision,.1)?s.wobbleMultiplier=1+e.intensity:s.wobbleMultiplier=1}if(a.accentResponse?.enabled){const e=this.adapter.getAccentedValue(1,a.accentResponse.multiplier||1.5);s.accentMultiplier=e}const o=this.adapter.getPattern();return o&&a.patternOverrides?.[o]&&Object.assign(s,a.patternOverrides[o]),s}applyParticleRhythm(e,t){if(!this.enabled||!e.rhythm?.enabled)return{};const i=this.adapter.getTimeInfo(),n=e.rhythm,a={};if(n.particleEmission){const e=n.particleEmission;"beat"===e.syncMode&&this.adapter.isOnBeat(.1)?a.emitBurst=e.burstSize||3:void 0!==e.offBeatRate&&(a.emissionRate=e.offBeatRate)}if(n.glowSync){const e=n.glowSync,t=this.adapter.getBeatSync(e.intensityRange[0]||1,e.intensityRange[1]||2,"pulse");a.glowIntensity=t}if("bars"===n.breathSync?.mode){const e=n.breathSync,t=i.bar%e.barsPerBreath/e.barsPerBreath;a.breathPhase=t*Math.PI*2}return a}applyBehaviorRhythm(e,t,i){if(!this.enabled||!e.rhythm?.enabled)return{};const n=this.adapter.getTimeInfo(),a=e.rhythm,s={};if(a.glitchTiming){const e=a.glitchTiming;if(this.adapter.isOnSubdivision(e.subdivision,.05)&&Math.random()<e.probability){const t=this.adapter.isOnBeat()?e.intensityOnBeat:e.intensityOffBeat;s.triggerGlitch=!0,s.glitchIntensity=t}}if(a.orbitRhythm){const e=a.orbitRhythm;"tempo"===e.baseSpeed&&(s.speedMultiplier=this.adapter.getBPM()/120),e.beatAcceleration&&this.adapter.isOnBeat(.1)&&(s.speedBoost=e.beatAcceleration),e.barReset&&0===n.beatInBar&&(s.resetOrbit=!0)}if(a.stutterSync){const e=a.stutterSync,t=this.adapter.getPattern();if(t&&e.patterns?.[t]){const i=e.patterns[t];i.freezeOnDrop&&2===n.beatInBar?(s.freeze=!0,s.freezeDuration=i.dropDuration):i.randomFreeze&&Math.random()<i.randomFreeze&&(s.freeze=!0,s.freezeDuration=i.duration)}}return s}handleBeat(e){this.lastBeatInfo=e}handleBar(e){this.lastBarInfo=e}getMusicalDuration(e,t){if(!this.enabled||!e?.durationSync)return t;const i=e.durationSync;return"bars"===i.mode?this.adapter.beatsToMs(4*i.bars):"beats"===i.mode?this.adapter.beatsToMs(i.beats):t}isEnabled(){return this.enabled&&this.adapter.isPlaying()}start(e=120,t="straight"){e&&ve.setBPM(e),t&&ve.setPattern(t),ve.start(),this.enabled=!0}stop(){ve.stop(),this.enabled=!1,this.bpmLocked=!1,this.lockedBPM=null}setPattern(e){ve.setPattern(e)}setBPM(e){ve.setBPM(e),this.bpmLocked&&(this.lockedBPM=e)}resampleBPM(){this.bpmLocked=!1,this.lockedBPM=null}setTimeSignature(e){this.timeSignature=e;const t=document.getElementById("time-sig-display");t&&(t.textContent=e),"3/4"===e&&ve.getPattern()}syncToAudio(e,t){ve.syncToAudio(e,t)}},xt=new class{constructor(){this.emotionCache=new Map,this.visualParamsCache=new Map,this.modifiersCache=new Map,this.transitionCache=new Map,this.stats={hits:0,misses:0,loadTime:0,cacheSize:0},this.isInitialized=!1,this.loadStartTime=0,this.initialize()}initialize(){this.loadStartTime=performance.now();try{const e=[...Array.from(ue.keys()),...le()];e.forEach(e=>{this.cacheEmotion(e)}),this.cacheCommonTransitions(e),this.isInitialized=!0,this.stats.loadTime=performance.now()-this.loadStartTime,this.stats.cacheSize=this.emotionCache.size}catch(e){console.error("[EmotionCache] Initialization failed:",e),this.isInitialized=!1}}cacheEmotion(e){try{const t=me(e);t&&this.emotionCache.set(e,t);const i=pe(e);this.visualParamsCache.set(e,i);const n=ge(e);this.modifiersCache.set(e,n)}catch(t){console.warn(`[EmotionCache] Failed to cache emotion '${e}':`,t)}}cacheCommonTransitions(e){[["neutral","joy"],["neutral","sadness"],["neutral","anger"],["joy","sadness"],["sadness","joy"],["anger","calm"],["calm","anger"]].forEach(([t,i])=>{if(e.includes(t)&&e.includes(i))try{const e=fe(t,i),n=`${t}->${i}`;this.transitionCache.set(n,e)}catch(e){console.warn(`[EmotionCache] Failed to cache transition '${t}->${i}':`,e)}})}getEmotion(e){if(!this.isInitialized)return console.warn("[EmotionCache] Cache not initialized, falling back to direct access"),me(e);const t=this.emotionCache.get(e);return t?(this.stats.hits++,t):(this.stats.misses++,console.warn(`[EmotionCache] Cache miss for emotion '${e}', consider adding to pre-cache`),me(e))}getVisualParams(e){if(!this.isInitialized)return pe(e);const t=this.visualParamsCache.get(e);return t?(this.stats.hits++,t):(this.stats.misses++,pe(e))}getModifiers(e){if(!this.isInitialized)return ge(e);const t=this.modifiersCache.get(e);return t?(this.stats.hits++,t):(this.stats.misses++,ge(e))}getTransitionParams(e,t){if(!this.isInitialized)return fe(e,t);const i=`${e}->${t}`,n=this.transitionCache.get(i);return n?(this.stats.hits++,n):(this.stats.misses++,fe(e,t))}hasEmotion(e){return this.emotionCache.has(e)}getStats(){const e=this.stats.hits+this.stats.misses,t=e>0?(this.stats.hits/e*100).toFixed(2):0;return{isInitialized:this.isInitialized,loadTime:this.stats.loadTime,cacheSize:this.stats.cacheSize,hits:this.stats.hits,misses:this.stats.misses,hitRate:`${t}%`,emotions:this.emotionCache.size,visualParams:this.visualParamsCache.size,modifiers:this.modifiersCache.size,transitions:this.transitionCache.size}}clear(){this.emotionCache.clear(),this.visualParamsCache.clear(),this.modifiersCache.clear(),this.transitionCache.clear(),this.isInitialized=!1,this.stats={hits:0,misses:0,loadTime:0,cacheSize:0}}reinitialize(){this.clear(),this.initialize()}};function Ct(e){if(!e||0===e.length)return"#FFFFFF";let t=0,i=0;const n=[];for(const a of e)"string"==typeof a?(n.push({color:a,weight:null}),i++):a&&"object"==typeof a&&a.color&&(n.push({color:a.color,weight:a.weight||null}),a.weight?t+=a.weight:i++);const a=Math.max(0,100-t),s=i>0?a/i:0,o=[];let r=0;for(const e of n)r+=null!==e.weight?e.weight:s,o.push({color:e.color,threshold:r});const l=Math.random()*r;for(const e of o)if(l<=e.threshold)return e.color;return n[n.length-1].color}var Dt={name:"ambient",emoji:"☁️",description:"Gentle upward drift like smoke",initialize:function(e){e.vx=0,e.vy=-.04-.02*Math.random(),e.lifeDecay=.002,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={upwardSpeed:5e-4,waviness:0,friction:.998}},update:function(e,t,i,n){const a=e.behaviorData;e.vy*=Math.pow(a.friction,t),e.vy-=a.upwardSpeed*t,e.vx=0}};const Pt=2*Math.PI;var Bt={name:"orbiting",emoji:"💕",description:"Romantic firefly dance around the orb",initialize:function(e){e.lifeDecay=.001+.002*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.isSparkle="#FFE4E1"===e.color||"#FFCCCB"===e.color||"#FFC0CB"===e.color;const t=40*(e.scaleFactor||1)*(1.3+.9*Math.random());e.blinkPhase=Math.random()*Pt,e.blinkSpeed=.3+1.2*Math.random(),e.blinkIntensity=.6+.4*Math.random(),e.fadePhase=Math.random()*Pt,e.fadeSpeed=.1+.3*Math.random(),e.minOpacity=.2+.2*Math.random(),e.maxOpacity=.8+.2*Math.random(),e.isSparkle&&(e.blinkSpeed*=2,e.blinkIntensity=1,e.minOpacity=0,e.maxOpacity=1),e.behaviorData={angle:Math.random()*Pt,radius:t,baseRadius:t,angularVelocity:8e-4+.0017*Math.random(),swayAmount:3+7*Math.random(),swaySpeed:.2+.5*Math.random(),floatOffset:Math.random()*Pt,floatSpeed:.3+.7*Math.random(),floatAmount:2+6*Math.random(),twinklePhase:Math.random()*Pt,twinkleSpeed:2+3*Math.random()}},update:function(e,t,i,n){const a=e.behaviorData;a.angle+=a.angularVelocity*t;const s=Math.sin(a.angle*a.swaySpeed)*a.swayAmount,o=6*Math.sin(1.5*a.angle),r=(a.radius||a.baseRadius)+o+.2*s,l=i+Math.cos(a.angle)*r,h=n+Math.sin(a.angle)*r;a.floatOffset+=a.floatSpeed*t*.001;const c=Math.sin(a.floatOffset)*a.floatAmount;e.vx=.1*(l-e.x),e.vy=.1*(h+c-e.y),e.fadePhase+=e.fadeSpeed*t*.001;const u=.5*Math.sin(e.fadePhase)+.5,d=e.minOpacity+(e.maxOpacity-e.minOpacity)*u;let m;e.blinkPhase+=e.blinkSpeed*t*.002,e.isSparkle?(a.twinklePhase+=a.twinkleSpeed*t*.001,m=.7*Math.pow(Math.sin(a.twinklePhase),16)+.2*Math.sin(5*e.blinkPhase)+.1):m=.4*Math.sin(e.blinkPhase)+.3*Math.sin(3*e.blinkPhase)+.2*Math.sin(7*e.blinkPhase)+.1*Math.sin(11*e.blinkPhase);const p=.5*(m+1),g=.2+p*e.blinkIntensity*.8;e.opacity=e.baseOpacity*d*g,e.isSparkle?e.size=e.baseSize*(.5+1*p):e.size=e.baseSize*(.8+.3*p),e.isSparkle&&(e.tempColor=p>.85?"#FFFFFF":e.color)}},kt={name:"rising",emoji:"🎈",description:"Buoyant upward movement like balloons",initialize:function(e){e.vx=.02*(Math.random()-.5),e.vy=-.05-.03*Math.random(),e.lifeDecay=.002,e.baseOpacity=.7+.3*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={buoyancy:.001,driftAmount:.005}},update:function(e,t,i,n){const a=e.behaviorData;e.vy-=a.buoyancy*t,e.vx+=(Math.random()-.5)*a.driftAmount*t,e.vx*=Math.pow(.995,t),e.vy*=Math.pow(.998,t)}},Tt={name:"falling",emoji:"💧",description:"Heavy downward drift like tears",initialize:function(e){e.vx=0,e.vy=.04+.02*Math.random(),e.lifeDecay=.002,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors));const t=Math.random(),i=Math.random(),n=t*Math.PI*2,a=2*i-1,s=Math.sqrt(1-a*a);e.behaviorData={downwardSpeed:5e-4,friction:.998,fallingDir:{x:s*Math.cos(n),y:a,z:s*Math.sin(n)},orbitDistanceRatio:.7+.4*Math.random()}},update:function(e,t,i,n){const a=e.behaviorData;e.vy*=Math.pow(a.friction,t),e.vy+=a.downwardSpeed*t,e.vx=0}};const Et=2e3,It=3,At=8,Rt=.7;var zt={name:"popcorn",emoji:"🍿",description:"Spontaneous popping with gravity and bounces",initialize:function(e){if(e.vx=.1*(Math.random()-.5),e.vy=.1*(Math.random()-.5),e.lifeDecay=.008+.012*Math.random(),e.emotionColors&&e.emotionColors.length>0)e.color=Ct(e.emotionColors);else{const t=["#FFFFFF","#FFFACD","#FFF8DC","#FFFFE0","#FAFAD2"];e.color=Ct(t)}e.size=Math.random()<.3?(8+4*Math.random())*e.scaleFactor*e.particleSizeMultiplier:(2+4*Math.random())*e.scaleFactor*e.particleSizeMultiplier,e.baseSize=e.size,e.hasGlow=Math.random()<.2,e.glowSizeMultiplier=e.hasGlow?1.2:0,e.behaviorData={popDelay:Math.random()*Et,hasPopped:!1,popStrength:It+Math.random()*(At-It),gravity:.098,bounceDamping:Rt,bounceCount:0,maxBounces:2+Math.floor(2*Math.random()),spinRate:10*(Math.random()-.5),lifetime:0}},update:function(e,t,i,n){const a=e.behaviorData;if(a.lifetime+=16.67*t,!a.hasPopped&&a.lifetime>a.popDelay){a.hasPopped=!0;const t=Math.random()*Math.PI*2;e.vx=Math.cos(t)*a.popStrength*1.5,e.vy=Math.sin(t)*a.popStrength-.3,e.size=1.25*e.baseSize}if(a.hasPopped){e.vy+=a.gravity*t;const i=n+100*e.scaleFactor;e.y>i&&a.bounceCount<a.maxBounces&&(e.y=i,e.vy=-Math.abs(e.vy)*a.bounceDamping,e.vx*=.9,a.bounceCount++,e.size=e.baseSize*(1.5-.1*a.bounceCount)),a.bounceCount>=a.maxBounces&&(e.lifeDecay=.03+.02*Math.random(),e.size*=.95),Math.sqrt(e.vx*e.vx+e.vy*e.vy)<.5&&(e.lifeDecay*=1.5)}}},_t={name:"burst",emoji:"💥",description:"Explosive expansion from center",initialize:function(e){const t="suspicion"===e.emotion,i="surprise"===e.emotion,n="glitch"===e.emotion,a=Math.random()*Pt,s=t?1+.8*Math.random():i?7+5*Math.random():n?2+1.5*Math.random():3.5+2.5*Math.random();e.vx=Math.cos(a)*s,e.vy=Math.sin(a)*s,e.lifeDecay=t?.01:i?.006+.008*Math.random():n?.012:.015,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),t&&(e.size=(6+4*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1),e.baseSize=e.size,e.opacity=1,e.baseOpacity=e.opacity),e.behaviorData={isSuspicion:t,isSurprise:i,isGlitch:n,age:0,fadeStart:t?.3:.2,glitchPhase:Math.random()*Math.PI*2,glitchIntensity:n?.3:0,glitchFrequency:n?.1:0}},update:function(e,t,i,n){const a=e.behaviorData;if(a.isSurprise)if(a.age+=.016*t,a.age<.15){const i=.98;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t)}else if(a.age<.25){const i=.85;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t)}else{const i=.99;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t),e.vx+=.01*(Math.random()-.5)*t,e.vy+=.01*(Math.random()-.5)*t}else{const i=a.isSuspicion?.99:a.isGlitch?.97:.95;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t)}if(a.isSuspicion){const i=.001*Date.now();e.vx+=.01*Math.sin(2*i+e.id)*t}if(a.isGlitch){a.age+=.016*t,a.glitchPhase+=a.glitchFrequency*t;const i=Math.sin(a.glitchPhase)*a.glitchIntensity*t,n=Math.cos(1.3*a.glitchPhase)*a.glitchIntensity*t;if(e.vx+=i,e.vy+=n,Math.random()<.02){const t=Math.random()*Math.PI*2,i=.5+.5*Math.random();e.vx+=Math.cos(t)*i,e.vy+=Math.sin(t)*i}}}},Ot={name:"aggressive",emoji:"⚡",description:"Sharp, chaotic movement with violent bursts",initialize:function(e){const t=Math.random()*Pt,i=1.5+2*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.015,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={acceleration:.05,jitter:.3,speedDecay:.95}},update:function(e,t,i,n){const a=e.behaviorData;if(e.vx+=(Math.random()-.5)*a.jitter*t,e.vy+=(Math.random()-.5)*a.jitter*t,e.vx*=Math.pow(a.speedDecay,t),e.vy*=Math.pow(a.speedDecay,t),Math.random()<Math.min(.05*t,.5)){const t=Math.random()*Pt;e.vx+=Math.cos(t)*a.acceleration,e.vy+=Math.sin(t)*a.acceleration}}},Ft={name:"scattering",emoji:"😨",description:"Particles flee from center in panic",initialize:function(e){e.vx=0,e.vy=0,e.lifeDecay=.008,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={fleeSpeed:2,panicFactor:1.2,initialized:!1}},update:function(e,t,i,n){const a=e.behaviorData;if(!a.initialized){const t=e.x-i,s=e.y-n,o=Math.sqrt(t*t+s*s);if(o>0)e.vx=t/o*a.fleeSpeed,e.vy=s/o*a.fleeSpeed;else{const t=Math.random()*Pt;e.vx=Math.cos(t)*a.fleeSpeed,e.vy=Math.sin(t)*a.fleeSpeed}a.initialized=!0}const s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);r>0&&(e.vx+=s/r*a.panicFactor*.01*t,e.vy+=o/r*a.panicFactor*.01*t),e.vx+=.1*(Math.random()-.5)*t,e.vy+=.1*(Math.random()-.5)*t,e.vx*=Math.pow(.98,t),e.vy*=Math.pow(.98,t)}},Lt={name:"repelling",emoji:"🚫",description:"Particles pushed away from center, maintaining distance",initialize:function(e){e.vx=0,e.vy=0,e.lifeDecay=.01,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={repelStrength:.8,minDistance:50,initialized:!1}},update:function(e,t,i,n){const a=e.behaviorData,s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);if(!a.initialized||r<a.minDistance){if(r>0){const i=a.repelStrength/Math.max(r,5);e.vx+=s/r*i*t,e.vy+=o/r*i*t}a.initialized=!0}e.vx*=Math.pow(.99,t),e.vy*=Math.pow(.99,t)}},Gt={name:"connecting",emoji:"🔗",description:"Chaotic movement with center attraction for social states",initialize:function(e){const t=Math.random()*Pt,i=2+5*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.012,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={attractionForce:.008,chaosFactor:1,friction:.95}},update:function(e,t,i,n){const a=e.behaviorData;e.vx*=Math.pow(a.friction,t),e.vy*=Math.pow(a.friction,t);const s=(i-e.x)*a.attractionForce,o=(n-e.y)*a.attractionForce,r=(Math.random()-.5)*a.chaosFactor,l=(Math.random()-.5)*a.chaosFactor;e.vx+=s+r,e.vy+=o+l}},Vt={name:"resting",emoji:"😴",description:"Ultra-slow vertical drift for deep rest states",initialize:function(e){e.vx=0,e.vy=-.01,e.lifeDecay=.001,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={upwardSpeed:2e-5,friction:.999}},update:function(e,t,i,n){const a=e.behaviorData;e.vy*=Math.pow(a.friction,t),e.vy-=a.upwardSpeed*t,e.vx=0}},qt={name:"radiant",emoji:"☀️",description:"Particles radiate outward like sunbeams",initialize:function(e){const t=Math.random()*Pt,i=.8+.4*Math.random();if(e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.006,e.emotionColors&&e.emotionColors.length>0)e.color=Ct(e.emotionColors);else{const t=["#FFD700","#FFB347","#FFA500","#FF69B4"];e.color=Ct(t)}e.hasGlow=Math.random()<.7,e.glowSizeMultiplier=e.hasGlow?1.5+.5*Math.random():0,e.behaviorData={radialSpeed:.02,shimmer:Math.random()*Pt,shimmerSpeed:.1,friction:.99}},update:function(e,t,i,n){const a=e.behaviorData,s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);if(r>0){const i=s/r,n=o/r;e.vx+=i*a.radialSpeed*t,e.vy+=n*a.radialSpeed*t}a.shimmer+=a.shimmerSpeed*t;const l=Math.sin(a.shimmer);e.size=e.baseSize*(1+.2*l),e.opacity=e.baseOpacity*(1+.3*l),e.vx*=Math.pow(a.friction,t),e.vy*=Math.pow(a.friction,t)}};function Nt(e){e.vx=.02*(Math.random()-.5),e.vy=-.03-.02*Math.random(),e.lifeDecay=8e-4,e.size=(6+6*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1)*1.33,e.baseSize=e.size,e.baseOpacity=.2+.2*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={ascensionSpeed:3e-4,waveFactor:.5,waveFrequency:.001,friction:.998,fadeStartDistance:100}}var jt={name:"ascending",emoji:"🧘",description:"Slow steady upward float like incense smoke",initialize:Nt,update:function(e,t,i,n){const a=e.behaviorData;if(!a)return void Nt(e);e.vx*=Math.pow(a.friction,t),e.vy*=Math.pow(a.friction,t),e.vy-=a.ascensionSpeed*t;const s=Math.sin(e.age*a.waveFrequency*1e3)*a.waveFactor;e.vx+=.001*s*t,void 0===e.initialY&&(e.initialY=e.y);const o=e.initialY-e.y;if(o>a.fadeStartDistance){const t=(o-a.fadeStartDistance)/100,i=Math.max(0,1-t);e.baseOpacity*=.995,i<.5&&(e.lifeDecay*=1.02)}Math.abs(e.vx)>.05&&(e.vx*=Math.pow(.95,t)),e.vy<-.1&&(e.vy=-.1)}},Ut={name:"erratic",emoji:"😰",description:"Nervous jittery movement for anxious states",initialize:function(e){const t=Math.random()*Pt,i=.1+.15*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.004,e.size=(2+4*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1),e.baseSize=e.size,e.baseOpacity=.4+.3*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={jitterStrength:.02,directionChangeRate:.1,speedVariation:.3,spinRate:.05+.1*Math.random()}},update:function(e,t){const i=e.behaviorData;if(e.vx+=(Math.random()-.5)*i.jitterStrength*t,e.vy+=(Math.random()-.5)*i.jitterStrength*t,Math.random()<Math.min(i.directionChangeRate*t,.5)){const t=Math.random()*Pt,i=Math.sqrt(e.vx*e.vx+e.vy*e.vy);e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i}const n=1+(Math.random()-.5)*i.speedVariation*t;e.vx*=n,e.vy*=n;const a=e.age*i.spinRate*1e3;e.size=e.baseSize*(1+.2*Math.sin(a)),e.opacity=e.baseOpacity*(.8+.4*Math.random()),e.vx*=Math.pow(.98,t),e.vy*=Math.pow(.98,t);const s=Math.sqrt(e.vx*e.vx+e.vy*e.vy);s>.5&&(e.vx=e.vx/s*.5,e.vy=e.vy/s*.5)}},Ht={name:"cautious",emoji:"🤨",description:"Slow careful movement with watchful pauses",initialize:function(e){const t=Math.random()*Pt,i=.02+.03*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.001,e.life=1,e.size=(4+4*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1),e.baseSize=e.size,e.baseOpacity=.8+.2*Math.random(),e.opacity=e.baseOpacity,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={pauseTimer:2*Math.random(),pauseDuration:.5+.5*Math.random(),moveDuration:1+.5*Math.random(),isMoving:Math.random()>.5,moveTimer:0,originalVx:e.vx,originalVy:e.vy,watchRadius:50+30*Math.random()}},update:function(e,t,i,n){const a=e.behaviorData;if(a.moveTimer+=t,a.isMoving)a.moveTimer>a.moveDuration?(a.isMoving=!1,a.moveTimer=0,e.vx=0,e.vy=0):(e.vx=a.originalVx,e.vy=a.originalVy);else if(a.moveTimer>a.pauseDuration){a.isMoving=!0,a.moveTimer=0;const t=Math.random()*Pt,i=.02+.03*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,a.originalVx=e.vx,a.originalVy=e.vy}const s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);if(r>a.watchRadius){const i=.02;e.vx-=s/r*i*t,e.vy-=o/r*i*t}e.vx*=Math.pow(.995,t),e.vy*=Math.pow(.995,t),a.isMoving?e.opacity=e.baseOpacity:e.opacity=e.baseOpacity*(.9+.1*Math.sin(5*e.age))}},Wt={name:"surveillance",emoji:"👁️",description:"Searchlight scanning with paranoid watchfulness",initialize(e,t){e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorState={scanAngle:Math.random()*Math.PI-Math.PI/2,scanDirection:Math.random()<.5?1:-1,scanSpeed:.3+.2*Math.random(),scanRange:Math.PI/3+Math.random()*Math.PI/4,scanCenter:Math.random()*Math.PI*2,pauseTimer:0,pauseDuration:500+500*Math.random(),mode:"scanning",modeTimer:0,nextModeChange:2e3+3e3*Math.random(),dartTarget:{x:0,y:0},dartSpeed:0,patrolRadius:150+100*Math.random(),patrolAngle:Math.random()*Math.PI*2,alertLevel:0,lastPosition:{x:e.x,y:e.y}};const i=Math.random();i<.7?e.behaviorState.primaryRole="scanner":i<.9?(e.behaviorState.primaryRole="patroller",e.behaviorState.mode="patrolling"):(e.behaviorState.primaryRole="watcher",e.behaviorState.mode="frozen")},update(e,t,i){const n=e.behaviorState;if(n){switch(n.modeTimer+=16*t,n.modeTimer>n.nextModeChange&&(this.changeMode(e,n,i),n.modeTimer=0,n.nextModeChange=2e3+4e3*Math.random()),n.mode){case"scanning":this.updateScanning(e,t,n,i);break;case"darting":this.updateDarting(e,t,n,i);break;case"frozen":this.updateFrozen(e,t,n,i);break;case"patrolling":this.updatePatrolling(e,t,n,i)}e.vy+=.05*t,e.x+=e.vx*t,e.y+=e.vy*t,n.lastPosition.x=e.x,n.lastPosition.y=e.y}},updateScanning(e,t,i,n){i.pauseTimer>0?(i.pauseTimer-=16*t,e.vx*=.9,e.vy*=.9):(i.scanAngle+=i.scanDirection*i.scanSpeed*t*.02,Math.abs(i.scanAngle)>i.scanRange/2&&(i.scanDirection*=-1,i.pauseTimer=i.pauseDuration,i.scanAngle=Math.sign(i.scanAngle)*i.scanRange/2));const a=i.scanCenter+i.scanAngle,s=.8+.5*i.alertLevel;e.vx=Math.cos(a)*s,e.vy=Math.sin(a)*s*.3},updateDarting(e,t,i,n){const a=i.dartTarget.x-e.x,s=i.dartTarget.y-e.y,o=Math.sqrt(a*a+s*s);o>5?(e.vx=a/o*i.dartSpeed,e.vy=s/o*i.dartSpeed):(i.mode="scanning",i.modeTimer=0)},updateFrozen(e,t,i,n){e.vx*=.95,e.vy*=.95,Math.random()<.01&&(e.vx+=.5*(Math.random()-.5),e.vy+=.5*(Math.random()-.5))},updatePatrolling(e,t,i,n){i.patrolAngle+=.01*t;const a=n.corePosition?.x??n.canvasWidth/2,s=n.corePosition?.y??n.canvasHeight/2,o=a+Math.cos(i.patrolAngle)*i.patrolRadius,r=s+Math.sin(i.patrolAngle)*i.patrolRadius,l=o-e.x,h=r-e.y;e.vx=.02*l,e.vy=.02*h},changeMode(e,t,i){const n=Math.random(),a=i?.corePosition?.x??(i?.canvasWidth/2||e.x),s=i?.corePosition?.y??(i?.canvasHeight/2||e.y);"scanner"===t.primaryRole?n<.1?(t.mode="darting",t.dartTarget={x:a+200*(Math.random()-.5),y:s+200*(Math.random()-.5)},t.dartSpeed=3+2*Math.random()):t.mode=n<.2?"frozen":"scanning":"patroller"===t.primaryRole?t.mode=n<.1?"frozen":"patrolling":t.mode=n<.3?"scanning":"frozen"}},Xt={name:"glitchy",emoji:"⚡",description:"Digital glitch with stuttering orbits and corruption",rhythm:{enabled:!0,glitchTiming:{mode:"subdivision",subdivision:"sixteenth",probability:.3,intensityOnBeat:2,intensityOffBeat:.5},stutterSync:{mode:"pattern",patterns:{dubstep:{freezeOnDrop:!0,dropDuration:100},breakbeat:{randomFreeze:.1,duration:50}}},orbitRhythm:{baseSpeed:"tempo",wobbleSync:"eighth",beatAcceleration:1.5,barReset:!0},rgbSync:{enabled:!0,amount:"intensity",direction:"beat",maxSplit:10},noiseRhythm:{trigger:"accent",duration:50,intensity:"drop"}},initialize(e,t,i,n){e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorState={orbitAngle:Math.random()*Math.PI*2,orbitRadius:300+400*Math.random(),orbitSpeed:.01+.02*Math.random(),glitchTimer:0,nextGlitch:500*Math.random()+100,isGlitching:!1,glitchDuration:0,glitchOffset:{x:0,y:0},stutterTimer:0,nextStutter:200*Math.random()+50,isFrozen:!1,frozenPosition:{x:0,y:0},frozenVelocity:{x:0,y:0},hasGhost:Math.random()<.3,ghostOffset:20*Math.random()+10,ghostAngle:Math.random()*Math.PI*2,rgbSplit:Math.random()<.4,rgbPhase:Math.random()*Math.PI*2,noiseLevel:0,noiseBurst:!1,beatPhase:Math.random()*Math.PI*2,beatFrequency:.05+.03*Math.random(),dropIntensity:0},e.lifeDecay=.0015,e.hasGlow=!0,e.glowSizeMultiplier=3+2*Math.random()},update(e,t,i,n){const a=e.behaviorState;if(!a)return;a.glitchTimer+=16*t,a.stutterTimer+=16*t,a.stutterTimer>a.nextStutter&&(a.isFrozen?(a.isFrozen=!1,a.stutterTimer=0,a.nextStutter=100+300*Math.random(),Math.random()<.3&&(e.x+=60*(Math.random()-.5),e.y+=60*(Math.random()-.5))):(a.isFrozen=!0,a.frozenPosition={x:e.x,y:e.y},a.frozenVelocity={x:e.vx,y:e.vy},a.stutterTimer=0,a.nextStutter=20+40*Math.random())),a.glitchTimer>a.nextGlitch&&!a.isGlitching&&(a.isGlitching=!0,a.glitchDuration=50+100*Math.random(),a.glitchOffset={x:80*(Math.random()-.5),y:80*(Math.random()-.5)},a.glitchTimer=0,Math.random()<.5&&e.emotionColors&&(e.color=Ct(e.emotionColors))),a.isGlitching&&a.glitchTimer>a.glitchDuration&&(a.isGlitching=!1,a.glitchTimer=0,a.nextGlitch=200+800*Math.random(),a.glitchOffset={x:0,y:0}),a.beatPhase+=a.beatFrequency*t;const s=.5*Math.sin(a.beatPhase)+.5;if(a.beatPhase%(4*Math.PI)<.5*Math.PI?a.dropIntensity=Math.min(1,a.dropIntensity+.1*t):a.dropIntensity=Math.max(0,a.dropIntensity-.05*t),a.isFrozen)e.vx=.5*(Math.random()-.5),e.vy=.5*(Math.random()-.5);else{a.orbitAngle+=a.orbitSpeed*t*(1+.5*s);const o=a.orbitRadius*(1+.3*a.dropIntensity*Math.sin(4*a.beatPhase));let r=i+Math.cos(a.orbitAngle)*o,l=n+Math.sin(a.orbitAngle)*o*.6;if(a.isGlitching&&(r+=a.glitchOffset.x*Math.random()*.8,l+=a.glitchOffset.y*Math.random()*.8),a.rgbSplit){const e=3*(1+a.dropIntensity);r+=Math.sin(a.rgbPhase)*e,l+=Math.cos(a.rgbPhase)*e,a.rgbPhase+=.1*t}a.dropIntensity>.8&&Math.random()<.1&&(r+=30*(Math.random()-.5),l+=30*(Math.random()-.5));const h=a.isGlitching?.02:.03;e.vx=(r-e.x)*h,e.vy=(l-e.y)*h,e.vx+=(Math.random()-.5)*s*2,e.vy+=(Math.random()-.5)*s*2}e.x+=e.vx*t,e.y+=e.vy*t,Math.random()<.02&&(e.opacity=.1+.9*Math.random()),e.size=e.baseSize*(1+.3*s+.5*a.dropIntensity)}},Yt={name:"spaz",description:"Ultra-aggressive particles with explosive spread and chaotic motion",initialize(e,t,i,n){e.x=i,e.y=n,e.life=1,e.size=3+4*Math.random();const a=Math.random()*Math.PI*2,s=200+300*Math.random();e.vx=Math.cos(a)*s,e.vy=Math.sin(a)*s,e.behaviorState={explosionPhase:0,explosionTimer:0,explosionDuration:1e3+2e3*Math.random(),chaosTimer:0,nextChaosChange:100+200*Math.random(),chaosAngle:a,chaosSpeed:50+100*Math.random(),spazIntensity:.8+.4*Math.random(),zigzagPattern:Math.random()<.5,spiralPattern:Math.random()<.3,teleportChance:.02,sizePulse:!0,sizePulseSpeed:.1+.05*Math.random(),sizePulsePhase:Math.random()*Math.PI*2,colorShift:Math.random()<.3,colorShiftSpeed:.05+.03*Math.random()},e.lifeDecay=8e-4,e.hasGlow=!0,e.glowSizeMultiplier=4+3*Math.random(),e.glowIntensity=1.5+.5*Math.random()},update(e,t,i,n){const a=e.behaviorState;if(a.explosionTimer+=t,a.chaosTimer+=t,0===a.explosionPhase&&a.explosionTimer<500)e.vx*=.98,e.vy*=.98,Math.random()<.1&&(e.vx+=100*(Math.random()-.5),e.vy+=100*(Math.random()-.5));else if(0===a.explosionPhase&&a.explosionTimer>=500)a.explosionPhase=1,a.chaosAngle=Math.random()*Math.PI*2,a.chaosSpeed=30+70*Math.random();else if(1===a.explosionPhase){a.chaosTimer>=a.nextChaosChange&&(a.chaosAngle=Math.random()*Math.PI*2,a.chaosSpeed=20+80*Math.random(),a.nextChaosChange=50+150*Math.random(),a.chaosTimer=0);const t=Math.cos(a.chaosAngle)*a.chaosSpeed,i=Math.sin(a.chaosAngle)*a.chaosSpeed;if(e.vx=.7*e.vx+.3*t,e.vy=.7*e.vy+.3*i,a.zigzagPattern){const t=.01*a.chaosTimer;e.vx+=20*Math.sin(t),e.vy+=20*Math.cos(t)}if(a.spiralPattern){const t=.005*a.chaosTimer,i=50+30*Math.sin(.003*a.chaosTimer);e.vx+=Math.cos(t)*i*.1,e.vy+=Math.sin(t)*i*.1}}if(Math.random()<a.teleportChance){const t=Math.random()*Math.PI*2,a=200+400*Math.random();e.x=i+Math.cos(t)*a,e.y=n+Math.sin(t)*a,e.vx=200*(Math.random()-.5),e.vy=200*(Math.random()-.5)}if(e.x+=e.vx*(t/1e3),e.y+=e.vy*(t/1e3),a.sizePulse){a.sizePulsePhase+=a.sizePulseSpeed*t;const i=1+.5*Math.sin(a.sizePulsePhase);e.size=(3+4*Math.random())*i}a.colorShift&&(a.colorShiftPhase=(a.colorShiftPhase||0)+a.colorShiftSpeed*t),e.vx*=.995,e.vy*=.995,e.life-=e.lifeDecay*t,(e.life<=0||Math.abs(e.x-i)>2e3||Math.abs(e.y-n)>2e3)&&(e.life=0)},getSpawnPosition(e,t){const i=Math.random()*Math.PI*2,n=100+200*Math.random();return{x:e+Math.cos(i)*n,y:t+Math.sin(i)*n}},getVisualProperties:()=>({glowColor:"#FF00AA",glowIntensity:2,particleColors:[{color:"#FF00AA",weight:30},{color:"#00FFAA",weight:25},{color:"#FFAA00",weight:20},{color:"#AA00FF",weight:15},{color:"#00AAFF",weight:10}]})},$t={name:"directed",emoji:"🎯",description:"Focused, straight-line movement toward target",config:{speed:3,acceleration:.15,focusStrength:.8,randomness:.1,edgeBuffer:50},initialize(e,t,i,n,a){const s=t-e.x,o=i-e.y,r=Math.sqrt(s*s+o*o);if(r>0)e.vx=s/r*this.config.speed,e.vy=o/r*this.config.speed;else{const t=Math.random()*Math.PI*2;e.vx=Math.cos(t)*this.config.speed,e.vy=Math.sin(t)*this.config.speed}e.targetX=t,e.targetY=i,e.directedPhase=0},update(e,t,i,n,a,s){e.directedPhase+=.05*t;const o=e.targetX-e.x,r=e.targetY-e.y,l=Math.sqrt(o*o+r*r);if(l>10){const i=o/l*this.config.speed,n=r/l*this.config.speed;e.vx+=(i-e.vx)*this.config.acceleration*t,e.vy+=(n-e.vy)*this.config.acceleration*t,e.vx+=(Math.random()-.5)*this.config.randomness,e.vy+=(Math.random()-.5)*this.config.randomness}else{const t=Math.random()*Math.PI*2,o=100+200*Math.random();e.targetX=i+Math.cos(t)*o,e.targetY=n+Math.sin(t)*o,e.targetX=Math.max(this.config.edgeBuffer,Math.min(a-this.config.edgeBuffer,e.targetX)),e.targetY=Math.max(this.config.edgeBuffer,Math.min(s-this.config.edgeBuffer,e.targetY))}e.x+=e.vx*t,e.y+=e.vy*t,(e.x<=0||e.x>=a)&&(e.vx*=-.8,e.x=Math.max(0,Math.min(a,e.x)),e.targetX=i+300*(Math.random()-.5)),(e.y<=0||e.y>=s)&&(e.vy*=-.8,e.y=Math.max(0,Math.min(s,e.y)),e.targetY=n+300*(Math.random()-.5))},visuals:{trailLength:"medium",opacity:.9,sizeMultiplier:1,blurAmount:.2}},Qt={name:"fizzy",emoji:"🫧",description:"Bubbly, effervescent movement like carbonation",config:{baseRiseSpeed:2.5,wobbleAmplitude:30,wobbleFrequency:.15,popChance:.002,popForce:8,fizziness:.3,gravity:-.05},initialize(e,t,i,n,a){e.vx=2*(Math.random()-.5),e.vy=-this.config.baseRiseSpeed-2*Math.random(),e.wobblePhase=Math.random()*Math.PI*2,e.wobbleSpeed=this.config.wobbleFrequency*(.8+.4*Math.random()),e.bubbleSize=.5+.5*Math.random(),e.popTimer=0,e.isFizzing=!0},update(e,t,i,n,a,s){e.wobblePhase+=e.wobbleSpeed*t;const o=Math.sin(e.wobblePhase)*this.config.wobbleAmplitude;if(e.vx=.05*o+(Math.random()-.5)*this.config.fizziness,e.vy+=this.config.gravity*t,e.vy+=(Math.random()-.5)*this.config.fizziness,Math.random()<this.config.popChance){const t=Math.random()*Math.PI*2;e.vx=Math.cos(t)*this.config.popForce,e.vy=Math.sin(t)*this.config.popForce*.7,e.popTimer=1,e.bubbleSize=.3+.7*Math.random()}e.popTimer>0&&(e.popTimer-=.05*t,e.vx*=.95,e.vy*=.95),e.x+=e.vx*t,e.y+=e.vy*t,e.y<-50&&(e.y=s+50,e.x=i+300*(Math.random()-.5),e.vy=-this.config.baseRiseSpeed-2*Math.random(),e.bubbleSize=.5+.5*Math.random()),(e.x<=0||e.x>=a)&&(e.vx*=-.5,e.x=Math.max(0,Math.min(a,e.x))),e.y>s+50&&(e.y=s,e.vy=1.5*-this.config.baseRiseSpeed),e.size=e.baseSize*e.bubbleSize*(1+.1*Math.sin(2*e.wobblePhase))},visuals:{trailLength:"short",opacity:.6,sizeMultiplier:1.2,blurAmount:.5,sparkle:!0}};var Zt={name:"zen",emoji:"☯️",description:"Peaceful orbital movement like a hovering aura",initialize:function(e){e.vx=.5*(Math.random()-.5),e.vy=.5*(Math.random()-.5),e.lifeDecay=.003,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={orbitAngle:Math.random()*Math.PI*2,orbitRadius:40+60*Math.random(),orbitSpeed:8e-4+6e-4*Math.random(),floatOffset:Math.random()*Math.PI*2,breathingOffset:Math.random()*Math.PI*2,lifetime:0}},update:function(e,t,i,n){const a=e.behaviorData;if(!a)return;a.lifetime+=t;const s=(a.lifetime+8e3*a.breathingOffset)/8e3,o=.5*Math.sin(s*Math.PI*2)+.5;e.size=e.baseSize*(.95+.05*o),a.orbitAngle+=a.orbitSpeed*t;const r=10*Math.sin(1e-4*a.lifetime+a.floatOffset),l=a.orbitRadius+r,h=i+Math.cos(a.orbitAngle)*l,c=n+Math.sin(a.orbitAngle)*l,u=15*Math.sin(3e-4*a.lifetime+a.breathingOffset),d=h-e.x,m=c+u-e.y;e.vx=.03*d,e.vy=.03*m,e.vx+=.02*(Math.random()-.5),e.vy+=.02*(Math.random()-.5),e.vx*=.98,e.vy*=.98}};const Jt=new Map;var Kt=function(e){return Jt.get(e)||null},ei=function(){return Array.from(Jt.keys())};const ti={};function ii(e){if(ti[e])return ti[e];return Kt(e)||null}function ni(e,t){const i=ii(t);return i&&i.initialize?(i.initialize(e),!0):"ambient"!==t&&(console.warn(`⚠️ Behavior '${t}' not found, falling back to ambient`),ni(e,"ambient"))}function ai(e,t,i,n,a){const s=ii(t);return!(!s||!s.update||(s.update(e,i,n,a),0))}[Dt,$t,Qt,Bt,kt,Tt,zt,_t,Ot,Ft,Lt,Gt,Vt,qt,jt,Ut,Ht,Wt,Xt,Yt,Zt].forEach(e=>{ti[e.name]=e}),"undefined"!=typeof window&&window.DEBUG_PARTICLES&&(window.ParticleBehaviors={registry:ti,list:function(){return[...Object.values(ti).map(e=>({name:e.name,emoji:e.emoji||"🎯",description:e.description||"No description",type:"core"})),...ei().map(e=>{const t=Kt(e);return{name:t.name,emoji:t.emoji||"🔌",description:t.description||"Plugin behavior",type:"plugin"}})]},get:ii});class si{constructor(e,t,i="ambient",n=1,a=1,s=null){const o=Math.random();this.z=o<1/13?.5+.5*Math.random():.9*Math.random()-1;const r=this.z>0?(20+20*Math.random())*n:3*n,l=Math.random()*Math.PI*2;this.x=e+Math.cos(l)*r,this.y=t+Math.sin(l)*r,this.vx=0,this.vy=0,this.vz=0,this.life=0,this.maxLife=1,this.lifeDecay=.01,this.fadeInTime=.15,this.fadeOutTime=.3,this.isFadingOut=!1,this.age=0,this.scaleFactor=n,this.particleSizeMultiplier=a,this.size=(4+6*Math.random())*n*a,this.baseSize=this.size,this.emotionColors=s,this.color="#ffffff",this.opacity=1,this.hasGlow=Math.random()<.333,this.glowSizeMultiplier=this.hasGlow?1.33+.33*Math.random():0,this.isCellShaded=Math.random()<.333,this.baseOpacity=.3+.4*Math.random(),this.cachedColors=new Map,this.maxCachedColors=20,this.colorAccessOrder=[],this.lastColor=null,this.lastOpacity=-1,this.behavior=i,this.behaviorData={},this.gestureData={initialX:e,initialY:t},ni(this,i)}update(e,t,i,n=null,a=null,s=0,o=null){const r=Math.min(e,50)/16.67,l=a&&a.type&&s>0&&function(e){const t=ft(e);return!!t&&"override"===t.type}(a.type);let h,c;if(l?this.applyGestureMotion(a,s,r,t,i):"falling"===this.gestureBehavior?ai(this,"falling",r,t,i):"radiant"===this.gestureBehavior?ai(this,"radiant",r,t,i):(ai(this,this.behavior,r,t,i),a&&s>0&&this.applyGestureMotion(a,s,r,t,i)),l||(this.x+=this.vx*r,this.y+=this.vy*r),o)h=o.width,c=o.height;else{const e=document.getElementById("card-mascot")||document.getElementById("cherokee-guide-mascot")||document.querySelector("canvas");h=e?e.width:2*t,c=e?e.height:2*i}const u=t-h/2+20,d=t+h/2-20,m=i-c/2+20,p=i+c/2-20;this.x-this.size<u?(this.x=u+this.size,this.vx=.5*Math.abs(this.vx)):this.x+this.size>d&&(this.x=d-this.size,this.vx=.5*-Math.abs(this.vx)),this.y-this.size<m?(this.y=m+this.size,this.vy=.5*Math.abs(this.vy)):this.y+this.size>p&&(this.y=p-this.size,this.vy=.5*-Math.abs(this.vy)),this.age+=this.lifeDecay*r,this.age<this.fadeInTime?this.life=this.age/this.fadeInTime:this.age<1-this.fadeOutTime?this.life=1:(this.life=(1-this.age)/this.fadeOutTime,this.isFadingOut=!0,"popcorn"===this.behavior&&(this.size=this.baseSize*(.5+.5*this.life))),this.life=Math.max(0,Math.min(1,this.life)),"falling"===this.behavior?this.opacity=this.life:this.opacity=this.easeInOutCubic(this.life),"burst"===this.behavior&&this.behaviorData&&this.life<this.behaviorData.fadeStart&&(this.size=this.baseSize*(this.life/this.behaviorData.fadeStart))}applyUndertoneModifier(e,t){}applyGestureMotion(e,t,i,n,a){!function(e,t,i,n,a,s){if(!i||!i.type||n>=1)return;e.gestureData||(e.gestureData={originalVx:e.vx,originalVy:e.vy,initialX:e.x,initialY:e.y,startAngle:Math.atan2(e.y-s,e.x-a),startRadius:Math.sqrt(Math.pow(e.x-a,2)+Math.pow(e.y-s,2))});const o=ft(i.type);if(!o)return;let r=i;if(St.isEnabled()&&o.rhythm?.enabled){const a=St.applyGestureRhythm(o,e,n,t);r={...i,amplitude:(i.amplitude||1)*(a.amplitudeMultiplier||1)*(a.accentMultiplier||1),wobbleAmount:(i.wobbleAmount||0)*(a.wobbleMultiplier||1),rhythmModulation:a}}o.apply&&o.apply(e,n,r,t,a,s),n>=.99&&o.cleanup&&(o.cleanup(e),e.gestureData=null)}(this,i,e,t,n,a)}isOutOfBounds(e,t){return this.x<-50||this.x>e+50||this.y<-50||this.y>t+50}isAlive(){return this.life>0}setOutwardVelocity(e){if(this.behaviorData&&void 0!==this.behaviorData.outwardSpeed){const t=this.behaviorData.outwardSpeed;this.vx=Math.cos(e)*t,this.vy=Math.sin(e)*t+(this.behaviorData.upwardBias||0)}}getDepthAdjustedSize(){const e=1+.2*this.z;return this.size*e}getState(){return{position:{x:this.x,y:this.y,z:this.z},velocity:{x:this.vx,y:this.vy,z:this.vz},life:this.life,behavior:this.behavior,size:this.size,opacity:this.opacity}}reset(e,t,i="ambient",n=1,a=1,s=null){const o=Math.random();this.z=o<1/13?.5+.5*Math.random():.9*Math.random()-1;const r=this.z>0?(20+20*Math.random())*n:3*n,l=Math.random()*Math.PI*2;if(this.x=e+Math.cos(l)*r,this.y=t+Math.sin(l)*r,this.vx=0,this.vy=0,this.vz=0,this.life=0,this.age=0,this.scaleFactor=n,this.particleSizeMultiplier=a,this.size=(4+6*Math.random())*n*a,this.baseSize=this.size,this.emotionColors=s,this.cachedColors.clear(),this.colorAccessOrder=[],this.opacity=0,this.isFadingOut=!1,this.baseOpacity=.3+.4*Math.random(),this.color="#ffffff",this.behavior=i,this.gestureData=null,this.behaviorData)for(const e in this.behaviorData)delete this.behaviorData[e];else this.behaviorData={};ni(this,i)}getCachedColor(e,t){const i=Math.round(100*t)/100,n=`${e}_${i}`;if(this.cachedColors.has(n)){const e=this.colorAccessOrder.indexOf(n);-1!==e&&this.colorAccessOrder.splice(e,1),this.colorAccessOrder.push(n)}else{if(this.cachedColors.size>=this.maxCachedColors){const e=this.colorAccessOrder.shift();this.cachedColors.delete(e)}this.cachedColors.set(n,this.hexToRgba(e,i)),this.colorAccessOrder.push(n)}return this.cachedColors.get(n)}hexToRgba(e,t){const i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return i?`rgba(${parseInt(i[1],16)}, ${parseInt(i[2],16)}, ${parseInt(i[3],16)}, ${t})`:`rgba(255, 255, 255, ${t})`}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}render(e,t="#ffffff"){if(this.life<=0)return;if(!isFinite(this.x)||!isFinite(this.y))return;const i=this.x,n=this.y,a=Math.max(.1,this.size),s=this.tempColor||this.color||t;if(e.save(),this.isCellShaded){e.strokeStyle=this.getCachedColor(s,.9*this.opacity),e.lineWidth=2,e.beginPath(),e.arc(i,n,a,0,2*Math.PI),e.stroke();const t=Math.floor(3*this.opacity)/3;e.fillStyle=this.getCachedColor(s,t*(this.baseOpacity||.5)*.5),e.beginPath(),e.arc(i,n,Math.max(.1,a-1),0,2*Math.PI),e.fill(),t>.5&&(e.fillStyle=this.getCachedColor("#FFFFFF",.3),e.beginPath(),e.arc(i-.3*a,n-.3*a,.3*a,0,2*Math.PI),e.fill())}else{const t=e.createRadialGradient(i,n,0,i,n,a);if(t.addColorStop(0,this.getCachedColor(s,this.opacity*(this.baseOpacity||.5))),t.addColorStop(.5,this.getCachedColor(s,this.opacity*(this.baseOpacity||.5)*.5)),t.addColorStop(1,this.getCachedColor(s,0)),e.fillStyle=t,e.beginPath(),e.arc(i,n,a,0,2*Math.PI),e.fill(),this.hasGlow&&this.glowSizeMultiplier>0){const t=a*this.glowSizeMultiplier,o=e.createRadialGradient(i,n,.5*a,i,n,t),r=.3,l=Math.max(r,this.opacity),h=Math.min(1,this.glowSizeMultiplier/3);o.addColorStop(0,this.getCachedColor(s,Math.max(.5,.8*l)*h)),o.addColorStop(.25,this.getCachedColor(s,Math.max(.3,.6*l)*h)),o.addColorStop(.5,this.getCachedColor(s,Math.max(.2,.4*l)*h)),o.addColorStop(.75,this.getCachedColor(s,Math.max(.1,.2*l)*h)),o.addColorStop(1,this.getCachedColor(s,0)),e.save(),e.globalCompositeOperation="screen",e.fillStyle=o,e.beginPath(),e.arc(i,n,t,0,2*Math.PI),e.fill(),e.restore()}}e.restore()}}class oi{constructor(e=50){this.poolSize=Math.min(e,50),this.pool=[],this.totalParticlesCreated=0,this.totalParticlesDestroyed=0,this.poolHits=0,this.poolMisses=0}getParticle(e,t,i,n,a,s,o,r=null){let l;return this.pool.length>0?(l=this.pool.pop(),l.reset(e,t,i,n,a,s),this.poolHits++):(l=new si(e,t,i,n,a,s),this.poolMisses++,this.totalParticlesCreated++),l.emotion=o,r&&(l.gestureBehavior=r),l}returnParticle(e){if(this.pool.length<this.poolSize){if(e.cachedGradient=null,e.cachedGradientKey=null,e.behaviorData)for(const t in e.behaviorData)delete e.behaviorData[t];this.pool.push(e)}else this.totalParticlesDestroyed++}refreshPool(){const e=this.pool.length-this.poolSize;e>0&&(this.pool.splice(this.poolSize),this.totalParticlesDestroyed+=e)}getStats(){return{poolSize:this.pool.length,poolHits:this.poolHits,poolMisses:this.poolMisses,totalCreated:this.totalParticlesCreated,totalDestroyed:this.totalParticlesDestroyed}}clear(){this.pool=[],this.poolHits=0,this.poolMisses=0,this.totalParticlesCreated=0,this.totalParticlesDestroyed=0}}class ri{constructor(){this.spawnAccumulator=0}getSpawnPosition(e,t,i,n,a,s=null){const o=Math.min(n,a)/12,r=2.5*o,l=1.1*r,h=Math.min(t-30,n-t-30),c=Math.min(i-30,a-i-30),u=Math.min(1.5*r,h,c);switch(e){case"ambient":case"resting":{const e=Math.random()*Math.PI*2,n=.9*r;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n,angle:e}}case"rising":{const e=Math.random()*Math.PI*2,n=l+Math.random()*(u-l);return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"falling":{const e=Math.random()*Math.PI*2,n=.9*r;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n,angle:e}}case"aggressive":{const e=Math.random()*Math.PI*2,n=r+Math.random()*o;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"scattering":default:return{x:t,y:i};case"burst":{const e=Math.random()*Math.PI*2;if("suspicion"===s){const n=1.5*o;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}if("surprise"===s){const n=1.2*o;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}return{x:t,y:i}}case"repelling":{const e=Math.random()*Math.PI*2,n=.9*r;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"orbiting":{const e=Math.random()*Math.PI*2,n=1.2*r+Math.random()*r*.5;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"glitchy":{const e=Math.random()*Math.PI*2,n=3*r+Math.random()*r*4;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"spaz":{const e=Math.random()*Math.PI*2,n=2*r+Math.random()*r*3;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}}}clampToCanvas(e,t,i,n,a=30){return{x:Math.max(a,Math.min(i-a,e)),y:Math.max(a,Math.min(n-a,t))}}calculateSpawnRate(e,t){if(e<=0)return 0;const i=Math.min(t,50),n=e/1e3;this.spawnAccumulator+=n*i,this.spawnAccumulator=Math.min(this.spawnAccumulator,3);let a=0;for(;this.spawnAccumulator>=1;)a++,this.spawnAccumulator-=1;return a}resetAccumulator(){this.spawnAccumulator=0}}class li{render(e,t,i="#ffffff",n=null){const a=[];for(const e of t)e.life<=0||a.push(e);this._renderParticles(e,a,i,n)}renderLayer(e,t,i="#ffffff",n=!1,a=null){const s=[],o=e.canvas.width,r=e.canvas.height;for(const e of t)e.z>=0===n&&(e.x<-50||e.x>o+50||e.y<-50||e.y>r+50||e.life<=0||s.push(e));return s.sort((e,t)=>e.isCellShaded!==t.isCellShaded?e.isCellShaded?-1:1:e.hasGlow!==t.hasGlow?e.hasGlow?-1:1:0),this._renderParticles(e,s,i,a),s}_renderParticles(e,t,i,n=null){e.save();let a=null;for(const s of t)if(s.isCellShaded)s.render(e,i),a=null;else{const t=s.color||i;if(t!==a&&(e.fillStyle=t,a=t),!isFinite(s.x)||!isFinite(s.y))continue;const o=s.getDepthAdjustedSize?s.getDepthAdjustedSize():s.size;let r=Math.max(.1,o),l=1;if(n&&n.fireflyEffect){const e=(.01*s.x+.01*s.y+.1*s.size)%(2*Math.PI),t=n.fireflyTime||.001*Date.now(),i=n.particleGlow||2;l=.3+Math.max(0,Math.sin(3*t+e))*i}if(n&&n.flickerEffect){const e=(.02*s.x+.02*s.y)%(2*Math.PI),t=n.flickerTime||.001*Date.now(),i=n.particleGlow||2;l=.5+Math.sin(12*t+e)*i*.5}if(n&&n.shimmerEffect){const t=s.x-e.canvas.width/2,i=s.y-e.canvas.height/2,a=Math.sqrt(t*t+i*i)/200,o=n.shimmerTime||.001*Date.now(),r=n.shimmerWave||0,h=n.particleGlow||1.2;l=1+.15*Math.sin(3*o-a+r)*h}if(n&&n.glowEffect){const t=n.glowProgress||0,i=n.particleGlow||2,a=s.x-e.canvas.width/2,o=s.y-e.canvas.height/2,l=Math.sqrt(a*a+o*o)/300,h=Math.min(.3*l,.5),c=Math.max(0,(t-h)/(1-h)),u=Math.sin(c*Math.PI);s._originalGlow||(s._originalGlow={hasGlow:s.hasGlow,glowSizeMultiplier:s.glowSizeMultiplier||0}),s.hasGlow=!0,s.glowSizeMultiplier=Math.max(3,s._originalGlow.glowSizeMultiplier)+u*i*3,r*=1+.3*u,t>=.99&&s._originalGlow&&(s.hasGlow=s._originalGlow.hasGlow,s.glowSizeMultiplier=s._originalGlow.glowSizeMultiplier,delete s._originalGlow)}if(s.hasGlow||l>1){const t=Math.max(.1,r*(s.glowSizeMultiplier||1.5)*l),i=e.globalCompositeOperation;e.globalCompositeOperation="screen",e.globalAlpha=.15*s.opacity*l,e.beginPath(),e.arc(s.x,s.y,t,0,2*Math.PI),e.fill(),e.globalAlpha=.25*s.opacity*l,e.beginPath(),e.arc(s.x,s.y,.6*t,0,2*Math.PI),e.fill(),e.globalCompositeOperation=i}e.globalAlpha=s.opacity*(s.baseOpacity||.5)*.6*Math.min(2,l),e.beginPath(),e.arc(s.x,s.y,r,0,2*Math.PI),e.fill()}e.restore()}}class hi{constructor(e=50,t=null){this.errorBoundary=t,this.maxParticles=e,this.absoluteMaxParticles=2*e,this.particles=[],this.particlePool=new oi(e),this.particleSpawner=new ri,this.particleRenderer=new li,this.containmentBounds=null,this.stateChangeCount=0,this.lastMemoryCheck=Date.now(),this.lastLeakedCount=0,this.particleCount=0,this.cleanupTimer=0,this.cleanupInterval=5e3}get pool(){return this.particlePool.pool}get poolSize(){return this.particlePool.poolSize}get poolHits(){return this.particlePool.poolHits}get poolMisses(){return this.particlePool.poolMisses}get totalParticlesCreated(){return this.particlePool.totalParticlesCreated}get totalParticlesDestroyed(){return this.particlePool.totalParticlesDestroyed}get spawnAccumulator(){return this.particleSpawner.spawnAccumulator}set spawnAccumulator(e){this.particleSpawner.spawnAccumulator=e}getParticleFromPool(e,t,i){return this.particlePool.getParticle(e,t,i,this.scaleFactor||1,this.particleSizeMultiplier||1,this.currentEmotionColors,this.currentEmotion,this.gestureBehavior)}returnParticleToPool(e){this.particlePool.returnParticle(e)}spawn(e,t,i,n,a,s,o=null,r=0,l=10,h=1,c=1,u=null,d=null){if(this.scaleFactor=h,this.particleSizeMultiplier=c,this.errorBoundary)return this.errorBoundary.wrap(()=>{this._spawn(e,t,i,n,a,s,o,r,l,u,d)},"particle-spawn")();this._spawn(e,t,i,n,a,s,o,r,l,u,d)}resetAccumulator(){this.particleSpawner.resetAccumulator()}_spawn(e,t,i,n,a,s,o,r=0,l=10,h=null,c=null){this.currentEmotion=t,this.baseEmotionColors=h,this.currentUndertone=c,this.currentEmotionColors=h&&c?function(e,t){return e&&Array.isArray(e)&&t&&"clear"!==t?e.map(e=>"string"==typeof e?Mt(e,t):e&&"object"==typeof e&&e.color?{...e,color:Mt(e.color,t)}:e):e}(h,c):h;let u=i;if(St.isEnabled()){const i=xt&&xt.isInitialized?xt.getEmotion(t):me(t);if(i){const t=St.applyParticleRhythm(i,this);if(t.emitBurst)for(let i=0;i<t.emitBurst&&this.particles.length<l;i++)this.spawnSingleParticle(e,n,a);void 0!==t.emissionRate&&(u*=t.emissionRate)}}if(null!==o){for(let t=0;t<o&&this.particles.length<this.maxParticles;t++)this.spawnSingleParticle(e,n,a);return}if(this.skipSpawnThisFrame)return;for(;this.particles.length<r&&this.particles.length<this.maxParticles;)this.spawnSingleParticle(e,n,a);if(this.particles.length>=l)return;if(u<=0)return;const d=this.particleSpawner.calculateSpawnRate(u,s);for(let t=0;t<d&&this.particles.length<l;t++)this.spawnSingleParticle(e,n,a)}getSpawnPosition(e,t,i,n,a){return this.particleSpawner.getSpawnPosition(e,t,i,n,a,this.currentEmotion)}clampToCanvas(e,t,i,n,a=30){return this.particleSpawner.clampToCanvas(e,t,i,n,a)}spawnSingleParticle(e,t,i){if(this.particles.length>=this.absoluteMaxParticles)return;const n=this.canvasWidth||2*t,a=this.canvasHeight||2*i,s=this.particleSpawner.getSpawnPosition(e,t,i,n,a,this.currentEmotion),o=this.particleSpawner.clampToCanvas(s.x,s.y,n,a);s.x=o.x,s.y=o.y;const r=this.getParticleFromPool(s.x,s.y,e);"meditation_swirl"===e&&s.palmCenter&&(r.palmCenter=s.palmCenter,r.swirlAngle=s.swirlAngle),this.particles.push(r),this.particleCount++}update(e,t,i,n=null,a=0,s=null){if(this.errorBoundary)return this.errorBoundary.wrap((e,t,i,n,a,s)=>this._update(e,t,i,n,a,s),"particle-update")(e,t,i,n,a,s);this._update(e,t,i,n,a,s)}_update(e,t,i,n=null,a=0,s=null){for(this.particles=this.particles.filter(o=>(o.update(e,t,i,s,n,a,this.containmentBounds),o.isAlive()));this.particles.length>this.maxParticles;)this.removeParticle(0)}setGestureBehavior(e,t){this.gestureBehavior=t?e:null,t?this.particles.forEach(t=>{t.gestureBehavior=e}):this.particles.forEach(e=>{e.gestureBehavior=null})}removeParticle(e){if(e>=0&&e<this.particles.length){const t=this.particles.splice(e,1)[0];t.cachedGradient=null,t.cachedGradientKey=null,this.returnParticleToPool(t),this.particleCount=Math.max(0,this.particleCount-1)}}render(e,t="#ffffff",i=null){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._render(e,t,i)},"particle-render")();this._render(e,t,i)}renderBackground(e,t="#ffffff",i=null){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._renderLayer(e,t,!1,i)},"particle-render-bg")();this._renderLayer(e,t,!1,i)}renderForeground(e,t="#ffffff",i=null){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._renderLayer(e,t,!0,i)},"particle-render-fg")();this._renderLayer(e,t,!0,i)}_renderLayer(e,t,i,n=null){this.particleRenderer.renderLayer(e,this.particles,t,i,n)}_render(e,t,i=null){this.particleRenderer.render(e,this.particles,t,i)}clear(){for(this.stateChangeCount++;this.particles.length>0;){const e=this.particles.pop();if(e.cachedColors&&e.cachedColors.clear(),e.behaviorData)for(const t in e.behaviorData)delete e.behaviorData[t];this.pool.length<this.poolSize&&!this.pool.includes(e)&&this.pool.push(e)}if(this.particles.length=0,this.particleCount=0,this.spawnAccumulator=0,this.pool.length>this.poolSize){const e=this.pool.length-this.poolSize;this.pool.splice(this.poolSize,e)}}burst(e,t,i,n){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._burst(e,t,i,n)},"particle-burst")();this._burst(e,t,i,n)}_burst(e,t,i,n){const a=Math.min(e,this.maxParticles-this.particles.length);for(let e=0;e<a;e++)this.spawnSingleParticle(t,i,n)}performCleanup(){if(this.pool.length>this.poolSize){const e=this.pool.length-this.poolSize;for(let t=0;t<e;t++){const e=this.pool.pop();e&&(e.cachedGradient=null,e.cachedGradientKey=null,e.behaviorData=null)}}for(const e of this.particles)e.cachedGradient&&e.life<.5&&(e.cachedGradient=null,e.cachedGradientKey=null)}getStats(){return{activeParticles:this.particles.length,maxParticles:this.maxParticles,poolSize:this.pool.length,poolHits:this.poolHits,poolMisses:this.poolMisses,poolEfficiency:this.poolHits/Math.max(1,this.poolHits+this.poolMisses),spawnAccumulator:this.spawnAccumulator}}setMaxParticles(e){for(this.originalMaxParticles=this.originalMaxParticles||this.maxParticles,this.maxParticles=Math.max(1,e);this.particles.length>this.maxParticles;)this.removeParticle(0)}cleanupDeadParticles(){const e=this.particles.length;this.particles=this.particles.filter(e=>e.isAlive());const t=e-this.particles.length;return this.pool.length>20&&(this.pool.length=20),t}getParticlesByBehavior(e){return this.particles.filter(t=>t.behavior===e)}validateParticles(){for(const e of this.particles)if(!e.isAlive()||e.life<0||e.life>1)return!1;return!0}cleanup(){for(let e=this.particles.length-1;e>=0;e--)this.particles[e].isAlive()||this.removeParticle(e)}refreshPool(){this.particlePool.clear();for(const e of this.particles)e.life=0}setContainmentBounds(e){this.containmentBounds=e}destroy(){this.clear(),this.particlePool.clear()}}class ci{constructor(t={}){this.worldScale=t.worldScale||.2,this.baseRadius=t.baseRadius||.15,this.depthScale=t.depthScale||.75,this.verticalScale=t.verticalScale||1,this.coreRadius3D=t.coreRadius3D||1,this.tempVec3=new e.Vector3,this.tempVec3_2=new e.Vector3,this.behaviorTranslators=this._initBehaviorTranslators(),this.currentGestureData=null}setCoreRadius3D(e){this.coreRadius3D=e}updateRotationState(e,t,i=null){this.rotationState=e,this.deltaTime=t,this.currentGestureData=i}_initBehaviorTranslators(){return{ambient:this._translateAmbient.bind(this),orbiting:this._translateOrbiting.bind(this),rising:this._translateRising.bind(this),falling:this._translateFalling.bind(this),popcorn:this._translatePopcorn.bind(this),burst:this._translateBurst.bind(this),aggressive:this._translateAggressive.bind(this),scattering:this._translateScattering.bind(this),repelling:this._translateRepelling.bind(this),connecting:this._translateConnecting.bind(this),resting:this._translateResting.bind(this),radiant:this._translateRadiant.bind(this),ascending:this._translateAscending.bind(this),erratic:this._translateErratic.bind(this),cautious:this._translateCautious.bind(this),surveillance:this._translateSurveillance.bind(this),glitchy:this._translateGlitchy.bind(this),spaz:this._translateSpaz.bind(this),directed:this._translateDirected.bind(this),fizzy:this._translateFizzy.bind(this),zen:this._translateZen.bind(this),gravitationalAccretion:this._translateGravitationalAccretion.bind(this)}}translate2DTo3D(e,t,i){const n=(this.behaviorTranslators[e.behavior]||this._translateDefault.bind(this))(e,t,i);return this.currentGestureData&&"spin"===this.currentGestureData.gestureName?this._applySpinRotation(n,t,this.currentGestureData.progress):n}_applySpinRotation(e,t,i){const n=e.x-t.x,a=e.y-t.y,s=e.z-t.z,o=Math.sin(i*Math.PI)*Math.PI*2,r=Math.cos(o),l=Math.sin(o),h=n*r-s*l,c=n*l+s*r;return this.tempVec3.set(t.x+h,t.y+a,t.z+c)}_canvasToWorld(e,t,i,n,a,s){const o=(e-n)/n,r=-(t-a)/a,l=1+i*this.depthScale,h=o*this.worldScale*l+s.x,c=r*this.worldScale*this.verticalScale*l+s.y,u=i*this.worldScale*.5+s.z;return this.tempVec3.set(h,c,u)}_hash(e){const t=43758.5453123*Math.sin(e);return t-Math.floor(t)}_getUniformDirection3D(e){const t=e.behaviorData||{};if(t.direction3D)return t.direction3D;const i=127.1*e.x+311.7*e.y+74.7*(e.vx||0)+159.3*(e.vy||0),n=this._hash(i),a=this._hash(i+1),s=n*Math.PI*2,o=2*a-1,r=Math.sqrt(1-o*o),l=r*Math.cos(s),h=o,c=r*Math.sin(s);return t.direction3D={x:l,y:h,z:c},t.direction3D}_toSpherical(e,t,i,n){const a=e-n.x,s=t-n.y,o=i-n.z,r=Math.sqrt(a*a+s*s+o*o);return{radius:r,theta:Math.atan2(o,a),phi:Math.acos(s/(r||1))}}_toCartesian(e,t,i,n){const a=e*Math.sin(i)*Math.cos(t)+n.x,s=e*Math.cos(i)+n.y,o=e*Math.sin(i)*Math.sin(t)+n.z;return this.tempVec3_2.set(a,s,o)}_translateDefault(e,t,i){return this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t)}_translateAmbient(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.6*this.coreRadius3D,c=h+l*(1.2*this.coreRadius3D-h),u=.5*e.age,d=.03*this.coreRadius3D,m=Math.cos(u)*d,p=Math.sin(u)*d;return this.tempVec3.set(t.x+n.x*c+m,t.y+n.y*c*this.verticalScale,t.z+n.z*c+p)}_translateOrbiting(e,t,i){const n=e.behaviorData||{};if(!n.orbitPlane){const t=e.x+.5*e.y,i=.7*e.x+e.y;n.orbitPlane={inclination:.5*(Math.sin(.1*t)+1)*Math.PI,rotation:.5*(Math.sin(.1*i)+1)*Math.PI*2}}const{inclination:a,rotation:s}=n.orbitPlane,o=n.angle||0,r=.01*(n.radius||100)*this.baseRadius*.25*(1+e.z*this.depthScale),l=Math.cos(o)*r,h=Math.sin(o)*r,c=Math.cos(a),u=Math.sin(a),d=Math.cos(s),m=Math.sin(s),p=l*d-h*c*m,g=h*u,f=l*m+h*c*d;return this.tempVec3.set(t.x+p,t.y+g*this.verticalScale,t.z+f)}_translateRising(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=-.01*e.vy;return n.y+=a,n}_translateFalling(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.6*this.coreRadius3D,c=h+l*(1.2*this.coreRadius3D-h),u=.6*e.age*this.coreRadius3D;return this.tempVec3.set(t.x+n.x*c,t.y+n.y*c*this.verticalScale-u,t.z+n.z*c)}_translatePopcorn(e,t,i){const n=i.width/2,a=i.height/2,s=e.behaviorData||{},o=this._getUniformDirection3D(e);if(!s.hasPopped){const e=.7*this.coreRadius3D;return this.tempVec3.set(t.x+o.x*e,t.y+o.y*e*this.verticalScale,t.z+o.z*e)}const r=e.x-n,l=e.y-a,h=Math.sqrt(r*r+l*l),c=Math.min(h/n,1.5),u=1.2*this.coreRadius3D,d=u+c*(4*this.coreRadius3D-u);return this.tempVec3.set(t.x+o.x*d,t.y+o.y*d*this.verticalScale,t.z+o.z*d)}_translateBurst(e,t,i){const n=this._getUniformDirection3D(e),a=1-e.life,s=this.coreRadius3D*(1+1*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateAggressive(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.3*this.coreRadius3D,c=h+l*(.55*this.coreRadius3D-h),u=.04*this.coreRadius3D,d=Math.sin(10*e.age+.1*e.x)*u,m=Math.cos(12*e.age+.1*e.y)*u,p=Math.sin(8*e.age+.1*e.vx)*u;return this.tempVec3.set(t.x+n.x*c+d,t.y+n.y*c*this.verticalScale+m,t.z+n.z*c+p)}_translateScattering(e,t,i){const n=this._getUniformDirection3D(e),a=Math.min(.8*e.age,1),s=this.coreRadius3D*(.3+.3*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateRepelling(e,t,i){const n=this._getUniformDirection3D(e),a=Math.min(.6*e.age,1),s=this.coreRadius3D*(.3+.3*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateConnecting(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=.3*(1-e.life),s=this.tempVec3_2.set(t.x-n.x,t.y-n.y,t.z-n.z).normalize();return n.add(s.multiplyScalar(a)),n}_translateResting(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.25*this.coreRadius3D,c=h+l*(.45*this.coreRadius3D-h),u=.3*e.age,d=Math.sin(u)*this.coreRadius3D*.01;return this.tempVec3.set(t.x+n.x*c,t.y+n.y*c*this.verticalScale+d,t.z+n.z*c)}_translateRadiant(e,t,i){const n=this._getUniformDirection3D(e),a=1-e.life,s=this.coreRadius3D*(1+.8*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateAscending(e,t,i){const n=e.behaviorData||{},a=n.spiralAngle||0,s=.01*(n.spiralRadius||50)*this.coreRadius3D,o=e.age*this.coreRadius3D*.5,r=Math.cos(a)*s+t.x,l=o+t.y,h=Math.sin(a)*s+t.z;return this.tempVec3.set(r,l,h)}_translateErratic(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=10*e.age;return n.x+=.1*Math.sin(1.1*a),n.y+=.1*Math.cos(1.3*a),n.z+=.1*Math.sin(1.7*a),n}_translateCautious(e,t,i){return this._translateAmbient(e,t,i)}_translateSurveillance(e,t,i){const n=this._getUniformDirection3D(e),a=.5*e.age,s=1.2*this.coreRadius3D,o={x:0*n.y-1*n.z,y:0*n.z-0*n.x,z:1*n.x-0*n.y},r=Math.sqrt(o.x*o.x+o.y*o.y+o.z*o.z);r>0&&(o.x/=r,o.y/=r,o.z/=r);const l=Math.cos(a)*n.x+Math.sin(a)*o.x,h=Math.cos(a)*n.y+Math.sin(a)*o.y,c=Math.cos(a)*n.z+Math.sin(a)*o.z;return this.tempVec3.set(t.x+l*s,t.y+h*s*this.verticalScale,t.z+c*s)}_translateGlitchy(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t);return Math.floor(10*e.age)%3==0&&(n.x+=.3*(Math.random()-.5),n.y+=.3*(Math.random()-.5),n.z+=.3*(Math.random()-.5)),n}_translateSpaz(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=.15,s=20*e.age;return n.x+=Math.sin(2.1*s)*a,n.y+=Math.cos(2.3*s)*a,n.z+=Math.sin(2.7*s)*a,n}_translateDirected(e,t,i){const n=e.behaviorData||{};if(void 0!==n.targetX&&void 0!==n.targetY){const a=this._canvasToWorld(n.targetX,n.targetY,e.z,i.width/2,i.height/2,t),s=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),o=1-e.life;return this.tempVec3.lerpVectors(s,a,o)}const a=this._getUniformDirection3D(e),s=i.width/2,o=i.height/2,r=e.x-s,l=e.y-o,h=Math.sqrt(r*r+l*l)/s,c=1*this.coreRadius3D,u=c+h*(1.6*this.coreRadius3D-c);return this.tempVec3.set(t.x+a.x*u,t.y+a.y*u*this.verticalScale,t.z+a.z*u)}_translateFizzy(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=.05*Math.sin(8*e.age);return n.x+=a,n.z+=.05*Math.cos(8*e.age),n.y+=.5*e.age,n}_translateZen(e,t,i){const n=this._getUniformDirection3D(e),a=.2*e.age,s=1.4*this.coreRadius3D,o={x:0*n.y-1*n.z,y:0*n.z-0*n.x,z:1*n.x-0*n.y},r=Math.sqrt(o.x*o.x+o.y*o.y+o.z*o.z);r>0&&(o.x/=r,o.y/=r,o.z/=r);const l=Math.cos(a)*n.x+Math.sin(a)*o.x,h=Math.cos(a)*n.y+Math.sin(a)*o.y,c=Math.cos(a)*n.z+Math.sin(a)*o.z;return this.tempVec3.set(t.x+l*s,t.y+h*s*this.verticalScale,t.z+c*s)}_translateGravitationalAccretion(e,t,i){const n=e.behaviorData||{},a=.25;if(n.orbitRadius||(e.x,e.y,n.orbitRadius=a*(2.5+5.5*Math.random()),n.orbitAngle=Math.PI+Math.random()*Math.PI,n.diskInclination=.1*(Math.random()-.5),n.angularVelocity=.5/Math.sqrt(n.orbitRadius/a),n.tidalStretch={x:1,y:1,z:1}),n.orbitRadius-=1e-4*this.baseRadius,n.angularVelocity=.5/Math.sqrt(n.orbitRadius/a),n.orbitAngle+=n.angularVelocity*(this.deltaTime||16)*.001,n.orbitAngle=n.orbitAngle%(2*Math.PI),n.orbitAngle<0&&(n.orbitAngle+=2*Math.PI),n.orbitAngle<Math.PI)return e.isAlive=!1,e.life=0,this.tempVec3.set(t.x,t.y,t.z);const s=n.orbitRadius/a;if(s<=1)e.isAlive=!1,e.life=0;else if(s<=1.5)n.tidalStretch.x=.3,n.tidalStretch.y=3,n.tidalStretch.z=.3;else if(s<=2.5){const e=(2.5-s)/1;n.tidalStretch.x=1-.7*e,n.tidalStretch.y=1+2*e,n.tidalStretch.z=1-.7*e}else n.tidalStretch.x=1,n.tidalStretch.y=1,n.tidalStretch.z=1;const o=Math.cos(n.orbitAngle)*n.orbitRadius,r=Math.sin(n.orbitAngle)*n.orbitRadius,l=.025*Math.sin(3*n.orbitAngle+e.x)*Math.sin(n.diskInclination),h=o*n.tidalStretch.x,c=l*n.tidalStretch.y,u=r*n.tidalStretch.z,d=.25;return this.tempVec3.set(t.x+h*d,t.y+c*d,t.z+u*d)}setWorldScale(e){this.worldScale=e}setBaseRadius(e){this.baseRadius=e}cleanupParticleCaches(e){for(const t of e)!t.isAlive&&t.behaviorData&&(t.behaviorData.direction3D&&(t.behaviorData.direction3D=null),t.behaviorData.orbitPlane&&(t.behaviorData.orbitPlane=null),t.behaviorData.orbitPath&&(t.behaviorData.orbitPath=null),t.behaviorData.orbitRadius&&(t.behaviorData.orbitRadius=null,t.behaviorData.orbitAngle=null,t.behaviorData.diskInclination=null,t.behaviorData.angularVelocity=null,t.behaviorData.tidalStretch=null))}dispose(){this.tempVec3=null,this.tempVec3_2=null,this.rotationState=null,this.currentGestureData=null}}let ui=null,di=null;const mi=`\n uniform float time;\n uniform vec3 emotionColor;\n uniform float energyIntensity;\n uniform float driftEnabled;\n uniform float driftSpeed;\n uniform float crossWaveEnabled;\n uniform float crossWaveSpeed;\n uniform float ghostMode; // 0.0 = solid, 1.0 = ghost (only visible through bloom)\n uniform float baseOpacity; // Base opacity when not in ghost mode (default 1.0)\n uniform float phaseOffset1; // Phase offset for primary drift (radians)\n uniform float phaseOffset2; // Phase offset for secondary drift (radians)\n uniform float phaseOffset3; // Phase offset for crosswave (radians)\n\n // Blend layer uniforms\n uniform float blendLayer1Mode;\n uniform float blendLayer1Strength;\n uniform float blendLayer1Enabled;\n uniform float blendLayer2Mode;\n uniform float blendLayer2Strength;\n uniform float blendLayer2Enabled;\n\n varying vec3 vPosition;\n varying vec3 vNormal;\n\n // Blend modes (injected from blendModesGLSL)\n ${S}\n\n // Smooth noise function\n float noise3D(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n float n = i.x + i.y * 157.0 + i.z * 113.0;\n vec4 v = fract(sin(vec4(n, n+1.0, n+157.0, n+158.0)) * 43758.5453);\n return mix(mix(v.x, v.y, f.x), mix(v.z, v.w, f.x), f.y);\n }\n\n void main() {\n // Drifting energy clouds - slow, ethereal movement\n // Start with zero energy - only effects add to it\n float driftEnergy = 0.0;\n float crossWaveEnergy = 0.0;\n\n // Spatially triangulated fire bands - each owns a 120° wedge of the geometry\n // Bands can never overlap because they're physically separated\n float angle = atan(vPosition.x, vPosition.z); // -π to π\n float normalizedAngle = (angle + 3.14159) / 6.28318; // 0 to 1\n\n // Determine which zone this fragment belongs to (0, 1, or 2)\n float zone = floor(normalizedAngle * 3.0);\n float zonePos = fract(normalizedAngle * 3.0); // Position within zone (0-1)\n\n // Time-based phase for each zone (120° offset in time)\n float phaseSpeed = 0.15;\n float t = time * phaseSpeed;\n float phase1Time = sin(t + phaseOffset1) * 0.5 + 0.5;\n float phase2Time = sin(t + phaseOffset2) * 0.5 + 0.5;\n float phase3Time = sin(t + phaseOffset3) * 0.5 + 0.5;\n\n // Only ONE phase affects this fragment - the one that owns this spatial zone\n float activePhase = zone < 1.0 ? phase1Time : (zone < 2.0 ? phase2Time : phase3Time);\n\n float primaryDrift = 0.0;\n float secondaryDrift = 0.0;\n\n if (driftEnabled > 0.5) {\n float t = time * driftSpeed;\n // Primary drift - moving in one direction\n float drift1 = noise3D(vPosition * 2.0 + vec3(t, t * 0.7, t * 0.3));\n float drift2 = noise3D(vPosition * 3.0 - vec3(t * 0.5, t, t * 0.8));\n // Use max instead of multiply to avoid near-zero products\n primaryDrift = max(drift1, drift2);\n primaryDrift = max(0.0, primaryDrift - 0.4) * 2.0; // Rescale after threshold\n\n // Secondary drift - offset in opposite direction to fill gaps\n float drift3 = noise3D(vPosition * 2.5 - vec3(t * 0.8, t * 0.4, t));\n float drift4 = noise3D(vPosition * 1.8 + vec3(t * 0.6, t * 0.9, t * 0.2));\n secondaryDrift = max(drift3, drift4);\n secondaryDrift = max(0.0, secondaryDrift - 0.4) * 2.0;\n\n driftEnergy = primaryDrift + secondaryDrift;\n }\n\n // Horizontal cross wave - thin bands sweeping across\n float rawCrossWave = 0.0;\n if (crossWaveEnabled > 0.5) {\n float t = time * crossWaveSpeed;\n float wave = sin(vPosition.x * 4.0 + vPosition.z * 2.0 - t) * 0.5 + 0.5;\n // pow(4) for thin bright bands\n rawCrossWave = pow(wave, 4.0);\n crossWaveEnergy = rawCrossWave;\n }\n\n // Mix the effects - normalize to prevent blowout\n // driftEnergy can be 0-2 (two drifts), rawCrossWave is 0-1\n float normalizedDrift = min(1.0, driftEnergy * 0.5);\n float normalizedWave = rawCrossWave;\n\n // activePhase is 0-1, remap to visibility range\n // 0.53 floor (just above 0.52 threshold), 0.58 ceiling (subtle glow)\n float remappedPhase = 0.53 + activePhase * 0.05;\n\n // Effects add subtle variation (max 0.05)\n float effectContrib = (normalizedDrift * 0.03) + (normalizedWave * 0.02);\n float phasedActivity = remappedPhase + effectContrib;\n\n // Keep unclamped for visibility threshold check (ghost mode needs full range)\n float rawEffectActivity = phasedActivity;\n // Clamp for color intensity (floor: guaranteed visible, ceiling: no blowout)\n float effectActivity = clamp(phasedActivity, 0.53, 0.60);\n\n // Total energy for color calculation (reduced for subtler bloom)\n float totalEnergy = 0.25 + effectActivity * 0.55; // Base glow + effect contribution\n\n // Edge glow - adds rim lighting\n vec3 viewDir = normalize(-vPosition);\n float edgeGlow = 1.0 - abs(dot(vNormal, viewDir));\n edgeGlow = pow(edgeGlow, 2.0) * 0.4;\n\n // Final color before blend layers\n vec3 coreColor = emotionColor * totalEnergy * energyIntensity;\n coreColor += emotionColor * edgeGlow * 0.3;\n\n // Apply blend layers to the entire soul color\n if (blendLayer1Enabled > 0.5) {\n int mode = int(blendLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(coreColor, emotionColor * blendLayer1Strength, mode);\n coreColor = mix(coreColor, blendResult, blendLayer1Strength);\n }\n if (blendLayer2Enabled > 0.5) {\n int mode = int(blendLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(coreColor, emotionColor * blendLayer2Strength, mode);\n coreColor = mix(coreColor, blendResult, blendLayer2Strength);\n }\n\n // Ghost mode: ONLY the traveling fire bands are visible\n // Everything below the threshold is completely invisible\n float alpha = baseOpacity;\n if (ghostMode > 0.01) {\n // High threshold - only the peaks of the thin bands pass through\n float threshold = 0.4 + ghostMode * 0.4; // 0.4-0.8 range\n float visibility = smoothstep(threshold, threshold + 0.05, rawEffectActivity);\n\n // Hard cutoff - only bright fire bands visible\n alpha = visibility * baseOpacity;\n\n // Discard everything that isn't a bright fire band\n if (alpha < 0.05) {\n discard;\n }\n\n // Boost color intensity for visible fire\n coreColor *= 1.2 + visibility * 0.6;\n }\n\n // Output the computed core color\n gl_FragColor = vec4(coreColor, alpha);\n }\n`;class pi{constructor(e={}){this.radius=e.radius||.15,this.detail=e.detail||1,this.geometryType=e.geometryType||"crystal",this.renderer=e.renderer||null,this.assetBasePath=e.assetBasePath||"/assets",this.mesh=null,this.material=null,this.parentMesh=null,this.baseScale=1,this._pendingParent=null,this._disposed=!1,this._createMesh()}static _loadInclusionGeometry(t="/assets"){return ui?Promise.resolve(ui.clone()):di?di.then(e=>e.clone()):(di=new Promise(i=>{(new f).load(`${t}/models/Crystal/inclusion.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z),n.rotateX(Math.PI/2),n.computeBoundingBox();const a=new e.Vector3;n.boundingBox.getSize(a);const s=.3/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),ui=n,i(n.clone())}else console.warn("[🔮 SOUL] No mesh in inclusion.obj, using fallback"),i(null)},void 0,e=>{console.warn("[🔮 SOUL] Failed to load inclusion.obj:",e),i(null)})}),di)}_createMesh(){let t;console.log(`[CrystalSoul] _createMesh() START, inclusionGeometryCache=${!!ui}`),this.material=new e.ShaderMaterial({uniforms:{time:{value:0},emotionColor:{value:new e.Color(1,1,1)},energyIntensity:{value:1.5},driftEnabled:{value:1},driftSpeed:{value:.5},crossWaveEnabled:{value:1},crossWaveSpeed:{value:.4},ghostMode:{value:.36},baseOpacity:{value:1},phaseOffset1:{value:0},phaseOffset2:{value:2.094},phaseOffset3:{value:4.189},blendLayer1Mode:{value:2},blendLayer1Strength:{value:2.3},blendLayer1Enabled:{value:1},blendLayer2Mode:{value:0},blendLayer2Strength:{value:1},blendLayer2Enabled:{value:1}},vertexShader:"\n varying vec3 vPosition;\n varying vec3 vNormal;\n\n void main() {\n vPosition = position;\n vNormal = normalize(normalMatrix * normal);\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n",fragmentShader:mi,transparent:!0,depthWrite:!0,depthTest:!0,side:e.FrontSide}),t=ui?ui.clone():new e.OctahedronGeometry(this.radius,this.detail),this.mesh=new e.Mesh(t,this.material),this.mesh.name="crystalSoul",this.mesh.renderOrder=0,this.mesh.layers.set(2)}attachTo(e,t){this._disposed||(e?this.mesh?(this.mesh.parent&&this.mesh.parent.remove(this.mesh),this.parentMesh=e,this._scene=t,t&&!this.mesh.parent&&t.add(this.mesh),this._syncPosition(),this.mesh.visible=!0):console.warn("[CrystalSoul] Cannot attach - mesh is null"):console.warn("[CrystalSoul] Cannot attach to null parent"))}_syncPosition(){this.parentMesh&&this.mesh&&(this.parentMesh.getWorldPosition(this.mesh.position),this.parentMesh.getWorldQuaternion(this.mesh.quaternion))}detach(){this.mesh&&(this.mesh.visible=!1,this.parentMesh=null)}update(e,t,i=1){if(!this.material||!this.material.uniforms)return;this._syncPosition();const{uniforms:n}=this.material;n.time&&(n.time.value+=e/1e3),n.emotionColor&&t&&n.emotionColor.value.setRGB(t[0],t[1],t[2]),n.energyIntensity&&(n.energyIntensity.value=.8),this.mesh&&this.mesh.scale.setScalar(this.baseScale*i)}setSize(e){if(!this.mesh)return;const t=.05+.95*e;this.baseScale=t,this.mesh.scale.setScalar(t)}setEffects(e={}){if(!this.material||!this.material.uniforms)return;const{uniforms:t}=this.material;void 0!==e.driftEnabled&&t.driftEnabled&&(t.driftEnabled.value=e.driftEnabled?1:0),void 0!==e.driftSpeed&&t.driftSpeed&&(t.driftSpeed.value=Math.max(.1,Math.min(3,e.driftSpeed))),void 0!==e.crossWaveEnabled&&t.crossWaveEnabled&&(t.crossWaveEnabled.value=e.crossWaveEnabled?1:0),void 0!==e.crossWaveSpeed&&t.crossWaveSpeed&&(t.crossWaveSpeed.value=Math.max(.1,Math.min(3,e.crossWaveSpeed))),void 0!==e.phaseOffset1&&t.phaseOffset1&&(t.phaseOffset1.value=e.phaseOffset1),void 0!==e.phaseOffset2&&t.phaseOffset2&&(t.phaseOffset2.value=e.phaseOffset2),void 0!==e.phaseOffset3&&t.phaseOffset3&&(t.phaseOffset3.value=e.phaseOffset3)}setColor(e){this.material&&this.material.uniforms&&this.material.uniforms.emotionColor&&this.material.uniforms.emotionColor.value.setRGB(e[0],e[1],e[2])}setBlendLayers(e){if(!this.material||!this.material.uniforms)return;const t=this.material.uniforms;e[0]?(t.blendLayer1Mode&&(t.blendLayer1Mode.value=e[0].mode??0),t.blendLayer1Strength&&(t.blendLayer1Strength.value=e[0].strength??0),t.blendLayer1Enabled&&(t.blendLayer1Enabled.value=e[0].enabled?1:0)):t.blendLayer1Enabled&&(t.blendLayer1Enabled.value=0),e[1]?(t.blendLayer2Mode&&(t.blendLayer2Mode.value=e[1].mode??0),t.blendLayer2Strength&&(t.blendLayer2Strength.value=e[1].strength??0),t.blendLayer2Enabled&&(t.blendLayer2Enabled.value=e[1].enabled?1:0)):t.blendLayer2Enabled&&(t.blendLayer2Enabled.value=0)}isAttached(){return null!==this.parentMesh&&null!==this.mesh&&null!==this.mesh.parent}setVisible(e){this.mesh&&(this.mesh.visible=e)}setGhostMode(e){this.material&&this.material.uniforms&&this.material.uniforms.ghostMode&&(this.material.uniforms.ghostMode.value=e?1:0)}setBaseOpacity(e){this.material&&this.material.uniforms&&this.material.uniforms.baseOpacity&&(this.material.uniforms.baseOpacity.value=Math.max(0,Math.min(1,e)))}dispose(){if(this._disposed)return;this._disposed=!0,this.mesh&&(this.mesh.visible=!1);const e=this.mesh,t=this.material;e?.parent&&e.parent.remove(e),this.mesh=null,this.material=null,this.parentMesh=null,requestAnimationFrame(()=>{e?.geometry&&e.geometry.dispose(),t&&t.dispose()})}}class gi{constructor(e=50,t={}){this.maxParticles=e,this.options=t,this.geometry=null,this.material=null,this.points=null,this.positions=null,this.sizes=null,this.colors=null,this.alphas=null,this.glowIntensities=null,this.depths=null,this.styles=null,this.particleCount=0,this.gestureEffects={firefly:!1,flicker:!1,shimmer:!1,glow:!1,time:0},this._initGeometry(),this._initMaterial(),this._initPoints()}_initGeometry(){this.geometry=new e.BufferGeometry;const{maxParticles:t}=this;this.positions=new Float32Array(3*t),this.sizes=new Float32Array(t),this.colors=new Float32Array(3*t),this.alphas=new Float32Array(t),this.glowIntensities=new Float32Array(t),this.depths=new Float32Array(t),this.styles=new Float32Array(t),this.geometry.setAttribute("position",new e.BufferAttribute(this.positions,3)),this.geometry.setAttribute("size",new e.BufferAttribute(this.sizes,1)),this.geometry.setAttribute("customColor",new e.BufferAttribute(this.colors,3)),this.geometry.setAttribute("alpha",new e.BufferAttribute(this.alphas,1)),this.geometry.setAttribute("glowIntensity",new e.BufferAttribute(this.glowIntensities,1)),this.geometry.setAttribute("depth",new e.BufferAttribute(this.depths,1)),this.geometry.setAttribute("style",new e.BufferAttribute(this.styles,1)),this.geometry.attributes.position.setUsage(e.DynamicDrawUsage),this.geometry.attributes.size.setUsage(e.DynamicDrawUsage),this.geometry.attributes.customColor.setUsage(e.DynamicDrawUsage),this.geometry.attributes.alpha.setUsage(e.DynamicDrawUsage),this.geometry.attributes.glowIntensity.setUsage(e.DynamicDrawUsage),this.geometry.attributes.depth.setUsage(e.DynamicDrawUsage),this.geometry.attributes.style.setUsage(e.DynamicDrawUsage),this.geometry.setDrawRange(0,0)}_initMaterial(){this.material=new e.ShaderMaterial({uniforms:{coreScale:{value:1},viewportHeight:{value:600},pixelRatio:{value:1}},vertexShader:"\n/**\n * Particle Vertex Shader - Simple 2D-style particles in 3D space\n * Matches the 2D canvas particle appearance\n */\n\n// Per-particle attributes\nattribute float size;\nattribute vec3 customColor;\nattribute float alpha;\nattribute float glowIntensity;\nattribute float style; // 0.0 = solid/gradient, 1.0 = cell-shaded (ring with transparent center)\n\n// Uniforms\nuniform float coreScale;\nuniform float viewportHeight;\nuniform float pixelRatio;\n\n// Varying to fragment shader\nvarying vec3 vColor;\nvarying float vAlpha;\nvarying float vGlowIntensity;\nvarying float vStyle;\n\nvoid main() {\n // Pass attributes to fragment shader\n vColor = customColor;\n vAlpha = alpha;\n vGlowIntensity = glowIntensity;\n vStyle = style;\n\n // Calculate position in clip space\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n\n // Calculate point size with perspective scaling\n float perspectiveScale = coreScale * (75.0 / length(mvPosition.xyz)) * (viewportHeight / 600.0) / pixelRatio;\n gl_PointSize = size * perspectiveScale;\n\n // Final position\n gl_Position = projectionMatrix * mvPosition;\n}\n",fragmentShader:"\n/**\n * Particle Fragment Shader - Solid colored circles matching 2D appearance\n * Uses premultiplied alpha for proper blending\n */\n\nvarying vec3 vColor;\nvarying float vAlpha;\nvarying float vGlowIntensity;\nvarying float vStyle;\n\nvoid main() {\n // Distance from center (0 at center, 0.5 at edge)\n vec2 center = gl_PointCoord - vec2(0.5);\n float dist = length(center);\n\n // Hard circle cutoff - discard everything outside\n if (dist > 0.45) {\n discard;\n }\n\n vec3 finalColor = vColor;\n\n // Base opacity from particle (already includes baseOpacity variation)\n float alpha = vAlpha;\n\n // Gesture glow boost\n if (vGlowIntensity >= 2.0) {\n float gestureBoost = (vGlowIntensity - 2.0) / 13.0;\n finalColor *= (1.0 + gestureBoost * 0.5);\n alpha = min(alpha * (1.0 + gestureBoost * 0.3), 1.0);\n }\n\n // Cell-shaded particles are slightly more opaque\n float opacityBoost = vStyle > 0.5 ? 1.0 : 0.85;\n alpha *= opacityBoost;\n\n // Output with proper alpha for blending\n // Premultiply alpha for correct compositing\n gl_FragColor = vec4(finalColor * alpha, alpha);\n}\n",transparent:!0,blending:e.CustomBlending,blendSrc:e.OneFactor,blendDst:e.OneMinusSrcAlphaFactor,blendSrcAlpha:e.OneFactor,blendDstAlpha:e.OneMinusSrcAlphaFactor,depthWrite:!1,depthTest:!0})}_initPoints(){this.points=new e.Points(this.geometry,this.material),this.points.frustumCulled=!0}updateParticles(e,t,i,n,a,s,o,r,l){this.particleCount=Math.min(e.length,this.maxParticles),void 0!==r&&(this.material.uniforms.coreScale.value=r),n&&n.height&&(this.material.uniforms.viewportHeight.value=n.height),this.options.renderer&&(this.material.uniforms.pixelRatio.value=this.options.renderer.getPixelRatio()),this.gestureEffects.time+=.016,this.gestureEffects.time>2*Math.PI&&(this.gestureEffects.time=this.gestureEffects.time%(2*Math.PI)),a&&s&&t.updateRotationState(a,s,o);for(let a=0;a<this.particleCount;a++){const s=e[a];if(!s.isAlive()){this.alphas[a]=0;continue}const o=t.translate2DTo3D(s,i,n);if(("crystal"===l||"heart"===l||"rough"===l)&&o.z>.15){this.alphas[a]=0;continue}const r=3*a;this.positions[r+0]=o.x,this.positions[r+1]=o.y,this.positions[r+2]=o.z;const h=s.getDepthAdjustedSize?s.getDepthAdjustedSize():s.size,c="popcorn"===s.behavior?1.2:.85;this.sizes[a]=h*c;const u=this._parseColor(s.color||"#ffffff"),d=3*a;this.colors[d+0]=u.r,this.colors[d+1]=u.g,this.colors[d+2]=u.b,this.alphas[a]=s.opacity*(s.baseOpacity||1);let m=s.hasGlow?1*(s.glowSizeMultiplier||1.5):0;m=this._applyGestureEffects(s,m,a),this.glowIntensities[a]=m;const p=.5*(1-s.z);this.depths[a]=Math.max(0,Math.min(1,p)),this.styles[a]=s.isCellShaded?1:0}this.geometry.attributes.position.needsUpdate=!0,this.geometry.attributes.size.needsUpdate=!0,this.geometry.attributes.customColor.needsUpdate=!0,this.geometry.attributes.alpha.needsUpdate=!0,this.geometry.attributes.glowIntensity.needsUpdate=!0,this.geometry.attributes.depth.needsUpdate=!0,this.geometry.attributes.style.needsUpdate=!0,this.geometry.setDrawRange(0,this.particleCount)}_applyGestureEffects(e,t,i){let n=t;if(this.gestureEffects.firefly){const t=(.01*e.x+.01*e.y+.1*e.size)%(2*Math.PI),i=2+.5*(Math.sin(3*this.gestureEffects.time+t)+1)*10;n=Math.max(n,i)}if(this.gestureEffects.flicker){const t=(.02*e.x+.02*e.y)%(2*Math.PI),a=15*this.gestureEffects.time,s=.5*(Math.sin(a+t)+1),o=Math.floor(10*a+i),r=2+10*(.3*s+.5*(Math.sin(123.456*o)+1)*.7);n=Math.max(n,r)}if(this.gestureEffects.shimmer){const t=e.x-(this.gestureEffects.centerX||0),i=e.y-(this.gestureEffects.centerY||0),a=Math.sqrt(t*t+i*i)/200,s=2+.5*(Math.sin(3*this.gestureEffects.time-a)+1)*8;n=Math.max(n,s)}if(this.gestureEffects.glow){const e=this.gestureEffects.glowProgress||0,t=3+12*Math.sin(e*Math.PI);n=Math.max(n,t)}return n}_parseColor(e){const t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?{r:parseInt(t[1],16)/255,g:parseInt(t[2],16)/255,b:parseInt(t[3],16)/255}:{r:1,g:1,b:1}}setGestureEffects(e){if(!e)return this.gestureEffects.firefly=!1,this.gestureEffects.flicker=!1,this.gestureEffects.shimmer=!1,void(this.gestureEffects.glow=!1);this.gestureEffects.firefly=e.fireflyEffect||!1,this.gestureEffects.flicker=e.flickerEffect||!1,this.gestureEffects.shimmer=e.shimmerEffect||!1,this.gestureEffects.glow=e.glowEffect||!1,this.gestureEffects.glowProgress=e.glowProgress,this.gestureEffects.centerX=e.centerX,this.gestureEffects.centerY=e.centerY}getPoints(){return this.points}setVisible(e){this.points.visible=e}resize(e){e!==this.maxParticles&&(this.geometry&&this.geometry.dispose(),this.maxParticles=e,this._initGeometry(),this.points&&(this.points.geometry=this.geometry))}cleanupParticleStates(e){for(const t of e)!t.isAlive()&&t.behaviorData&&(t.behaviorData.direction3D&&(t.behaviorData.direction3D=null),t.behaviorData.orbitPlane&&(t.behaviorData.orbitPlane=null),t.behaviorData.orbitPath&&(t.behaviorData.orbitPath=null),t.behaviorData=null)}dispose(){this.geometry&&this.geometry.dispose(),this.material&&this.material.dispose(),this.positions=null,this.sizes=null,this.colors=null,this.alphas=null,this.glowIntensities=null,this.depths=null,this.styles=null}}class fi{constructor(){this.cachedConfigs=new Map,this.maxCacheSize=100}calculate(e,t=null){const i=`${e}:${t||"none"}`;if(this.cachedConfigs.has(i))return this.cachedConfigs.get(i);const n=me(e);if(!n)return console.warn(`[ParticleEmotionCalculator] Unknown emotion: ${e}`),this._getDefaultConfig();const a=this._extractBaseConfig(n,e),s=this._applyUndertoneModifiers(a,t),o=this._applySpecialBehaviors(s,e);if(this.cachedConfigs.size>=this.maxCacheSize){const e=this.cachedConfigs.keys().next().value;this.cachedConfigs.delete(e)}return this.cachedConfigs.set(i,o),o}_extractBaseConfig(e,t){const i=e.visual||{};return{behavior:i.particleBehavior||"ambient",rate:i.particleRate||1,min:void 0!==i.minParticles?i.minParticles:0,max:void 0!==i.maxParticles?i.maxParticles:10,colors:i.particleColors||null,emotion:t}}_applyUndertoneModifiers(e,t){if(!t)return e;const i=vt(t);if(!i||!i.particles)return e;const n=i.particles,a={...e};return n.behaviorOverride&&(a.behavior=n.behaviorOverride),n.rateMultiplier&&(a.rate=e.rate*n.rateMultiplier,a.max=Math.floor(e.max*n.rateMultiplier)),void 0!==n.minParticles&&(a.min=n.minParticles),void 0!==n.maxParticles&&(a.max=n.maxParticles),a}_applySpecialBehaviors(e,t){return"zen"===t?{...e,specialBehavior:"zen-mixing"}:e}selectZenBehavior(){return Math.random()<.6?"falling":"orbiting"}_getDefaultConfig(){return{behavior:"ambient",rate:1,min:0,max:10,colors:null,emotion:"neutral"}}clearCache(){this.cachedConfigs.clear()}getCacheSize(){return this.cachedConfigs.size}}class yi{constructor(){this.previousGesture=null}extract(e,t){if(!e||0===e.length)return this.previousGesture=null,null;const i=e[0],n=this._calculateProgress(i,t);if(n>=1)return this.previousGesture=null,null;const a=this._extractGestureName(i);if(!a)return null;const s=this._buildGestureMotion(i,a);return this.previousGesture=a,{motion:s,progress:n,config:i.config||{},gestureName:a,animation:i}}_calculateProgress(e,t){const i=(t-e.startTime)/e.duration;return Math.max(0,Math.min(1,i))}_extractGestureName(e){return e.gestureName||e.name||e.config?.gestureName||null}_buildGestureMotion(e,t){const i=e.config||{};return{type:t,amplitude:i.amplitude||1,strength:i.strength||1,wobbleAmount:i.wobbleAmount||0,duration:e.duration}}hasGestureChanged(e){return!(!e&&!this.previousGesture||(e||!this.previousGesture)&&(!e||this.previousGesture)&&e.gestureName===this.previousGesture)}extractAll(e,t){if(!e||0===e.length)return[];const i=[];for(const n of e){const e=this._calculateProgress(n,t);if(e>=1)continue;const a=this._extractGestureName(n);if(!a)continue;const s=this._buildGestureMotion(n,a);i.push({motion:s,progress:e,config:n.config||{},gestureName:a,animation:n})}return i}reset(){this.previousGesture=null}}class vi{constructor(){this.effectMap={sparkle:this.buildFireflyEffect.bind(this),twinkle:this.buildFireflyEffect.bind(this),flicker:this.buildFlickerEffect.bind(this),shimmer:this.buildShimmerEffect.bind(this),glow:this.buildGlowEffect.bind(this),burst:this.buildGlowEffect.bind(this),flash:this.buildFlickerEffect.bind(this)}}build(e,t,i){if(!e||!e.motion)return null;const{gestureName:n}=e,a=this.effectMap[n];return a?a(e,t,i):null}buildFireflyEffect(e,t,i){const n=e.config||{};return{fireflyEffect:!0,fireflyTime:.001*Date.now(),particleGlow:n.particleGlow||2,centerX:t,centerY:i}}buildFlickerEffect(e,t,i){const n=e.config||{};return{flickerEffect:!0,flickerTime:.001*Date.now(),particleGlow:n.particleGlow||2,centerX:t,centerY:i}}buildShimmerEffect(e,t,i){const n=e.config||{},a=e.progress||0;return{shimmerEffect:!0,shimmerTime:.001*Date.now(),shimmerWave:a*Math.PI*2,particleGlow:n.particleGlow||1.2,centerX:t,centerY:i}}buildGlowEffect(e,t,i){const n=e.config||{};return{glowEffect:!0,glowProgress:e.progress||0,particleGlow:n.particleGlow||2,centerX:t,centerY:i}}registerEffect(e,t){this.effectMap[e]=t.bind(this)}hasEffect(e){return!!this.effectMap[e]}getEffectGestures(){return Object.keys(this.effectMap)}buildAll(e,t,i){if(!e||0===e.length)return[];const n=[];for(const a of e){const e=this.build(a,t,i);e&&n.push(e)}return n}mergeEffects(e){if(!e||0===e.length)return null;if(1===e.length)return e[0];const t={};for(const i of e)Object.assign(t,i);return t}destroy(){this.effectMap=null}}class bi{constructor(e,t,i){this.particleSystem=e,this.translator=t,this.renderer=i,this.emotionCalculator=new fi,this.gestureExtractor=new yi,this.effectsBuilder=new vi,this.currentEmotion=null,this.currentUndertone=null,this.currentConfig=null}update(e,t,i,n,a,s,o,r,l,h){void 0!==h&&this.translator.setCoreRadius3D(h);const c=this._updateEmotionConfig(t,i),u=this.gestureExtractor.extract(n,a);this._spawnParticles(c,e,o),this._updatePhysics(c,u,e,o,i),this._updateRendering(u,s,o,r,e,l)}_updateEmotionConfig(e,t){return this.currentEmotion===e&&this.currentUndertone===t||(this.currentEmotion=e,this.currentUndertone=t,this.currentConfig=this.emotionCalculator.calculate(e,t),this.particleSystem.clear()),this.currentConfig}_spawnParticles(e,t,i){const n=i.width/2,a=i.height/2;let s=e.behavior;"zen-mixing"===e.specialBehavior&&(s=this.emotionCalculator.selectZenBehavior()),this.particleSystem.spawn(s,e.emotion,e.rate,n,a,t,null,e.min,e.max,1,1,e.colors,this.currentUndertone)}_updatePhysics(e,t,i,n,a){const s=n.width/2,o=n.height/2,r=a?{undertone:a}:null;this.particleSystem.update(i,s,o,t?t.motion:null,t?t.progress:0,r)}_updateRendering(e,t,i,n,a,s){const o=i.width/2,r=i.height/2,l=e?this.effectsBuilder.build(e,o,r):null;this.renderer.updateParticles(this.particleSystem.particles,this.translator,t,i,n,a,e,s,this.geometryType),this.renderer.setGestureEffects(l)}setEmotion(e,t=null){this.currentEmotion=null,this.currentUndertone=null}setGeometryType(e){this.geometryType=e}clear(){this.particleSystem.clear()}setEnabled(e){this.renderer.setVisible(e),e||this.clear()}getParticleCount(){return this.particleSystem.particles.length}getCurrentConfig(){return this.currentConfig}registerEffect(e,t){this.effectsBuilder.registerEffect(e,t)}destroy(){this.particleSystem.destroy(),this.renderer.dispose(),this.translator&&(this.translator.dispose?.(),this.translator=null),this.emotionCalculator.clearCache(),this.emotionCalculator=null,this.gestureExtractor.reset(),this.gestureExtractor=null,this.effectsBuilder&&(this.effectsBuilder.destroy?.(),this.effectsBuilder=null)}}const wi="off",Mi="annular",Si="total",xi={[wi]:{shadowCoverage:0,coronaIntensity:1,coronaRaysEnabled:!1,baileyBeadsEnabled:!1,baileyBeadsCount:0,baileyBeadsSize:0},[Mi]:{shadowCoverage:.95,coronaIntensity:.8,coronaRaysEnabled:!1,baileyBeadsEnabled:!0,baileyBeadsCount:12,baileyBeadsSize:.015},[Si]:{shadowCoverage:1.019,coronaIntensity:4,coronaRaysEnabled:!0,baileyBeadsEnabled:!0,baileyBeadsCount:6,baileyBeadsSize:.025}};function Ci(e){return xi[e]||xi[wi]}class Di{constructor(t,i){this.scene=t,this.sunRadius=i,this.heroBeadCount=3,this.supportBeadCount=15,this.beadCount=this.heroBeadCount+this.supportBeadCount,this.beads=[],this.visible=!1,this._directionToCamera=new e.Vector3,this._up=new e.Vector3(0,1,0),this._right=new e.Vector3,this._upVector=new e.Vector3,this._beadOffset=new e.Vector3,this._tempColor=new e.Color,this.sharedTexture=null,this.createBeads()}createBeads(){const t=document.createElement("canvas");t.width=64,t.height=64;const i=t.getContext("2d"),n=i.createRadialGradient(32,32,0,32,32,32);n.addColorStop(0,"rgba(255, 255, 255, 1.0)"),n.addColorStop(.1,"rgba(255, 255, 255, 0.9)"),n.addColorStop(.3,"rgba(255, 240, 200, 0.6)"),n.addColorStop(.6,"rgba(255, 220, 150, 0.2)"),n.addColorStop(1,"rgba(255, 200, 100, 0.0)"),i.fillStyle=n,i.fillRect(0,0,64,64);const a=new e.CanvasTexture(t);a.needsUpdate=!0,this.sharedTexture=a;const s=this.generateLunarValleys();for(let t=0;t<this.beadCount;t++){const i=new e.Group,n=new e.SpriteMaterial({map:a.clone(),blending:e.AdditiveBlending,transparent:!0,depthWrite:!1,opacity:0,color:this._tempColor.setRGB(1,.3,.3)}),o=new e.Sprite(n);o.scale.set(.08,.08,1),i.add(o);const r=new e.SpriteMaterial({map:a.clone(),blending:e.AdditiveBlending,transparent:!0,depthWrite:!1,opacity:0,color:this._tempColor.setRGB(.8,1,.8)}),l=new e.Sprite(r);l.scale.set(.08,.08,1),i.add(l);const h=new e.SpriteMaterial({map:a,blending:e.AdditiveBlending,transparent:!0,depthWrite:!1,opacity:0,color:this._tempColor.setRGB(.3,.5,1)}),c=new e.Sprite(h);c.scale.set(.08,.08,1),i.add(c),i.userData={angle:s[t].angle,depth:s[t].depth,baseIntensity:s[t].baseIntensity,isHero:s[t].isHero,sizeMultiplier:s[t].isHero?1.5:1,targetOpacity:0,currentOpacity:0,redSprite:o,greenSprite:l,blueSprite:c},this.beads.push(i),this.scene.add(i)}}generateLunarValleys(){const e=[];let t=12345;const i=()=>(t=(9301*t+49297)%233280,t/233280),n=i()*Math.PI*2;for(let t=0;t<this.heroBeadCount;t++){const a=n+t*Math.PI*2/3;e.push({angle:a,depth:.8+.2*i(),baseIntensity:.8+.2*i(),isHero:!0})}for(let t=0;t<this.supportBeadCount;t++){const a=n+Math.floor(t/(this.supportBeadCount/3))*Math.PI*2/3,s=1.2*(i()-.5);e.push({angle:a+s,depth:.3+.5*i(),baseIntensity:.4+.4*i(),isHero:!1})}return e}update(e,t,i,n,a=1){const s=this.sunRadius*a*1,o=e.position;this._directionToCamera.subVectors(o,t).normalize(),this._right.crossVectors(this._directionToCamera,this._up).normalize(),this._upVector.crossVectors(this._right,this._directionToCamera).normalize();for(const e of this.beads){const{angle:i,redSprite:n,greenSprite:o,blueSprite:r,sizeMultiplier:l}=e.userData,h=Math.cos(i)*s,c=Math.sin(i)*s;this._beadOffset.set(0,0,0),this._beadOffset.addScaledVector(this._right,h),this._beadOffset.addScaledVector(this._upVector,c),this._beadOffset.addScaledVector(this._directionToCamera,.01*s);const u=t.x+this._beadOffset.x,d=t.y+this._beadOffset.y,m=t.z+this._beadOffset.z,p=.008*a,g=Math.cos(i)*p,f=Math.sin(i)*p;n.position.set(g,f,.001),o.position.set(0,0,0),r.position.set(-g,-f,-.001),e.position.set(u,d,m),e.updateMatrixWorld(!0);const y=.15*a*l;n.scale.set(y,y,1),o.scale.set(y,y,1),r.scale.set(y,y,1)}if(this.visible){const e=.9,t=.97,n=1;for(const a of this.beads){let s=0;if(i>=e&&i<n){const o=(i-e)/(n-e)*Math.PI*2,r=Math.abs((a.userData.angle-o+Math.PI)%(2*Math.PI)-Math.PI);let l=1;i<t&&(l=(i-e)/(t-e)),s=Math.max(0,1-r/1)*a.userData.baseIntensity*l*a.userData.depth,s*=200}a.userData.targetOpacity=s}}else for(const e of this.beads)e.userData.targetOpacity=0;for(const e of this.beads){const{redSprite:t,greenSprite:i,blueSprite:a}=e.userData,s=e.userData.targetOpacity-e.userData.currentOpacity;e.userData.currentOpacity+=3*s*(n/1e3),e.userData.currentOpacity<.001&&(e.userData.currentOpacity=0),t.material.opacity=.7*e.userData.currentOpacity,i.material.opacity=1*e.userData.currentOpacity,a.material.opacity=.7*e.userData.currentOpacity}}setVisible(e){this.visible=e}dispose(){for(const e of this.beads){const{redSprite:t,greenSprite:i,blueSprite:n}=e.userData;t.material.map&&t.material.map.dispose(),t.material.dispose(),i.material.map&&i.material.map.dispose(),i.material.dispose(),n.material.map&&n.material.map.dispose(),n.material.dispose(),this.scene.remove(e)}this.beads=[],this.sharedTexture&&(this.sharedTexture.dispose(),this.sharedTexture=null),this._directionToCamera=null,this._up=null,this._right=null,this._upVector=null,this._beadOffset=null,this._tempColor=null,this.scene=null}}class Pi{constructor(t,i,n=null){this.scene=t,this.sunRadius=i,this.sunMesh=n,this.eclipseType=wi,this.previousEclipseType=wi,this.enabled=!1,this.time=0,this.randomSeed=12345,this.isTransitioning=!1,this.transitionProgress=0,this.transitionDuration=400,this.transitionDirection="in",this.manualControl=!1,this.customShadowCoverage=void 0,this._directionToCamera=new e.Vector3,this._up=new e.Vector3(0,1,0),this._right=new e.Vector3,this._upVector=new e.Vector3,this._tempOffset=new e.Vector3,this._tempColor=new e.Color,this.createShadowDisk(),this.createCoronaDisk(),this.createCounterCoronaDisk(),this.sunMesh&&(this.scene.remove(this.coronaDisk),this.scene.remove(this.counterCoronaDisk),this.sunMesh.add(this.coronaDisk),this.sunMesh.add(this.counterCoronaDisk)),this.baileysBeads=new Di(t,i)}createShadowDisk(){const t=this.sunRadius,i=new e.CircleGeometry(t,256),n=new e.MeshBasicMaterial({color:0,transparent:!0,opacity:1,blending:e.MultiplyBlending,premultipliedAlpha:!0,side:e.DoubleSide,depthWrite:!1,depthTest:!1,fog:!1});this.shadowDisk=new e.Mesh(i,n),this.shadowDisk.renderOrder=1e4,this.shadowDisk.position.set(200,0,0),this.scene.add(this.shadowDisk)}createCoronaDisk(){const t=2.05*this.sunRadius,i=.6*this.sunRadius,n=new e.RingGeometry(i,t,256),a=new e.ShaderMaterial({uniforms:{time:{value:0},glowColor:{value:new e.Color(.9,.95,1)},intensity:{value:2.4},randomSeed:{value:this.randomSeed},uvRotation:{value:0},rayElongation:{value:1},uberHeroElongation:{value:1},isTotalEclipse:{value:0},layer1Mode:{value:11},layer1Strength:{value:2.155},layer1Enabled:{value:1},layer2Mode:{value:5},layer2Strength:{value:.695},layer2Enabled:{value:1},layer3Mode:{value:0},layer3Strength:{value:1},layer3Enabled:{value:0},layer4Mode:{value:0},layer4Strength:{value:1},layer4Enabled:{value:0}},vertexShader:"\n uniform float uvRotation;\n varying vec2 vUv;\n\n void main() {\n // Rotate UVs around center (0.5, 0.5)\n vec2 centeredUV = uv - 0.5;\n float cosRot = cos(uvRotation);\n float sinRot = sin(uvRotation);\n mat2 rotMatrix = mat2(cosRot, -sinRot, sinRot, cosRot);\n vec2 rotatedUV = rotMatrix * centeredUV;\n vUv = rotatedUV + 0.5;\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",fragmentShader:`\n uniform float time;\n uniform vec3 glowColor;\n uniform float intensity;\n uniform float randomSeed;\n uniform float rayElongation;\n uniform float uberHeroElongation;\n uniform float isTotalEclipse;\n\n // Blend Layer Uniforms (up to 4 layers)\n uniform float layer1Mode;\n uniform float layer1Strength;\n uniform float layer1Enabled;\n\n uniform float layer2Mode;\n uniform float layer2Strength;\n uniform float layer2Enabled;\n\n uniform float layer3Mode;\n uniform float layer3Strength;\n uniform float layer3Enabled;\n\n uniform float layer4Mode;\n uniform float layer4Strength;\n uniform float layer4Enabled;\n\n varying vec2 vUv;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // UNIVERSAL BLEND MODES (injected from utils/blendModes.js)\n // ═══════════════════════════════════════════════════════════════════════════\n ${S}\n\n // Hash function for pseudo-random variation\n float hash(float n) {\n return fract(sin(n) * 43758.5453123);\n }\n\n // 2D hash for more variation\n float hash2(vec2 p) {\n return fract(sin(dot(p, vec2(12.9898 + randomSeed, 78.233 + randomSeed))) * 43758.5453);\n }\n\n void main() {\n // Calculate distance and angle from center\n vec2 center = vec2(0.5, 0.5);\n vec2 toCenter = vUv - center;\n float dist = length(toCenter) * 2.0; // Normalize to 0-1 range\n float angle = atan(toCenter.y, toCenter.x); // UVs are already rotated in vertex shader\n\n // Shadow edge - where corona rays start\n // Ring inner edge is at (sunRadius*0.85)/coronaRadius = 0.765/1.845 = 0.415\n // Start rays at sun's geometric edge (0.488) so they don't show inside sun\n float shadowEdge = 0.488;\n\n // Varied radial streamer pattern with artistic composition\n float rayIntensity = 0.0;\n\n // RULE OF THIRDS: Place 3 hero rays at compositionally strong points\n // Golden angles based on rule of thirds: 1/3, 2/3, and offset positions\n float heroAngles[3];\n heroAngles[0] = hash(randomSeed * 1.234) * 6.28318; // First hero ray (random rotation)\n heroAngles[1] = heroAngles[0] + 2.0944; // 120° apart (1/3 circle)\n heroAngles[2] = heroAngles[0] + 4.1888; // 240° apart (2/3 circle)\n\n // Process hero rays first (3 extra-long dramatic rays)\n for (int h = 0; h < 3; h++) {\n float rayAngle = heroAngles[h];\n float angleDiff = abs(mod(angle - rayAngle + 3.14159, 6.28318) - 3.14159);\n\n // Hero rays: extra long and prominent (fit within 0.535 normalized space)\n float baseHeroLength = 0.45 + hash(float(h) * 31.415 + randomSeed) * 0.08; // 0.45 to 0.53 (max available, longer!)\n\n // Apply UBER elongation: hero rays ALWAYS get extreme elongation (regardless of angle)\n // This creates 3 dramatic streamers that extend far in their respective directions\n float heroLength = baseHeroLength * uberHeroElongation;\n\n // Uber hero rays: keep them narrow but visible for dramatic pointy effect\n // Width scales with elongation to stay sharp but visible\n float baseHeroWidth = 0.15 + hash(float(h) * 27.183 + randomSeed) * 0.15; // 0.15 to 0.3 base width\n float narrowingFactor = mix(1.0, 0.3, (uberHeroElongation - 1.0) / max(uberHeroElongation, 1.0)); // 1.0 → 0.3 (70% narrower at max elongation)\n float heroWidth = baseHeroWidth * narrowingFactor; // Narrow when elongated = pointy!\n\n float distFromEdge = dist - shadowEdge;\n\n // Ghostly ethereal taper - very gradual falloff\n float taper = pow(1.0 - clamp(distFromEdge / max(heroLength, 0.001), 0.0, 1.0), 3.0);\n float rayWidth = heroWidth * taper;\n\n // Soft feathered edges instead of hard cutoff\n float edgeSoftness = 0.15; // Wider feather for smooth edges\n float angularMask = smoothstep(rayWidth + edgeSoftness, rayWidth - edgeSoftness, angleDiff);\n\n // Very gentle radial falloff for ethereal look\n float radialFalloff = pow(taper, 0.8);\n\n // Soft radial range with feathered ends\n float radialMask = smoothstep(-0.1, 0.05, distFromEdge) *\n smoothstep(heroLength + 0.15, heroLength - 0.05, distFromEdge);\n\n float heroIntensity = angularMask * radialFalloff * radialMask * 0.7; // Reduced intensity for ghostly effect\n rayIntensity = max(rayIntensity, heroIntensity);\n }\n\n // 20 supporting rays with rule-of-thirds-aware distribution\n for (float i = 0.0; i < 20.0; i++) {\n // Cluster more rays around hero ray positions (rule of thirds)\n float clusterTarget = mod(i, 3.0); // Which hero ray to cluster near\n float clusterAngle = heroAngles[int(clusterTarget)];\n\n // Base distribution with clustering tendency\n float spreadAngle = (i / 20.0) * 6.28318;\n float clusterPull = (hash(i * 13.579 + randomSeed) - 0.5) * 1.5; // Stronger variation\n float rayAngle = spreadAngle + clusterPull;\n\n float angleDiff = abs(mod(angle - rayAngle + 3.14159, 6.28318) - 3.14159);\n\n // Unique random values per ray\n float random1 = hash(i * 12.9898 + randomSeed);\n float random2 = hash(i * 78.233 + randomSeed);\n float random3 = hash(i * 37.719 + randomSeed);\n float random4 = hash(i * 93.989 + randomSeed);\n\n // Varied lengths following power law distribution (more short, fewer long)\n float lengthVariation = random1 * random1; // Squared for naturalistic distribution\n float baseRayLength = 0.1 + lengthVariation * 0.7; // 0.1 to 0.8\n\n // 20% chance of long streamers (supporting the hero rays)\n float isLong = step(0.80, random2);\n baseRayLength = mix(baseRayLength, 0.7 + random3 * 0.6, isLong); // 0.7 to 1.3\n\n // Apply directional elongation: rays pointing up/down (vertical) get elongated\n float verticalWeight = abs(sin(rayAngle));\n float elongationFactor = mix(1.0, rayElongation, verticalWeight);\n float rayLength = baseRayLength * elongationFactor;\n\n // EQUATORIAL ASYMMETRY (total eclipse only): rays along equator are more prominent\n // Solar minimum: streamers cluster along equatorial plane\n float equatorialWeight = abs(cos(rayAngle)); // 1.0 at horizontal, 0.0 at vertical\n float asymmetryBoost = mix(1.0, 1.0 + equatorialWeight * 0.5, isTotalEclipse);\n rayLength *= asymmetryBoost;\n\n // Varied widths with power law (more thin, fewer thick)\n float baseWidth = 0.03 + (random4 * random4) * 0.2; // 0.03 to 0.23 (naturally varied)\n\n // Taper: wide at base, narrow at tip\n float distFromEdge = dist - shadowEdge;\n\n // Ghostly ethereal taper - very gradual falloff\n float taper = pow(1.0 - clamp(distFromEdge / max(rayLength, 0.001), 0.0, 1.0), 3.5);\n float rayWidth = baseWidth * taper;\n\n // Soft feathered edges for ethereal wisps\n float edgeSoftness = 0.10; // Wider feather for smooth edges\n float angularMask = smoothstep(rayWidth + edgeSoftness, rayWidth - edgeSoftness, angleDiff);\n\n // Very gentle radial falloff for ghostly appearance\n float radialFalloff = pow(taper, 1.0);\n\n // Soft radial range with feathered ends\n float radialMask = smoothstep(-0.08, 0.03, distFromEdge) *\n smoothstep(rayLength + 0.12, rayLength - 0.03, distFromEdge);\n\n float streamerIntensity = angularMask * radialFalloff * radialMask * 0.5; // Reduced for ethereal wisps\n rayIntensity = max(rayIntensity, streamerIntensity);\n }\n\n // Base corona glow - thinner during total eclipse for realism\n float baseGlowWidth = mix(0.04, 0.015, isTotalEclipse); // Thinner during totality\n float baseGlow = smoothstep(shadowEdge - 0.01, shadowEdge, dist) *\n (1.0 - smoothstep(shadowEdge + baseGlowWidth * 0.5, shadowEdge + baseGlowWidth, dist));\n\n // Enhanced gradient: white → cool blue-white → deep blue with distance\n // Distance normalized to corona extent (0 = shadow edge, 1 = far corona)\n float coronaDist = clamp((dist - shadowEdge) / 0.6, 0.0, 1.0);\n\n // ═══════════════════════════════════════════════════════════════════════════\n // TOTAL ECLIPSE ENHANCEMENTS (scaled continuously by isTotalEclipse 0.0-1.0)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // 1. CHROMOSPHERE RED RIM - thin pink/red ring at sun's edge (hydrogen emission)\n float rimStart = shadowEdge;\n float rimEnd = shadowEdge + 0.025;\n float chromosphereRim = smoothstep(rimStart - 0.005, rimStart, dist) *\n (1.0 - smoothstep(rimEnd - 0.01, rimEnd, dist));\n chromosphereRim *= 0.6 * isTotalEclipse; // Scale by eclipse progress\n vec3 chromosphereColor = vec3(1.0, 0.3, 0.4); // Pink-red (H-alpha emission)\n\n // 2. STRONGER BRIGHTNESS FALLOFF - inner corona much brighter\n // Mix between 1.0 (normal) and enhanced falloff based on isTotalEclipse\n float enhancedFalloff = mix(3.0, 0.3, pow(coronaDist, 0.7));\n float brightnessMultiplier = mix(1.0, enhancedFalloff, isTotalEclipse);\n\n // 3. F-CORONA OUTER GLOW - faint diffuse glow from interplanetary dust\n float fCoronaDist = clamp((dist - shadowEdge) / 1.2, 0.0, 1.0);\n float fCorona = (1.0 - fCoronaDist) * 0.08;\n fCorona *= smoothstep(0.3, 0.5, coronaDist);\n fCorona *= isTotalEclipse; // Scale by eclipse progress\n\n // 4. WISPY TENDRILS - add fine detail noise to ray intensity\n float noiseAngle = angle * 8.0 + time * 0.1;\n float noiseRadius = dist * 15.0;\n float wispyDetail = hash(noiseAngle + noiseRadius + randomSeed * 3.0) * 0.15;\n wispyDetail *= rayIntensity * isTotalEclipse; // Scale by eclipse progress\n\n // Combine: base glow + streamers + wispy detail\n float finalIntensity = (baseGlow * 0.6 + rayIntensity + wispyDetail) * intensity;\n finalIntensity *= brightnessMultiplier;\n\n // Multi-stage color gradient for realistic corona\n vec3 innerGlow = vec3(1.0, 1.0, 1.0); // Pure white at base\n vec3 middleGlow = vec3(0.9, 0.95, 1.0); // Cool white\n vec3 outerGlow = vec3(0.6, 0.75, 0.95); // Pale blue\n vec3 farGlow = vec3(0.3, 0.5, 0.8); // Deep blue\n\n // Three-stage color mix\n vec3 coronaColor;\n if (coronaDist < 0.3) {\n // Inner: white → cool white\n coronaColor = mix(innerGlow, middleGlow, coronaDist / 0.3);\n } else if (coronaDist < 0.7) {\n // Middle: cool white → pale blue\n coronaColor = mix(middleGlow, outerGlow, (coronaDist - 0.3) / 0.4);\n } else {\n // Outer: pale blue → deep blue\n coronaColor = mix(outerGlow, farGlow, (coronaDist - 0.7) / 0.3);\n }\n\n vec3 finalColor = coronaColor * finalIntensity;\n\n // Add chromosphere red rim (total eclipse only)\n finalColor += chromosphereColor * chromosphereRim * intensity;\n\n // Add F-corona outer glow (total eclipse only)\n finalColor += vec3(0.9, 0.85, 0.8) * fCorona * intensity; // Slightly warm white\n\n // ═══════════════════════════════════════════════════════════════════════════\n // BLEND LAYERS (Applied globally to entire corona)\n // These allow adjusting the appearance of the corona to prevent black edges\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Layer 1\n if (layer1Enabled > 0.5) {\n vec3 blendColor1 = vec3(min(layer1Strength, 1.0));\n int mode1 = int(layer1Mode + 0.5);\n vec3 blended1 = clamp(applyBlendMode(finalColor, blendColor1, mode1), 0.0, 1.0);\n finalColor = clamp(blended1, 0.0, 1.0);\n }\n\n // Layer 2\n if (layer2Enabled > 0.5) {\n vec3 blendColor2 = vec3(min(layer2Strength, 1.0));\n int mode2 = int(layer2Mode + 0.5);\n vec3 blended2 = clamp(applyBlendMode(finalColor, blendColor2, mode2), 0.0, 1.0);\n finalColor = clamp(blended2, 0.0, 1.0);\n }\n\n // Layer 3\n if (layer3Enabled > 0.5) {\n vec3 blendColor3 = vec3(min(layer3Strength, 1.0));\n int mode3 = int(layer3Mode + 0.5);\n vec3 blended3 = clamp(applyBlendMode(finalColor, blendColor3, mode3), 0.0, 1.0);\n finalColor = clamp(blended3, 0.0, 1.0);\n }\n\n // Layer 4\n if (layer4Enabled > 0.5) {\n vec3 blendColor4 = vec3(min(layer4Strength, 1.0));\n int mode4 = int(layer4Mode + 0.5);\n vec3 blended4 = clamp(applyBlendMode(finalColor, blendColor4, mode4), 0.0, 1.0);\n finalColor = clamp(blended4, 0.0, 1.0);\n }\n\n // Sharp alpha falloff to prevent black bleeding in bloom\n // Higher power = sharper cutoff at edges (less semi-transparent area)\n float alphaFalloff = pow(1.0 - coronaDist, 3.0);\n float alpha = finalIntensity * alphaFalloff * 0.95;\n\n gl_FragColor = vec4(finalColor, alpha);\n }\n `,transparent:!0,blending:e.AdditiveBlending,depthWrite:!1,side:e.DoubleSide});this.coronaDisk=new e.Mesh(n,a),this.coronaDisk.position.set(0,0,0),this.coronaDisk.renderOrder=9998,this.scene.add(this.coronaDisk)}createCounterCoronaDisk(){const t=this.coronaDisk.geometry,i=this.randomSeed+5e3,n=new e.ShaderMaterial({uniforms:{time:{value:0},glowColor:{value:new e.Color(.9,.95,1)},intensity:{value:2.4},randomSeed:{value:i},uvRotation:{value:0},rayElongation:{value:1},uberHeroElongation:{value:1},isTotalEclipse:{value:0},layer1Mode:{value:11},layer1Strength:{value:2.155},layer1Enabled:{value:1},layer2Mode:{value:5},layer2Strength:{value:.695},layer2Enabled:{value:1},layer3Mode:{value:0},layer3Strength:{value:1},layer3Enabled:{value:0},layer4Mode:{value:0},layer4Strength:{value:1},layer4Enabled:{value:0}},vertexShader:this.coronaDisk.material.vertexShader,fragmentShader:this.coronaDisk.material.fragmentShader,transparent:!0,blending:e.AdditiveBlending,depthWrite:!1,side:e.DoubleSide});this.counterCoronaDisk=new e.Mesh(t,n),this.counterCoronaDisk.position.set(0,0,0),this.counterCoronaDisk.renderOrder=9997,this.scene.add(this.counterCoronaDisk)}setShadowCoverage(e){this.customShadowCoverage=e}setCoronaBlendLayer(e,t){if(e<1||e>4)return void console.error(`❌ Invalid corona layer number: ${e} (must be 1-4)`);const{mode:i=0,strength:n=1,enabled:a=!1}=t;this.coronaDisk?.material?.uniforms&&(this.coronaDisk.material.uniforms[`layer${e}Mode`].value=i,this.coronaDisk.material.uniforms[`layer${e}Strength`].value=n,this.coronaDisk.material.uniforms[`layer${e}Enabled`].value=a?1:0),this.counterCoronaDisk?.material?.uniforms&&(this.counterCoronaDisk.material.uniforms[`layer${e}Mode`].value=i,this.counterCoronaDisk.material.uniforms[`layer${e}Strength`].value=n,this.counterCoronaDisk.material.uniforms[`layer${e}Enabled`].value=a?1:0)}setEclipseType(e){if(e===this.eclipseType)return;const t=this.enabled;this.previousEclipseType=this.eclipseType,this.eclipseType=e,this.enabled=e!==wi,this.manualControl=!1;const i=Ci(this.previousEclipseType),n=Ci(e);this.startShadowCoverage=i.shadowCoverage,this.targetShadowCoverage=n.shadowCoverage,!t&&this.enabled?(this.transitionDirection="in",this.isTransitioning=!0,this.transitionProgress=0):t&&!this.enabled?(this.transitionDirection="out",this.isTransitioning=!0,this.transitionProgress=0):t&&this.enabled&&(this.isTransitioning=!0,this.transitionProgress=0,this.transitionDirection="switch")}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}setManualProgress(e){this.manualControl=!0,this.transitionProgress=Math.max(0,Math.min(1,e)),this.isTransitioning=!0,this.transitionDirection="in"}setManualShadowPosition(e){this.manualControl=!0,this.manualShadowPosition=Math.max(-2,Math.min(2,e)),this.isTransitioning=!0,this.transitionDirection="manual"}update(e,t,i,n=null){const a=e.position,s=t.position,o=t.scale.x;let r=1;if(null!==n&&n>.5){const e=2*(n-.5);r=e*(2-e)}else if(null!==n&&n<=.5){const e=2*n;r=1-e*e}const l=this.eclipseType===wi?3:1;if(this.time+=i*l,this.isTransitioning&&!this.manualControl){const e=i/this.transitionDuration;this.transitionProgress+=e,this.transitionProgress>=1&&(this.transitionProgress=1,this.isTransitioning=!1)}if(this.enabled||"out"===this.transitionDirection&&this.isTransitioning){const e="out"===this.transitionDirection&&this.isTransitioning?this.previousEclipseType:this.eclipseType,t=Ci(e),n=this.sunRadius*o,l=this.easeInOutCubic(this.transitionProgress);let h;h=void 0!==this.customShadowCoverage?this.customShadowCoverage:"switch"===this.transitionDirection&&this.isTransitioning&&void 0!==this.startShadowCoverage&&void 0!==this.targetShadowCoverage?this.startShadowCoverage+(this.targetShadowCoverage-this.startShadowCoverage)*l:t.shadowCoverage;const c=n*h/this.sunRadius;this.shadowDisk.scale.setScalar(c),this.currentShadowPosX=-2,"manual"===this.transitionDirection&&void 0!==this.manualShadowPosition?this.currentShadowPosX=this.manualShadowPosition:this.isTransitioning?"in"===this.transitionDirection?this.currentShadowPosX=2*l-2:"out"===this.transitionDirection?this.currentShadowPosX=0+1*l:"switch"===this.transitionDirection&&(this.currentShadowPosX=0):this.currentShadowPosX=0;const u=this.currentShadowPosX,d=2.5*n,m=u*d*.5,p=-u*u*d*.25;this._directionToCamera.subVectors(a,s).normalize(),this._right.crossVectors(this._directionToCamera,this._up).normalize(),this._upVector.crossVectors(this._right,this._directionToCamera).normalize();const g=0;this._tempOffset.copy(this._directionToCamera).multiplyScalar(g),this.shadowDisk.position.copy(s).add(this._tempOffset),this._tempOffset.copy(this._right).multiplyScalar(m),this.shadowDisk.position.add(this._tempOffset),this._tempOffset.copy(this._upVector).multiplyScalar(p),this.shadowDisk.position.add(this._tempOffset),this.shadowDisk.lookAt(a),this.coronaDisk.parent&&this.coronaDisk.parent!==this.scene||(this.coronaDisk.position.copy(s),this.counterCoronaDisk.position.copy(s),this.coronaDisk.scale.setScalar(o),this.counterCoronaDisk.scale.setScalar(o));const f=Math.abs(this.currentShadowPosX||0),y=2,v=Math.max(0,1-f/y);let b=0;if("switch"===this.transitionDirection&&this.isTransitioning){const e=this.previousEclipseType===Si,t=this.eclipseType===Si;t&&!e?b=l:!t&&e&&(b=1-l)}else e===Si&&(b=1);const w=1+(1+24*Math.pow(v,4)-1)*b,M=1+(1+199*Math.pow(v,5)-1)*b;this.coronaDisk.material.uniforms.rayElongation.value=w,this.counterCoronaDisk.material.uniforms.rayElongation.value=w,this.coronaDisk.material.uniforms.uberHeroElongation.value=M,this.counterCoronaDisk.material.uniforms.uberHeroElongation.value=M;const S=.5,x=.99,C=Math.max(0,Math.min(1,(v-S)/(x-S))),D=C*C*(3-2*C),P=D*b;this.coronaDisk.material.uniforms.isTotalEclipse.value=P,this.counterCoronaDisk.material.uniforms.isTotalEclipse.value=P;const B=b>0&&v>=S,k=1-.947*D*b;this.setCoronaBlendLayer(3,{mode:1,strength:k,enabled:B}),this.coronaDisk.lookAt(a),this.counterCoronaDisk.lookAt(a);let T=0;if(e===wi)T=i/1e3*.075;else if(e===Mi){const e=.075;T=i/1e3*(e-(e-.25*e)*v)}else if(e===Si){const e=.075;T=i/1e3*(e-(e-.05*e)*v)}this.coronaDisk.material.uniforms.uvRotation.value+=T,this.counterCoronaDisk.material.uniforms.uvRotation.value-=T;let E=1.2;if(e===wi)E=3.6;else if(e===Mi){const e=3.6,t=.08*e;this.transitionDirection,E=e-(e-t)*v}else if(e===Si){const e=3.6,t=.65*e;this.transitionDirection,E=e-(e-t)*v}this.coronaDisk.material.uniforms.intensity.value=E*r,this.counterCoronaDisk.material.uniforms.intensity.value=E*r,this.coronaDisk.material.uniforms.time.value=this.time,this.counterCoronaDisk.material.uniforms.time.value=this.time}else{this.shadowDisk.position.set(200,0,0),this.coronaDisk.parent&&this.coronaDisk.parent!==this.scene||(this.coronaDisk.position.copy(s),this.counterCoronaDisk.position.copy(s),this.coronaDisk.scale.setScalar(o),this.counterCoronaDisk.scale.setScalar(o)),this.coronaDisk.material.uniforms.rayElongation.value=1,this.counterCoronaDisk.material.uniforms.rayElongation.value=1,this.coronaDisk.material.uniforms.uberHeroElongation.value=1,this.counterCoronaDisk.material.uniforms.uberHeroElongation.value=1,this.coronaDisk.material.uniforms.isTotalEclipse.value=0,this.counterCoronaDisk.material.uniforms.isTotalEclipse.value=0,this.coronaDisk.material.uniforms.intensity.value=3.06*r,this.counterCoronaDisk.material.uniforms.intensity.value=3.06*r,this.setCoronaBlendLayer(3,{mode:1,strength:0,enabled:!1}),this.coronaDisk.lookAt(a),this.counterCoronaDisk.lookAt(a);const e=i/1e3*.075;this.coronaDisk.material.uniforms.uvRotation.value+=e,this.counterCoronaDisk.material.uniforms.uvRotation.value-=e,this.coronaDisk.material.uniforms.intensity.value=3.6*r,this.counterCoronaDisk.material.uniforms.intensity.value=3.6*r,this.coronaDisk.material.uniforms.time.value=this.time,this.counterCoronaDisk.material.uniforms.time.value=this.time}if(this.eclipseType===Si){let t=0,n=!1;if("manual"===this.transitionDirection){const e=Math.abs(this.currentShadowPosX),i=2;t=Math.max(0,Math.min(1,1-e/i)),t>=.9&&t<=1&&(n=!0)}else if("in"===this.transitionDirection&&this.isTransitioning){const e=.8;this.transitionProgress>=e&&(n=!0,t=.9+(this.transitionProgress-e)/(1-e)*.1)}else if("out"===this.transitionDirection&&this.isTransitioning){const e=.2;this.transitionProgress<=e&&(n=!0,t=1-this.transitionProgress/e*.1)}else this.isTransitioning||(t=1,n=!0);this.baileysBeads.setVisible(n),this.baileysBeads.update(e,s,t,i,o)}else this.baileysBeads.setVisible(!1),this.baileysBeads.update(e,s,0,i,o)}dispose(){this.shadowDisk&&(this.scene.remove(this.shadowDisk),this.shadowDisk.geometry.dispose(),this.shadowDisk.material.dispose(),this.shadowDisk=null),this.coronaDisk&&(this.coronaDisk.parent&&this.coronaDisk.parent.remove(this.coronaDisk),this.coronaDisk.geometry.dispose(),this.coronaDisk.material.dispose(),this.coronaDisk=null),this.counterCoronaDisk&&(this.counterCoronaDisk.parent&&this.counterCoronaDisk.parent.remove(this.counterCoronaDisk),this.counterCoronaDisk.material.dispose(),this.counterCoronaDisk=null),this.baileysBeads&&(this.baileysBeads.dispose(),this.baileysBeads=null),this._directionToCamera=null,this._up=null,this._right=null,this._upVector=null,this._tempOffset=null,this._tempColor=null,this.scene=null,this.sunMesh=null}}class Bi{constructor(e){this.material=e,this.eclipseType="off",this.progress=0,this.targetProgress=0,this.animating=!1,this.bloodMoonColor={r:.85,g:.18,b:.08},this.animationDuration=3e3,this.startTime=0,this.shadowX=-2,this.shadowY=0,this.shadowRadius=.7,this.targetShadowX=-2,this.shadowSpeed=1,this.material.uniforms.eclipseProgress||(this.material.uniforms.eclipseProgress={value:0},this.material.uniforms.eclipseIntensity={value:0},this.material.uniforms.bloodMoonColor={value:[this.bloodMoonColor.r,this.bloodMoonColor.g,this.bloodMoonColor.b]},this.material.uniforms.eclipseShadowPos={value:[this.shadowX,this.shadowY]},this.material.uniforms.eclipseShadowRadius={value:this.shadowRadius})}setEclipseType(e){if(this.eclipseType===e)return;const t="off"===this.eclipseType;switch(this.eclipseType=e,t&&"off"!==e&&(this.shadowX=-2,this.material.uniforms.eclipseShadowPos.value=[this.shadowX,this.shadowY]),e){case"off":this.targetProgress=0,this.targetShadowX=2;break;case"penumbral":this.targetProgress=.3,this.targetShadowX=-1;break;case"partial":this.targetProgress=.65,this.targetShadowX=-.6;break;case"total":this.targetProgress=1,this.targetShadowX=0;break;default:return void console.warn(`Unknown lunar eclipse type: ${e}`)}this.animating=!0,this.startTime=performance.now()}update(e){if(!this.animating)return;const t=performance.now()-this.startTime,i=Math.min(t/this.animationDuration,1),n=this.easeInOutCubic(i);this.progress=this.progress+(this.targetProgress-this.progress)*n,this.shadowX=this.shadowX+(this.targetShadowX-this.shadowX)*n*this.shadowSpeed,this.material.uniforms.eclipseProgress.value=this.progress,this.material.uniforms.eclipseShadowPos.value=[this.shadowX,this.shadowY];let a=0;"total"===this.eclipseType?a=this.progress:"partial"===this.eclipseType?a=.6*this.progress:"penumbral"===this.eclipseType&&(a=.25*this.progress),this.material.uniforms.eclipseIntensity.value=a,i>=1&&(this.animating=!1)}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}reset(){this.progress=0,this.targetProgress=0,this.shadowX=-2,this.targetShadowX=-2,this.animating=!1,this.eclipseType="off",this.material.uniforms.eclipseProgress&&(this.material.uniforms.eclipseProgress.value=0,this.material.uniforms.eclipseIntensity.value=0,this.material.uniforms.eclipseShadowPos.value=[this.shadowX,this.shadowY])}dispose(){}}const ki={quartz:{sssStrength:.8,sssAbsorption:[2.8,2.9,3],sssScatterDistance:[.2,.2,.25],sssThicknessBias:.6,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.12,frostiness:.15,innerGlowStrength:.2,fresnelIntensity:1.5,causticIntensity:1.2},emerald:{sssStrength:2,sssAbsorption:[.05,4,.1],sssScatterDistance:[.1,.5,.1],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.2,innerGlowStrength:.15,fresnelIntensity:1.2,emotionColorBleed:.35},ruby:{sssStrength:1.8,sssAbsorption:[4,.03,.08],sssScatterDistance:[.4,.04,.08],sssThicknessBias:.65,sssThicknessScale:1.9,sssCurvatureScale:2.5,sssAmbient:.08,frostiness:.12,innerGlowStrength:.12,fresnelIntensity:1.2,causticIntensity:1.15,emotionColorBleed:.35},sapphire:{sssStrength:2.2,sssAbsorption:[.15,.4,4],sssScatterDistance:[.1,.15,.5],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.18,innerGlowStrength:.15,fresnelIntensity:1.3,emotionColorBleed:.35},amethyst:{sssStrength:2.5,sssAbsorption:[3,.05,4.5],sssScatterDistance:[.4,.05,.5],sssThicknessBias:.7,sssThicknessScale:2,sssCurvatureScale:3,sssAmbient:.08,frostiness:.18,innerGlowStrength:.12,fresnelIntensity:1.4,emotionColorBleed:.35}},Ti=`\nuniform float time;\nuniform vec3 emotionColor;\nuniform float glowIntensity;\nuniform float opacity;\n\n// Crystal appearance controls\nuniform float frostiness; // 0 = clear glass, 1 = fully frosted (default: 0.7)\nuniform float fresnelPower; // Edge brightness falloff (default: 3.0)\nuniform float fresnelIntensity; // Edge brightness strength (default: 1.2)\nuniform float innerGlowStrength; // How much inner soul shows through (default: 0.8)\nuniform float surfaceRoughness; // Surface texture variation (default: 0.3)\n\n// Enhanced lighting controls\nuniform float shadowDarkness; // How dark shadows can get (0-1, default: 0.4)\nuniform float specularIntensity; // Edge highlight brightness (default: 0.8)\nuniform float specularPower; // Specular falloff sharpness (default: 32.0)\nuniform float transmissionContrast; // Thin/thick brightness ratio (default: 1.5)\nuniform float minBrightness; // Minimum brightness floor (default: 0.05)\n\n// Noise scale controls\nuniform float surfaceNoiseScale; // Scale of surface frost pattern (default: 1.5)\nuniform float noiseFrequency; // Frequency of hash noise pattern (default: 1.0)\n\n// Internal caustics - light pooling inside the gem\nuniform float causticIntensity; // Brightness of internal caustics (default: 0.4)\nuniform float causticScale; // Scale of caustic pattern (default: 3.0)\nuniform float causticSpeed; // Animation speed of caustics (default: 0.15)\n\n// Texture\nuniform sampler2D crystalTexture;\nuniform float textureStrength; // How much texture affects appearance (default: 0.5)\n\n// Soul refraction - samples soul rendered to texture with optical distortion\nuniform sampler2D soulTexture; // Soul mesh rendered to texture\nuniform vec2 resolution; // Screen resolution for UV calculation\nuniform vec2 soulTextureSize; // Soul render target size (may differ from screen)\nuniform vec2 soulScreenCenter; // Soul center projected to screen UV (0-1 range)\nuniform float refractionIndex; // Index of refraction (1.5 glass, 2.4 diamond)\nuniform float refractionStrength; // Distortion magnitude (0.1-0.5)\n\n// Physically-based subsurface scattering\nuniform float sssStrength; // Overall SSS intensity (0-1)\nuniform vec3 sssAbsorption; // Absorption coefficients per RGB channel\nuniform vec3 sssScatterDistance; // Mean free path / scatter radius per RGB\nuniform float sssThicknessBias; // Thickness offset (0-1)\nuniform float sssThicknessScale; // Thickness multiplier\nuniform float sssCurvatureScale; // How much curvature affects SSS\nuniform float sssAmbient; // Ambient SSS contribution\nuniform vec3 sssLightDir; // Primary light direction for SSS\nuniform vec3 sssLightColor; // Light color for SSS\n\n// Emotion color bleed - how much soul color tints the gem material\nuniform float emotionColorBleed; // 0 = gem color only, 1 = full emotion tint (default: 0.0)\n\n// Component-specific blend layers\n// Shell layers - affect the frosted crystal shell\nuniform float shellLayer1Mode;\nuniform float shellLayer1Strength;\nuniform float shellLayer1Enabled;\nuniform float shellLayer2Mode;\nuniform float shellLayer2Strength;\nuniform float shellLayer2Enabled;\n\n// Soul layers - affect the inner glowing soul color\nuniform float soulLayer1Mode;\nuniform float soulLayer1Strength;\nuniform float soulLayer1Enabled;\nuniform float soulLayer2Mode;\nuniform float soulLayer2Strength;\nuniform float soulLayer2Enabled;\n\n// Rim layers - affect the fresnel rim glow\nuniform float rimLayer1Mode;\nuniform float rimLayer1Strength;\nuniform float rimLayer1Enabled;\nuniform float rimLayer2Mode;\nuniform float rimLayer2Strength;\nuniform float rimLayer2Enabled;\n\n// SSS layers - affect subsurface scattering contribution\nuniform float sssLayer1Mode;\nuniform float sssLayer1Strength;\nuniform float sssLayer1Enabled;\nuniform float sssLayer2Mode;\nuniform float sssLayer2Strength;\nuniform float sssLayer2Enabled;\n\nvarying vec3 vPosition;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// NOISE FUNCTIONS for surface variation and frosted effect\n// ═══════════════════════════════════════════════════════════════════════════\n\n// Simple 3D noise for frosted surface\nfloat hash(vec3 p) {\n p = p * noiseFrequency; // Apply frequency control\n p = fract(p * vec3(443.8975, 397.2973, 491.1871));\n p += dot(p.zxy, p.yxz + 19.19);\n return fract(p.x * p.y * p.z);\n}\n\nfloat noise3D(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n f = f * f * (3.0 - 2.0 * f); // Smoothstep\n\n float n = mix(\n mix(\n mix(hash(i), hash(i + vec3(1, 0, 0)), f.x),\n mix(hash(i + vec3(0, 1, 0)), hash(i + vec3(1, 1, 0)), f.x),\n f.y\n ),\n mix(\n mix(hash(i + vec3(0, 0, 1)), hash(i + vec3(1, 0, 1)), f.x),\n mix(hash(i + vec3(0, 1, 1)), hash(i + vec3(1, 1, 1)), f.x),\n f.y\n ),\n f.z\n );\n return n;\n}\n\n// Fractal Brownian Motion for natural-looking frosted texture\nfloat fbm(vec3 p) {\n float value = 0.0;\n float amplitude = 0.5;\n float frequency = 1.0;\n\n for (int i = 0; i < 3; i++) {\n value += amplitude * noise3D(p * frequency);\n frequency *= 2.0;\n amplitude *= 0.5;\n }\n return value;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// BLEND MODES (from universal library)\n// ═══════════════════════════════════════════════════════════════════════════\n${S}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ENHANCED LIGHTING FUNCTIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n// Calculate ambient occlusion from geometry\nfloat calculateAO(vec3 normal, vec3 viewDir, vec3 position) {\n // Faces pointing away from view are in shadow\n float viewAO = max(0.0, dot(normal, viewDir));\n\n // Use light direction for directional shadow instead of gravity\n // This creates shadows on the side away from light\n vec3 lightDir = normalize(vec3(0.5, 1.0, 0.8)); // Match sssLightDir default\n float lightAO = dot(normal, lightDir) * 0.5 + 0.5;\n\n // Combine AO factors - no gravity term\n return viewAO * 0.5 + lightAO * 0.5;\n}\n\n// Calculate specular highlights on facet edges\nfloat calculateFacetSpecular(vec3 normal, vec3 viewDir, vec3 lightDir, float power) {\n // Detect facet edges from normal discontinuities\n float edgeDetect = length(fwidth(normal)) * 15.0;\n edgeDetect = smoothstep(0.1, 0.5, edgeDetect);\n\n // Standard Blinn-Phong specular\n vec3 halfVec = normalize(lightDir + viewDir);\n float specular = pow(max(0.0, dot(normal, halfVec)), power);\n\n // Boost specular on edges\n specular += edgeDetect * 0.5;\n\n return specular;\n}\n\n// Calculate "fire" - intense sparkle points that real gems exhibit\n// These are concentrated, view-dependent highlights from light dispersion\nfloat calculateFire(vec3 normal, vec3 viewDir, vec3 lightDir) {\n // Primary fire highlight - VERY sharp falloff for pinpoint sparkles\n vec3 reflectDir = reflect(-lightDir, normal);\n float fire1 = pow(max(0.0, dot(reflectDir, viewDir)), 512.0);\n\n // Secondary fire from different light angle (simulates environment)\n vec3 lightDir2 = normalize(vec3(-0.3, 0.8, 0.5));\n vec3 reflectDir2 = reflect(-lightDir2, normal);\n float fire2 = pow(max(0.0, dot(reflectDir2, viewDir)), 384.0);\n\n // Third fire point for more sparkle\n vec3 lightDir3 = normalize(vec3(0.7, 0.4, -0.6));\n vec3 reflectDir3 = reflect(-lightDir3, normal);\n float fire3 = pow(max(0.0, dot(reflectDir3, viewDir)), 256.0);\n\n // Combine fire points - only keep the brightest peaks\n float fire = fire1 + fire2 * 0.7 + fire3 * 0.5;\n\n // Facet edges catch more fire\n float edgeFactor = length(fwidth(normal)) * 20.0;\n fire *= (1.0 + edgeFactor * 2.0);\n\n return fire;\n}\n\n// Calculate bright lines along facet edges where bevels catch light\nfloat calculateFacetEdgeLines(vec3 normal, vec3 viewDir, vec3 lightDir) {\n // Detect edges from normal discontinuities\n float edgeMag = length(fwidth(normal));\n\n // Sharp threshold to create distinct lines\n float edgeLine = smoothstep(0.02, 0.08, edgeMag);\n\n // Modulate by light angle - edges facing light are brighter\n float lightFacing = max(0.0, dot(normal, lightDir));\n edgeLine *= (0.3 + lightFacing * 0.7);\n\n // View-dependent - edges perpendicular to view are more visible\n float viewPerp = 1.0 - abs(dot(normal, viewDir));\n edgeLine *= (0.5 + viewPerp * 0.5);\n\n return edgeLine;\n}\n\n// Calculate light transmission based on thickness\nfloat calculateTransmission(vec3 position, vec3 normal, vec3 viewDir, float contrast) {\n // Thickness estimation - edges are thin, center is thick\n float distFromCenter = length(position);\n float thickness = smoothstep(0.0, 0.6, distFromCenter);\n\n // View angle affects perceived thickness\n float viewThickness = 1.0 - abs(dot(normal, viewDir));\n thickness = mix(thickness, viewThickness, 0.5);\n\n // Thin areas transmit more light (brighter), thick areas are darker\n float transmission = 1.0 - thickness * contrast * 0.5;\n\n return clamp(transmission, 0.3, 1.5);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// PHYSICALLY-BASED SUBSURFACE SCATTERING\n// ═══════════════════════════════════════════════════════════════════════════\n\n// ═══════════════════════════════════════════════════════════════════════════\n// PHYSICALLY-BASED SUBSURFACE SCATTERING\n// Based on Disney's Burley Normalized Diffusion (2015)\n// ═══════════════════════════════════════════════════════════════════════════\n\n// SSS Uniforms - declare these in your shader\n// uniform float sssStrength; // Overall SSS intensity (0-1)\n// uniform vec3 sssAbsorption; // Absorption coefficients per RGB channel\n// uniform vec3 sssScatterDistance; // Mean free path / scatter radius per RGB\n// uniform float sssThicknessBias; // Thickness offset (0-1)\n// uniform float sssThicknessScale; // Thickness multiplier\n// uniform float sssCurvatureScale; // How much curvature affects SSS\n// uniform float sssAmbient; // Ambient SSS contribution\n// uniform vec3 sssLightDir; // Primary light direction for SSS\n// uniform vec3 sssLightColor; // Light color for SSS\n\n/**\n * Estimate local thickness from geometry\n * Uses the relationship between view angle and surface normal\n * Combined with a simple depth approximation\n *\n * @param normal - Surface normal in view space\n * @param viewDir - View direction\n * @param position - Vertex position (for depth-based estimation)\n * @param thicknessBias - Base thickness value\n * @param thicknessScale - Thickness multiplier\n * @return Estimated thickness (0-1)\n */\nfloat estimateThickness(vec3 normal, vec3 viewDir, vec3 position, float thicknessBias, float thicknessScale) {\n // Method 1: View-dependent thickness\n // Surfaces facing away from viewer are "thicker" (light travels further)\n float viewThickness = 1.0 - abs(dot(normal, viewDir));\n\n // Method 2: Position-based depth (simple spherical assumption)\n // Objects are thinner at edges, thicker in center\n float posDepth = 1.0 - length(position) * 0.5;\n posDepth = clamp(posDepth, 0.0, 1.0);\n\n // Method 3: Curvature hint from normal variation\n // High-frequency normal changes indicate thin areas (edges, details)\n // This is approximated by the gradient of the normal\n float curvatureHint = length(fwidth(normal)) * 10.0;\n curvatureHint = 1.0 - clamp(curvatureHint, 0.0, 1.0);\n\n // Combine methods with weighting\n float thickness = viewThickness * 0.4 + posDepth * 0.4 + curvatureHint * 0.2;\n\n // Apply bias and scale\n thickness = thicknessBias + thickness * thicknessScale;\n\n return clamp(thickness, 0.01, 1.0);\n}\n\n/**\n * Beer's Law absorption - light attenuates exponentially through material\n * Different wavelengths absorb at different rates, creating color shifts\n *\n * @param thickness - Distance light travels through material\n * @param absorption - Absorption coefficients per RGB (higher = more absorbed)\n * @return Transmittance per RGB channel (0-1)\n */\nvec3 beersLawAbsorption(float thickness, vec3 absorption) {\n // Beer-Lambert Law: T = e^(-σ * d)\n // Where σ is absorption coefficient, d is distance\n return exp(-absorption * thickness * 4.0);\n}\n\n/**\n * Burley Normalized Diffusion Profile\n * Disney's approximation of the full BSSRDF, energy-conserving\n *\n * R(r) = A * s * (e^(-s*r) + e^(-s*r/3)) / (8πr)\n *\n * @param radius - Distance from entry point (normalized)\n * @param scatterDist - Mean free path / diffusion length\n * @return Diffusion weight at this radius\n */\nfloat burleyDiffusionProfile(float radius, float scatterDist) {\n // Prevent division by zero\n float r = max(radius, 0.001);\n float s = 1.0 / max(scatterDist, 0.001);\n\n // Burley's two-term approximation\n float term1 = exp(-s * r);\n float term2 = exp(-s * r / 3.0);\n\n // Normalized profile (simplified, without 8πr for real-time)\n float profile = (term1 + term2) * s * 0.25;\n\n return profile;\n}\n\n/**\n * Christensen-Burley Normalized Diffusion\n * Improved version with better energy conservation\n *\n * @param radius - Distance from entry point\n * @param A - Surface albedo\n * @param d - Diffusion length (mean free path)\n * @return RGB diffusion weights\n */\nvec3 christensenBurleyDiffusion(float radius, vec3 A, vec3 d) {\n vec3 result = vec3(0.0);\n\n // Per-channel diffusion (different scatter distances for RGB)\n for (int i = 0; i < 3; i++) {\n float s = 1.9 - A[i] + 3.5 * (A[i] - 0.8) * (A[i] - 0.8);\n s = 1.0 / (s * max(d[i], 0.001));\n\n float r = max(radius, 0.001);\n\n // Two-exponential fit\n float profile = s * (exp(-s * r) + exp(-s * r / 3.0)) / (8.0 * 3.14159 * r);\n\n result[i] = profile;\n }\n\n return result;\n}\n\n/**\n * Calculate curvature factor for SSS intensity\n * SSS is more visible on curved surfaces (fingers, ears, edges)\n *\n * @param normal - Surface normal\n * @return Curvature factor (higher = more curved)\n */\nfloat calculateCurvature(vec3 normal) {\n // Use screen-space derivatives to estimate curvature\n vec3 dx = dFdx(normal);\n vec3 dy = dFdy(normal);\n\n // Curvature magnitude\n float curvature = length(dx) + length(dy);\n\n // Normalize to useful range\n return clamp(curvature * 5.0, 0.0, 1.0);\n}\n\n/**\n * Full physically-based SSS calculation\n * Combines all components for realistic translucent materials\n *\n * @param normal - Surface normal (view space)\n * @param viewDir - View direction\n * @param position - Vertex position\n * @param lightDir - Light direction\n * @param lightColor - Light color\n * @param baseColor - Material base/albedo color\n * @param sssStrength - Overall SSS strength\n * @param absorption - Absorption coefficients RGB (inverted: higher = MORE of that color)\n * @param scatterDist - Scatter distance RGB (higher = more scatter)\n * @param thicknessBias - Base thickness\n * @param thicknessScale - Thickness multiplier\n * @param curvatureScale - Curvature influence\n * @param ambient - Ambient SSS contribution\n * @return Final SSS color contribution\n */\nvec3 calculatePhysicalSSS(\n vec3 normal,\n vec3 viewDir,\n vec3 position,\n vec3 lightDir,\n vec3 lightColor,\n vec3 baseColor,\n float sssStrength,\n vec3 absorption,\n vec3 scatterDist,\n float thicknessBias,\n float thicknessScale,\n float curvatureScale,\n float ambient\n) {\n if (sssStrength < 0.001) {\n return vec3(0.0);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // THICKNESS ESTIMATION\n // ─────────────────────────────────────────────────────────────────────\n float thickness = estimateThickness(normal, viewDir, position, thicknessBias, thicknessScale);\n\n // ─────────────────────────────────────────────────────────────────────\n // ABSORPTION COLOR (Beer's Law with artist-friendly values)\n // Creates the characteristic color of translucent materials\n // absorption values: high value = MORE of that color passes through (transmitted)\n // This is inverted from physics but intuitive: jade has high green absorption\n // ─────────────────────────────────────────────────────────────────────\n // Use absorption directly as transmittance - higher = more of that color shows\n // Normalize to prevent any channel from dominating\n float maxAbsorption = max(absorption.r, max(absorption.g, absorption.b));\n vec3 normalizedTransmit = absorption / max(maxAbsorption, 0.001);\n\n // Apply thickness-based falloff - thin areas show more color\n float thicknessFactor = 1.0 - thickness * 0.3;\n vec3 colorShift = normalizedTransmit * thicknessFactor;\n\n // Ensure minimum color presence\n colorShift = max(colorShift, vec3(0.15));\n\n // ─────────────────────────────────────────────────────────────────────\n // SCATTER INTENSITY\n // How much light scatters based on material properties\n // ─────────────────────────────────────────────────────────────────────\n // Higher scatter distance = more light gets through, but keep it subtle\n vec3 scatterIntensity = scatterDist * 0.8;\n scatterIntensity = clamp(scatterIntensity, vec3(0.1), vec3(1.0));\n\n // ─────────────────────────────────────────────────────────────────────\n // LIGHTING TERMS - Boosted for visibility\n // ─────────────────────────────────────────────────────────────────────\n\n // Back-lighting: light passing through from behind (strongest SSS cue)\n float NdotL = dot(normal, lightDir);\n float backLight = max(0.0, -NdotL);\n backLight = pow(backLight, 1.2) * 1.5; // Boosted\n\n // Wrap lighting: soft diffuse that wraps around\n float wrapLight = (NdotL + 1.0) * 0.5; // Full wrap, 0-1 range\n wrapLight = wrapLight * wrapLight;\n\n // View-dependent translucency (looking through thin parts)\n float VdotL = dot(viewDir, -lightDir);\n float translucency = pow(max(0.0, VdotL), 1.5) * 1.2; // Boosted\n\n // Edge glow (fresnel-like SSS at silhouettes)\n float edgeGlow = pow(1.0 - abs(dot(normal, viewDir)), 2.0);\n\n // ─────────────────────────────────────────────────────────────────────\n // THICKNESS-BASED TRANSMISSION\n // Thin areas let more light through\n // ─────────────────────────────────────────────────────────────────────\n float thinTransmission = 1.0 - thickness * 0.5;\n thinTransmission = max(thinTransmission, 0.3);\n\n // ─────────────────────────────────────────────────────────────────────\n // CURVATURE ENHANCEMENT\n // ─────────────────────────────────────────────────────────────────────\n float curvature = calculateCurvature(normal);\n float curvatureFactor = 1.0 + curvature * curvatureScale;\n\n // ─────────────────────────────────────────────────────────────────────\n // COMBINE ALL TERMS\n // ─────────────────────────────────────────────────────────────────────\n\n // Total light contribution (more additive for visibility)\n float totalLight = backLight + translucency * 0.8 + wrapLight * 0.4 + edgeGlow * 0.5;\n totalLight *= curvatureFactor * thinTransmission;\n\n // Base SSS color - colorShift IS the tint (e.g., green for jade)\n // Don't multiply by baseColor to avoid washing out with emotionColor\n vec3 sssColor = colorShift * scatterIntensity;\n\n // Ambient SSS (always visible, gives material its translucent look)\n vec3 ambientSSS = sssColor * ambient;\n\n // Direct SSS from lighting - subtle contribution\n vec3 directSSS = sssColor * lightColor * totalLight * 0.5;\n\n // Final combination\n vec3 finalSSS = directSSS + ambientSSS;\n\n // Apply overall strength (linear, no boost to prevent blowout)\n return finalSSS * sssStrength;\n}\n\n/**\n * Simplified SSS for performance-critical scenarios\n * Uses pre-computed approximations\n *\n * @param normal - Surface normal\n * @param viewDir - View direction\n * @param lightDir - Light direction\n * @param thickness - Pre-computed or approximated thickness\n * @param baseColor - Material color\n * @param scatterColor - Scatter tint color\n * @param strength - SSS strength\n * @return SSS color contribution\n */\nvec3 calculateSimpleSSS(\n vec3 normal,\n vec3 viewDir,\n vec3 lightDir,\n float thickness,\n vec3 baseColor,\n vec3 scatterColor,\n float strength\n) {\n if (strength < 0.001) {\n return vec3(0.0);\n }\n\n // Back-lighting\n float backLight = pow(max(0.0, dot(viewDir, -lightDir)), 2.0);\n\n // Transmittance (simplified Beer's law)\n float transmit = exp(-thickness * 2.0);\n\n // Edge enhancement\n float edge = pow(1.0 - abs(dot(normal, viewDir)), 2.0);\n\n // Combine\n float sssIntensity = (backLight * transmit + edge * 0.3) * strength;\n\n return mix(baseColor, scatterColor, 0.5) * sssIntensity;\n}\n\n\nvoid main() {\n vec3 normal = normalize(vNormal);\n vec3 viewDir = normalize(vViewPosition);\n\n // ═══════════════════════════════════════════════════════════════════════\n // FRESNEL EFFECT - Colored rim at edges (cyan-tinted)\n // ═══════════════════════════════════════════════════════════════════════\n float fresnel = pow(1.0 - abs(dot(normal, viewDir)), fresnelPower);\n fresnel *= fresnelIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════\n // AMBIENT OCCLUSION - Dark shadows for depth\n // ═══════════════════════════════════════════════════════════════════════\n float ao = calculateAO(normal, viewDir, vPosition);\n float shadowFactor = mix(1.0, ao, shadowDarkness);\n\n // ═══════════════════════════════════════════════════════════════════════\n // SPECULAR HIGHLIGHTS - Bright catches on facet edges\n // ═══════════════════════════════════════════════════════════════════════\n vec3 lightDir = normalize(sssLightDir);\n float specular = calculateFacetSpecular(normal, viewDir, lightDir, specularPower);\n specular *= specularIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════\n // LIGHT TRANSMISSION - Thin areas glow, thick areas darken\n // ═══════════════════════════════════════════════════════════════════════\n float transmission = calculateTransmission(vPosition, normal, viewDir, transmissionContrast);\n\n // ═══════════════════════════════════════════════════════════════════════\n // TEXTURE SAMPLING - Crystal surface detail from UV-mapped texture\n // ═══════════════════════════════════════════════════════════════════════\n vec4 texColor = texture2D(crystalTexture, vUv);\n float texValue = (texColor.r + texColor.g + texColor.b) / 3.0; // Grayscale\n\n // ═══════════════════════════════════════════════════════════════════════\n // FROSTED SURFACE - Subtle cloudy variation (not opaque white!)\n // ═══════════════════════════════════════════════════════════════════════\n float surfaceNoise = fbm(vPosition * surfaceNoiseScale + time * 0.02);\n surfaceNoise = surfaceNoise * surfaceRoughness;\n\n // ═══════════════════════════════════════════════════════════════════════\n // INNER SOUL GLOW - The glowing core visible through the crystal\n // ═══════════════════════════════════════════════════════════════════════\n\n // Animated internal glow - subtle pulsing\n float glowPulse = sin(time * 0.5) * 0.15 + 0.85;\n\n // Core glow - strongest in center, fades toward edges with sharper falloff\n float distFromCenter = length(vPosition);\n float coreGlow = exp(-distFromCenter * 2.5) * glowPulse;\n\n // ═══════════════════════════════════════════════════════════════════════\n // INTERNAL CAUSTICS - Light refraction pools inside the gem\n // Creates bright concentrated spots that shift with viewing angle\n // Real caustics form where refracted light rays converge inside the gem\n // Now with CHROMATIC ABERRATION - different wavelengths refract differently\n // ═══════════════════════════════════════════════════════════════════════\n\n // Refract view direction through gem surface with different IOR per wavelength\n // Red refracts less (higher IOR ratio), blue refracts more (lower IOR ratio)\n // Chromatic separation is REDUCED for colored gems to avoid color contamination\n // Quartz (low sssStrength) gets full rainbow, colored gems get subtle dispersion\n float chromaticStrength = 1.0 - clamp((sssStrength - 0.5) * 0.8, 0.0, 0.8);\n float iorR = mix(0.57, 0.70, chromaticStrength); // Red - approaches green for colored gems\n float iorB = mix(0.57, 0.44, chromaticStrength); // Blue - approaches green for colored gems\n vec3 refractDirR = refract(-viewDir, normal, iorR);\n vec3 refractDirG = refract(-viewDir, normal, 0.57); // Green - always medium\n vec3 refractDirB = refract(-viewDir, normal, iorB);\n\n // Animated drift\n float causticTime = time * causticSpeed;\n vec3 drift = vec3(causticTime * 0.3, causticTime * 0.2, causticTime * 0.1);\n\n // Sample positions for each color channel\n // Offset is also reduced for colored gems to minimize chromatic contamination\n float spatialOffset = mix(1.0, 3.0, chromaticStrength);\n vec3 causticPosR = vPosition * causticScale + refractDirR * spatialOffset + drift;\n vec3 causticPosG = vPosition * causticScale + refractDirG * spatialOffset + drift;\n vec3 causticPosB = vPosition * causticScale + refractDirB * spatialOffset + drift;\n\n // Create caustic pattern for each channel\n // Red channel\n float waveR1 = sin(causticPosR.x * 2.0 + causticPosR.y * 1.5 + causticPosR.z);\n float waveR2 = sin(causticPosR.y * 2.3 - causticPosR.x * 1.2 + causticPosR.z * 1.8);\n float waveR3 = sin(causticPosR.z * 1.9 + causticPosR.x * 0.8 - causticPosR.y * 1.4);\n float interferenceR = (waveR1 + waveR2 + waveR3) / 3.0;\n float causticR = smoothstep(0.3, 0.8, interferenceR);\n\n // Green channel\n float waveG1 = sin(causticPosG.x * 2.0 + causticPosG.y * 1.5 + causticPosG.z);\n float waveG2 = sin(causticPosG.y * 2.3 - causticPosG.x * 1.2 + causticPosG.z * 1.8);\n float waveG3 = sin(causticPosG.z * 1.9 + causticPosG.x * 0.8 - causticPosG.y * 1.4);\n float interferenceG = (waveG1 + waveG2 + waveG3) / 3.0;\n float causticG = smoothstep(0.3, 0.8, interferenceG);\n\n // Blue channel\n float waveB1 = sin(causticPosB.x * 2.0 + causticPosB.y * 1.5 + causticPosB.z);\n float waveB2 = sin(causticPosB.y * 2.3 - causticPosB.x * 1.2 + causticPosB.z * 1.8);\n float waveB3 = sin(causticPosB.z * 1.9 + causticPosB.x * 0.8 - causticPosB.y * 1.4);\n float interferenceB = (waveB1 + waveB2 + waveB3) / 3.0;\n float causticB = smoothstep(0.3, 0.8, interferenceB);\n\n // Combine into RGB caustic with chromatic separation\n vec3 causticRGB = vec3(causticR, causticG, causticB);\n\n // Add noise variation to break up uniformity\n float noiseVar = noise3D(causticPosG * 0.5);\n causticRGB *= (0.7 + noiseVar * 0.6);\n\n // Clamp caustic peaks to prevent hot spot blobs\n // This keeps caustics subtle and distributed rather than concentrated\n causticRGB = min(causticRGB, vec3(0.6));\n\n // Caustics are MORE visible in thick areas (center) where light has more\n // material to refract through and pool\n float thickness = abs(dot(normal, viewDir)); // 1 at center, 0 at edges\n causticRGB *= (0.3 + thickness * 0.7);\n\n // Apply intensity control\n causticRGB *= causticIntensity;\n\n // Boost caustic visibility for colored gems to compensate for reduced chromatic spread\n // Colored gems (high sssStrength) have suppressed chromatic aberration, so boost their\n // monochromatic caustics to maintain internal "life" and sparkle\n float causticBoost = 1.0 + clamp((sssStrength - 0.5) * 0.8, 0.0, 0.6);\n causticRGB *= causticBoost;\n\n // Also keep a scalar caustic for compatibility\n float caustic = (causticRGB.r + causticRGB.g + causticRGB.b) / 3.0;\n\n // Animation pattern (0-1 range) - core glow + caustic hot spots\n float animationPattern = coreGlow * 0.7 + caustic * 0.3;\n\n // Soul intensity controls overall brightness with more dramatic falloff\n // Brighter near core, darker at edges\n float baseLevel = 0.1; // Lower base for more contrast\n float patternContrast = 0.9; // Higher contrast for more variation\n float soulIntensity = (baseLevel + animationPattern * patternContrast) * innerGlowStrength;\n\n // Apply transmission to soul - thin areas glow brighter\n soulIntensity *= transmission;\n\n // Soul color from emotion\n // NOTE: emotionColor is pre-normalized by normalizeColorLuminance() in Core3DManager\n // This ensures consistent perceived brightness across all emotions (yellow won't wash out, blue stays visible)\n // Reduced intensity to prevent blowout - soul should be visible but not white\n float glowCurve = sqrt(innerGlowStrength * glowIntensity) * 0.5;\n vec3 soulColor = emotionColor * soulIntensity * glowCurve;\n // Clamp soul color to prevent blowout\n soulColor = min(soulColor, vec3(0.8));\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFRACTED SOUL SAMPLING - True optical lensing through crystal\n // The soul is rendered to a texture, then sampled with refraction distortion\n // This creates the effect of looking at the soul through a crystal lens\n // ═══════════════════════════════════════════════════════════════════════\n\n // ═══════════════════════════════════════════════════════════════════\n // REFRACTED SOUL SAMPLING\n // Sample the soul texture with physical refraction distortion\n // Creates the "looking through glass" lensing effect\n // ═══════════════════════════════════════════════════════════════════\n vec3 refractedSoulColor = vec3(0.0);\n float refractedSoulAlpha = 0.0;\n\n if (soulTextureSize.x > 0.0 && soulScreenCenter.x >= 0.0) {\n // Fragment's screen UV position\n vec2 fragUV = gl_FragCoord.xy / soulTextureSize;\n\n // Calculate refraction offset using Snell's law\n float ior = refractionIndex;\n vec3 refractedDir = refract(-viewDir, normal, 1.0 / ior);\n\n // Apply refraction distortion toward the soul center\n // This creates the magnifying glass effect - bending light toward center\n vec2 refractionOffset = refractedDir.xy * refractionStrength * 0.1;\n\n // Sample at fragment position with refraction offset\n // The soul texture contains the soul rendered at its actual screen position\n vec2 soulUV = fragUV + refractionOffset;\n\n // Clamp to valid UV range\n soulUV = clamp(soulUV, 0.0, 1.0);\n\n // Sample the soul texture\n vec4 soulSample = texture2D(soulTexture, soulUV);\n\n // Store for later use in final composition\n refractedSoulColor = soulSample.rgb;\n refractedSoulAlpha = soulSample.a;\n\n // Also blend into soulColor for existing pipeline\n soulColor = mix(soulColor, soulSample.rgb, soulSample.a * 0.5);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // SOUL BLEND LAYERS - Apply before combining with shell\n // ═══════════════════════════════════════════════════════════════════════\n if (soulLayer1Enabled > 0.5) {\n int mode = int(soulLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(soulColor, emotionColor * soulLayer1Strength, mode);\n soulColor = mix(soulColor, blendResult, soulLayer1Strength);\n }\n if (soulLayer2Enabled > 0.5) {\n int mode = int(soulLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(soulColor, emotionColor * soulLayer2Strength, mode);\n soulColor = mix(soulColor, blendResult, soulLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FROSTED SHELL - Milky white layer with INTERNAL lighting model\n // Lit from inside: thin edges bright, thick center dark\n // ═══════════════════════════════════════════════════════════════════════\n\n // Frosted glass base - will be modulated by thickness\n // Lower base values allow for darker thick areas while maintaining bright edges\n vec3 frostBase = vec3(0.45, 0.48, 0.55) * frostiness;\n\n // THICKNESS-BASED DARKNESS (internal lighting model)\n // Face-on facets are THICK (light travels far through) = DARK\n // Edge-on facets are THIN (light escapes easily) = BRIGHT\n float edgeThinness = 1.0 - abs(dot(normal, viewDir)); // 1 at edges, 0 facing camera\n\n // Apply curve to make face-on areas darker more aggressively\n float thinness = pow(edgeThinness, 0.7); // Push more area toward dark\n\n // Thickness multiplier: thin edges=bright (1.0), thick face-on=dark (0.01 for near-black)\n float thicknessMultiplier = 0.01 + thinness * 0.99;\n frostBase *= thicknessMultiplier;\n\n // Surface variation adds subtle texture\n frostBase += vec3(surfaceNoise * 0.03);\n\n // Specular highlights on facet edges (external light catch)\n float facetHighlight = pow(max(0.0, dot(normal, normalize(vec3(0.5, 1.0, 0.8)))), 16.0);\n frostBase += vec3(facetHighlight * 0.2);\n\n // SOUL BLEED - Inner glow illuminates the shell from inside\n // Use gentler falloff so color reaches the shell surface\n float soulBleed = exp(-distFromCenter * 1.2) * innerGlowStrength;\n // Stronger color contribution - tint the frost with emotion color\n frostBase = mix(frostBase, frostBase + emotionColor * 0.4, soulBleed);\n\n // ═══════════════════════════════════════════════════════════════════════\n // SHELL BLEND LAYERS - Apply to frosted shell\n // ═══════════════════════════════════════════════════════════════════════\n if (shellLayer1Enabled > 0.5) {\n int mode = int(shellLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(frostBase, emotionColor * shellLayer1Strength, mode);\n frostBase = mix(frostBase, blendResult, shellLayer1Strength);\n }\n if (shellLayer2Enabled > 0.5) {\n int mode = int(shellLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(frostBase, emotionColor * shellLayer2Strength, mode);\n frostBase = mix(frostBase, blendResult, shellLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FRESNEL RIM - Bright emotion-colored edge glow\n // ═══════════════════════════════════════════════════════════════════════\n vec3 rimColor = mix(vec3(0.5, 0.9, 1.0), emotionColor, 0.6);\n vec3 rimGlow = rimColor * fresnel * 1.2;\n\n // ═══════════════════════════════════════════════════════════════════════\n // RIM BLEND LAYERS - Apply to fresnel rim glow\n // ═══════════════════════════════════════════════════════════════════════\n if (rimLayer1Enabled > 0.5) {\n int mode = int(rimLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(rimGlow, emotionColor * rimLayer1Strength, mode);\n rimGlow = mix(rimGlow, blendResult, rimLayer1Strength);\n }\n if (rimLayer2Enabled > 0.5) {\n int mode = int(rimLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(rimGlow, emotionColor * rimLayer2Strength, mode);\n rimGlow = mix(rimGlow, blendResult, rimLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // PHYSICALLY-BASED SUBSURFACE SCATTERING\n // Uses BSSRDF with Beer's Law absorption and Burley diffusion profile\n // ═══════════════════════════════════════════════════════════════════════\n vec3 sss = calculatePhysicalSSS(\n normal,\n viewDir,\n vPosition,\n normalize(sssLightDir),\n sssLightColor,\n emotionColor,\n sssStrength,\n sssAbsorption,\n sssScatterDistance,\n sssThicknessBias,\n sssThicknessScale,\n sssCurvatureScale,\n sssAmbient\n );\n\n // ═══════════════════════════════════════════════════════════════════════\n // SSS BLEND LAYERS - Apply to subsurface scattering contribution\n // ═══════════════════════════════════════════════════════════════════════\n if (sssLayer1Enabled > 0.5) {\n int mode = int(sssLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(sss, emotionColor * sssLayer1Strength, mode);\n sss = mix(sss, blendResult, sssLayer1Strength);\n }\n if (sssLayer2Enabled > 0.5) {\n int mode = int(sssLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(sss, emotionColor * sssLayer2Strength, mode);\n sss = mix(sss, blendResult, sssLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // COMBINE - Frosted shell base + soul glow (soul adds to shell, doesn't replace)\n // ═══════════════════════════════════════════════════════════════════════\n\n // Start with shell as base - preserves dark shadows\n vec3 finalColor = frostBase;\n\n // Add soul glow on top (additive, not replacement) - concentrated in center\n // Soul should illuminate dark areas but not wash out entirely\n float soulBlendFactor = soulIntensity * 0.6;\n finalColor += soulColor * soulBlendFactor;\n\n // Apply texture - blend based on texture brightness and strength\n vec3 texContribution = texColor.rgb * textureStrength;\n finalColor = mix(finalColor, finalColor + texContribution, textureStrength);\n\n // Apply SSS material color - PRESERVE BRIGHTNESS, only change HUE\n // The sssAbsorption values define the material color hue\n // But thickness-based darkness must be preserved for gemstone look\n if (sssStrength > 0.01) {\n // Get current brightness (this includes thickness darkening)\n float currentLum = dot(finalColor, vec3(0.299, 0.587, 0.114));\n\n // Normalize absorption to get hue direction (0-1 range)\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 hue = absorption / max(maxAbs, 0.001);\n\n // Create material color that PRESERVES current brightness\n // This keeps dark areas dark while tinting them with the gem color\n float hueLum = dot(hue, vec3(0.299, 0.587, 0.114));\n vec3 materialColor = hue * currentLum / max(hueLum, 0.001);\n\n // Clamp to prevent blowout on bright areas\n materialColor = min(materialColor, vec3(1.0));\n\n // Add subtle variation from SSS lighting calculation\n float sssLum = dot(sss, vec3(0.299, 0.587, 0.114));\n materialColor *= (0.9 + sssLum * 0.2);\n\n // Replace crystal color with material color\n float replaceAmount = sssStrength * 0.7;\n finalColor = mix(finalColor, materialColor, replaceAmount);\n }\n\n // Add rim glow, tinted toward material color\n if (sssStrength > 0.01) {\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 hue = absorption / max(maxAbs, 0.001);\n // Stronger tint for colored gems - use gem hue directly\n float rimTintStrength = clamp(sssStrength * 0.6, 0.0, 0.95);\n vec3 tintedRim = rimGlow * mix(vec3(1.0), hue * 1.2, rimTintStrength);\n // Cap rim to prevent bloom\n tintedRim = min(tintedRim, vec3(0.5));\n finalColor += tintedRim;\n } else {\n finalColor += rimGlow;\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // SPECULAR HIGHLIGHTS - Add bright hot spots\n // Tinted by gem color for colored gems to prevent white bloom\n // ═══════════════════════════════════════════════════════════════════════\n vec3 specularColor = vec3(1.0, 0.98, 0.95); // Warm white highlights for clear gems\n float specularIntensityMod = 1.0;\n\n if (sssStrength > 0.5) {\n // Tint specular by gem color to prevent white bloom\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 gemHue = absorption / max(maxAbs, 0.001);\n float colorStrength = clamp((sssStrength - 0.5) * 0.5, 0.0, 1.0);\n // Use gem hue for specular color\n specularColor = mix(specularColor, gemHue * 1.3, colorStrength);\n // Also reduce specular intensity for colored gems\n specularIntensityMod = mix(1.0, 0.4, colorStrength);\n }\n\n vec3 specularContrib = specularColor * specular * transmission * specularIntensityMod;\n specularContrib = min(specularContrib, vec3(0.5)); // Cap specular to prevent bloom\n finalColor += specularContrib;\n\n // ═══════════════════════════════════════════════════════════════════════\n // FACET EDGE LINES - Bright catches along beveled edges\n // ═══════════════════════════════════════════════════════════════════════\n float edgeLines = calculateFacetEdgeLines(normal, viewDir, lightDir);\n finalColor += vec3(edgeLines * 0.15) * transmission;\n\n // ═══════════════════════════════════════════════════════════════════════\n // SATURATION BOOST AT THIN EDGES\n // Real gems have MORE saturated color at thin edges where light escapes\n // ═══════════════════════════════════════════════════════════════════════\n if (sssStrength > 0.01) {\n // thinness: 1 at edges, 0 facing camera\n float satBoost = thinness * 0.4; // Up to 40% saturation boost at edges\n\n // Get current color's saturation\n float maxC = max(max(finalColor.r, finalColor.g), finalColor.b);\n float minC = min(min(finalColor.r, finalColor.g), finalColor.b);\n float currentSat = maxC > 0.001 ? (maxC - minC) / maxC : 0.0;\n\n // Boost saturation at thin areas\n if (maxC > 0.001 && currentSat > 0.01) {\n // Calculate luminance\n float lum = dot(finalColor, vec3(0.299, 0.587, 0.114));\n // Increase saturation by moving away from gray toward the color\n vec3 gray = vec3(lum);\n float newSat = min(currentSat + satBoost, 1.0);\n float satRatio = currentSat > 0.001 ? newSat / currentSat : 1.0;\n finalColor = gray + (finalColor - gray) * satRatio;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FINAL THICKNESS APPLICATION - Apply AFTER all additive terms\n // This ensures thick areas stay dark even with glow added\n // ═══════════════════════════════════════════════════════════════════════\n // thicknessMultiplier: 0.15 in thick center, 1.0 at thin edges\n finalColor *= thicknessMultiplier;\n\n // ═══════════════════════════════════════════════════════════════════════\n // INTERNAL CAUSTICS - Bright spots from light concentration inside gem\n // Now with chromatic aberration for rainbow dispersion effect\n // Applied AFTER thickness darkening so they punch through dark areas\n // ═══════════════════════════════════════════════════════════════════════\n if (causticIntensity > 0.01) {\n // Get material hue for tinting caustics\n vec3 causticTint = vec3(1.0); // Default white\n float causticTintStrength = 0.4; // Default for clear gems\n if (sssStrength > 0.5) {\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 hue = absorption / max(maxAbs, 0.001);\n // Stronger tint for colored gems to prevent white bloom\n causticTintStrength = clamp((sssStrength - 0.5) * 0.8 + 0.4, 0.4, 0.9);\n causticTint = mix(vec3(1.0), hue * 1.2, causticTintStrength);\n }\n // Add RGB caustic with chromatic aberration\n // Reduce raw RGB blend for colored gems\n float rawBlend = mix(0.3, 0.1, clamp((sssStrength - 0.5) * 0.5, 0.0, 1.0));\n vec3 causticFinal = causticRGB * causticTint + causticRGB * rawBlend;\n causticFinal = min(causticFinal, vec3(0.4)); // Cap to prevent bloom\n finalColor += causticFinal;\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FIRE - Intense sparkle points from light dispersion in facets\n // The "fire" effect that makes gems sparkle brilliantly\n // ═══════════════════════════════════════════════════════════════════════\n float fire = calculateFire(normal, viewDir, lightDir);\n\n // Tint fire by gem color - colored gems should have tinted highlights\n // Pure white fire only for quartz/clear gems (low sssStrength)\n vec3 fireColor = vec3(1.0, 0.99, 0.97); // Base warm white\n float fireIntensity = 0.3; // Base intensity for clear gems\n float fireClamp = 1.5; // Max fire value for clear gems\n\n if (sssStrength > 0.5) {\n // Get gem hue from absorption - this IS the gem's color\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 gemHue = absorption / max(maxAbs, 0.001);\n\n // For colored gems, fire should BE the gem color, not white\n // The more colored the gem (higher sssStrength), the more the fire matches the gem\n float colorStrength = clamp((sssStrength - 0.5) * 0.5, 0.0, 1.0);\n\n // Use gem hue directly as fire color - NOT mixed with white\n // This ensures fire can never bloom to white\n fireColor = gemHue * 1.2; // Slight brightness boost but stay saturated\n\n // Reduce fire intensity AND clamp for colored gems to prevent bloom washout\n // Colored gems should have subtle, saturated fire, not bright white spots\n fireIntensity = mix(0.3, 0.08, colorStrength); // Much lower for colored gems\n fireClamp = mix(1.5, 0.5, colorStrength); // Much lower clamp for colored gems\n }\n\n // Apply fire clamp BEFORE multiplying by color\n fire = min(fire, fireClamp);\n\n // Calculate fire contribution and clamp to prevent any channel from blooming\n vec3 fireContribution = fireColor * fire * fireIntensity;\n fireContribution = min(fireContribution, vec3(0.4)); // Hard cap on fire brightness\n finalColor += fireContribution;\n\n // Ensure minimum brightness - allow near-black for gemstones\n // minBrightness of 0.01 allows true darks while preventing total black\n finalColor = max(finalColor, vec3(minBrightness));\n\n // ═══════════════════════════════════════════════════════════════════════\n // ALPHA - More opaque for visibility\n // ═══════════════════════════════════════════════════════════════════════\n\n // Higher base opacity\n float baseAlpha = 0.6 + frostiness * 0.25;\n\n // Fresnel makes edges solid\n float rimAlpha = fresnel * 0.3;\n\n // Soul glow adds opacity\n float glowAlpha = soulIntensity * 0.15;\n\n float finalAlpha = min(baseAlpha + rimAlpha + glowAlpha, 0.95) * opacity;\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFRACTED SOUL - Add the soul visible through the crystal\n // This is the actual soul mesh rendered to texture and sampled with refraction\n // ═══════════════════════════════════════════════════════════════════════\n if (refractedSoulAlpha > 0.01) {\n // The soul should glow through the crystal, tinted by the crystal's color\n // Use additive blending so the soul illuminates the crystal from within\n vec3 soulGlow = refractedSoulColor * refractedSoulAlpha;\n\n // Tint the soul by the crystal's SSS color for colored gems\n // emotionColorBleed controls how much pure emotion color comes through\n // 0 = fully tinted by gem color, 1 = pure emotion color\n if (sssStrength > 0.01) {\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 gemHue = absorption / max(maxAbs, 0.001);\n float tintAmount = sssStrength * 0.5 * (1.0 - emotionColorBleed);\n soulGlow *= mix(vec3(1.0), gemHue, tintAmount);\n }\n\n // Add soul glow to final color\n finalColor += soulGlow * 0.8;\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // EMOTION COLOR BLEED - Additional inner glow from soul emotion\n // Adds pure emotion color as light shining through the gem from the soul\n // ═══════════════════════════════════════════════════════════════════════\n if (emotionColorBleed > 0.001 && sssStrength > 0.01) {\n // Inner glow based on thickness - thinner areas show more soul light\n float innerGlow = 1.0 - abs(dot(normal, viewDir)); // Edges are thin\n innerGlow = pow(innerGlow, 1.5) * emotionColorBleed;\n\n // Also add glow near the core\n float coreProximity = exp(-distFromCenter * 2.0);\n innerGlow += coreProximity * emotionColorBleed * 0.5;\n\n // Add pure emotion color as inner light\n finalColor += emotionColor * innerGlow * 0.4;\n }\n\n gl_FragColor = vec4(finalColor, finalAlpha);\n}\n`,Ei={time:0,glowIntensity:1,opacity:1,frostiness:.55,fresnelPower:2.8,fresnelIntensity:.35,innerGlowStrength:.55,surfaceRoughness:.12,shadowDarkness:.6,specularIntensity:.9,specularPower:28,transmissionContrast:1,minBrightness:.005,surfaceNoiseScale:1.5,noiseFrequency:1.33,causticIntensity:.8,causticScale:2,causticSpeed:.12,textureStrength:.55,refractionIndex:1.5,refractionStrength:.5,resolution:[1920,1080],soulTextureSize:[1920,1080],soulScreenCenter:[.5,.5],sssStrength:.65,sssAbsorption:[2.4,2.5,2.8],sssScatterDistance:[.35,.4,.45],sssThicknessBias:.18,sssThicknessScale:.6,sssCurvatureScale:1.8,sssAmbient:.3,sssLightDir:[.5,1,.8],sssLightColor:[1,.98,.95],shellLayer1Mode:0,shellLayer1Strength:0,shellLayer1Enabled:0,shellLayer2Mode:0,shellLayer2Strength:0,shellLayer2Enabled:0,soulLayer1Mode:0,soulLayer1Strength:0,soulLayer1Enabled:0,soulLayer2Mode:0,soulLayer2Strength:0,soulLayer2Enabled:0,rimLayer1Mode:0,rimLayer1Strength:0,rimLayer1Enabled:0,rimLayer2Mode:0,rimLayer2Strength:0,rimLayer2Enabled:0,sssLayer1Mode:0,sssLayer1Strength:0,sssLayer1Enabled:0,sssLayer2Mode:0,sssLayer2Strength:0,sssLayer2Enabled:0};function Ii(t,i,n={}){const{glowColor:a=[1,1,.95],glowIntensity:s=1,materialVariant:o=null,emotionData:r=null,assetBasePath:l="/assets"}=n;return"custom"===i.material?function(t,i,n,a,s,o){const r=new e.TextureLoader;switch(t){case"moon":return function(t,i,n,a=null,s="/assets"){if("multiplexer"===a)return{material:U(t,{resolution:"2k",glowColor:new e.Color(i[0],i[1],i[2]),glowIntensity:n,assetBasePath:s}),type:"moon-multiplexer"};return{material:L(t,{resolution:"2k",glowColor:new e.Color(i[0],i[1],i[2]),glowIntensity:n,moonPhase:"full",assetBasePath:s}),type:"moon"}}(r,i,n,a,o);case"crystal":return Ai(i,n,"crystal",{sssPreset:"quartz"},o);case"rough":return Ai(i,n,"rough",{frostiness:.05,innerGlowStrength:0,fresnelIntensity:1.6},o);case"heart":return Ai(i,n,"heart",{frostiness:.475,innerGlowStrength:.117,fresnelIntensity:1.206},o);case"star":return Ai(i,n,"star",{sssPreset:"citrine"},o);default:return console.warn("Unknown custom material type:",t),null}}(t,a,s,o,0,l):"emissive"===i.material?function(t,i,n,a,s,o){const r=new e.TextureLoader;return"sun"===t?function(e,t,i,n=null,a=null,s="/assets"){return{material:X(e,{glowColor:t,glowIntensity:i,resolution:"4k",materialVariant:n,assetBasePath:s}),type:"sun"}}(r,i,n,a,s,o):(console.warn("Unknown emissive material type:",t),null)}(t,a,s,o,r,l):null}function Ai(t,i,n="crystal",a={},s="/assets"){const{vertexShader:o,fragmentShader:r}={vertexShader:"\nvarying vec3 vPosition;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n vPosition = position;\n vNormal = normalize(normalMatrix * normal);\n\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = -mvPosition.xyz;\n\n gl_Position = projectionMatrix * mvPosition;\n}\n",fragmentShader:Ti};let l=null;if(n){const t=new e.TextureLoader,i={crystal:`${s}/textures/Crystal/crystal.jpg`,rough:`${s}/textures/Crystal/rough.jpg`,heart:`${s}/textures/Crystal/heart.jpg`,star:`${s}/textures/Crystal/star.jpg`},a=i[n]||i.crystal;l=t.load(a,void 0,e=>console.warn(`💎 ${n} texture failed to load:`,e))}const h=a.sssPreset?ki[a.sssPreset]:null;return{material:new e.ShaderMaterial({uniforms:{time:{value:0},emotionColor:{value:new e.Color(t[0],t[1],t[2])},glowIntensity:{value:i},opacity:{value:1},frostiness:{value:a.frostiness??Ei.frostiness},fresnelPower:{value:a.fresnelPower??Ei.fresnelPower},fresnelIntensity:{value:a.fresnelIntensity??Ei.fresnelIntensity},innerGlowStrength:{value:a.innerGlowStrength??Ei.innerGlowStrength},surfaceRoughness:{value:Ei.surfaceRoughness},shadowDarkness:{value:a.shadowDarkness??Ei.shadowDarkness},specularIntensity:{value:a.specularIntensity??Ei.specularIntensity},specularPower:{value:a.specularPower??Ei.specularPower},transmissionContrast:{value:a.transmissionContrast??Ei.transmissionContrast},minBrightness:{value:a.minBrightness??Ei.minBrightness},surfaceNoiseScale:{value:Ei.surfaceNoiseScale},noiseFrequency:{value:Ei.noiseFrequency},causticIntensity:{value:a.causticIntensity??Ei.causticIntensity},causticScale:{value:a.causticScale??Ei.causticScale},causticSpeed:{value:a.causticSpeed??Ei.causticSpeed},crystalTexture:{value:l},textureStrength:{value:"heart"===n?.35:n?Ei.textureStrength:0},soulTexture:{value:null},resolution:{value:new e.Vector2(Ei.resolution[0],Ei.resolution[1])},soulTextureSize:{value:new e.Vector2(Ei.soulTextureSize[0],Ei.soulTextureSize[1])},soulScreenCenter:{value:new e.Vector2(Ei.soulScreenCenter[0],Ei.soulScreenCenter[1])},refractionIndex:{value:a.refractionIndex??Ei.refractionIndex},refractionStrength:{value:a.refractionStrength??Ei.refractionStrength},sssStrength:{value:a.sssStrength??h?.sssStrength??Ei.sssStrength},sssAbsorption:{value:new e.Vector3(...a.sssAbsorption??h?.sssAbsorption??Ei.sssAbsorption)},sssScatterDistance:{value:new e.Vector3(...a.sssScatterDistance??h?.sssScatterDistance??Ei.sssScatterDistance)},sssThicknessBias:{value:a.sssThicknessBias??h?.sssThicknessBias??Ei.sssThicknessBias},sssThicknessScale:{value:a.sssThicknessScale??h?.sssThicknessScale??Ei.sssThicknessScale},sssCurvatureScale:{value:a.sssCurvatureScale??h?.sssCurvatureScale??Ei.sssCurvatureScale},sssAmbient:{value:a.sssAmbient??h?.sssAmbient??Ei.sssAmbient},sssLightDir:{value:new e.Vector3(...a.sssLightDir??Ei.sssLightDir)},sssLightColor:{value:new e.Vector3(...a.sssLightColor??Ei.sssLightColor)},emotionColorBleed:{value:a.emotionColorBleed??h?.emotionColorBleed??0},shellLayer1Mode:{value:Ei.shellLayer1Mode},shellLayer1Strength:{value:Ei.shellLayer1Strength},shellLayer1Enabled:{value:Ei.shellLayer1Enabled},shellLayer2Mode:{value:Ei.shellLayer2Mode},shellLayer2Strength:{value:Ei.shellLayer2Strength},shellLayer2Enabled:{value:Ei.shellLayer2Enabled},soulLayer1Mode:{value:Ei.soulLayer1Mode},soulLayer1Strength:{value:Ei.soulLayer1Strength},soulLayer1Enabled:{value:Ei.soulLayer1Enabled},soulLayer2Mode:{value:Ei.soulLayer2Mode},soulLayer2Strength:{value:Ei.soulLayer2Strength},soulLayer2Enabled:{value:Ei.soulLayer2Enabled},rimLayer1Mode:{value:Ei.rimLayer1Mode},rimLayer1Strength:{value:Ei.rimLayer1Strength},rimLayer1Enabled:{value:Ei.rimLayer1Enabled},rimLayer2Mode:{value:Ei.rimLayer2Mode},rimLayer2Strength:{value:Ei.rimLayer2Strength},rimLayer2Enabled:{value:Ei.rimLayer2Enabled},sssLayer1Mode:{value:Ei.sssLayer1Mode},sssLayer1Strength:{value:Ei.sssLayer1Strength},sssLayer1Enabled:{value:Ei.sssLayer1Enabled},sssLayer2Mode:{value:Ei.sssLayer2Mode},sssLayer2Strength:{value:Ei.sssLayer2Strength},sssLayer2Enabled:{value:Ei.sssLayer2Enabled}},vertexShader:o,fragmentShader:r,transparent:!0,side:e.DoubleSide,depthWrite:!1,blending:e.NormalBlending}),type:"crystal"}}function Ri(e){e&&(e.map&&e.map.dispose(),e.normalMap&&e.normalMap.dispose(),e.emissiveMap&&e.emissiveMap.dispose(),e.roughnessMap&&e.roughnessMap.dispose(),e.metalnessMap&&e.metalnessMap.dispose())}const zi=new Map;async function _i(e,t={}){if(zi.has(e)){const t=zi.get(e);if(t.loaded)return t}const i=ie[e];if(!i)return console.warn(`[GeometryCache] Unknown geometry type: ${e}`),null;const n={geometry:null,material:null,materialType:null,config:i,loaded:!1};if(i.geometryLoader?n.geometry=await i.geometryLoader(t.assetBasePath):n.geometry=i.geometry,"custom"===i.material||"emissive"===i.material){const a=Ii(e,i,{glowColor:t.glowColor||[1,1,.95],glowIntensity:t.glowIntensity||1,materialVariant:t.materialVariant,emotionData:t.emotionData,assetBasePath:t.assetBasePath});a&&(n.material=a.material,n.materialType=a.type)}return n.loaded=!0,zi.set(e,n),n}async function Oi(e={}){await Promise.all(["crystal","rough","heart","moon","sun"].map(t=>_i(t,e)))}function Fi(){for(const[e,t]of zi.entries())t.material&&(Ri(t.material),t.material.dispose());zi.clear()}var Li={preload:_i,preloadAll:Oi,get:function(e){const t=zi.get(e);return t&&t.loaded?t:null},has:function(e){const t=zi.get(e);return t&&t.loaded},updateMaterialOptions:function(e,t){const i=zi.get(e);if(!i||!i.material)return;const{uniforms:n}=i.material;n&&(t.glowColor&&n.glowColor&&n.glowColor.value.set(...t.glowColor),void 0!==t.glowIntensity&&n.glowIntensity&&(n.glowIntensity.value=t.glowIntensity))},dispose:Fi,getStatus:function(){const e={};for(const[t,i]of zi.entries())e[t]={loaded:i.loaded,hasGeometry:!!i.geometry,hasMaterial:!!i.material,materialType:i.materialType};return e}};class Gi{constructor(t,i={}){this._instanceId=Math.random().toString(36).substr(2,6),this.canvas=t,this.options=i,this._destroyed=!1,this._ready=!1,this._readyPromise=null,this.assetBasePath=i.assetBasePath||"/assets",this.geometryType=i.geometry||"sphere";const n="moon"===this.geometryType;this.renderer=new M(t,{enablePostProcessing:!1!==i.enablePostProcessing,enableShadows:i.enableShadows||!1,enableControls:!1!==i.enableControls,autoRotate:!n&&!1!==i.autoRotate,autoRotateSpeed:i.autoRotateSpeed,cameraDistance:i.cameraDistance,fov:i.fov,minZoom:i.minZoom,maxZoom:i.maxZoom,assetBasePath:this.assetBasePath});const a=ie[this.geometryType];a?this.geometryConfig=a:(console.warn(`Unknown geometry: ${this.geometryType}, falling back to sphere`),this.geometryConfig=ie.sphere),this.geometry=this.geometryConfig.geometry,this.geometry&&!this.geometry.isGroup&&(this.geometry.userData.geometryType=this.geometryType),this.materialVariant=i.materialVariant||null,this.onMaterialSwap=null;let s=null;const o=me(this.emotion),r=Ii(this.geometryType,this.geometryConfig,{glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:o,assetBasePath:this.assetBasePath});if(r&&(s=r.material,this.customMaterial=s,this.customMaterialType=r.type),this.geometryConfig.geometryLoader?this._readyPromise=this._loadAsyncGeometry():(this._ready=!0,this._readyPromise=Promise.resolve()),null===this.geometry&&this.geometryConfig.geometryLoader?this._deferredMeshCreation=!0:(this.coreMesh=this.renderer.createCoreMesh(this.geometry,s),"crystal"===this.customMaterialType&&this.createCrystalInnerCore()),this.calibrationRotation=[0,0,0],this.cameraRoll=0,"moon"===this.geometryType){const e=Math.PI/180;this.calibrationRotation=[B*e,k*e,T*e],this.cameraRoll=0}if("crystal"===this.geometryType||"rough"===this.geometryType||"heart"===this.geometryType||"star"===this.geometryType){const e=Math.PI/180;this.calibrationRotation=[0*e,30*e,0*e]}if(this.animator=new ne,this.breathingAnimator=new ae,this.breathingEnabled=!1!==i.enableBreathing,this._breathPhase=null,this._breathPhaseStartTime=0,this._breathPhaseDuration=0,this._breathPhaseStartScale=1,this._breathPhaseTargetScale=1,this._breathPhaseScale=1,this.gestureBlender=new se,this.geometryMorpher=new Me,this.blinkAnimator=new ye(this.geometryConfig),this.blinkAnimator.setEmotion(this.emotion),this.blinkingManuallyDisabled=!1,!1===i.enableBlinking&&(this.blinkAnimator.pause(),this.blinkingManuallyDisabled=!0),this.rotationBehavior=null,this.rotationDisabled=!1===i.autoRotate,this.wobbleEnabled=!0,this.rightingBehavior=new xe({strength:5,damping:.85,centerOfMass:[0,-.3,0],axes:{pitch:!0,roll:!0,yaw:!1}}),this.facingBehavior=null,n&&E.enabled){const e=Math.PI/180;this.facingBehavior=new Ce({strength:E.strength,lockedFace:E.lockedFace,lerpSpeed:E.lerpSpeed,calibrationRotation:[B*e,k*e,T*e]},this.renderer.camera)}this.emotion=i.emotion||"neutral",this.undertone=i.undertone||null,this.glowColor=[1,1,1],this.glowColorHex="#FFFFFF",this.glowIntensity=1,this.coreGlowEnabled=!0,this.glowIntensityOverride=null,this.intensityCalibrationOffset=0,this.baseEuler=[0,0,0],this.baseQuaternion=new e.Quaternion,this.gestureQuaternion=new e.Quaternion,this.tempEuler=new e.Euler,this.rotation=[0,0,0],this.baseScale=.16,this.scale=.16,this.position=[0,0,0],this.rhythmEngine=i.rhythmEngine||null,this.rhythm3DAdapter=we,this.rhythmEnabled=!1!==i.enableRhythm,this.rhythmEnabled&&this.rhythm3DAdapter.initialize(),this.particlesEnabled=!1!==i.enableParticles,this.particleVisibility=this.particlesEnabled;const l=new hi(50);l.canvasWidth=t.width,l.canvasHeight=t.height;const h=new ci({worldScale:2,baseRadius:1.5,depthScale:.75,verticalScale:1,coreRadius3D:2}),c=new gi(150,{renderer:this.renderer.renderer}),u=c.getPoints();if(u.layers.set(1),this.renderer.scene.add(u),this.particleOrchestrator=new bi(l,h,c),this.particleOrchestrator.setGeometryType(this.geometryType),this.particlesEnabled||c.geometry.setDrawRange(0,0),"sun"===this.geometryType){const e=this.geometry.parameters?.radius||.5;this.solarEclipse=new Pi(this.renderer.scene,e,this.coreMesh)}"moon"===this.geometryType&&this.customMaterial&&(this.lunarEclipse=new Bi(this.customMaterial)),this.virtualParticlePool=this.createVirtualParticlePool(5),this.nextPoolIndex=0,this.geometryConfig.defaultGlassMode&&!this.customMaterial&&this.setGlassMaterialEnabled(!0),this.setEmotion(this.emotion)}createVirtualParticlePool(e){const t=[];for(let i=0;i<e;i++)t.push({x:0,y:0,vx:0,vy:0,size:1,baseSize:1,opacity:1,scaleFactor:1,gestureData:null});return t}getVirtualParticleFromPool(){const e=this.virtualParticlePool[this.nextPoolIndex];return this.nextPoolIndex=(this.nextPoolIndex+1)%this.virtualParticlePool.length,e.x=0,e.y=0,e.vx=0,e.vy=0,e.size=1,e.baseSize=1,e.opacity=1,e.scaleFactor=1,e.gestureData=null,e}setEmotion(t,i=null){this.emotion=t,this.undertone=i;const n=me(t);if(n&&n.visual){if(n.visual.glowColor){let e=(a=(a=n.visual.glowColor).replace("#",""),[parseInt(a.substring(0,2),16)/255,parseInt(a.substring(2,4),16)/255,parseInt(a.substring(4,6),16)/255]);e=function(e,t){if(!t||"clear"===t||"none"===t)return e;const i={intense:{saturation:2.5,lightness:1.3},confident:{saturation:1.8,lightness:1.15},nervous:{saturation:1.6,lightness:1.1},tired:{saturation:.4,lightness:.65},subdued:{saturation:.25,lightness:.55}}[t];if(!i)return e;const n=function(e,t,i){const n=Math.max(e,t,i),a=Math.min(e,t,i),s=n-a,o=n+a;let r=0,l=0;const h=o/2;if(0!==s)switch(l=h>.5?s/(2-o):s/o,n){case e:r=((t-i)/s+(t<i?6:0))/6;break;case t:r=((i-e)/s+2)/6;break;case i:r=((e-t)/s+4)/6}return[360*r,100*l,100*h]}(e[0],e[1],e[2]);return n[1]=Math.min(100,n[1]*i.saturation),n[2]=Math.min(100,Math.max(0,n[2]*i.lightness)),function(e,t,i){let n,a,s;if(e/=360,i/=100,0==(t/=100))n=a=s=i;else{const o=(e,t,i)=>(i<0&&(i+=1),i>1&&(i-=1),i<1/6?e+6*(t-e)*i:i<.5?t:i<2/3?e+(t-e)*(2/3-i)*6:e),r=i<.5?i*(1+t):i+t-i*t,l=2*i-r;n=o(l,r,e+1/3),a=o(l,r,e),s=o(l,r,e-1/3)}return[n,a,s]}(n[0],n[1],n[2])}(e,i),this.glowColor=e,this.glowColorHex=n.visual.glowColor;const t=this.renderer.materialMode||"glass";this.glowIntensity=b(n.visual.glowColor,this.intensityCalibrationOffset,t)}if(this.renderer.updateLighting(t,n),this.customMaterial&&"moon"===this.customMaterialType){const t=new e.Color(this.glowColor[0],this.glowColor[1],this.glowColor[2]);N(this.customMaterial,t,this.glowIntensity)}else this.customMaterial&&"sun"===this.customMaterialType&&$(this.coreMesh,this.glowColor,this.glowIntensity,0)}var a;const s="sun"===this.geometryType?W:null;this.rotationDisabled||"moon"===this.geometryType?this.rotationBehavior=null:n&&n["3d"]&&n["3d"].rotation?this.rotationBehavior?this.rotationBehavior.updateConfig(n["3d"].rotation):(this.rotationBehavior=new Se(n["3d"].rotation,this.rhythmEngine,s),this.rotationBehavior.setWobbleEnabled(this.wobbleEnabled)):this.rotationBehavior||this.rotationDisabled||(this.rotationBehavior=new Se({type:"gentle",speed:1,axes:[0,.01,0]},this.rhythmEngine,s),this.rotationBehavior.setWobbleEnabled(this.wobbleEnabled)),this.rightingBehavior&&this.rightingBehavior.reset(),this.baseEuler[0]=0,this.baseEuler[2]=0;const o=vt(i);if(o&&o["3d"]){const e=o["3d"];e.rotation&&this.rotationBehavior&&this.rotationBehavior.applyUndertoneMultipliers(e.rotation),e.righting&&this.rightingBehavior&&this.rightingBehavior.applyUndertoneMultipliers(e.righting)}this.animator.stopAll();const r=n?.visual?.glowColor||"#00BCD4",l=this.renderer.materialMode||"glass";if(this.baseGlowIntensity=b(r,this.intensityCalibrationOffset,l),o&&o["3d"]&&o["3d"].glow&&(this.baseGlowIntensity,this.baseGlowIntensity*=o["3d"].glow.intensityMultiplier),this.breathingAnimator.setEmotion(t,o),this.blinkAnimator.setEmotion(t),this.renderer.updateBloom(this.baseGlowIntensity,1,this.geometryType),this.animator.playEmotion(t),this.particlesEnabled&&this.particleOrchestrator&&this.particleOrchestrator.setEmotion(t,i),n&&n.soulAnimation){const e=n.soulAnimation;this.setCrystalSoulEffects({driftEnabled:!0,driftSpeed:e.driftSpeed||.5,shimmerEnabled:!0,shimmerSpeed:e.shimmerSpeed||.5})}}setCoreGlowEnabled(e){this.coreGlowEnabled=e,this.crystalSoul&&this.crystalSoul.setVisible(e)}setGlassMaterialEnabled(e){const t=e?"glass":"glow";this.renderer.setMaterialMode(t)}setGlowIntensity(e){this.glowIntensityOverride=e,null!==e&&(this.glowIntensity=e,this.baseGlowIntensity=e)}sliderToIntensity(e){const t=e/100;return.3*Math.pow(10/.3,t)}setIntensityCalibration(e){this.intensityCalibrationOffset=e,this.setEmotion(this.emotion,this.undertone)}getGlowIntensity(){return this.glowIntensity}playGesture(e){const t=ft(e);if(!t)return void console.warn(`Unknown gesture: ${e}`);const i=this.getVirtualParticleFromPool(),n=t.config||{},a=n.musicalDuration?.musical?500*(n.musicalDuration.beats||2):n.duration||800,s=this.animator.time;if(this.position,this.rotation,this.scale,this.animator.animations.length>=10){const e=this.animator.animations.shift();console.warn(`⚠️ Animation limit reached (10), removed oldest: ${e.gestureName||"unknown"}`)}const o={initialized:!1};this.animator.animations.push({gestureName:e,duration:a,startTime:s,config:n,evaluate:e=>{i.x=0,i.y=0,i.vx=0,i.vy=0,i.size=1,i.opacity=1,t.apply&&t.apply(i,o,n,e,1,0,0);const a={...n,particle:i,config:n,strength:n.strength||1};return t["3d"]&&t["3d"].evaluate?t["3d"].evaluate.call(t,e,a):{position:[0,0,0],rotation:[0,0,0],scale:1}},callbacks:{onUpdate:(e,t)=>{e.position&&(this.position=e.position),e.rotation&&(this.tempEuler.set(e.rotation[0],e.rotation[1],e.rotation[2],"XYZ"),this.gestureQuaternion.setFromEuler(this.tempEuler)),void 0!==e.scale&&(this.scale=this.baseScale*e.scale),void 0!==e.glowIntensity&&(this.glowIntensity=this.baseGlowIntensity*e.glowIntensity)},onComplete:()=>{t.cleanup&&t.cleanup(i),this.position=[0,0,0],this.scale=this.baseScale}}})}setSunShadow(e="off"){"sun"===this.geometryType&&this.solarEclipse?this.solarEclipse.setEclipseType(e):console.warn("⚠️ Eclipse only available for sun geometry")}startSolarEclipse(e={}){const t=e.type||"total";"sun"===this.geometryType&&this.solarEclipse?this.solarEclipse.setEclipseType(t):(this.morphToShape("sun"),setTimeout(()=>{this.solarEclipse&&this.solarEclipse.setEclipseType(t)},600))}startLunarEclipse(e={}){const t=e.type||"total";"moon"===this.geometryType&&this.lunarEclipse?this.lunarEclipse.setEclipseType(t):(this.morphToShape("moon"),setTimeout(()=>{this.lunarEclipse&&this.lunarEclipse.setEclipseType(t)},600))}stopEclipse(){this.solarEclipse&&this.solarEclipse.setEclipseType("off"),this.lunarEclipse&&this.lunarEclipse.setEclipseType("off")}setMoonEclipse(e="off"){"moon"===this.geometryType&&this.lunarEclipse?this.lunarEclipse.setEclipseType(e):console.warn("⚠️ Lunar eclipse only available for moon geometry")}setBloodMoonBlend(e={}){"moon"===this.geometryType&&this.customMaterial?(void 0!==e.blendMode&&(this.customMaterial.uniforms.blendMode.value=e.blendMode),void 0!==e.blendStrength&&(this.customMaterial.uniforms.blendStrength.value=e.blendStrength),void 0!==e.emissiveStrength&&(this.customMaterial.uniforms.emissiveStrength.value=e.emissiveStrength),void 0!==e.eclipseIntensity&&(this.customMaterial.uniforms.eclipseIntensity.value=e.eclipseIntensity)):console.warn("⚠️ Blood moon blend only available for moon geometry")}setBlendLayer(e,t={}){if("moon"!==this.geometryType&&"sun"!==this.geometryType||!this.customMaterial)return void console.warn("⚠️ Blend layers only available for moon and sun geometry");const i=`layer${e}`;void 0!==t.mode&&this.customMaterial.uniforms[`${i}Mode`]&&(this.customMaterial.uniforms[`${i}Mode`].value=t.mode),void 0!==t.strength&&this.customMaterial.uniforms[`${i}Strength`]&&(this.customMaterial.uniforms[`${i}Strength`].value=t.strength),void 0!==t.enabled&&this.customMaterial.uniforms[`${i}Enabled`]&&(this.customMaterial.uniforms[`${i}Enabled`].value=t.enabled?1:0)}setAllBlendLayers(e){"moon"!==this.geometryType&&"sun"!==this.geometryType||!this.customMaterial?console.warn("⚠️ Blend layers only available for moon and sun geometry"):e.forEach((e,t)=>{this.setBlendLayer(t+1,e)})}setCrystalBlendLayer(e,t,i={}){if("crystal"!==this.geometryType&&"rough"!==this.geometryType||!this.customMaterial||"crystal"!==this.customMaterialType)return;const n=`${e}Blend${t}`;void 0!==i.mode&&this.customMaterial.uniforms[`${n}Mode`]&&(this.customMaterial.uniforms[`${n}Mode`].value=i.mode),void 0!==i.strength&&this.customMaterial.uniforms[`${n}Strength`]&&(this.customMaterial.uniforms[`${n}Strength`].value=i.strength),void 0!==i.enabled&&this.customMaterial.uniforms[`${n}Enabled`]&&(this.customMaterial.uniforms[`${n}Enabled`].value=i.enabled?1:0)}setCrystalUniforms(e={}){if("crystal"!==this.geometryType&&"rough"!==this.geometryType||!this.customMaterial||"crystal"!==this.customMaterialType)return void console.warn("⚠️ Crystal uniforms only available with crystal blend-layers material");const{uniforms:t}=this.customMaterial,i=(e,t,i=0,n=10)=>{e&&"number"==typeof t&&!isNaN(t)&&isFinite(t)&&(e.value=Math.max(i,Math.min(n,t)))};i(t.coreGlowStrength,e.coreGlowStrength,0,2),void 0===e.coreGlowFalloff||isNaN(e.coreGlowFalloff)||(i(t.coreGlowFalloff,e.coreGlowFalloff,.1,3),this.setCrystalCoreSize(e.coreGlowFalloff)),i(t.fresnelStrength,e.fresnelStrength,0,2),i(t.fresnelPower,e.fresnelPower,.5,10),i(t.transmissionStrength,e.transmissionStrength,0,1),i(t.facetStrength,e.facetStrength,0,2),i(t.iridescenceStrength,e.iridescenceStrength,0,1),i(t.chromaticAberration,e.chromaticAberration,0,1),i(t.causticStrength,e.causticStrength,0,1),i(t.emissiveIntensity,e.emissiveIntensity,0,5),i(t.sparkleEnabled,e.sparkleEnabled,0,1),i(t.sparkleSpeed,e.sparkleSpeed,.1,5),i(t.causticEnabled,e.causticEnabled,0,1),i(t.causticSpeed,e.causticSpeed,.1,10),i(t.causticScale,e.causticScale,.5,10),i(t.causticCoverage,e.causticCoverage,0,1),i(t.energyPulseEnabled,e.energyPulseEnabled,0,1),i(t.energyPulseSpeed,e.energyPulseSpeed,.1,5)}createCrystalInnerCore(){if(this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null),!this.coreMesh)return;const e=this._targetGeometryType||this.geometryType;this.crystalSoul=new pi({radius:.35,detail:1,geometryType:e,renderer:this.renderer,assetBasePath:this.assetBasePath}),this.crystalSoul.attachTo(this.coreMesh,this.renderer?.scene);let t=1;"heart"===e?(this.crystalShellBaseScale=2.4,t=1):"rough"===e?(this.crystalShellBaseScale=1.6,t=1):"star"===e?(this.crystalShellBaseScale=2,t=1.4):"crystal"===e&&(this.crystalShellBaseScale=2,t=1),this.crystalSoul.baseScale=t,this.crystalSoul.mesh.scale.setScalar(t),this.crystalSoul.setVisible(this.coreGlowEnabled),this.crystalInnerCore=this.crystalSoul.mesh,this.crystalInnerCoreMaterial=this.crystalSoul.material,this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale}updateCrystalInnerCore(e,t=0){if(!this.crystalSoul)return;const i=this.breathingAnimator&&this.breathingEnabled?this.breathingAnimator.getBreathingScale():1;this.crystalSoul.update(t,e,i),this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale}setCrystalSoulEffects(e={}){this.crystalSoul&&this.crystalSoul.setEffects(e)}setCrystalCoreSize(e){this.crystalSoul&&(this.crystalSoul.setSize(e),this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale)}setCrystalShellSize(e){!this.coreMesh||"crystal"!==this.geometryType&&"rough"!==this.geometryType&&"heart"!==this.geometryType||(this.crystalShellBaseScale=e)}setWobbleEnabled(e){this.wobbleEnabled=e,this.rotationBehavior&&this.rotationBehavior.setWobbleEnabled(e),e||(this.rightingBehavior&&this.rightingBehavior.reset(),this.baseEuler[0]=0,this.baseEuler[2]=0)}setMaterialVariant(e){this.materialVariant=e}setRhythmEnabled(e){this.rhythmEnabled=e,e&&this.rhythm3DAdapter&&!this.rhythm3DAdapter.enabled&&this.rhythm3DAdapter.initialize()}setGrooveEnabled(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setGrooveEnabled(e)}setBeatSyncStrength(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setBeatSyncStrength(e)}setGrooveConfig(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setGrooveConfig(e)}isRhythmPlaying(){return this.rhythm3DAdapter?.isPlaying()||!1}getRhythmBPM(){return this.rhythm3DAdapter?.getBPM()||120}startRhythm(e=120,t="straight"){this.rhythm3DAdapter&&this.rhythm3DAdapter.start(e,t)}stopRhythm(){this.rhythm3DAdapter&&this.rhythm3DAdapter.stop()}setRhythmBPM(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setBPM(e)}setRhythmPattern(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setPattern(e)}breathePhase(e,t){const i=Math.max(.5,Math.min(30,t));switch(this._breathPhaseStartScale=this._breathPhaseScale,this._breathPhaseStartTime=performance.now(),this._breathPhaseDuration=1e3*i,this._breathPhase=e,e){case"inhale":this._breathPhaseTargetScale=1.3;break;case"exhale":this._breathPhaseTargetScale=.85;break;default:this._breathPhaseTargetScale=this._breathPhaseStartScale}console.log(`[Core3D] breathePhase: ${e} for ${i}s (${this._breathPhaseStartScale.toFixed(2)} → ${this._breathPhaseTargetScale.toFixed(2)})`)}stopBreathingPhase(){this._breathPhase=null,this._breathPhaseScale=1,this._breathPhaseStartScale=1,this._breathPhaseTargetScale=1,console.log("[Core3D] breathePhase stopped, scale reset to 1.0")}_updateBreathingPhase(e){if(!this._breathPhase)return this._breathPhaseScale;const t=performance.now()-this._breathPhaseStartTime,i=this._breathPhaseDuration,n=Math.min(1,t/i),a=Math.sin(n*Math.PI/2);return this._breathPhaseScale=this._breathPhaseStartScale+(this._breathPhaseTargetScale-this._breathPhaseStartScale)*a,n>=1&&(this._breathPhaseScale=this._breathPhaseTargetScale,this._breathPhase=null),this._breathPhaseScale}morphToShape(e,t=800){const i=ie[e];i?this.geometryMorpher.startMorph(this.geometryType,e,t)&&(this.geometryMorpher.getInterruptedTarget(),this.blinkAnimator.pause(),this._targetGeometryConfig=i,this._targetGeometryType=e,i.geometryLoader&&!i.geometry?(this._targetGeometry=null,this._pendingGeometryLoad=i.geometryLoader(this.assetBasePath).then(e=>{this._targetGeometry=e,i.geometry=e,this._pendingGeometryLoad=null})):(this._targetGeometry=i.geometry,this._pendingGeometryLoad=null)):console.warn(`Unknown shape: ${e}`)}isMorphing(){return this.geometryMorpher.isTransitioning}getMorphState(){return this.geometryMorpher.getState()}growIn(e=500){this.geometryMorpher.growIn(this.geometryType,e)}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}render(e){if(this._destroyed)return;if(!this._ready)return;this.animator.update(e);const t=this.geometryMorpher.update(e);if(t.shouldSwapGeometry&&this._pendingGeometryLoad&&this.geometryMorpher.pauseAtSwap(),t.waitingForGeometry&&this._targetGeometry&&!this._pendingGeometryLoad&&(this.geometryMorpher.resumeFromSwap(),this.geometryMorpher.hasSwappedGeometry=!1),t.shouldSwapGeometry&&this._targetGeometry){const e=this.geometryType;this.customMaterial&&function(e,t){switch(e){case"moon":!function(e){if(!e||!e.uniforms)return;const t=e.uniforms;t.shadowOffset&&t.shadowOffset.value.set(I.full.x,I.full.y),t.shadowCoverage&&(t.shadowCoverage.value=.5),t.shadowSoftness&&(t.shadowSoftness.value=.05),t.eclipseProgress&&(t.eclipseProgress.value=0),t.eclipseIntensity&&(t.eclipseIntensity.value=0),t.bloodMoonColor&&(t.bloodMoonColor.value=[.85,.18,.08]),t.emissiveStrength&&(t.emissiveStrength.value=.39),t.eclipseShadowPos&&(t.eclipseShadowPos.value=[-2,0]),t.eclipseShadowRadius&&(t.eclipseShadowRadius.value=1.2),t.shadowDarkness&&(t.shadowDarkness.value=.53),t.eclipseShadowColor&&(t.eclipseShadowColor.value=[1,.58,0]),t.eclipseMidtoneColor&&(t.eclipseMidtoneColor.value=[.71,.43,.03]),t.eclipseHighlightColor&&(t.eclipseHighlightColor.value=[1,.28,.1]),t.eclipseGlowColor&&(t.eclipseGlowColor.value=[.09,.09,.09]),t.eclipseBrightnessModel&&(t.eclipseBrightnessModel.value=0),t.layer1Mode&&(t.layer1Mode.value=9),t.layer1Strength&&(t.layer1Strength.value=.322),t.layer1Enabled&&(t.layer1Enabled.value=1),t.layer2Mode&&(t.layer2Mode.value=0),t.layer2Strength&&(t.layer2Strength.value=2.785),t.layer2Enabled&&(t.layer2Enabled.value=1),t.layer3Mode&&(t.layer3Mode.value=7),t.layer3Strength&&(t.layer3Strength.value=.199),t.layer3Enabled&&(t.layer3Enabled.value=1),t.layer4Mode&&(t.layer4Mode.value=0),t.layer4Strength&&(t.layer4Strength.value=0),t.layer4Enabled&&(t.layer4Enabled.value=0),t.opacity&&(t.opacity.value=1)}(t);break;case"sun":!function(e){if(!e||!e.uniforms)return;const t=e.uniforms;t.eclipseProgress&&(t.eclipseProgress.value=0),t.eclipseShadowPos&&(t.eclipseShadowPos.value=[-2,0]),t.eclipseShadowRadius&&(t.eclipseShadowRadius.value=.882),t.shadowDarkness&&(t.shadowDarkness.value=1),t.shadowOffset&&t.shadowOffset.value.set(200,0),t.shadowCoverage&&(t.shadowCoverage.value=.5),t.shadowSoftness&&(t.shadowSoftness.value=.1),t.layer1Mode&&(t.layer1Mode.value=0),t.layer1Strength&&(t.layer1Strength.value=.23),t.layer1Enabled&&(t.layer1Enabled.value=1),t.layer2Mode&&(t.layer2Mode.value=0),t.layer2Strength&&(t.layer2Strength.value=0),t.layer2Enabled&&(t.layer2Enabled.value=0),t.layer3Mode&&(t.layer3Mode.value=0),t.layer3Strength&&(t.layer3Strength.value=0),t.layer3Enabled&&(t.layer3Enabled.value=0),t.layer4Mode&&(t.layer4Mode.value=0),t.layer4Strength&&(t.layer4Strength.value=0),t.layer4Enabled&&(t.layer4Enabled.value=0),t.emissiveIntensity&&(t.emissiveIntensity.value=4),t.opacity&&(t.opacity.value=1),t.time&&(t.time.value=0)}(t);break;case"crystal":case"diamond":!function(e){if(!e||!e.uniforms)return;const t=e.uniforms,i=Ei;t.frostiness&&(t.frostiness.value=i.frostiness),t.fresnelPower&&(t.fresnelPower.value=i.fresnelPower),t.fresnelIntensity&&(t.fresnelIntensity.value=i.fresnelIntensity),t.innerGlowStrength&&(t.innerGlowStrength.value=i.innerGlowStrength),t.surfaceRoughness&&(t.surfaceRoughness.value=i.surfaceRoughness),t.surfaceNoiseScale&&(t.surfaceNoiseScale.value=i.surfaceNoiseScale),t.noiseFrequency&&(t.noiseFrequency.value=i.noiseFrequency),t.causticIntensity&&(t.causticIntensity.value=i.causticIntensity),t.causticScale&&(t.causticScale.value=i.causticScale),t.causticSpeed&&(t.causticSpeed.value=i.causticSpeed),t.textureStrength&&(t.textureStrength.value=i.textureStrength),t.layer1Mode&&(t.layer1Mode.value=i.layer1Mode),t.layer1Strength&&(t.layer1Strength.value=i.layer1Strength),t.layer1Enabled&&(t.layer1Enabled.value=i.layer1Enabled),t.layer2Mode&&(t.layer2Mode.value=i.layer2Mode),t.layer2Strength&&(t.layer2Strength.value=i.layer2Strength),t.layer2Enabled&&(t.layer2Enabled.value=i.layer2Enabled),t.layer3Mode&&(t.layer3Mode.value=i.layer3Mode),t.layer3Strength&&(t.layer3Strength.value=i.layer3Strength),t.layer3Enabled&&(t.layer3Enabled.value=i.layer3Enabled),t.layer4Mode&&(t.layer4Mode.value=i.layer4Mode),t.layer4Strength&&(t.layer4Strength.value=i.layer4Strength),t.layer4Enabled&&(t.layer4Enabled.value=i.layer4Enabled),t.glowIntensity&&(t.glowIntensity.value=i.glowIntensity),t.opacity&&(t.opacity.value=i.opacity),t.time&&(t.time.value=i.time)}(t)}}(e,this.customMaterial),this.geometry=this._targetGeometry,this.geometryType=this._targetGeometryType,this.geometryConfig=this._targetGeometryConfig,this.customMaterial&&(Ri(this.customMaterial),this.renderer.disposeMaterial(this.customMaterial),this.customMaterial=null,this.customMaterialType=null);let t=null;const i=me(this.emotion),n=Ii(this._targetGeometryType,this._targetGeometryConfig,{glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:i,assetBasePath:this.assetBasePath});if(n&&(t=n.material,this.customMaterial=t,this.customMaterialType=n.type),t)this.renderer.swapGeometry(this.geometry,t);else{this.renderer.swapGeometry(this.geometry);const e=!0===this._targetGeometryConfig.defaultGlassMode;this.setGlassMaterialEnabled(e)}if(this.onMaterialSwap&&this.onMaterialSwap({geometryType:this._targetGeometryType,material:this.customMaterial,materialType:this.customMaterialType}),this.blinkAnimator.setGeometry(this._targetGeometryConfig),this.rightingBehavior&&this.rightingBehavior.reset(),this.rotation=[0,0,0],"sun"===this._targetGeometryType){if(!this.solarEclipse){const e=this.geometry.parameters?.radius||.5;this.solarEclipse=new Pi(this.renderer.scene,e,this.renderer.coreMesh)}}else this.solarEclipse&&(this.solarEclipse.dispose(),this.solarEclipse=null);if("moon"===this._targetGeometryType?!this.lunarEclipse&&this.customMaterial&&(this.lunarEclipse=new Bi(this.customMaterial)):this.lunarEclipse&&(this.lunarEclipse.dispose(),this.lunarEclipse=null),"crystal"===this._targetGeometryType||"rough"===this._targetGeometryType||"heart"===this._targetGeometryType||"star"===this._targetGeometryType?"crystal"===this.customMaterialType&&this.createCrystalInnerCore():this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null,this.crystalInnerCore=null,this.crystalInnerCoreMaterial=null),"moon"===this._targetGeometryType){this.rotationBehavior=null,this.renderer?.controls&&(this.renderer.controls.autoRotate=!1),this.renderer?.setCameraPreset&&this.renderer.setCameraPreset("front",0,!0);const e=Math.PI/180;this.calibrationRotation[0]=B*e,this.calibrationRotation[1]=k*e,this.calibrationRotation[2]=T*e,!this.facingBehavior&&E.enabled&&(this.facingBehavior=new Ce({strength:E.strength,lockedFace:E.lockedFace,lerpSpeed:E.lerpSpeed,calibrationRotation:[B*e,k*e,T*e]},this.renderer.camera))}else{if(this.facingBehavior&&(this.facingBehavior.dispose(),this.facingBehavior=null),this.renderer?.controls&&!1!==this.options.autoRotate&&(this.renderer.controls.autoRotate=!0),"crystal"===this._targetGeometryType||"rough"===this._targetGeometryType||"heart"===this._targetGeometryType){const e=Math.PI/180;this.calibrationRotation[0]=0*e,this.calibrationRotation[1]=30*e,this.calibrationRotation[2]=0*e}else this.calibrationRotation[0]=0,this.calibrationRotation[1]=0,this.calibrationRotation[2]=0;if(this.rotationDisabled)this.rotationBehavior=null;else{const e=me(this.emotion);e&&e["3d"]&&e["3d"].rotation&&(this.rotationBehavior?this.rotationBehavior.updateConfig(e["3d"].rotation):(this.rotationBehavior=new Se(e["3d"].rotation,this.rhythmEngine),this.rotationBehavior.setWobbleEnabled(this.wobbleEnabled)))}}}t.completed&&(this._targetGeometry=null,this._targetGeometryType=null,this._targetGeometryConfig=null,this.blinkingManuallyDisabled||this.blinkAnimator.resume()),this.breathingAnimator.update(e,this.emotion,vt(this.undertone));const i=this._updateBreathingPhase(e),n=1!==i?i:this.breathingEnabled?this.breathingAnimator.getBreathingScale():1,a=t.scaleMultiplier,s=this.blinkAnimator.update(e);this.rotationBehavior?this.rotationBehavior.update(e,this.baseEuler):"moon"===this.geometryType||this.rotationDisabled||(this.baseEuler[1]+=3e-4*e),this.rightingBehavior&&this.rightingBehavior.update(e,this.baseEuler),this.facingBehavior&&(this.baseEuler[0]=0,this.baseEuler[1]=0,this.baseEuler[2]=0);this.baseEuler[0]=Math.max(-.35,Math.min(.35,this.baseEuler[0])),this.baseEuler[2]=Math.max(-.35,Math.min(.35,this.baseEuler[2])),this.tempEuler.set(this.baseEuler[0],this.baseEuler[1],this.baseEuler[2],"XYZ"),this.baseQuaternion.setFromEuler(this.tempEuler),this.rhythm3DAdapter&&this.rhythm3DAdapter.update(e);const o=this.gestureBlender.blend(this.animator.animations,this.animator.time,this.baseQuaternion,this.baseScale,this.baseGlowIntensity),r=this.rhythm3DAdapter?.isPlaying()?this.rhythm3DAdapter.getModulation():null,l=this.animator.animations.length>0;this.position=r&&!l?[o.position[0]+r.grooveOffset[0],o.position[1]+r.grooveOffset[1],o.position[2]+r.grooveOffset[2]]:r&&l?[o.position[0]*r.positionMultiplier,o.position[1]*r.positionMultiplier,o.position[2]*r.positionMultiplier]:o.position,this.rotation=r&&!l?[o.rotation[0]+r.grooveRotation[0],o.rotation[1]+r.grooveRotation[1],o.rotation[2]+r.grooveRotation[2]]:o.rotation,this.scale=r&&!l?o.scale*r.grooveScale:r&&l?o.scale*r.scaleMultiplier:o.scale,null===this.glowIntensityOverride&&(this.glowIntensity=r&&l?o.glowIntensity*r.glowMultiplier:o.glowIntensity),this.gestureQuaternion=o.gestureQuaternion,this.glowBoost=o.glowBoost||0,s.isBlinking&&s.rotation&&(this.rotation[0]+=s.rotation[0],this.rotation[1]+=s.rotation[1],this.rotation[2]+=s.rotation[2]);const h="crystal"!==this.geometryType&&"rough"!==this.geometryType,c=s.isBlinking&&h?s.scale[1]:1,u=this.crystalShellBaseScale||2,d=this.scale*a*n*c*u;if(this.particleVisibility&&this.particleOrchestrator){const t=this.geometryConfig?.particleRadiusMultiplier||1,i=(this.crystalShellBaseScale||2)*this.scale*n*t;this.particleOrchestrator.update(e,this.emotion,this.undertone,this.animator.animations,this.animator.time,{x:this.position[0],y:this.position[1],z:this.position[2]},{width:this.canvas.width,height:this.canvas.height},{euler:this.baseEuler,quaternion:this.baseQuaternion,angularVelocity:this.rotationBehavior?this.rotationBehavior.axes:[0,0,0]},this.baseScale,i)}const m=s.isBlinking&&s.glowBoost?1+s.glowBoost:1,p=this.coreGlowEnabled?this.glowIntensity*m:0,g=this.emotiveEngine?.getVirtualParticle(),f=p*(g?.opacity??1),y=t.isTransitioning?.3:.1;if(this.renderer.updateBloom(f,y,this.geometryType),this.glowBoost>0||this.renderer.glowLayer&&this.renderer.glowLayer.isActive()){const t=this.coreMesh?.position;this.renderer.updateGlowLayer(this.glowBoost,this.glowColor,t,e)}if("sun"===this.customMaterialType&&$(this.coreMesh,this.glowColor,f,e),"moon"!==this.customMaterialType&&"moon-multiplexer"!==this.customMaterialType||!this.customMaterial||this.customMaterial.uniforms&&this.customMaterial.uniforms.glowIntensity&&(this.customMaterial.uniforms.glowIntensity.value=f),"crystal"===this.customMaterialType&&this.customMaterial){if(this.customMaterial.uniforms){this.customMaterial.uniforms.time.value+=e/1e3,this.customMaterial.uniforms.glowIntensity&&(this.customMaterial.uniforms.glowIntensity.value=f);const t=v(this.glowColor,.3),i=[t.r,t.g,t.b];if(this.customMaterial.uniforms.emotionColor.value.setRGB(i[0],i[1],i[2]),this.customMaterial.uniforms.blinkIntensity){const e=s.isBlinking?Math.sin(s.progress*Math.PI):0;this.customMaterial.uniforms.blinkIntensity.value=e}}if(this.coreGlowEnabled){const t=v(this.glowColor,.3),i=[t.r,t.g,t.b];this.updateCrystalInnerCore(i,e)}}this.renderer.render({position:this.position,rotation:this.rotation,scale:d,glowColor:this.glowColor,glowColorHex:this.glowColorHex,glowIntensity:f,hasActiveGesture:this.animator.animations.length>0,calibrationRotation:this.calibrationRotation,solarEclipse:this.solarEclipse,deltaTime:e,morphProgress:t.isTransitioning?t.visualProgress:null}),this.lunarEclipse&&this.lunarEclipse.update(e)}async _loadAsyncGeometry(){try{const e=await _i(this.geometryType,{glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:me(this.emotion),assetBasePath:this.assetBasePath});if(this._destroyed)return;if(!e||!e.geometry)return console.warn(`[Core3D:${this._instanceId}] Async geometry load returned null!`),void(this._ready=!0);const t=e.geometry.clone();if(t.userData.geometryType=this.geometryType,this.geometry=t,this._deferredMeshCreation){if(this.coreMesh=this.renderer.createCoreMesh(t,this.customMaterial),this._destroyed)return;if("crystal"===this.customMaterialType&&(await this._createCrystalInnerCoreAsync(),this._destroyed))return;this._deferredMeshCreation=!1}else if(this.coreMesh){const e=this.coreMesh.geometry;if(this.coreMesh.geometry=t,e&&e!==t&&e.dispose(),this._destroyed)return;if("crystal"===this.customMaterialType&&(await this._createCrystalInnerCoreAsync(),this._destroyed))return}if(this._destroyed)return;this._logSceneHierarchy(),this._ready=!0}catch(e){console.warn(`[Core3D:${this._instanceId}] Async geometry load FAILED:`,e),this._destroyed||(this._ready=!0)}}_logSceneHierarchy(){const e=this.renderer?.scene;e&&e.children.forEach((e,t)=>{const i=null===e?"NULL!":void 0===e?"UNDEFINED!":null===e.visible?"visible=NULL!":void 0===e.visible?"visible=UNDEF!":"OK";console.log(` [${t}] ${e?.name||e?.type||"UNKNOWN"} status=${i} uuid=${e?.uuid?.slice(0,8)||"N/A"}`)})}async _createCrystalInnerCoreAsync(){if(this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null),!this.coreMesh)return;if(await pi._loadInclusionGeometry(this.assetBasePath),this._destroyed||!this.coreMesh)return;this.crystalSoul=new pi({radius:.35,detail:1,geometryType:this.geometryType,renderer:this.renderer,assetBasePath:this.assetBasePath}),this.crystalSoul.attachTo(this.coreMesh,this.renderer?.scene);let e=1;"heart"===this.geometryType?(this.crystalShellBaseScale=2.4,e=1):"rough"===this.geometryType?(this.crystalShellBaseScale=1.6,e=1):"crystal"===this.geometryType&&(e=1),this.crystalSoul.baseScale=e,this.crystalSoul.mesh.scale.setScalar(e),this.crystalSoul.setVisible(this.coreGlowEnabled),this.crystalInnerCore=this.crystalSoul.mesh,this.crystalInnerCoreMaterial=this.crystalSoul.material,this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale}isReady(){return this._ready}async waitUntilReady(){this._ready||this._readyPromise&&await this._readyPromise}destroy(){if(this._instanceId,this._ready,this._destroyed,this.crystalSoul,this.renderer,this._destroyed=!0,this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null,this.crystalInnerCore=null,this.crystalInnerCoreMaterial=null),this.particleOrchestrator){const e=this.particleOrchestrator.renderer;if(e){const t=e.getPoints();t&&this.renderer?.scene&&this.renderer.scene.remove(t)}this.particleOrchestrator.destroy(),this.particleOrchestrator=null}this.solarEclipse&&(this.solarEclipse.dispose(),this.solarEclipse=null),this.lunarEclipse&&(this.lunarEclipse.dispose(),this.lunarEclipse=null),this.customMaterial&&(this.renderer.disposeMaterial(this.customMaterial),this.customMaterial=null,this.customMaterialType=null),this.facingBehavior&&(this.facingBehavior.dispose(),this.facingBehavior=null),this.animator.stopAll(),this.renderer.destroy(),this.virtualParticlePool&&(this.virtualParticlePool.length=0,this.virtualParticlePool=null),this.animator.destroy?.(),this.breathingAnimator.destroy?.(),this.gestureBlender.destroy?.(),this.geometryMorpher.destroy?.(),this.blinkAnimator.destroy?.(),this.rotationBehavior&&(this.rotationBehavior.destroy?.(),this.rotationBehavior=null),this.rightingBehavior&&(this.rightingBehavior.destroy?.(),this.rightingBehavior=null),this.tempEuler=null,this.baseQuaternion=null,this.gestureQuaternion=null,this.geometry=null,this.geometryConfig=null,this._targetGeometry=null,this._targetGeometryConfig=null,this._targetGeometryType=null,this.canvas=null,this.options=null,this.coreMesh=null,this.rhythmEngine=null,this.rhythm3DAdapter=null,this.emotiveEngine=null,Fi()}async preloadGeometries(){const e={glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:me(this.emotion)};await Oi(e)}}class Vi{constructor(){this.listeners=new Map,this.groups=new Map,this.stats={registered:0,removed:0,active:0}}addEventListener(e,t,i,n={},a="default"){const s=this.generateId(),o={id:s,target:e,eventType:t,handler:i,options:n,group:a,active:!0};return this.listeners.set(s,o),this.groups.has(a)||this.groups.set(a,new Set),this.groups.get(a).add(s),e.addEventListener(t,i,n),this.stats.registered++,this.stats.active++,s}removeEventListener(e){const t=this.listeners.get(e);if(!t||!t.active)return!1;t.target.removeEventListener(t.eventType,t.handler,t.options),t.active=!1;const i=this.groups.get(t.group);return i&&(i.delete(e),0===i.size&&this.groups.delete(t.group)),this.listeners.delete(e),this.stats.removed++,this.stats.active--,!0}removeGroup(e){const t=this.groups.get(e);if(!t)return 0;let i=0;for(const e of t)this.removeEventListener(e)&&i++;return i}removeAllForTarget(e){let t=0;for(const[i,n]of this.listeners.entries())n.target===e&&n.active&&this.removeEventListener(i)&&t++;return t}removeAllOfType(e){let t=0;for(const[i,n]of this.listeners.entries())n.eventType===e&&n.active&&this.removeEventListener(i)&&t++;return t}removeAll(){let e=0;for(const[t,i]of this.listeners.entries())i.active&&this.removeEventListener(t)&&e++;return e}createAutoRemove(e,t,i,n={}){const a=this.addEventListener(e,t,i,n);return{id:a,remove:()=>this.removeEventListener(a)}}once(e,t,i,n={}){const a=this.addEventListener(e,t,e=>{i(e),this.removeEventListener(a)},n);return a}debounced(e,t,i,n=250,a={}){let s;return this.addEventListener(e,t,e=>{clearTimeout(s),s=setTimeout(()=>i(e),n)},a)}throttled(e,t,i,n=100,a={}){let s=!1;return this.addEventListener(e,t,e=>{s||(i(e),s=!0,setTimeout(()=>{s=!1},n))},a)}generateId(){return`listener_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}getStats(){return{...this.stats,groups:this.groups.size,listeners:this.listeners.size}}getActiveListeners(){const e=[];for(const[t,i]of this.listeners.entries())i.active&&e.push({id:t,eventType:i.eventType,group:i.group,target:i.target.constructor.name});return e}analyzeLeaks(){const e={totalListeners:this.listeners.size,activeListeners:this.stats.active,inactiveButNotRemoved:0,byTarget:new Map,byType:new Map,potentialLeaks:[]};for(const[t,i]of this.listeners.entries()){const n=i.target.constructor.name;e.byTarget.set(n,(e.byTarget.get(n)||0)+1),e.byType.set(i.eventType,(e.byType.get(i.eventType)||0)+1),i.active||(e.inactiveButNotRemoved++,e.potentialLeaks.push({id:t,eventType:i.eventType,target:n}))}return e.byTarget=Object.fromEntries(e.byTarget),e.byType=Object.fromEntries(e.byType),e}cleanup(){let e=0;for(const[t,i]of this.listeners.entries())i.active||(this.listeners.delete(t),e++);return e}destroy(){const e=this.removeAll();return this.listeners.clear(),this.groups.clear(),this.stats={registered:0,removed:0,active:0},e}}class qi{constructor(){this.errors=[],this.maxErrors=10,this.errorCounts=new Map,this.defaults={emotion:"neutral",gesture:null,audioLevel:0,particleCount:0,glowIntensity:.7,coreSize:1,breathRate:1,color:"#B0B0B0"}}wrap(e,t,i=null){return(...n)=>{try{return e(...n)}catch(e){return this.logError(e,t),null!==i?i:this.getDefault(t)}}}logError(e,t){const i={timestamp:(new Date).toISOString(),context:t,message:e.message,stack:e.stack};this.errors.push(i);const n=this.errorCounts.get(t)||0;this.errorCounts.set(t,n+1),this.errors.length>this.maxErrors&&this.errors.shift()}getDefault(e){const t={"emotion-transition":this.defaults.emotion,"gesture-execution":this.defaults.gesture,"audio-processing":this.defaults.audioLevel,"particle-system":this.defaults.particleCount,rendering:{glowIntensity:this.defaults.glowIntensity,coreSize:this.defaults.coreSize,color:this.defaults.color},"canvas-operations":null,"state-management":this.defaults.emotion};return Object.prototype.hasOwnProperty.call(t,e)?t[e]:null}validateInput(e,t,i){try{switch(t){case"emotion":return["neutral","joy","sadness","anger","fear","surprise","disgust","love","euphoria"].includes(e)?e:i;case"undertone":return null===e||["nervous","confident","tired","intense","subdued"].includes(e)?e:null;case"gesture":return["bounce","pulse","shake","spin","nod","tilt","expand","contract","flash","drift"].includes(e)?e:i;case"number":return"number"!=typeof e||isNaN(e)?i:e;case"string":return"string"==typeof e?e:i;case"boolean":return"boolean"==typeof e?e:i;default:return null!=e?e:i}}catch(e){return this.logError(e,"input-validation"),i}}hasExceededThreshold(e,t=5){return(this.errorCounts.get(e)||0)>=t}getErrorStats(){return{totalErrors:this.errors.length,errorsByContext:Object.fromEntries(this.errorCounts),recentErrors:this.errors.slice(-5)}}clearErrors(){this.errors=[],this.errorCounts.clear()}async attemptRecovery(e,t,i=3){let n=0;for(;n<i;)try{return await t()}catch(t){if(n++,this.logError(t,`recovery-${e}-attempt-${n}`),n>=i)throw new Error(`Recovery failed for ${e} after ${i} attempts`);await new Promise(e=>setTimeout(e,100*Math.pow(2,n)))}}}const Ni={quartz:{sssStrength:.8,sssAbsorption:[2.8,2.9,3],sssScatterDistance:[.2,.2,.25],sssThicknessBias:.6,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.12,frostiness:.15,innerGlowStrength:.2,fresnelIntensity:1.5,causticIntensity:1.2,emotionColorBleed:0},emerald:{sssStrength:2,sssAbsorption:[.05,4,.1],sssScatterDistance:[.1,.5,.1],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.2,innerGlowStrength:.15,fresnelIntensity:1.2,causticIntensity:1,emotionColorBleed:.35},ruby:{sssStrength:1.8,sssAbsorption:[4,.03,.08],sssScatterDistance:[.4,.04,.08],sssThicknessBias:.65,sssThicknessScale:1.9,sssCurvatureScale:2.5,sssAmbient:.08,frostiness:.12,innerGlowStrength:.12,fresnelIntensity:1.2,causticIntensity:1.15,emotionColorBleed:.35},sapphire:{sssStrength:2.2,sssAbsorption:[.15,.4,4],sssScatterDistance:[.1,.15,.5],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.18,innerGlowStrength:.15,fresnelIntensity:1.3,causticIntensity:1,emotionColorBleed:.35},amethyst:{sssStrength:2.5,sssAbsorption:[3,.05,4.5],sssScatterDistance:[.4,.05,.5],sssThicknessBias:.7,sssThicknessScale:2,sssCurvatureScale:3,sssAmbient:.08,frostiness:.18,innerGlowStrength:.12,fresnelIntensity:1.4,causticIntensity:1,emotionColorBleed:.35},topaz:{sssStrength:1.5,sssAbsorption:[3.5,2,.1],sssScatterDistance:[.3,.2,.05],sssThicknessBias:.6,sssThicknessScale:1.7,sssCurvatureScale:2.8,sssAmbient:.12,frostiness:.14,innerGlowStrength:.18,fresnelIntensity:1.4,causticIntensity:1.1,emotionColorBleed:.25},citrine:{sssStrength:1.6,sssAbsorption:[3.8,2.5,.05],sssScatterDistance:[.35,.25,.05],sssThicknessBias:.58,sssThicknessScale:1.6,sssCurvatureScale:2.6,sssAmbient:.14,frostiness:.12,innerGlowStrength:.22,fresnelIntensity:1.3,causticIntensity:1.2,emotionColorBleed:.2},diamond:{sssStrength:.5,sssAbsorption:[2.5,2.5,2.5],sssScatterDistance:[.15,.15,.15],sssThicknessBias:.55,sssThicknessScale:1.5,sssCurvatureScale:4,sssAmbient:.15,frostiness:.08,innerGlowStrength:.25,fresnelIntensity:2,causticIntensity:1.5,emotionColorBleed:0}};function ji(e,t){if(!t||!e?.core3D?.customMaterial?.uniforms)return!1;const i=Ni[t];if(!i)return!1;const n=e.core3D.customMaterial.uniforms;return n.sssStrength&&(n.sssStrength.value=i.sssStrength),n.sssAbsorption&&n.sssAbsorption.value.set(...i.sssAbsorption),n.sssScatterDistance&&n.sssScatterDistance.value.set(...i.sssScatterDistance),n.sssThicknessBias&&(n.sssThicknessBias.value=i.sssThicknessBias),n.sssThicknessScale&&(n.sssThicknessScale.value=i.sssThicknessScale),n.sssCurvatureScale&&(n.sssCurvatureScale.value=i.sssCurvatureScale),n.sssAmbient&&(n.sssAmbient.value=i.sssAmbient),n.frostiness&&(n.frostiness.value=i.frostiness),n.innerGlowStrength&&(n.innerGlowStrength.value=i.innerGlowStrength),n.fresnelIntensity&&(n.fresnelIntensity.value=i.fresnelIntensity),void 0!==i.causticIntensity&&n.causticIntensity&&(n.causticIntensity.value=i.causticIntensity),n.emotionColorBleed&&(n.emotionColorBleed.value=i.emotionColorBleed??0),!0}function Ui(){return Object.keys(Ni)}function Hi(e){return Ni[e]||null}const Wi=["bouncing up and down","hopping around","rocking back and forth","side to side","light on feet","spring in step","leaning forward","leaning in","leaning closer","leaning toward","reaching out","reaching toward","pointing at","pointing to","waving hello","waving goodbye","nodding head","shaking head","head shake","head nod","head bob","head tilt","deep breath","taking a breath","breathing deeply","settling down","calming down","winding down","getting bigger","getting smaller","puffing up","spinning around","twirling around","at peace","in love","on cloud nine","over the moon","on top of the world","in awe","grossed out","freaked out","low key","low-key","high key","on edge","keyed up","wound up","low energy","no energy","running low","just a bit","just a little","a little bit","kind of","sort of","a bit","a little","a lot","over the top","off the charts","through the roof","split second","one time","few times","many times","again and again","over and over","on repeat","blood moon","full moon","new moon","half moon","solar eclipse","lunar eclipse","total eclipse","ring of fire","diamond ring","killing it","crushing it","nailed it","sussy baka","side eye"],Xi=/[,;|\/]+/,Yi=new Set(["a","an","the","is","are","am","be","being","been","i","me","my","it","its","to","of","for","with","as","this","that","these","those","just","only","also","too","please","pls","plz"]),$i=new Set(["but","and","or","yet","while","although","not","no","never","very","really","so","quite","rather","slightly","barely","extremely","completely","feeling","feel","feels","become","becoming","morph","morphing"]);function Qi(e){return e.toLowerCase().trim().replace(/['']/g,"'").replace(/[""]/g,'"').replace(/\s+/g," ")}function Zi(e){return["but","and","or","yet","while","although","with"].includes(e)}function Ji(e){return["not","no","never","don't","dont","doesn't","doesnt","isn't","isnt"].includes(e)}const Ki={nervous:{candidates:[{category:"emotion",target:"fear",priority:1},{category:"undertone",target:"nervous",priority:2}],rule:"standalone_is_emotion",examples:[{input:"nervous",resolved:{emotion:"fear"}},{input:"happy but nervous",resolved:{emotion:"joy",undertone:"nervous"}}]},anxious:{candidates:[{category:"emotion",target:"fear",priority:1},{category:"undertone",target:"nervous",priority:2}],rule:"standalone_is_emotion"},confident:{candidates:[{category:"emotion",target:"trust",priority:2},{category:"undertone",target:"confident",priority:1}],rule:"prefer_undertone",examples:[{input:"confident",resolved:{undertone:"confident"}},{input:"feeling confident",resolved:{emotion:"trust"}}]},tired:{candidates:[{category:"emotion",target:"sadness",priority:2},{category:"undertone",target:"tired",priority:1}],rule:"prefer_undertone",examples:[{input:"tired",resolved:{undertone:"tired"}},{input:"feeling tired",resolved:{emotion:"sadness",undertone:"tired"}}]},intense:{candidates:[{category:"undertone",target:"intense",priority:1},{category:"modifier",target:"intensity.very",priority:2}],rule:"prefer_undertone"},curious:{candidates:[{category:"emotion",target:"focused",priority:1},{category:"gesture",target:"lean",priority:2}],rule:"standalone_is_emotion",examples:[{input:"curious",resolved:{emotion:"focused"}},{input:"curious, leaning in",resolved:{emotion:"focused",gesture:"lean"}}]},interested:{candidates:[{category:"emotion",target:"focused",priority:1},{category:"gesture",target:"lean",priority:2}],rule:"standalone_is_emotion"},excited:{candidates:[{category:"emotion",target:"joy",priority:1},{category:"gesture",target:"bounce",priority:3}],rule:"standalone_is_emotion"},shaking:{candidates:[{category:"gesture",target:"shake",priority:1},{category:"emotion",target:"fear",priority:2}],rule:"standalone_is_gesture"},nodding:{candidates:[{category:"gesture",target:"nod",priority:1}],rule:"always_gesture"},glowing:{candidates:[{category:"gesture",target:"glow",priority:1},{category:"shape",target:"sun",priority:3}],rule:"standalone_is_gesture"},spinning:{candidates:[{category:"gesture",target:"spin",priority:1}],rule:"always_gesture"},love:{candidates:[{category:"emotion",target:"love",priority:1},{category:"shape",target:"heart",priority:2}],rule:"standalone_is_emotion",examples:[{input:"love",resolved:{emotion:"love"}},{input:"love heart",resolved:{emotion:"love",shape:"heart"}},{input:"become love",resolved:{shape:"heart"}}]},suspicious:{candidates:[{category:"emotion",target:"suspicion",priority:1},{category:"shape",target:"suspicion",priority:2}],rule:"standalone_is_emotion"},bright:{candidates:[{category:"emotion",target:"joy",priority:2},{category:"shape",target:"sun",priority:3},{category:"modifier",target:"intensity.very",priority:4}],rule:"context_dependent"},yes:{candidates:[{category:"gesture",target:"nod",priority:1}],rule:"always_gesture"},no:{candidates:[{category:"gesture",target:"shake",priority:1}],rule:"always_gesture"},agree:{candidates:[{category:"gesture",target:"nod",priority:1},{category:"emotion",target:"trust",priority:2}],rule:"standalone_is_gesture"},disagree:{candidates:[{category:"gesture",target:"shake",priority:1}],rule:"always_gesture"}},en={emotionContext:["feeling","feel","feels","felt","emotion","emotional","emotionally","mood","moody","state","am","is","are","being","becoming","become","grew","growing"],gestureContext:["do","doing","does","did","perform","performing","action","move","moving","movement","start","starting","begin","beginning","physically","motion"],shapeContext:["morph","morphing","morphed","transform","transforming","transformed","become","becoming","turn into","shape","form","look like","change to","change into"],undertoneContext:["but","yet","while","although","with","and also","mixed with","underneath","underlying","beneath","a bit","slightly","somewhat"],modifierContext:["very","really","so","extremely","slightly","barely","completely","quickly","slowly","briefly"]};function tn(e,t,i){const n=en[`${i}Context`];if(!n)return!1;const a=Math.max(0,t-3),s=Math.min(e.length,t+4);for(let i=a;i<s;i++)if(i!==t&&n.includes(e[i]))return!0;return!1}function nn(e,t){switch(t){case"emotion":return null!==e.emotion;case"gesture":return e.gestures&&e.gestures.length>0;case"shape":return null!==e.shape;case"undertone":return null!==e.undertone;default:return!1}}function an(e,t,i,n){const a=Ki[e];if(!a)return null;const{candidates:s,rule:o}=a;if(1===s.length)return s[0];switch(o){case"standalone_is_emotion":if(nn(n,"emotion")){const e=s.find(e=>"emotion"!==e.category);if(e)return e}return tn(t,i,"emotion"),s.find(e=>"emotion"===e.category)||s[0];case"standalone_is_gesture":if(nn(n,"gesture")){const e=s.find(e=>"gesture"!==e.category);if(e)return e}return tn(t,i,"gesture"),s.find(e=>"gesture"===e.category)||s[0];case"prefer_undertone":return tn(t,i,"emotion")?s.find(e=>"emotion"===e.category)||s[0]:s.find(e=>"undertone"===e.category)||s[0];case"always_gesture":return s.find(e=>"gesture"===e.category)||s[0];case"always_emotion":return s.find(e=>"emotion"===e.category)||s[0];case"context_dependent":for(const e of["emotion","gesture","shape","undertone"])if(tn(t,i,e)){const t=s.find(t=>t.category===e);if(t)return t}return s.sort((e,t)=>e.priority-t.priority)[0];default:return s.sort((e,t)=>e.priority-t.priority)[0]}}function sn(e){return e in Ki}const on={neutral:["neutral","default","normal","baseline","standard","nothing special","nothing particular","no strong feeling","not much","meh","whatever","indifferent","balanced","even","steady","stable","centered","level","middle ground","in between","ready","waiting","standing by","at attention","present","here","available","attentive","reset","clear","blank","empty","clean slate"],joy:["happy","joy","joyful","joyous","pleased","glad","content","satisfied","gratified","comfortable","good","cheerful","cheery","merry","jovial","jolly","upbeat","sunny","bright","lighthearted","buoyant","delighted","thrilled","overjoyed","elated","jubilant","exultant","gleeful","glowing","beaming","radiant","pumped","stoked","psyched","amped","hyped","vibing","living","slaying","winning","lit","fire","sick","dope","chuffed","pleased as punch","over the moon","made up","tickled","tickled pink","felicitous","beatific","blissful","smiling","grinning","laughing","giggling"],calm:["calm","peaceful","serene","tranquil","relaxed","at ease","comfortable","loose","unwound","decompressed","chilled","still","quiet","hushed","silent","soft","gentle","mild","placid","smooth","composed","collected","centered","grounded","untroubled","unworried","unbothered","unfazed","meditative","zen","mindful","contemplative","reflective","introspective","soothed","eased","mellowed","softened","chill","coasting","floating","drifting","laid back","easy going","low key","sorted","easy peasy"],excited:["excited","exciting","excitable","enthusiastic","eager","keen","avid","passionate","fervent","ardent","zealous","energetic","energized","animated","lively","spirited","vivacious","vibrant","dynamic","bouncy","peppy","perky","sprightly","anticipating","expectant","looking forward","itching","raring","chomping at the bit","fired up","charged","electric","electrified","buzzing","tingling","crackling","sparking","jazzed","juiced","geeked","hype","turnt","going off","well excited","buzzing","restless","fidgety","antsy","jumpy","twitchy","keyed up","wound up"],sadness:["sad","sadness","saddened","unhappy","down","low","blue","glum","bummed","disappointed","let down","discouraged","disheartened","dispirited","deflated","melancholy","melancholic","somber","gloomy","mournful","sorrowful","doleful","woeful","heavy-hearted","downcast","crestfallen","heartbroken","devastated","crushed","shattered","despairing","despondent","desolate","inconsolable","grief","grieving","mourning","bereft","empty","hollow","numb","void","wistful","longing","yearning","pining","nostalgic","bummed out","down in the dumps","in a funk","in the dumps","feeling low","gutted","choked","crying","tearful","weeping","sobbing","sighing","drooping","wilting","slumping"],anger:["angry","anger","angered","mad","annoyed","irritated","bothered","irked","peeved","miffed","vexed","displeased","put out","ticked off","ticked","frustrated","aggravated","exasperated","fed up","sick of","had enough","cross","upset","worked up","furious","enraged","livid","irate","incensed","infuriated","outraged","seething","fuming","boiling","burning","smoldering","raging","ballistic","apoplectic","berserk","seeing red","losing it","pissed","pissed off","salty","pressed","triggered","tilted","heated","steaming","narked","cheesed off","brassed off","shirty","stroppy","mardy","ropeable","filthy","spewing","clenching","tensing","grinding"],fear:["afraid","scared","fear","fearful","uneasy","unsettled","apprehensive","wary","concerned","worried","jittery","shaky","trembling","quivering","tense","tight","clenched","knotted","frightened","alarmed","startled","spooked","freaked","freaked out","creeped out","on edge","rattled","unnerved","terrified","petrified","horrified","panicked","panic","panicking","terror","dread","paranoid","distrustful","looking over shoulder","sketched","sketched out","wigged out","shook","bricking it","having kittens","in a flap","frozen","paralyzed","deer in headlights","heart racing","heart pounding","sweating"],surprise:["surprised","surprise","surprising","oh","huh","hmm","interesting","unexpected","caught off guard","astonished","amazed","astounded","startled","taken aback","struck","shocked","stunned","staggered","floored","dumbfounded","flabbergasted","gobsmacked","blown away","mind blown","speechless","wow","whoa","omg","no way","incredible","unbelievable","amazing","alarmed","dismayed","appalled","bewildered","baffled","perplexed","puzzled","confused","disoriented","thrown","shooketh","gagged","dead","wait what","blimey","crikey","bloody hell","jaw dropped","eyes wide","double take","gasp","gasping"],disgust:["disgusted","disgust","disgusting","distaste","dislike","aversion","put off","turned off","off-putting","repulsed","revolted","repelled","grossed out","creeped out","icked out","sickened","nauseated","nauseous","appalled","horrified","scandalized","offended","outraged","indignant","contempt","contemptuous","disdain","scorn","gagging","retching","cringing","wincing","recoiling","shrinking back","gross","ew","eww","yuck","yucky","ick","nasty","foul","vile","rank","minging","manky","grotty"],love:["love","loving","loved","affection","affectionate","fond","fondness","tender","tenderness","gentle","caring","care","nurturing","supportive","protective","devoted","dedicated","warm","warmth","warm-hearted","kind","kind-hearted","compassionate","sympathetic","adoring","adore","cherish","cherishing","treasure","treasuring","doting","romantic","amorous","passionate","smitten","infatuated","enamored","besotted","head over heels","falling for","connected","bonded","attached","close","intimate","deep","profound","heart eyes","crushing","swooning","melting","hugging","embracing","holding","cuddling","snuggling","nuzzling"],euphoria:["euphoric","euphoria","bliss","blissful","transcendent","otherworldly","sublime","heavenly","divine","ethereal","celestial","ecstatic","ecstasy","rapture","rapturous","exultant","exalted","elevated","peak","pinnacle","height","climax","breakthrough","revelation","epiphany","overwhelming joy","pure joy","absolute joy","complete happiness","total bliss","floating","soaring","flying","weightless","radiating","shining","on cloud nine","in heaven","on top of the world","walking on air","living my best life","ascended"],focused:["focused","focus","focusing","concentrating","concentration","concentrated","attentive","attention","attending","thinking","thought","thoughtful","pondering","considering","contemplating","reflecting","musing","mulling","engaged","absorbed","immersed","engrossed","rapt","riveted","captivated","enthralled","intent","determined","resolute","single-minded","laser focused","zeroed in","working","processing","analyzing","examining","studying","learning","figuring out","locked in","dialed in","in the zone","flow state","deep work","grinding","staring","gazing","peering","squinting","furrowed brow"],suspicion:["suspicious","suspicion","suspect","doubtful","doubt","doubting","skeptical","skepticism","questioning","uncertain","unsure","unconvinced","wary","cautious","guarded","careful","leery","circumspect","vigilant","distrustful","mistrust","mistrustful","disbelieving","incredulous","unbelieving","scrutinizing","examining","assessing","evaluating","judging","sizing up","sus","sussy","suss","side eye","giving side eye","side-eyeing","eyeing","not buying it","narrowed eyes","squinting","raised eyebrow","cocked head","tilted head","looking askance"],resting:["resting","rest","restful","tired","weary","fatigued","exhausted","drained","spent","depleted","worn out","sleepy","drowsy","dozy","groggy","yawning","nodding off","drifting off","sluggish","lethargic","listless","languid","lazy","idle","inactive","recovering","recuperating","recharging","winding down","powering down","shutting down","sleeping","asleep","slumbering","dozing","napping","snoozing","zonked","wiped","beat","dead tired","running on empty","out of gas","crashed","knackered","shattered","cream crackered"],glitch:["glitch","glitchy","glitching","malfunction","malfunctioning","broken","bugged","buggy","error","erroring","corrupted","corruption","scrambled","garbled","distorted","warped","static","noise","interference","pixelated","artifacting","tearing","haywire","fritzing","shorting out","going crazy","spazzing","unstable","erratic","unpredictable","flickering","stuttering","lagging","does not compute","syntax error","crash"]},rn={nervous:["nervous","nervously","anxious","anxiously","worried","worriedly","uneasy","uneasily","apprehensive","jittery","shaky","trembling","quivering","fidgety","restless","twitchy","tense","tensely","on edge","edgy","keyed up","wound up","uptight","self-conscious","awkward","awkwardly","hesitant","hesitantly","uncertain","uncertainly","sketchy","stressed","stressing","low-key panicking","kinda freaking out"],confident:["confident","confidently","confidence","assured","assuredly","certain","certainly","sure","surely","positive","positively","bold","boldly","brave","bravely","daring","daringly","fearless","fearlessly","strong","strongly","powerful","powerfully","firm","firmly","solid","solidly","authoritative","commanding","assertive","decisive","decisively","resolute","resolutely","poised","self-assured","unflappable","unfazed","owning it","killing it","crushing it","boss","like a boss"],tired:["tired","tiredly","tiredness","exhausted","weary","wearily","fatigued","drained","spent","depleted","sluggish","sluggishly","slow","slowly","lethargic","listless","languid","low energy","no energy","out of energy","running low","running on fumes","droopy","drooping","sagging","slumping","heavy","weighted","dragging","wiped","beat","dead","zonked","burned out","fried","cooked","toast"],intense:["intense","intensely","intensity","heightened","elevated","amplified","magnified","increased","enhanced","forceful","forcefully","powerful","powerfully","fierce","fiercely","strong","strongly","passionate","passionately","fervent","fervently","ardent","ardently","vehement","vehemently","sharp","sharply","acute","acutely","keen","keenly","piercing","piercingly","extreme","extremely","deeply","profoundly","tremendously","immensely","incredibly","super","mega","ultra","hella","mad","crazy"],subdued:["subdued","subduedly","soft","softly","gentle","gently","mild","mildly","light","lightly","restrained","held back","contained","tempered","moderated","toned down","quiet","quietly","hushed","muted","understated","subtle","subtly","modest","modestly","humble","humbly","reserved","demure","unassuming","faint","faintly","dim","dimly","pale","faded","washed out","low key","lowkey","easy","easy going"],clear:["clear","clearly","pure","purely","clean","cleanly","simple","simply","plain","plainly","direct","directly","straightforward","honest","honestly","frank","frankly","transparent","transparently","open","openly","obvious","obviously","evident","evidently","unmodified","unaltered","unchanged","normal","normally","regular","regularly","standard","basic","baseline"]},ln={bounce:["bounce","bouncing","bouncy","hop","hopping","hoppy","spring","springing","springy","boing","boinging","bouncing up and down","hopping around","spring in step","light on feet"],pulse:["pulse","pulsing","pulsate","pulsating","throb","throbbing","beat","beating","pulsing gently","steady pulse","heartbeat","heart beat"],shake:["shake","shaking","shaky","shudder","shuddering","tremble","trembling","quake","quaking","shiver","shivering","no","nope","nah","disagree","disagreeing","refuse","refusing","deny","denying","shaking head","shake head","head shake","saying no","shaking no"],nod:["nod","nodding","yes","yeah","yep","yup","agree","agreeing","acknowledge","acknowledging","confirm","confirming","accept","accepting","approve","approving","understand","understanding","got it","gotcha","i see","makes sense","understood","nodding head","nod head","head nod","nodding along","nodding yes"],vibrate:["vibrate","vibrating","vibration","buzz","buzzing","hum","humming","quiver","quivering","vibrating slightly","gentle buzz","low hum","subtle vibration"],orbit:["orbit","orbiting","circle","circling","revolve","revolving","rotate","rotating","circling around","going around","rotating slowly","orbital motion"],sway:["sway","swaying","rock","rocking","swing","swinging","oscillate","oscillating","swaying gently","rocking back and forth","gentle sway","side to side"],float:["float","floating","drift","drifting","hover","hovering","glide","gliding","levitate","levitating","weightless","weightlessness","buoyant","airy","floating gently","drifting along","hovering in place","light as air"],lean:["lean","leaning","incline","inclining","tilt","tilting","leaning in","lean in","leaning forward","lean forward","leaning toward","lean toward","leaning closer","lean closer","moving closer","coming closer","drawing near","approaching","interested","intrigued","curious","engaged","attentive","listening closely","paying attention"],reach:["reach","reaching","extend","extending","stretch","stretching","reaching out","reach out","reaching toward","reach toward","extending toward","stretching toward","offer","offering","present","presenting","give","giving","help","helping"],point:["point","pointing","indicate","indicating","gesture","gesturing","direct","directing","pointing at","pointing to","pointing toward","gesturing toward","showing","directing attention"],wave:["wave","waving","greet","greeting","hello","hi","hey","goodbye","bye","farewell","welcome","welcoming","waving hello","waving goodbye","friendly wave","waving hand"],headBob:["headbob","head bob","headbobbing","head bobbing","bobbing","bob","nodding to beat","nodding to music","bobbing along","bobbing to rhythm","vibing","grooving","jamming","bobbing head","bob head","feeling the beat","moving to music"],wiggle:["wiggle","wiggling","wiggly","jiggle","jiggling","jiggly","squirm","squirming","wriggle","wriggling","wiggling around","little wiggle","happy wiggle","excited wiggle"],groove:["groove","grooving","groovy","dance","dancing","boogie","boogying","funk","funky","rhythmic","moving to music","feeling the music","in the groove","getting down","busting a move","doing a little dance"],twitch:["twitch","twitching","twitchy","spasm","spasming","jerk","jerking","jerky","flinch","flinching","quick twitch","nervous twitch","sudden movement"],jitter:["jitter","jittering","jittery","stutter","stuttering","jittering around","slight jitter","nervous jitter"],spin:["spin","spinning","twirl","twirling","whirl","whirling","rotate","rotating","turn","turning","spinning around","quick spin","full rotation","twirling around"],jump:["jump","jumping","jumpy","leap","leaping","spring","springing","bound","bounding","jumping up","leap up","spring up","jumping for joy"],stretch:["stretch","stretching","stretchy","elongate","elongating","extend","extending","lengthen","lengthening","stretching out","big stretch","reaching up","stretching tall"],expand:["expand","expanding","grow","growing","enlarge","enlarging","swell","swelling","inflate","inflating","bloat","bloating","getting bigger","growing larger","puffing up","expanding outward"],contract:["contract","contracting","shrink","shrinking","compress","compressing","deflate","deflating","reduce","reducing","getting smaller","shrinking down","pulling in","contracting inward"],twist:["twist","twisting","twisty","contort","contorting","warp","warping","distort","distorting","twisting around","getting twisted","warping shape"],tilt:["tilt","tilting","tilted","angle","angling","angled","cock","cocking","cocked","tilting head","tilt head","cocking head","curious tilt","angling sideways","head tilt"],hula:["hula","hula-ing","hip sway","swaying hips","circular sway","round motion","hula motion","hula dance"],sparkle:["sparkle","sparkling","sparkly","twinkle","twinkling","twinkly","glitter","glittering","glittery","shine","shining","shiny","celebrate","celebrating","celebration","celebratory","festive","party","partying","victory","triumphant","triumph","winning","success","successful","achievement","accomplished","nailed it","slay","slaying","killing it","yasss","yay","woo","woohoo"],shimmer:["shimmer","shimmering","shimmery","glisten","glistening","gleam","gleaming","lustrous","luminous","soft shimmer","gentle gleam","shimmering light","pearlescent"],glow:["glow","glowing","glowy","radiate","radiating","emanate","emanating","luminous","luminescent","bright","brighten","brightening","soft glow","warm glow","inner glow","glowing warmly","lighting up","lit up"],flash:["flash","flashing","flashy","blink","blinking","strobe","strobing","flare","flaring","quick flash","bright flash","flashing light","strobing light"],flicker:["flicker","flickering","flickery","flutter","fluttering","waver","wavering","guttering","flickering light","unsteady light","wavering glow","candle-like"],burst:["burst","bursting","explode","exploding","explosion","erupt","erupting","eruption","pop","popping","boom","booming","bursting out","burst of energy","explosive","big burst"],settle:["settle","settling","settled","calm","calming","ground","grounding","grounded","center","centering","centered","anchor","anchoring","anchored","root","rooting","rooted","relax","relaxing","unwind","unwinding","decompress","decompressing","settling down","calming down","winding down","cooling down","coming to rest","finding peace","sinking into","melting into"],breathe:["breathe","breathing","breath","inhale","inhaling","exhale","exhaling","sigh","sighing","respire","respiring","deep breath","deep breathing","slow breath","slow breathing","long breath","full breath","breathing deeply","breathing slowly","taking a breath","take a breath","catching breath","breath work","breathwork","inhale exhale","in and out","meditative breathing","calming breath","cleansing breath","relaxing breath","centering breath","mindful breathing"],peek:["peek","peeking","peer","peering","peep","peeping","glance","glancing","peeking out","peek out","looking shyly","shy glance","quick peek","sneaking a look"],fade:["fade","fading","dim","dimming","disappear","disappearing","vanish","vanishing","fading out","fading away","growing dim","becoming transparent","dissolving","melting away"],hold:["hold","holding","pause","pausing","paused","freeze","freezing","frozen","still","stillness","stop","stopping","stopped","holding still","staying still","frozen in place","completely still","motionless","stationary"],rain:["rain","raining","shower","showering","drip","dripping","pour","pouring","fall","falling","raining down","particles falling","gentle rain","shower of particles"]},hn={circle:["circle","circular","round","rounded","orb","ball","sphere","spherical","ring","disc","disk","whole","complete","unity","unified","endless","infinite","continuous","full circle","perfect round","come full circle"],sphere:["sphere","spherical","globe","globular","ball","3d circle","three dimensional","round ball","floating sphere"],square:["square","squared","boxy","box","rectangle","rectangular","quadrilateral","cube","cubic","block","blocky","stable","solid","grounded","sturdy","rigid","firm","structured","four sided","four corners","box shape"],triangle:["triangle","triangular","tri","pyramid","pyramidal","delta","wedge","arrow","arrowhead","pointed","sharp","dynamic","directional","ascending","three sided","three pointed","pointing up"],heart:["heart","hearted","hearts","love","loving","lovely","valentine","romantic","affection","affectionate","caring","care","tender","warmth","warm-hearted","heartfelt","compassion","compassionate","devotion","devoted","luv","wuv","<3","❤️","💕","💗","full of love","with love","heart shape","heart shaped","from the heart"],suspicion:["suspicion","suspicious","suspect","sly","slyly","sneaky","sneakily","mischievous","mischief","smirk","smirking","smirky","grin","grinning","sly grin","side eye","sideeye","side-eye","skeptical","skepticism","doubtful","doubt","doubting","wary","distrustful","distrust","sus","sussy","sussy baka","hmm","hmmm","hmmmm","shady","fishy","sketchy","not buying it","something fishy","seems off","up to something"],star:["star","starred","starry","stars","stellar","astral","twinkle","twinkling","achievement","achieved","excellence","excellent","gold star","five star","superstar","rockstar","rock star","wonder","wonderful","wondrous","magical","magic","miraculous","amazing","spectacular","reach for stars","seeing stars","star shape","shining star"],sun:["sun","sunny","sunshine","sunlight","solar","sol","daylight","daytime","day","radiant","radiance","radiating","bright","brightness","brilliant","glowing","glow","blazing","blaze","warm","warmth","cheerful","cheery","optimistic","optimism","hopeful","hope","positive","positivity","full of light","ray of sunshine","like the sun","sunny disposition"],moon:["moon","moony","moonlight","moonlit","lunar","crescent","nighttime","night","nocturnal","waxing","waning","gibbous","new moon","full moon","half moon","quarter moon","crescent moon","dreamy","dreamlike","dream","mysterious","mystery","mystical","ethereal","otherworldly","serene","serenity","tranquil","contemplative","reflective","moonlit night","by moonlight","moon shape","under the moon"],lunar:["lunar eclipse","blood moon","blood-moon","red moon","copper moon","rust moon","eclipsing","eclipsed","shadow crossing","earth shadow","ominous","foreboding","portentous","dramatic","intense","transforming","transformation","moon in shadow","moon turning red","eclipse phase","lunar event"],solar:["solar eclipse","total eclipse","corona","diamond ring","totality","umbra","penumbra","ring of fire","dark sun","blocked sun","occluded","awe","awesome","awe-inspiring","rare","momentous","historic","breathtaking","magnificent","sun blocked","sun covered","total darkness","corona visible"],eclipse:["eclipse","eclipsing","eclipsed","celestial event","astronomical event","overshadow","overshadowed","blocked","blocking","obscured","hidden","hiding","concealed","passing","crossing","alignment","in eclipse","going dark","being eclipsed","eclipsed by"]},cn={intensity:{barely:["barely","hardly","scarcely","faintly","slightly","marginally","just a bit","just a little","just barely","hint of","touch of","trace of"],slightly:["slightly","somewhat","a little","a bit","mildly","lightly","kind of","kinda","sort of","sorta","a tad","a touch","a smidge"],moderately:["moderately","reasonably","fairly","pretty","rather","quite"],normal:["normal","normally","regular","regularly","standard","typical","typically","average","ordinary"],notably:["notably","noticeably","clearly","definitely","certainly","decidedly","genuinely","truly","really"],very:["very","really","so","such","quite","highly","deeply","seriously","majorly","hella","super","extra","mad"],extremely:["extremely","incredibly","immensely","tremendously","enormously","hugely","intensely","fiercely","wildly","insanely","crazy","ridiculously","mega","ultra","hyper"],absolutely:["absolutely","completely","totally","utterly","entirely","wholly","fully","maximum","max","over the top","off the charts","through the roof","to the max"]},duration:{flash:["flash","instant","instantaneous","split second","split-second","momentary","fleeting","brief flash"],quick:["quick","quickly","fast","rapid","swift","swiftly","brief","briefly","short","shortly","snap"],normal:["normal","regular","standard","typical","usual"],slow:["slow","slowly","gradual","gradually","gentle","gently","easy","easily","leisurely","unhurried"],long:["long","prolonged","extended","sustained","lasting","lingering","drawn out","drawn-out"],persistent:["persistent","constant","continuous","ongoing","steady","maintained","held","holding","stay","staying","keep","keeping","remain","remaining"]},transition:{instant:["instant","instantly","immediate","immediately","sudden","suddenly","abrupt","abruptly","snap","cut","jump"],snappy:["snappy","crisp","sharp","sharply","brisk","briskly","punchy"],smooth:["smooth","smoothly","natural","naturally","fluid","fluidly","flowing"],gentle:["gentle","gently","soft","softly","gradual","gradually","easing","gliding","drifting"],dreamy:["dreamy","dreamlike","floaty","ethereal","languid","lazy","flowing","melting"]},repetition:{once:["once","one time","single","just once","only once","one shot"],few:["few","few times","couple","couple times","twice","two times","thrice","three times"],several:["several","several times","multiple","multiple times","repeatedly","again and again"],many:["many","many times","lots","lots of times","over and over","nonstop"],loop:["loop","looping","looped","continuous","continuously","forever","infinitely","endlessly","always","keep going","on repeat"]}},un={barely:{min:.1,max:.2,default:.15},slightly:{min:.2,max:.4,default:.3},moderately:{min:.4,max:.5,default:.45},normal:{min:.5,max:.6,default:.55},notably:{min:.6,max:.7,default:.65},very:{min:.7,max:.85,default:.8},extremely:{min:.85,max:.95,default:.9},absolutely:{min:.95,max:1,default:1}},dn={flash:{min:100,max:500,default:250},quick:{min:500,max:1e3,default:750},normal:{min:1e3,max:2e3,default:1500},slow:{min:2e3,max:4e3,default:3e3},long:{min:4e3,max:8e3,default:6e3},persistent:{min:8e3,max:1/0,default:1e4}};function mn(e){const t=new Map;for(const[i,n]of Object.entries(e)){for(const e of n){const n=e.toLowerCase().trim();t.set(n,i)}t.set(i.toLowerCase(),i)}return t}class pn{constructor(){this.emotionLookup=mn(on),this.undertoneLookup=mn(rn),this.gestureLookup=mn(ln),this.shapeLookup=mn(hn),this.modifierLookup=function(e){const t=new Map;for(const[i,n]of Object.entries(e))for(const[e,a]of Object.entries(n))for(const n of a){const a=n.toLowerCase().trim();t.set(a,{type:i,level:e})}return t}(cn)}parse(e){const t={emotion:null,undertone:"clear",gestures:[],shape:null,intensity:un.normal.default,duration:dn.normal.default,transition:"smooth",repetition:"once",unrecognized:[],raw:e};if(!e||"string"!=typeof e)return t;const{tokens:i}=function(e){if(!e||"string"!=typeof e)return{tokens:[],segments:[],phrases:new Map};const t=Qi(e),{processed:i,phrases:n}=function(e){const t=new Map;let i=e,n=0;for(const e of Wi){const a=Qi(e);if(i.includes(a)){const e=`__PHRASE_${n}__`;i=i.replace(new RegExp(a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),e),t.set(e,a),n++}}return{processed:i,phrases:t}}(t),a=i.split(Xi).map(e=>e.trim()).filter(e=>e.length>0),s=[],o=[];for(const e of a){let t=e;for(const[e,i]of n)t=t.replace(e,i);o.push(t.trim());const i=e.split(/\s+/);for(const e of i){if(n.has(e)){s.push(n.get(e));continue}if(!e)continue;if(Yi.has(e)&&!$i.has(e))continue;const t=e.replace(/^[^\w]+|[^\w]+$/g,"");t&&s.push(t)}}return{tokens:s,segments:o,phrases:n}}(e);if(0===i.length)return t;let n=!1;for(let e=0;e<i.length;e++){const a=i[e];if(!Zi(a))if(Ji(a))n=!0;else if(n)n=!1;else{if(sn(a)){const n=an(a,i,e,t);if(n){this._applyResolution(t,n);continue}}this._tryEmotion(a,t)||this._tryGesture(a,t)||this._tryShape(a,t)||this._tryUndertone(a,t)||this._tryModifier(a,t)||t.unrecognized.push(a)}}return t}_applyResolution(e,t){const{category:i,target:n}=t;switch(i){case"emotion":e.emotion||(e.emotion=n);break;case"undertone":"clear"===e.undertone&&(e.undertone=n);break;case"gesture":e.gestures.includes(n)||e.gestures.push(n);break;case"shape":e.shape||(e.shape=n)}}_tryEmotion(e,t){const i=this.emotionLookup.get(e);return!(!i||t.emotion||(t.emotion=i,0))}_tryGesture(e,t){const i=this.gestureLookup.get(e);return!(!i||t.gestures.includes(i)||(t.gestures.push(i),0))}_tryShape(e,t){const i=this.shapeLookup.get(e);return!(!i||t.shape||(t.shape=i,0))}_tryUndertone(e,t){const i=this.undertoneLookup.get(e);return!(!i||"clear"!==t.undertone||(t.undertone=i,0))}_tryModifier(e,t){const i=this.modifierLookup.get(e);if(i){const{type:e,level:n}=i;switch(e){case"intensity":t.intensity=un[n]?.default||t.intensity;break;case"duration":t.duration=dn[n]?.default||t.duration;break;case"transition":t.transition=n;break;case"repetition":t.repetition=n}return!0}return!1}validate(e){const t=[];return e.emotion||0!==e.gestures.length||e.shape||t.push("No actionable intent found (need emotion, gesture, or shape)"),(e.intensity<0||e.intensity>1)&&t.push(`Intensity ${e.intensity} out of range [0, 1]`),e.duration<=0&&t.push(`Duration ${e.duration} must be positive`),{valid:0===t.length,errors:t}}static getAvailableEmotions(){return Object.keys(on)}static getAvailableUndertones(){return Object.keys(rn)}static getAvailableGestures(){return Object.keys(ln)}static getAvailableShapes(){return Object.keys(hn)}}function gn(e=32,t=32){const i=[],n=[],a=[];for(let a=0;a<=t;a++){const s=a/t*Math.PI;for(let t=0;t<=e;t++){const a=t/e*Math.PI*2,o=Math.cos(a)*Math.sin(s),r=Math.cos(s),l=Math.sin(a)*Math.sin(s);i.push(o,r,l),n.push(o,r,l)}}for(let i=0;i<t;i++)for(let t=0;t<e;t++){const n=i*(e+1)+t,s=n+e+1,o=n+1,r=s+1;a.push(n,s,o),a.push(o,s,r)}return{vertices:new Float32Array(i),normals:new Float32Array(n),indices:new Uint16Array(a)}}function fn(e=6){const t=[],i=[],n=[],a=new Map;let s=0;function o(e,n,o,r,l,h){const c=`${e},${n},${o}`;return a.has(c)||(t.push(e,n,o),i.push(r,l,h),a.set(c,s++)),a.get(c)}const r=o(0,1.5,0,0,1,0),l=[];for(let t=0;t<e;t++){const i=t/e*Math.PI*2,n=o(.7*Math.cos(i),0,.7*Math.sin(i),Math.cos(i),0,Math.sin(i));l.push(n)}const h=o(0,-1.5,0,0,-1,0);for(let t=0;t<e;t++){const i=(t+1)%e;n.push(r,l[t],l[i])}for(let t=0;t<e;t++){const i=(t+1)%e;n.push(l[t],h,l[i])}return{vertices:new Float32Array(t),normals:new Float32Array(i),indices:new Uint16Array(n)}}function yn(){const e=[],t=[],i=[],n=[0,1.2,0],a=[0,-.8,0],s=[];for(let e=0;e<8;e++){const t=e/8*Math.PI*2;s.push([.8*Math.cos(t),0,.8*Math.sin(t)])}function o(n,a,s){const o=[a[0]-n[0],a[1]-n[1],a[2]-n[2]],r=[s[0]-n[0],s[1]-n[1],s[2]-n[2]],l=o[1]*r[2]-o[2]*r[1],h=o[2]*r[0]-o[0]*r[2],c=o[0]*r[1]-o[1]*r[0],u=Math.sqrt(l*l+h*h+c*c),d=[l/u,h/u,c/u],m=e.length/3;e.push(...n),t.push(...d),e.push(...a),t.push(...d),e.push(...s),t.push(...d),i.push(m,m+1,m+2)}for(let e=0;e<8;e++){const t=(e+1)%8;o(n,s[e],s[t])}for(let e=0;e<8;e++){const t=(e+1)%8;o(s[e],a,s[t])}return{vertices:new Float32Array(e),normals:new Float32Array(t),indices:new Uint16Array(i)}}const vn={sphere:gn(32,32),crystal:fn(6),diamond:yn()};function bn(){Object.values(vn).forEach(e=>{e&&e.vertices&&(e.vertices=null,e.normals=null,e.indices=null)})}class wn{constructor(e={}){this.config={canvasId:e.canvasId||"emotive-canvas",coreGeometry:e.coreGeometry||"sphere",targetFPS:e.targetFPS||60,enableParticles:!1!==e.enableParticles,defaultEmotion:e.defaultEmotion||"neutral",...e},this.container=null,this.webglCanvas=null,this.canvas2D=null,this.core3D=null,this.particleSystem=null,this.isRunning=!1,this._destroyed=!1,this.animationFrameId=null,this.lastFrameTime=0,this.gestureTimeouts=[],this.eventManager=new Vi,this.eventManager.emit||(this.eventManager._listeners={},this.eventManager.emit=(e,t)=>{const i=this.eventManager._listeners[e];i&&i.forEach(e=>e(t))},this.eventManager.on=(e,t)=>{this.eventManager._listeners[e]||(this.eventManager._listeners[e]=[]),this.eventManager._listeners[e].push(t)},this.eventManager.off=(e,t)=>{const i=this.eventManager._listeners[e];if(i){const e=i.indexOf(t);e>-1&&i.splice(e,1)}}),this.errorBoundary=new qi,this.emotion="neutral",this.undertone=null,this._intentParser=new pn,this._feelRateLimiter={calls:[],windowMs:1e3,maxCallsPerSecond:10}}init(e){try{if(this.setupCanvasLayers(e),this.core3D=new Gi(this.webglCanvas,{geometry:this.config.coreGeometry,emotion:this.config.defaultEmotion,enableParticles:this.config.enableParticles,enablePostProcessing:this.config.enablePostProcessing,enableShadows:this.config.enableShadows,enableControls:this.config.enableControls,autoRotate:this.config.autoRotate,enableBlinking:this.config.enableBlinking,enableBreathing:this.config.enableBreathing,cameraDistance:this.config.cameraDistance,fov:this.config.fov,minZoom:this.config.minZoom,maxZoom:this.config.maxZoom,materialVariant:this.config.materialVariant,assetBasePath:this.config.assetBasePath}),this.ctx2D=this.canvas2D.getContext("2d"),this.config.enableParticles&&!this.core3D?.particleOrchestrator){const e=this.config.maxParticles||300;this.particleSystem=new hi(e,this.errorBoundary),this.particleSystem.canvasWidth=this.canvas2D.width,this.particleSystem.canvasHeight=this.canvas2D.height}return this}catch(e){throw console.error("Failed to initialize 3D engine:",e),e}}setupCanvasLayers(e){if("CANVAS"===e.tagName){const t=e.parentElement;this.container=document.createElement("div"),this.container.style.position="relative",this.container.style.width="100%",this.container.style.height="100%",t.replaceChild(this.container,e)}else this.container=e,this.container.style.position&&"static"!==this.container.style.position||(this.container.style.position="relative");this.canvas2D=document.createElement("canvas"),this.canvas2D.id=`${this.config.canvasId}-particles`,this.canvas2D.width=this.container.offsetWidth||400,this.canvas2D.height=this.container.offsetHeight||400,this.canvas2D.style.position="absolute",this.canvas2D.style.top="0",this.canvas2D.style.left="0",this.canvas2D.style.width="100%",this.canvas2D.style.height="100%",this.canvas2D.style.background="transparent",this.canvas2D.style.zIndex="1",this.canvas2D.style.pointerEvents="none",this.container.appendChild(this.canvas2D),this.webglCanvas=document.createElement("canvas"),this.webglCanvas.id=`${this.config.canvasId}-3d`,this.webglCanvas.width=this.canvas2D.width,this.webglCanvas.height=this.canvas2D.height,this.webglCanvas.style.position="absolute",this.webglCanvas.style.top="0",this.webglCanvas.style.left="0",this.webglCanvas.style.width="100%",this.webglCanvas.style.height="100%",this.webglCanvas.style.background="transparent",this.webglCanvas.style.zIndex="2",this.config.enableControls?(this.webglCanvas.style.pointerEvents="auto",this.webglCanvas.style.touchAction="none"):(this.webglCanvas.style.pointerEvents="none",this.webglCanvas.style.touchAction="auto"),this.container.appendChild(this.webglCanvas)}async start(){this.isRunning||(this.core3D&&await this.core3D.waitUntilReady(),this.isRunning=!0,this.lastFrameTime=null,this.animationFrameId=requestAnimationFrame(this.animate.bind(this)))}stop(){this.isRunning=!1,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}animate(e){if(!this.isRunning||this._destroyed)return;if(null===this.lastFrameTime)return this.lastFrameTime=e,void(this.animationFrameId=requestAnimationFrame(this.animate.bind(this)));const t=e-this.lastFrameTime,i=Math.min(t,100);if(this.lastFrameTime=e,this.core3D&&!this._destroyed&&this.core3D.render(i),this.canvas2D&&this.ctx2D&&(this.ctx2D.clearRect(0,0,this.canvas2D.width,this.canvas2D.height),this.ctx2D.fillStyle="rgba(0,0,0,0)",this.ctx2D.fillRect(0,0,this.canvas2D.width,this.canvas2D.height),this.particleSystem)){const t=this.canvas2D.width/2,n=this.canvas2D.height/2,a=this.core3D?this.core3D.emotion:"neutral",s=me(a),o=this.core3D?this.rgbToHex(this.core3D.glowColor):"#FFFFFF",r=s?.visual?.particleBehavior||"ambient",l=s?.visual?.particleRate||15,h=s?.visual?.minParticles||5,c=s?.visual?.maxParticles||30,u=s?.visual?.particleColors||null;this.particleSystem.spawn(r,a,l,t,n,i,null,h,c,1,1,u,this.undertone);let d=null,m=0;if(this.currentGesture){const t=e-this.currentGesture.startTime;m=Math.min(t/this.currentGesture.duration,1),d={...this.currentGesture.config,type:this.currentGesture.name}}this.particleSystem.update(i,t,n,d,m,this.undertone),this.particleSystem.render(this.ctx2D,o,null)}this.animationFrameId=requestAnimationFrame(e=>this.animate(e))}setEmotion(e,t){this.eventManager&&this.eventManager._listeners&&(this.emotion=e,void 0!==t&&("string"==typeof t?this.undertone=t:t&&"object"==typeof t?this.undertone=t.undertone||null:null===t&&(this.undertone=null)),this.core3D&&this.core3D.setEmotion(e,this.undertone),this.particleSystem&&(this.particleSystem.particles=[]),this.eventManager.emit("emotion:change",{emotion:e,undertone:this.undertone}))}updateUndertone(e){this.undertone=e,this.core3D&&this.emotion&&this.core3D.setEmotion(this.emotion,e),this.eventManager.emit("undertone:change",{undertone:e})}setUndertone(e){this.updateUndertone(e)}express(e){if(!this.eventManager||!this.eventManager._listeners)return;this.core3D&&this.core3D.playGesture(e);const t=ft(e);if(t){const i=t.config||{},n=i.musicalDuration?.musical?500*(i.musicalDuration.beats||2):i.duration||800;this.currentGesture={name:e,gesture:t,config:i,startTime:performance.now(),duration:n};const a=setTimeout(()=>{this.currentGesture&&this.currentGesture.name===e&&(this.currentGesture=null)},n);this.gestureTimeouts.push(a)}this.eventManager.emit("gesture:trigger",{gesture:e})}chain(e){const t=("string"==typeof e?{rise:"breathe > sway+lean+tilt",flow:"sway > lean+tilt > spin > bounce",burst:"jump > nod > shake > flash",drift:"sway+breathe+float+drift",chaos:"shake+shake > spin+flash > bounce+pulse > twist+sparkle",morph:"expand > contract > morph+glow > expand+flash",rhythm:"pulse > pulse+sparkle > pulse+flicker",spiral:"spin > orbital > twist > orbital+sparkle",routine:"nod > bounce > spin+sparkle > sway+pulse > nod+flash",radiance:"sparkle > pulse+flicker > shimmer",twinkle:"sparkle > flash > pulse+sparkle > shimmer+flicker",stream:"wave > nod+pulse > sparkle > flash"}[e]||e:e.join(">")).split(">").map(e=>e.trim().split("+").map(e=>e.trim()).filter(e=>e.length>0));this.executeChainSequence(t)}executeChainSequence(e){if(!e||0===e.length)return;let t=0;const i=()=>{if(!(t>=e.length)&&(e[t].forEach(e=>{this.express(e)}),t++,t<e.length)){const e=setTimeout(i,800);this.gestureTimeouts.push(e)}};i()}morphTo(e,t={}){if(this.core3D){if(void 0!==t.materialVariant&&this.core3D.setMaterialVariant(t.materialVariant),t.onMaterialSwap){const e=this.core3D.onMaterialSwap;this.core3D.onMaterialSwap=i=>{e&&e(i),t.onMaterialSwap(i),this.core3D.onMaterialSwap=e}}const i=t.duration||800;this.core3D.morphToShape(e,i)}this.eventManager.emit("shape:morph",{shape:e})}feel(e){if(!this.eventManager||!this.eventManager._listeners)return{success:!1,error:"Engine destroyed",parsed:null};const t=Date.now(),i=this._feelRateLimiter;if(i.calls=i.calls.filter(e=>t-e<i.windowMs),i.calls.length>=i.maxCallsPerSecond)return console.warn("[feel] Rate limit exceeded. Max 10 calls per second."),{success:!1,error:"Rate limit exceeded",parsed:null};i.calls.push(t);const n=this._intentParser.parse(e),a=this._intentParser.validate(n);if(!a.valid)return console.warn("[feel] Invalid intent:",a.errors),{success:!1,error:a.errors.join("; "),parsed:n};try{if(n.emotion){const e={};n.undertone&&"clear"!==n.undertone&&(e.undertone=n.undertone),this.setEmotion(n.emotion,e)}for(const e of n.gestures)this.express(e);return n.shape&&this.morphTo(n.shape),{success:!0,error:null,parsed:n}}catch(e){return console.error("[feel] Execution error:",e),{success:!1,error:e.message,parsed:n}}}isMorphing(){return!!this.core3D&&this.core3D.isMorphing()}getMorphState(){return this.core3D?this.core3D.getMorphState():null}growIn(e=500){this.core3D&&this.core3D.growIn(e),this.eventManager.emit("animation:growIn",{duration:e})}setCoreGlowEnabled(e){this.core3D&&this.core3D.setCoreGlowEnabled(e),this.eventManager.emit("coreGlow:toggle",{enabled:e})}isCoreGlowEnabled(){return!this.core3D||this.core3D.coreGlowEnabled}enableAutoRotate(){this.core3D&&"moon"!==this.core3D.geometryType&&(this.core3D.renderer?.controls&&(this.core3D.renderer.controls.autoRotate=!0,this.core3D.renderer.controls.autoRotateSpeed=this.core3D.options?.autoRotateSpeed??.5),this.core3D.rotationDisabled=!1,this.setEmotion(this.core3D.emotion,this.undertone))}disableAutoRotate(){this.core3D?.renderer?.controls&&(this.core3D.renderer.controls.autoRotate=!1,this.core3D.renderer.controls.autoRotateSpeed=0),this.core3D&&(this.core3D.rotationDisabled=!0,this.core3D.rotationBehavior=null,this.core3D.baseEuler&&(this.core3D.baseEuler[0]=0,this.core3D.baseEuler[1]=0,this.core3D.baseEuler[2]=0))}setCameraPreset(e,t=1e3){this.core3D?.renderer?.setCameraPreset&&this.core3D.renderer.setCameraPreset(e,t)}get autoRotateEnabled(){return!1===this.core3D?.rotationDisabled}enableParticles(){if(this.core3D?.particleOrchestrator?.renderer&&(this.core3D.particleVisibility=!0,this.core3D.particleOrchestrator.renderer.setVisible(!0),this.core3D.particleOrchestrator.setEmotion(this.core3D.emotion,this.core3D.undertone)),!this.core3D?.particleOrchestrator&&!this.particleSystem&&this.canvas2D){const e=this.config.maxParticles||300;this.particleSystem=new hi(e,this.errorBoundary),this.particleSystem.canvasWidth=this.canvas2D.width,this.particleSystem.canvasHeight=this.canvas2D.height}}disableParticles(){this.core3D?.particleOrchestrator?.renderer&&(this.core3D.particleVisibility=!1,this.core3D.particleOrchestrator.renderer.setVisible(!1),this.core3D.particleOrchestrator.clear()),this.core3D?.particleOrchestrator||this.particleSystem&&(this.particleSystem.destroy(),this.particleSystem=null)}get particlesEnabled(){return this.core3D?.particleOrchestrator?!0===this.core3D.particleVisibility:null!==this.particleSystem}enableBlinking(){this.core3D&&(this.core3D.blinkingManuallyDisabled=!1,this.core3D.blinkAnimator&&this.core3D.blinkAnimator.resume())}disableBlinking(){this.core3D&&(this.core3D.blinkingManuallyDisabled=!0,this.core3D.blinkAnimator&&this.core3D.blinkAnimator.pause())}get blinkingEnabled(){return!(!this.core3D||!this.core3D.blinkAnimator)&&this.core3D.blinkAnimator.enabled}enableBreathing(){this.core3D&&(this.core3D.breathingEnabled=!0)}disableBreathing(){this.core3D&&(this.core3D.breathingEnabled=!1)}get breathingEnabled(){return!this.core3D||!1!==this.core3D.breathingEnabled}breathePhase(e,t){this.core3D&&this.core3D.breathePhase(e,t)}stopBreathingPhase(){this.core3D&&this.core3D.stopBreathingPhase()}enableWobble(){this.core3D&&this.core3D.setWobbleEnabled(!0)}disableWobble(){this.core3D&&this.core3D.setWobbleEnabled(!1)}get wobbleEnabled(){return!this.core3D||!1!==this.core3D.wobbleEnabled}enableRhythmSync(){this.core3D&&this.core3D.setRhythmEnabled(!0)}disableRhythmSync(){this.core3D&&this.core3D.setRhythmEnabled(!1)}get rhythmSyncEnabled(){return!!this.core3D&&this.core3D.rhythmEnabled}enableGroove(){this.core3D&&this.core3D.setGrooveEnabled(!0)}disableGroove(){this.core3D&&this.core3D.setGrooveEnabled(!1)}setBeatSyncStrength(e){this.core3D&&this.core3D.setBeatSyncStrength(e)}setGrooveConfig(e){this.core3D&&this.core3D.setGrooveConfig(e)}isRhythmPlaying(){return this.core3D?.isRhythmPlaying()||!1}getRhythmBPM(){return this.core3D?.getRhythmBPM()||120}startRhythm(e=120,t="straight"){this.core3D&&this.core3D.startRhythm(e,t)}stopRhythm(){this.core3D&&this.core3D.stopRhythm()}setRhythmBPM(e){this.core3D&&this.core3D.setRhythmBPM(e)}setRhythmPattern(e){this.core3D&&this.core3D.setRhythmPattern(e)}async connectAudio(e){if(!e)return;this._audioElement=e,this._audioContext||(this._audioContext=new(window.AudioContext||window.webkitAudioContext)),"suspended"===this._audioContext.state&&await this._audioContext.resume(),this._analyzerNode||(this._analyzerNode=this._audioContext.createAnalyser(),this._analyzerNode.fftSize=256,this._analyzerNode.smoothingTimeConstant=.8),this._audioSourceNode||(this._audioSourceNode=this._audioContext.createMediaElementSource(e),this._audioSourceNode.connect(this._analyzerNode),this._analyzerNode.connect(this._audioContext.destination));const t=()=>{const e=this._detectedBPM||120;this.startRhythm(e,"straight")},i=()=>{this.stopRhythm()},n=()=>{this.stopRhythm()};this._audioHandlers={onPlay:t,onPause:i,onEnded:n},e.addEventListener("play",t),e.addEventListener("pause",i),e.addEventListener("ended",n),e.paused||t(),this._startBPMDetection()}disconnectAudio(){this.stopRhythm(),this._audioElement&&this._audioHandlers&&(this._audioElement.removeEventListener("play",this._audioHandlers.onPlay),this._audioElement.removeEventListener("pause",this._audioHandlers.onPause),this._audioElement.removeEventListener("ended",this._audioHandlers.onEnded)),this._stopBPMDetection(),this._audioElement=null,this._audioHandlers=null}_startBPMDetection(){if(this._bpmDetectionInterval)return;const e=this._analyzerNode?.frequencyBinCount||128,t=new Uint8Array(e);let i=0;const n=[];this._bpmDetectionInterval=setInterval(()=>{if(!this._analyzerNode||!this._audioElement||this._audioElement.paused)return;this._analyzerNode.getByteFrequencyData(t);let e=0;for(let i=0;i<8;i++)e+=t[i];e/=8;const a=performance.now();if(e>180&&a-i>200){if(i>0){const e=a-i;if(n.push(e),n.length>8&&n.shift(),n.length>=4){const e=n.reduce((e,t)=>e+t,0)/n.length,t=Math.round(6e4/e);t>=60&&t<=180&&(this._detectedBPM=t,this.isRhythmPlaying()&&this.setRhythmBPM(t))}}i=a}},50)}_stopBPMDetection(){this._bpmDetectionInterval&&(clearInterval(this._bpmDetectionInterval),this._bpmDetectionInterval=null)}rgbToHex(e){return`#${[Math.round(255*e[0]),Math.round(255*e[1]),Math.round(255*e[2])].map(e=>{const t=e.toString(16);return 1===t.length?`0${t}`:t}).join("")}`}setPosition(e,t,i=0){if(!this.container)return;this.position={x:e,y:t,z:i};const n=window.innerWidth<768;this.container.style.transform=n?`translate(calc(-50% + ${e}px), calc(-50% + ${t}px))`:`translate(${e}px, calc(-50% + ${t}px))`}getPosition(){return this.position||{x:0,y:0,z:0}}animateToPosition(e,t,i=0,n=1e3,a="easeOutCubic"){if(!this.container)return;const s=this.getPosition(),o=performance.now(),r=a=>{const l=a-o,h=Math.min(l/n,1),c=(u=h,1-Math.pow(1-u,3));var u;const d=s.x+(e-s.x)*c,m=s.y+(t-s.y)*c,p=s.z+(i-s.z)*c;this.setPosition(d,m,p),h<1&&requestAnimationFrame(r)};requestAnimationFrame(r)}setContainment(e,t=1){if(this._containmentBounds=e,this._containmentScale=t,this.particleSystem&&1!==t){const e=this.config.particleSpawnRadius||150;this.particleSystem.setSpawnRadius(e*t)}return this}attachToElement(e,t={}){const i="string"==typeof e?document.querySelector(e):e;if(!i)return console.error(`[EmotiveMascot3D] Element not found: ${e}`),this;this._attachedElement=i,this._attachOptions={offsetX:t.offsetX||0,offsetY:t.offsetY||0,animate:!1!==t.animate,duration:t.duration||1e3,scale:t.scale||1,containParticles:!1!==t.containParticles},this._hasAttachedBefore=this._hasAttachedBefore||!1;const n=i.getBoundingClientRect();return this._attachOptions.containParticles?this.setContainment({width:n.width,height:n.height},this._attachOptions.scale):1!==this._attachOptions.scale&&this.setContainment(null,this._attachOptions.scale),this._updateAttachedPosition(),this._setupElementTracking(),this}_updateAttachedPosition(){if(!this._attachedElement||!this.container)return;const e=this._attachedElement.getBoundingClientRect(),t=window.innerWidth<768,i=e.left+e.width/2,n=e.top+e.height/2;let a,s;if(t)a=window.innerWidth/2,s=.18*window.innerHeight;else{const e=750;a=Math.max(20,(window.innerWidth/2-500)/2-375)+e/2,s=window.innerHeight/2}const o=i-a+this._attachOptions.offsetX,r=n-s+this._attachOptions.offsetY,l=!this._hasAttachedBefore;this._hasAttachedBefore=!0,l&&this._attachOptions.animate?this.animateToPosition(o,r,0,this._attachOptions.duration):this.setPosition(o,r,0)}_setupElementTracking(){this._elementTrackingHandlers||(this._elementTrackingHandlers={scroll:()=>this._updateAttachedPosition(),resize:()=>this._updateAttachedPosition()},window.addEventListener("scroll",this._elementTrackingHandlers.scroll,{passive:!0}),window.addEventListener("resize",this._elementTrackingHandlers.resize))}isAttachedToElement(){return!!this._attachedElement}detachFromElement(){return this._attachedElement=null,this._hasAttachedBefore=!1,this._elementTrackingHandlers&&(window.removeEventListener("scroll",this._elementTrackingHandlers.scroll),window.removeEventListener("resize",this._elementTrackingHandlers.resize),this._elementTrackingHandlers=null),this.setContainment(null,1),this.setEmotion("neutral"),this}setSSSPreset(e){this._currentSSSPreset=e,this.core3D&&!this._materialSwapCallbackSet&&(this._materialSwapCallbackSet=!0,this.core3D.onMaterialSwap=e=>{this._currentSSSPreset&&setTimeout(()=>{ji(this,this._currentSSSPreset)},50)});const t=ji(this,e);return t&&this.eventManager.emit("sss:presetChanged",{preset:e}),t}setGeometry(e,t={}){this.morphTo(e,t)}startSolarEclipse(e={}){this.core3D&&"function"==typeof this.core3D.startSolarEclipse?this.core3D.startSolarEclipse(e):(this.morphTo("sun"),this.eventManager.emit("eclipse:solar:start",{type:e.type||"total"}))}startLunarEclipse(e={}){this.core3D&&"function"==typeof this.core3D.startLunarEclipse?this.core3D.startLunarEclipse(e):(this.morphTo("moon"),this.eventManager.emit("eclipse:lunar:start",{type:e.type||"total"}))}stopEclipse(){this.core3D&&"function"==typeof this.core3D.stopEclipse&&this.core3D.stopEclipse(),this.eventManager&&this.eventManager.emit("eclipse:stop")}destroy(){this._destroyed=!0,this.stop(),this.disconnectAudio(),this._audioContext&&(this._audioContext.close(),this._audioContext=null),this._analyzerNode=null,this._audioSourceNode=null,this._elementTrackingHandlers&&(window.removeEventListener("scroll",this._elementTrackingHandlers.scroll),window.removeEventListener("resize",this._elementTrackingHandlers.resize),this._elementTrackingHandlers=null),this._attachedElement=null,this.gestureTimeouts.forEach(e=>clearTimeout(e)),this.gestureTimeouts=[],this.eventManager&&this.eventManager._listeners&&(Object.keys(this.eventManager._listeners).forEach(e=>{this.eventManager._listeners[e]=[]}),this.eventManager._listeners=null),this.core3D&&this.core3D.destroy(),this.particleSystem&&this.particleSystem.destroy(),this.webglCanvas&&this.webglCanvas.parentNode&&this.webglCanvas.parentNode.removeChild(this.webglCanvas),this.canvas2D&&this.canvas2D.parentNode&&this.canvas2D.parentNode.removeChild(this.canvas2D),this.container=null,this.webglCanvas=null,this.canvas2D=null,this.ctx2D=null,this.config=null,this.errorBoundary=null,this.currentGesture=null}}export{vn as CORE_GEOMETRIES,Gi as Core3DManager,wn as EmotiveMascot3D,Li as GeometryCache,I as MOON_PHASES,be as Rhythm3DAdapter,Ni as SSSPresets,q as animateMoonPhase,ji as applySSSPreset,x as blendModeNames,fn as createCrystal,yn as createDiamond,z as createMoon,G as createMoonCrescentMaterial,F as createMoonFallbackMaterial,O as createMoonMaterial,gn as createSphere,Y as createSunGeometry,X as createSunMaterial,wn as default,bn as disposeCoreGeometries,_ as disposeMoon,Q as disposeSun,D as getBlendModeIndex,C as getBlendModeName,A as getMoonPhaseNames,R as getPhaseFromProgress,Hi as getSSSPreset,Ui as getSSSPresetNames,we as rhythm3DAdapter,V as setMoonPhase,j as updateCrescentShadow,N as updateMoonGlow,$ as updateSunMaterial};
1
+ import*as e from"three";import{Vector2 as t,WebGLRenderTarget as i,HalfFloatType as n,RGBAFormat as a,LinearFilter as s,ShaderMaterial as o,Vector3 as r,AdditiveBlending as l,Color as h,MeshBasicMaterial as c}from"three";import{EffectComposer as u}from"three/examples/jsm/postprocessing/EffectComposer.js";import{RenderPass as d}from"three/examples/jsm/postprocessing/RenderPass.js";import{Pass as m,FullScreenQuad as p}from"three/examples/jsm/postprocessing/Pass.js";import{OrbitControls as g}from"three/examples/jsm/controls/OrbitControls.js";import{OBJLoader as f}from"three/examples/jsm/loaders/OBJLoader.js";new t(.5,.5),new t(.5,.5);class y extends m{constructor(e,u,d,m){super(),this.strength=void 0!==u?u:1,this.radius=d,this.threshold=m,this.resolution=void 0!==e?new t(e.x,e.y):new t(256,256);const g={minFilter:s,magFilter:s,format:a,type:n};this.renderTargetsHorizontal=[],this.renderTargetsVertical=[],this.nMips=5;let f=Math.round(.75*this.resolution.x),y=Math.round(.75*this.resolution.y);this.renderTargetBright=new i(f,y,g),this.renderTargetBright.texture.name="UnrealBloomPassAlpha.bright",this.renderTargetBright.texture.generateMipmaps=!1;for(let e=0;e<this.nMips;e++){const t=new i(f,y,g);t.texture.name=`UnrealBloomPassAlpha.h${e}`,t.texture.generateMipmaps=!1,this.renderTargetsHorizontal.push(t);const n=new i(f,y,g);n.texture.name=`UnrealBloomPassAlpha.v${e}`,n.texture.generateMipmaps=!1,this.renderTargetsVertical.push(n),f=Math.round(f/2),y=Math.round(y/2)}this.highPassUniforms={tDiffuse:{value:null},luminosityThreshold:{value:m},smoothWidth:{value:.01}},this.materialHighPassFilter=new o({uniforms:this.highPassUniforms,vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }",fragmentShader:"\n uniform sampler2D tDiffuse;\n uniform float luminosityThreshold;\n uniform float smoothWidth;\n varying vec2 vUv;\n\n void main() {\n vec4 texel = texture2D(tDiffuse, vUv);\n vec3 luma = vec3(0.299, 0.587, 0.114);\n float v = dot(texel.xyz, luma);\n float alpha = smoothstep(luminosityThreshold, luminosityThreshold + smoothWidth, v);\n\n // CRITICAL: Preserve original alpha, only filter by luminosity\n gl_FragColor = vec4(texel.rgb * alpha, texel.a);\n }"}),this.separableBlurMaterials=[];const v=[3,5,7,9,11];f=Math.round(.75*this.resolution.x),y=Math.round(.75*this.resolution.y);for(let e=0;e<this.nMips;e++)this.separableBlurMaterials.push(this.getSeperableBlurMaterial(v[e])),this.separableBlurMaterials[e].uniforms.texSize.value=new t(f,y),f=Math.round(f/2),y=Math.round(y/2);this.compositeMaterial=this.getCompositeMaterial(this.nMips),this.compositeMaterial.uniforms.blurTexture1.value=this.renderTargetsVertical[0].texture,this.compositeMaterial.uniforms.blurTexture2.value=this.renderTargetsVertical[1].texture,this.compositeMaterial.uniforms.blurTexture3.value=this.renderTargetsVertical[2].texture,this.compositeMaterial.uniforms.blurTexture4.value=this.renderTargetsVertical[3].texture,this.compositeMaterial.uniforms.blurTexture5.value=this.renderTargetsVertical[4].texture,this.compositeMaterial.uniforms.bloomStrength.value=u,this.compositeMaterial.uniforms.bloomRadius.value=.1,this.compositeMaterial.uniforms.bloomFactors.value=[1,.8,.6,.4,.2],this.bloomTintColors=[new r(1,1,1),new r(1,1,1),new r(1,1,1),new r(1,1,1),new r(1,1,1)],this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,this.materialCopy=new o({uniforms:{tDiffuse:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }",fragmentShader:"\n uniform sampler2D tDiffuse;\n varying vec2 vUv;\n void main() {\n gl_FragColor = texture2D(tDiffuse, vUv);\n }",blending:l,depthTest:!1,depthWrite:!1,transparent:!0}),this.enabled=!0,this.needsSwap=!1,this._oldClearColor=new h,this.oldClearAlpha=1,this.clearColor=new h(0,0,0),this.basic=new c({transparent:!0,depthTest:!1,depthWrite:!1}),this.fsQuad=new p(null)}dispose(){if(this.renderTargetsHorizontal)for(let e=0;e<this.renderTargetsHorizontal.length;e++)this.renderTargetsHorizontal[e]?.dispose();if(this.renderTargetsVertical)for(let e=0;e<this.renderTargetsVertical.length;e++)this.renderTargetsVertical[e]?.dispose();if(this.renderTargetBright?.dispose(),this.separableBlurMaterials)for(let e=0;e<this.separableBlurMaterials.length;e++)this.separableBlurMaterials[e]?.dispose();this.compositeMaterial?.dispose(),this.blendMaterial?.dispose(),this.basic?.dispose(),this.fsQuad?.dispose()}clearBloomBuffers(e){const t=e.getRenderTarget(),i=e.getClearColor(this._oldClearColor),n=e.getClearAlpha();e.setClearColor(0,0),e.setRenderTarget(this.renderTargetBright),e.clear();for(let t=0;t<this.renderTargetsHorizontal.length;t++)e.setRenderTarget(this.renderTargetsHorizontal[t]),e.clear();for(let t=0;t<this.renderTargetsVertical.length;t++)e.setRenderTarget(this.renderTargetsVertical[t]),e.clear();e.setRenderTarget(t),e.setClearColor(i,n)}setSize(e,i){let n=Math.round(.75*e),a=Math.round(.75*i);this.renderTargetBright.setSize(n,a);for(let e=0;e<this.nMips;e++)this.renderTargetsHorizontal[e].setSize(n,a),this.renderTargetsVertical[e].setSize(n,a),this.separableBlurMaterials[e].uniforms.texSize.value=new t(n,a),n=Math.round(n/2),a=Math.round(a/2)}render(e,t,i,n,a){e.getClearColor(this._oldClearColor),this.oldClearAlpha=e.getClearAlpha();const s=e.autoClear;e.autoClear=!1,e.setClearColor(this.clearColor,0),a&&e.state.buffers.stencil.setTest(!1),this.renderToScreen&&!this.skipBaseCopy&&(this.fsQuad.material=this.basic,this.basic.map=i.texture,e.setRenderTarget(null),this.fsQuad.render(e)),this.highPassUniforms.tDiffuse.value=i.texture,this.highPassUniforms.luminosityThreshold.value=this.threshold,this.fsQuad.material=this.materialHighPassFilter,e.setRenderTarget(this.renderTargetBright),e.clear(),this.fsQuad.render(e);let o=this.renderTargetBright;for(let t=0;t<this.nMips;t++)this.fsQuad.material=this.separableBlurMaterials[t],this.separableBlurMaterials[t].uniforms.colorTexture.value=o.texture,this.separableBlurMaterials[t].uniforms.direction.value=y.BlurDirectionX,e.setRenderTarget(this.renderTargetsHorizontal[t]),e.clear(),this.fsQuad.render(e),this.separableBlurMaterials[t].uniforms.colorTexture.value=this.renderTargetsHorizontal[t].texture,this.separableBlurMaterials[t].uniforms.direction.value=y.BlurDirectionY,e.setRenderTarget(this.renderTargetsVertical[t]),e.clear(),this.fsQuad.render(e),o=this.renderTargetsVertical[t];this.fsQuad.material=this.compositeMaterial,this.compositeMaterial.uniforms.bloomStrength.value=this.strength,this.compositeMaterial.uniforms.bloomRadius.value=this.radius,this.compositeMaterial.uniforms.bloomTintColors.value=this.bloomTintColors,e.setRenderTarget(this.renderTargetsHorizontal[0]),e.clear(),this.fsQuad.render(e),this.fsQuad.material=this.materialCopy,this.materialCopy.uniforms.tDiffuse.value=this.renderTargetsHorizontal[0].texture,a&&e.state.buffers.stencil.setTest(!0),this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(i),this.fsQuad.render(e)),e.setClearColor(this._oldClearColor,this.oldClearAlpha),e.autoClear=s}getSeperableBlurMaterial(e){return new o({defines:{MAX_RADIUS:e},uniforms:{colorTexture:{value:null},texSize:{value:new t(.5,.5)},direction:{value:new t(.5,.5)},kernelRadius:{value:1}},vertexShader:"\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n #include <common>\n varying vec2 vUv;\n uniform sampler2D colorTexture;\n uniform vec2 texSize;\n uniform vec2 direction;\n uniform float kernelRadius;\n\n float gaussianPdf(in float x, in float sigma) {\n return 0.39894 * exp( -0.5 * x * x / ( sigma * sigma ) ) / sigma;\n }\n\n void main() {\n vec2 invSize = 1.0 / texSize;\n float sigma = kernelRadius / 2.0;\n float weightSum = gaussianPdf(0.0, sigma);\n\n // CRITICAL: Accumulate RGB and alpha SEPARATELY\n // Include center pixel for BOTH RGB and alpha\n vec4 centerPixel = texture2D(colorTexture, vUv);\n vec3 diffuseSum = centerPixel.rgb * weightSum;\n float alphaSum = centerPixel.a * weightSum;\n\n vec2 delta = direction * invSize * kernelRadius / float(MAX_RADIUS);\n\n for( int i = 1; i < MAX_RADIUS; i ++ ) {\n float x = kernelRadius * float(i) / float(MAX_RADIUS);\n float w = gaussianPdf(x, sigma);\n\n vec2 uvOffset = delta * float(i);\n vec4 sample1 = texture2D(colorTexture, vUv + uvOffset);\n vec4 sample2 = texture2D(colorTexture, vUv - uvOffset);\n\n // Accumulate RGB and alpha separately\n diffuseSum += (sample1.rgb + sample2.rgb) * w;\n alphaSum += (sample1.a + sample2.a) * w;\n weightSum += 2.0 * w;\n }\n\n // Output with separately normalized alpha\n gl_FragColor = vec4(diffuseSum / weightSum, alphaSum / weightSum);\n }"})}getCompositeMaterial(e){return new o({uniforms:{blurTexture1:{value:null},blurTexture2:{value:null},blurTexture3:{value:null},blurTexture4:{value:null},blurTexture5:{value:null},bloomStrength:{value:1},bloomFactors:{value:null},bloomTintColors:{value:null},bloomRadius:{value:0}},vertexShader:"\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n }",fragmentShader:"\n varying vec2 vUv;\n uniform sampler2D blurTexture1;\n uniform sampler2D blurTexture2;\n uniform sampler2D blurTexture3;\n uniform sampler2D blurTexture4;\n uniform sampler2D blurTexture5;\n uniform float bloomStrength;\n uniform float bloomRadius;\n uniform float bloomFactors[5];\n uniform vec3 bloomTintColors[5];\n\n float lerpBloomFactor(const in float factor) {\n float mirrorFactor = 1.2 - factor;\n return mix(factor, mirrorFactor, bloomRadius);\n }\n\n void main() {\n // ALPHA PRESERVATION: Sample all textures and preserve their alpha\n vec4 sample1 = texture2D(blurTexture1, vUv);\n vec4 sample2 = texture2D(blurTexture2, vUv);\n vec4 sample3 = texture2D(blurTexture3, vUv);\n vec4 sample4 = texture2D(blurTexture4, vUv);\n vec4 sample5 = texture2D(blurTexture5, vUv);\n\n // Apply tint to RGB only, preserve alpha from samples\n vec4 color = bloomStrength * (\n lerpBloomFactor(bloomFactors[0]) * vec4(sample1.rgb * bloomTintColors[0], sample1.a) +\n lerpBloomFactor(bloomFactors[1]) * vec4(sample2.rgb * bloomTintColors[1], sample2.a) +\n lerpBloomFactor(bloomFactors[2]) * vec4(sample3.rgb * bloomTintColors[2], sample3.a) +\n lerpBloomFactor(bloomFactors[3]) * vec4(sample4.rgb * bloomTintColors[3], sample4.a) +\n lerpBloomFactor(bloomFactors[4]) * vec4(sample5.rgb * bloomTintColors[4], sample5.a)\n );\n\n gl_FragColor = color;\n }"})}}function v(e,t=.5){const[i,n,a]=e,s=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),o=s(i),r=s(n),l=s(a),h=.2126*o+.7152*r+.0722*l,c=t/Math.max(h,.001);let u=o*c,d=r*c,m=l*c;const p=Math.max(u,d,m);p>1&&(u/=p,d/=p,m/=p);const g=e=>e<=.0031308?12.92*e:1.055*Math.pow(e,1/2.4)-.055;return{r:Math.min(1,Math.max(0,g(u))),g:Math.min(1,Math.max(0,g(d))),b:Math.min(1,Math.max(0,g(m)))}}function b(e,t=0,i="glow"){const n=function(e){const t=parseInt(e.slice(1,3),16)/255,i=parseInt(e.slice(3,5),16)/255,n=parseInt(e.slice(5,7),16)/255,a=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);return.2126*a(t)+.7152*a(i)+.0722*a(n)}(e),a=(.5+t)/Math.max(n,.05);return Math.max(.3,Math.min(10,a))}y.BlurDirectionX=new t(1,0),y.BlurDirectionY=new t(0,1);class w{constructor(t){this.renderer=t,this.glowAmount=0,this.targetGlowAmount=0,this.glowColor=new e.Color(1,1,1),this.targetGlowColor=new e.Color(1,1,1),this.worldPosition=new e.Vector3(0,0,0),this.time=0,this.ringPhase=0,this.scene=new e.Scene,this.camera=new e.OrthographicCamera(-1,1,1,-1,.1,10),this.camera.position.z=1,this.createGlowMesh(),this._tempVector=new e.Vector3,this._tempColor=new e.Color}createGlowMesh(){const t=new e.PlaneGeometry(2,2),i=new e.ShaderMaterial({uniforms:{glowAmount:{value:0},glowColor:{value:new e.Color(1,1,1)},centerUV:{value:new e.Vector2(.5,.5)},time:{value:0},ringPhase:{value:0},aspectRatio:{value:1}},vertexShader:"\n varying vec2 vUv;\n\n void main() {\n vUv = uv;\n gl_Position = vec4(position.xy, 0.0, 1.0);\n }\n ",fragmentShader:"\n uniform float glowAmount;\n uniform vec3 glowColor;\n uniform vec2 centerUV;\n uniform float time;\n uniform float ringPhase;\n uniform float aspectRatio;\n\n varying vec2 vUv;\n\n void main() {\n // Aspect-correct UV coordinates - apply aspect to Y instead\n // This prevents horizontal clipping on wide screens\n vec2 centeredUV = vUv - centerUV;\n // Don't multiply by aspect - let glow be circular in screen space\n\n float dist = length(centeredUV);\n\n // Ring parameters that evolve with ringPhase\n // MUCH LARGER radii to prevent clipping - glow can extend to screen edges\n // At ringPhase=0: tight ring close to center\n // At ringPhase=1: expanded ring that can fill most of screen\n float innerRadius = mix(0.02, 0.08, ringPhase);\n float outerRadius = mix(0.15, 1.2, ringPhase); // Can extend beyond screen!\n float peakRadius = mix(0.06, 0.25, ringPhase);\n\n // Create soft ring falloff\n // Inner falloff: 0 at center, 1 at peak\n float innerFalloff = smoothstep(innerRadius * 0.3, peakRadius, dist);\n\n // Outer falloff: 1 at peak, 0 at outer edge (very gradual fade)\n float outerFalloff = 1.0 - smoothstep(peakRadius, outerRadius, dist);\n\n // Combine for ring shape\n float ringIntensity = innerFalloff * outerFalloff;\n\n // Add subtle shimmer/undulation\n float shimmer = 0.9 + 0.1 * sin(time * 3.0 + dist * 20.0);\n\n // Final intensity with glow amount control\n float intensity = ringIntensity * glowAmount * shimmer;\n\n // Soft glow color with intensity\n // Use HDR values (>1.0) for bloom pickup\n vec3 color = glowColor * intensity * 2.0;\n\n // Alpha for blending\n float alpha = intensity * 0.6;\n\n gl_FragColor = vec4(color, alpha);\n }\n ",transparent:!0,blending:e.AdditiveBlending,depthTest:!1,depthWrite:!1});this.glowMesh=new e.Mesh(t,i),this.scene.add(this.glowMesh)}setGlow(e,t,i){this.targetGlowAmount=Math.max(0,e),t&&(Array.isArray(t)?this.targetGlowColor.setRGB(t[0],t[1],t[2]):this.targetGlowColor.copy(t)),i&&this.worldPosition.copy(i)}update(e,t){const i=e/1e3;this.time+=i,this.glowAmount+=(this.targetGlowAmount-this.glowAmount)*Math.min(1,8*i),this.glowColor.lerp(this.targetGlowColor,Math.min(1,8*i));const n=Math.min(1,this.glowAmount);if(this.ringPhase+=(n-this.ringPhase)*Math.min(1,4*i),t){this._tempVector.copy(this.worldPosition),this._tempVector.project(t);const e=(this._tempVector.x+1)/2,i=(this._tempVector.y+1)/2;this.glowMesh.material.uniforms.centerUV.value.set(e,i)}this.glowMesh.material.uniforms.glowAmount.value=this.glowAmount,this.glowMesh.material.uniforms.glowColor.value.copy(this.glowColor),this.glowMesh.material.uniforms.time.value=this.time,this.glowMesh.material.uniforms.ringPhase.value=this.ringPhase;const a=this.renderer.domElement;this.glowMesh.material.uniforms.aspectRatio.value=a.width/a.height}render(e){if(this.glowAmount<.001)return;const{autoClear:t}=e;e.autoClear=!1,e.render(this.scene,this.camera),e.autoClear=t}isActive(){return this.glowAmount>.001||this.targetGlowAmount>0}dispose(){this.glowMesh&&(this.glowMesh.geometry.dispose(),this.glowMesh.material.dispose(),this.scene.remove(this.glowMesh),this.glowMesh=null),this.scene=null,this.camera=null,this._tempVector=null,this._tempColor=null}}class M{constructor(t,i={}){this.canvas=t,this.options=i,this._destroyed=!1,this.scene=new e.Scene,this.scene.background=null,this.renderer=new e.WebGLRenderer({canvas:t,alpha:!0,premultipliedAlpha:!1,antialias:!0,powerPreference:"high-performance",preserveDrawingBuffer:!1,precision:"highp",logarithmicDepthBuffer:!1,stencil:!1}),this.renderer.outputColorSpace=e.SRGBColorSpace,this.renderer.toneMapping=e.NoToneMapping,this.renderer.toneMappingExposure=1,this.renderer.setClearColor(0,0),this.renderer.autoClear=!1,this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,1.5)),this.renderer.setSize(t.width,t.height,!1),i.enableShadows&&(this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=e.PCFSoftShadowMap),this._contextLost=!1,this._boundHandleContextLost=this.handleContextLost.bind(this),this._boundHandleContextRestored=this.handleContextRestored.bind(this),t.addEventListener("webglcontextlost",this._boundHandleContextLost,!1),t.addEventListener("webglcontextrestored",this._boundHandleContextRestored,!1);const n=void 0!==i.fov?i.fov:45;this.camera=new e.PerspectiveCamera(n,t.width/t.height,.1,100),this.cameraDistance=void 0!==i.cameraDistance?i.cameraDistance:3,this.camera.position.set(0,0,this.cameraDistance),this.camera.lookAt(0,0,0),!1!==i.enableControls&&this.setupCameraControls(),this.setupLights(),!1!==i.enablePostProcessing&&this.setupPostProcessing(),this.coreMesh=null,this.materialMode="glow",this.glowMaterial=null,this.glassMaterial=null,this.mixer=null,this.clock=new e.Clock,this._tempColor=new e.Color,this._tempColor2=new e.Color,this._white=new e.Color(1,1,1),this._tempQuat=new e.Quaternion,this._tempEuler=new e.Euler,this._quatX=new e.Quaternion,this._quatY=new e.Quaternion,this._quatZ=new e.Quaternion,this._rollQuat=new e.Quaternion,this._meshQuat=new e.Quaternion,this._xAxis=new e.Vector3(1,0,0),this._yAxis=new e.Vector3(0,1,0),this._zAxis=new e.Vector3(0,0,1),this._cameraToMesh=new e.Vector3,this._cameraDir=new e.Vector3}setupCameraControls(){this.controls=new g(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.1;const e=void 0!==this.options.minZoom?this.options.minZoom:.5*this.cameraDistance,t=void 0!==this.options.maxZoom?this.options.maxZoom:2*this.cameraDistance;this.controls.minDistance=e,this.controls.maxDistance=t,this.controls.enablePan=!1,this.controls.autoRotate=!0===this.options.autoRotate,this.controls.autoRotateSpeed=void 0!==this.options.autoRotateSpeed?this.options.autoRotateSpeed:.5,this.controls.minPolarAngle=.2*Math.PI,this.controls.maxPolarAngle=.8*Math.PI,this.controls.rotateSpeed=.8,this.controls.zoomSpeed=1.5,("ontouchstart"in window||navigator.maxTouchPoints>0)&&(this.controls.rotateSpeed=1,this.controls.zoomSpeed=1.2),this.renderer.domElement.style.touchAction="none";const i=()=>{this.controls&&this.controls.update()};this.renderer.domElement.addEventListener("pointermove",i,{passive:!0}),this.renderer.domElement.addEventListener("pointerdown",i,{passive:!0})}setupLights(){this.ambientLight=new e.AmbientLight(16777215,.3),this.ambientLight.name="ambientLight",this.scene.add(this.ambientLight),this.keyLight=new e.DirectionalLight(16777215,.8),this.keyLight.position.set(2,2,2),this.keyLight.name="keyLight",this.options.enableShadows&&(this.keyLight.castShadow=!0,this.keyLight.shadow.mapSize.width=1024,this.keyLight.shadow.mapSize.height=1024,this.keyLight.shadow.camera.near=.5,this.keyLight.shadow.camera.far=10),this.scene.add(this.keyLight),this.fillLight=new e.DirectionalLight(16777215,.5),this.fillLight.position.set(-2,1,1),this.fillLight.name="fillLight",this.scene.add(this.fillLight),this.rimLight=new e.DirectionalLight(16777215,.7),this.rimLight.position.set(0,1,-2),this.rimLight.name="rimLight",this.scene.add(this.rimLight),this.accentLight1=new e.PointLight(54527,.3,10),this.accentLight1.position.set(-3,0,1),this.accentLight1.name="accentLight1",this.scene.add(this.accentLight1),this.accentLight2=new e.PointLight(16716947,.2,10),this.accentLight2.position.set(3,0,1),this.accentLight2.name="accentLight2",this.scene.add(this.accentLight2),this.accentLight3=new e.PointLight(16739125,.2,10),this.accentLight3.position.set(0,3,-1),this.accentLight3.name="accentLight3",this.scene.add(this.accentLight3),this.createEnvironmentMap()}async createEnvironmentMap(){if(this._destroyed)return;try{const{HDRLoader:t}=await import("three/examples/jsm/loaders/HDRLoader.js");if(this._destroyed)return;const i=new e.PMREMGenerator(this.renderer);i.compileEquirectangularShader();try{const n=new t,a=(this.options.assetBasePath||"/assets").replace("/assets",""),s=await n.loadAsync(`${a}/hdri/studio_1k.hdr`);if(!s||!s.image)throw new Error("HDR texture loaded but image data is missing");return this._destroyed?(s.dispose(),void i.dispose()):(s.mapping=e.EquirectangularReflectionMapping,this.envMap=i.fromEquirectangular(s).texture,s.dispose(),i.dispose(),void console.log("[Emotive] HDRI environment map loaded"))}catch(e){i.dispose()}}catch(e){}if(this._destroyed)return;const t=new e.WebGLCubeRenderTarget(512),i=new e.Scene,n=new e.Color(5609983),a=new e.Color(16739229),s=new e.Color(1710638),o=new e.HemisphereLight(n,s,1.5);i.add(o);const r=new e.PointLight(54527,2,20);r.position.set(-5,2,-5),i.add(r);const l=new e.PointLight(16716947,2,20);l.position.set(5,2,-5),i.add(l);const h=new e.PointLight(16755200,1.5,20);h.position.set(0,5,0),i.add(h),i.background=a;const c=new e.CubeCamera(.1,100,t);c.update(this.renderer,i),this.envMap=t.texture,this._envCubeRenderTarget=t,this._envScene=i,this._envCubeCamera=c}setupPostProcessing(){const t=new e.Vector2;this.renderer.getDrawingBufferSize(t);const i=new e.WebGLRenderTarget(t.x,t.y,{format:e.RGBAFormat,type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,stencilBuffer:!1,depthBuffer:!0});this.composer=new u(this.renderer,i);const n=new d(this.scene,this.camera);n.clearColor=new e.Color(0),n.clearAlpha=0,this.composer.addPass(n);const a="ontouchstart"in window||navigator.maxTouchPoints>0?.5:1,s=new e.Vector2(Math.floor(t.x*a),Math.floor(t.y*a));this.bloomPass=new y(s,1.2,.8,.3),this.bloomPass.name="bloomPass",this.bloomPass.enabled=!0,this.bloomPass.renderToScreen=!0,this.composer.addPass(this.bloomPass),this.particleRenderTarget=new e.WebGLRenderTarget(t.x,t.y,{format:e.RGBAFormat,type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,stencilBuffer:!1,depthBuffer:!0}),this.particleBloomPass=new y(s,.5,.4,.3),this.particleBloomPass.name="particleBloomPass",this.particleBloomPass.enabled=!0,this.particleBloomPass.clearColor=new e.Color(1,1,1),this.particleBloomPass.skipBaseCopy=!0,this.soulRenderTarget=new e.WebGLRenderTarget(t.x,t.y,{format:e.RGBAFormat,type:e.HalfFloatType,minFilter:e.LinearFilter,magFilter:e.LinearFilter,stencilBuffer:!1,depthBuffer:!0}),this.particleCompositeShader={uniforms:{tDiffuse:{value:null},tParticles:{value:null}},vertexShader:"\n varying vec2 vUv;\n void main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",fragmentShader:"\n uniform sampler2D tDiffuse;\n uniform sampler2D tParticles;\n varying vec2 vUv;\n\n void main() {\n vec4 base = texture2D(tDiffuse, vUv);\n vec4 particles = texture2D(tParticles, vUv);\n\n // Alpha-preserving composite: particles over base\n // Use particle alpha to blend\n vec3 blended = mix(base.rgb, particles.rgb, particles.a);\n float alpha = base.a + particles.a * (1.0 - base.a);\n\n gl_FragColor = vec4(blended, alpha);\n }\n "},this.glowLayer=new w(this.renderer)}handleContextLost(e){e.preventDefault(),this._contextLost=!0,console.warn("⚠️ WebGL context lost - rendering paused"),this.cameraAnimationId&&(cancelAnimationFrame(this.cameraAnimationId),this.cameraAnimationId=null)}handleContextRestored(){this._contextLost=!1,this.recreateResources()}recreateResources(){this.createEnvironmentMap(),"glow"===this.materialMode?(this.glowMaterial=this.createGlowMaterial(),this.coreMesh&&(this.coreMesh.material=this.glowMaterial)):"glass"===this.materialMode&&(this.glassMaterial=this.createGlassMaterial(),this.coreMesh&&(this.coreMesh.material=this.glassMaterial),this.coreMesh&&this.createInnerCore())}createCoreMesh(t,i=null){if(this.coreMesh&&(this.scene.remove(this.coreMesh),this.coreMesh.isGroup?this.coreMesh.traverse(e=>{e.geometry&&e.geometry.dispose(),e.material&&this.disposeMaterial(e.material)}):(this.coreMesh.geometry&&this.coreMesh.geometry.dispose(),this.coreMesh.material&&this.disposeMaterial(this.coreMesh.material)),this.coreMesh=null),t.isGroup)return this.coreMesh=t,this.coreMesh.name="coreMascot",this.options.enableShadows&&this.coreMesh.traverse(e=>{e.isMesh&&(e.castShadow=!0,e.receiveShadow=!0)}),this.scene.add(this.coreMesh),this.coreMesh;let n;return i?n=i:(this.glowMaterial||(this.glowMaterial=this.createGlowMaterial()),n="glass"===this.materialMode?this.glassMaterial||this.createGlassMaterial():this.glowMaterial),this.coreMesh=new e.Mesh(t,n),this.coreMesh.name="coreMascot",this.options.enableShadows&&(this.coreMesh.castShadow=!0,this.coreMesh.receiveShadow=!0),this.scene.add(this.coreMesh),"glass"===this.materialMode&&this.createInnerCore(),this.coreMesh}swapGeometry(t,i=null){if(!this.coreMesh)return;this.bloomPass&&this.bloomPass.clearBloomBuffers(this.renderer),this.particleBloomPass&&this.particleBloomPass.clearBloomBuffers(this.renderer);const n=this.coreMesh.geometry;if(n&&n.dispose(),this.coreMesh.geometry=t,i){if(this.coreMesh.material&&this.coreMesh.material!==this.glowMaterial&&this.coreMesh.material!==this.glassMaterial&&this.disposeMaterial(this.coreMesh.material),this.coreMesh.material=i,i.uniforms?.resolution){const t=this.renderer.getDrawingBufferSize(new e.Vector2);i.uniforms.resolution.value.set(t.x,t.y)}}else{const e="glass"===this.materialMode?this.glassMaterial||this.createGlassMaterial():this.glowMaterial;this.coreMesh.material!==e&&(this.coreMesh.material&&this.coreMesh.material!==this.glowMaterial&&this.coreMesh.material!==this.glassMaterial&&this.disposeMaterial(this.coreMesh.material),this.coreMesh.material=e)}"glass"!==this.materialMode||i||this.createInnerCore()}createGlowMaterial(){return new e.ShaderMaterial({uniforms:{glowColor:{value:new e.Color(1,1,1)},glowIntensity:{value:1},coreColor:{value:new e.Color(1,1,1)},fresnelPower:{value:3}},vertexShader:"\n varying vec3 vNormal;\n varying vec3 vViewPosition;\n\n void main() {\n // Transform normal to view space\n vNormal = normalize(normalMatrix * normal);\n\n // Calculate view space position\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = -mvPosition.xyz;\n\n // Output clip space position\n gl_Position = projectionMatrix * mvPosition;\n }\n ",fragmentShader:"\n uniform vec3 glowColor;\n uniform vec3 coreColor;\n uniform float glowIntensity;\n uniform float fresnelPower;\n\n varying vec3 vNormal;\n varying vec3 vViewPosition;\n\n void main() {\n // Fresnel effect: edges glow more than center\n vec3 viewDir = normalize(vViewPosition);\n float fresnel = pow(1.0 - abs(dot(vNormal, viewDir)), fresnelPower);\n\n // Combine white core with colored glow\n // Both core and glow respect glowIntensity for proper on/off toggle\n vec3 finalColor = (coreColor * glowIntensity) + (glowColor * glowIntensity * fresnel);\n\n gl_FragColor = vec4(finalColor, 1.0);\n }\n ",transparent:!1,side:e.FrontSide})}createGlassMaterial(){this.glassEmissiveMultiplier=.6;const t=new e.MeshPhysicalMaterial({transmission:1,thickness:2.7,roughness:.37,metalness:0,ior:1.5,reflectivity:.5,envMapIntensity:1.2,side:e.DoubleSide,transparent:!0,opacity:1,color:16777215,emissive:16777215,emissiveIntensity:.6,clearcoat:.8,clearcoatRoughness:.05,iridescence:.4,iridescenceIOR:1.3,iridescenceThicknessRange:[100,400]});return this.envMap&&(t.envMap=this.envMap),t}createInnerCore(){if(this.innerCore&&(this.coreMesh&&this.coreMesh.remove(this.innerCore),this.innerCore.geometry.dispose(),this.disposeMaterial(this.innerCore.material),this.innerCore=null,this.innerCoreMaterial=null),!this.coreMesh||!this.coreMesh.geometry)return;const t=this.coreMesh.geometry;let i;if("TorusGeometry"===t.type||void 0!==t.parameters?.tube){const n=t.parameters,a=n.radius||1,s=.25*(n.tube||.4),o=n.radialSegments||16,r=n.tubularSegments||100;i=new e.TorusGeometry(a,s,o,r)}else if("SphereGeometry"===t.type){const n=.2*(t.parameters.radius||1);i=new e.SphereGeometry(n,32,32)}else if("BoxGeometry"===t.type){const n=t.parameters,a=.2*(n.width||1),s=.2*(n.height||1),o=.2*(n.depth||1);i=new e.BoxGeometry(a,s,o)}else if("IcosahedronGeometry"===t.type||"OctahedronGeometry"===t.type){const n=t.parameters,a=.2*(n.radius||1),s=n.detail||2;i="IcosahedronGeometry"===t.type?new e.IcosahedronGeometry(a,s):new e.OctahedronGeometry(a,s)}else i=new e.IcosahedronGeometry(.2,2);const n=t.userData?.geometryType,a="IcosahedronGeometry"===t.type||"OctahedronGeometry"===t.type||"crystal"===n||"diamond"===n,s=new e.MeshStandardMaterial({emissive:16777215,emissiveIntensity:a?3.5:2,color:16777215,transparent:!1,opacity:1});this.innerCoreMaterial=s,this.innerCore=new e.Mesh(i,s),this.innerCore.name="innerCore",this.coreMesh.add(this.innerCore)}setMaterialMode(e){if(!this.coreMesh)return console.warn("Cannot set material mode: core mesh not created yet"),void(this.materialMode=e);if(e===this.materialMode)return;this.materialMode=e,"glass"!==e||this.glassMaterial?"glow"!==e||this.glowMaterial||(this.glowMaterial=this.createGlowMaterial()):this.glassMaterial=this.createGlassMaterial();const t="glass"===e?this.glassMaterial:this.glowMaterial;this.coreMesh.material=t,"glass"===e?this.createInnerCore():this.innerCore&&(this.coreMesh.remove(this.innerCore),this.innerCore.geometry.dispose(),this.disposeMaterial(this.innerCore.material),this.innerCore=null,this.innerCoreMaterial=null)}updateGlassProperties(e){this.glassMaterial&&(void 0!==e.transmission&&(this.glassMaterial.transmission=e.transmission,this.glassMaterial.needsUpdate=!0),void 0!==e.thickness&&(this.glassMaterial.thickness=e.thickness,this.glassMaterial.needsUpdate=!0),void 0!==e.roughness&&(this.glassMaterial.roughness=e.roughness,this.glassMaterial.needsUpdate=!0),void 0!==e.emissiveMultiplier&&(this.glassEmissiveMultiplier=e.emissiveMultiplier))}updateLighting(e,t,i=.15){if(!t||!t.visual)return;const n=t.visual.glowColor||"#FFFFFF";this._tempColor.set(n);const a=t.visual.glowIntensity||1;if(this.keyLight&&(this.keyLight.color.lerp(this._tempColor,i),this.keyLight.intensity+=(.8*a-this.keyLight.intensity)*i),this.fillLight&&(this._tempColor2.copy(this._tempColor).lerp(this._white,.7),this.fillLight.color.lerp(this._tempColor2,.5*i),this.fillLight.intensity+=(.3*a-this.fillLight.intensity)*i),this.ambientLight){const e=.4*a;this.ambientLight.intensity+=(e-this.ambientLight.intensity)*i}}normalizeIntensity(e){return.8+Math.log(e+1)/Math.log(11)*.4}calculateColorLuminance(e,t,i){const n=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);return.2126*n(e)+.7152*n(t)+.0722*n(i)}updateBloom(e,t=.1,i=null){if(this.bloomPass){const n=this.normalizeIntensity(e);let a,s,o;"sun"===i?(s=1.5,o=.4,a=.3):"crystal"===i||"rough"===i||"heart"===i?(s=1.8,o=.7,a=.35):"glass"===this.materialMode?(s=.3,o=.2,a=.85):(s=1+.8*n,o=.4,a=.85),this.bloomPass.strength+=(s-this.bloomPass.strength)*t,this.bloomPass.threshold+=(a-this.bloomPass.threshold)*t,this.bloomPass.radius=o}}setCameraPreset(t,i=1e3,n=!1){if(!this.controls)return;const a=this.cameraDistance,s={front:{x:0,y:0,z:a},side:{x:a,y:0,z:0},top:{x:0,y:a,z:0},angle:{x:.67*a,y:.5*a,z:.67*a},back:{x:0,y:0,z:-a},bottom:{x:0,y:-a,z:0}}[t];if(!s)return void console.warn(`Unknown camera preset: ${t}`);const o=n?this.controls.target.clone():null;if(0===i)return this.controls.reset(),this.camera.position.set(s.x,s.y,s.z),o?(this.controls.target.copy(o),this.camera.lookAt(o)):(this.controls.target.set(0,0,0),this.camera.lookAt(0,0,0)),void this.controls.update();n||this.controls.target.set(0,0,0);const r=this.camera.position.clone(),l=new e.Vector3(s.x,s.y,s.z),h=performance.now(),c=e=>{const t=e-h,n=Math.min(t/i,1),a=1-Math.pow(1-n,3);this.camera.position.lerpVectors(r,l,a),this.camera.lookAt(0,0,0),this.controls.update(),this.cameraAnimationId=n<1?requestAnimationFrame(c):null};this.cameraAnimationId=requestAnimationFrame(c)}resetCamera(){this.setCameraPreset("front",1e3)}toggleAutoRotate(e){this.controls&&(this.controls.autoRotate=void 0!==e?e:!this.controls.autoRotate)}isAutoRotateEnabled(){return!!this.controls&&this.controls.autoRotate}render(t={}){if(this._destroyed)return void console.log("[ThreeRenderer] render() BLOCKED - destroyed");if(!this.scene||!this.camera||!this.renderer)return void console.log(`[ThreeRenderer] render() BLOCKED - scene=${!!this.scene}, camera=${!!this.camera}, renderer=${!!this.renderer}`);const i=(e,t)=>{if(!e||!e.children)return!0;for(let n=0;n<e.children.length;n++){const a=e.children[n];null!=a?null!==a.visible&&void 0!==a.visible?i(a,`${t}.children[${n}]`):(console.error(`[ThreeRenderer] child.visible is NULL at ${t}.children[${n}] name=${a.name} - REMOVING!`),e.children.splice(n,1),n--):(console.error(`[ThreeRenderer] NULL CHILD at ${t}.children[${n}] - REMOVING!`),e.children.splice(n,1),n--)}return!0};i(this.scene,"scene");const{position:n=[0,0,0],rotation:a=[0,0,0],scale:s=1,glowColor:o=[1,1,1],glowIntensity:r=1,glowColorHex:l=null,hasActiveGesture:h=!1,calibrationRotation:c=[0,0,0],cameraRoll:u=0,solarEclipse:d=null,deltaTime:m=0,morphProgress:p=null}=t;if(this.controls&&this.controls.update(),this.coreMesh){if(this.coreMesh.position.set(...n),this._tempEuler.set(a[0],a[1],a[2],"XYZ"),this._tempQuat.setFromEuler(this._tempEuler),this._quatX.setFromAxisAngle(this._xAxis,c[0]),this._quatY.setFromAxisAngle(this._yAxis,c[1]),this._cameraToMesh.subVectors(this.coreMesh.position,this.camera.position).normalize(),this._quatZ.setFromAxisAngle(this._cameraToMesh,c[2]),this._tempQuat.multiply(this._quatX),this._tempQuat.multiply(this._quatY),this._tempQuat.multiply(this._quatZ),this.coreMesh.rotation.setFromQuaternion(this._tempQuat),0!==u&&(this._cameraDir.subVectors(this.coreMesh.position,this.camera.position).normalize(),this._rollQuat.setFromAxisAngle(this._cameraDir,u),this._meshQuat.setFromEuler(this.coreMesh.rotation),this._meshQuat.premultiply(this._rollQuat),this.coreMesh.rotation.setFromQuaternion(this._meshQuat)),this.coreMesh.scale.setScalar(s),d&&d.update(this.camera,this.coreMesh,m,p),this.coreMesh.material&&this.coreMesh.material.uniforms){if(this.coreMesh.material.uniforms.glowColor&&(this._tempColor.setRGB(...o),this.coreMesh.material.uniforms.glowColor.value.lerp(this._tempColor,.15)),this.coreMesh.material.uniforms.glowIntensity){let e;e=0===r?0:h?r:this.normalizeIntensity(r);const t=this.coreMesh.material.uniforms.glowIntensity.value,i=h?.5:.15;this.coreMesh.material.uniforms.glowIntensity.value+=(e-t)*i}}else if(this.coreMesh.material&&this.coreMesh.material.emissive){this._tempColor.setRGB(...o),this.coreMesh.material.emissive.lerp(this._tempColor,.15);const e=.15*r,t=this.coreMesh.material.emissiveIntensity,i=h?.5:.15;this.coreMesh.material.emissiveIntensity+=(e-t)*i,this.coreMesh.material.color.lerp(this._white,.15)}this.innerCore&&(this.innerCore.visible=r>0,this.innerCoreMaterial&&(this._tempColor.setRGB(...o),this.innerCoreMaterial.emissive.lerp(this._tempColor,.15)))}if(this.mixer){const e=this.clock.getDelta();this.mixer.update(e)}if(this.renderer.clear(),this.composer){if(this.soulRenderTarget){let e=null;if(this.scene.traverse(t=>{"crystalSoul"===t.name&&(e=t)}),this.renderer.setRenderTarget(this.soulRenderTarget),this.renderer.setClearColor(0,0),this.renderer.clear(),this.camera.layers.set(2),this.renderer.render(this.scene,this.camera),this.coreMesh?.material?.uniforms?.soulTexture&&(this.coreMesh.material.uniforms.soulTexture.value=this.soulRenderTarget.texture,this.coreMesh.material.uniforms.soulTextureSize&&this.coreMesh.material.uniforms.soulTextureSize.value.set(this.soulRenderTarget.width,this.soulRenderTarget.height),this.coreMesh.material.uniforms.soulScreenCenter&&e)){const t=e.position.clone().project(this.camera),i=.5*(t.x+1),n=.5*(t.y+1);this.coreMesh.material.uniforms.soulScreenCenter.value.set(i,n)}this.renderer.setRenderTarget(null),this.renderer.setClearColor(0,0)}if(this.camera.layers.set(0),this.composer.render(),this.particleRenderTarget&&this.particleBloomPass){this.renderer.setRenderTarget(this.particleRenderTarget),this.renderer.setClearColor(16777215,0),this.renderer.clear(),this.camera.layers.set(0);const t=this._depthOnlyMaterial||(this._depthOnlyMaterial=new e.MeshBasicMaterial({colorWrite:!1,depthWrite:!0}));this.scene.overrideMaterial=t,this.renderer.render(this.scene,this.camera),this.scene.overrideMaterial=null,this.camera.layers.set(1),this.renderer.render(this.scene,this.camera);const i=this.particleRenderTarget;this.particleBloomPass.renderToScreen=!0,this.particleBloomPass.render(this.renderer,null,i,0,!1),this.renderer.setClearColor(0,0),this.renderer.setRenderTarget(null)}else this.camera.layers.set(1),this.renderer.render(this.scene,this.camera);this.camera.layers.enableAll(),this.glowLayer&&this.glowLayer.isActive()&&this.glowLayer.render(this.renderer)}else this.renderer.render(this.scene,this.camera),this.glowLayer&&this.glowLayer.isActive()&&this.glowLayer.render(this.renderer)}updateGlowLayer(e,t,i,n){this.glowLayer&&(this.glowLayer.setGlow(e,t,i),this.glowLayer.update(n,this.camera))}resize(t,i){if(this.camera.aspect=t/i,this.camera.updateProjectionMatrix(),this.renderer.setSize(t,i,!1),this.composer){const t=new e.Vector2;this.renderer.getDrawingBufferSize(t),this.composer.setSize(t.x,t.y),this.bloomPass&&this.bloomPass.resolution&&this.bloomPass.resolution.set(t.x,t.y),this.particleRenderTarget&&this.particleRenderTarget.setSize(t.x,t.y),this.particleBloomPass&&this.particleBloomPass.setSize(t.x,t.y),this.soulRenderTarget&&this.soulRenderTarget.setSize(t.x,t.y),this.coreMesh?.material?.uniforms?.resolution&&this.coreMesh.material.uniforms.resolution.value.set(t.x,t.y)}}disposeMaterial(e){e&&(["map","lightMap","bumpMap","normalMap","specularMap","envMap","alphaMap","aoMap","displacementMap","emissiveMap","gradientMap","metalnessMap","roughnessMap"].forEach(t=>{e[t]&&e[t].dispose()}),e.uniforms&&Object.values(e.uniforms).forEach(e=>{e.value&&(e.value.isTexture?(e.value.dispose(),e.value=null):(e.value.isColor||e.value.isVector2||e.value.isVector3||e.value.isVector4)&&(e.value=null))}),e.dispose())}destroy(){console.log(`[ThreeRenderer] destroy() CALLED, scene children=${this.scene?.children?.length}`),this._destroyed=!0,this.canvas&&(this.canvas.removeEventListener("webglcontextlost",this._boundHandleContextLost,!1),this.canvas.removeEventListener("webglcontextrestored",this._boundHandleContextRestored,!1)),this.cameraAnimationId&&(cancelAnimationFrame(this.cameraAnimationId),this.cameraAnimationId=null),this.innerCore&&(this.coreMesh&&this.coreMesh.remove(this.innerCore),this.innerCore.geometry.dispose(),this.disposeMaterial(this.innerCore.material),this.innerCore=null,this.innerCoreMaterial=null),this.coreMesh&&(this.scene.remove(this.coreMesh),this.coreMesh.geometry.dispose(),this.disposeMaterial(this.coreMesh.material),this.coreMesh=null),this.glowMaterial&&(this.disposeMaterial(this.glowMaterial),this.glowMaterial=null),this.glassMaterial&&(this.disposeMaterial(this.glassMaterial),this.glassMaterial=null),this.composer&&(this.composer.dispose(),this.composer=null),this.particleRenderTarget&&(this.particleRenderTarget.dispose(),this.particleRenderTarget=null),this.particleBloomPass&&(this.particleBloomPass.dispose(),this.particleBloomPass=null),this.soulRenderTarget&&(this.soulRenderTarget.dispose(),this.soulRenderTarget=null),this.glowLayer&&(this.glowLayer.dispose(),this.glowLayer=null),this.controls&&(this.controls.dispose(),this.controls=null),this.keyLight?.shadow?.map&&this.keyLight.shadow.map.dispose(),this.fillLight?.shadow?.map&&this.fillLight.shadow.map.dispose(),this.rimLight?.shadow?.map&&this.rimLight.shadow.map.dispose(),this.keyLight=null,this.fillLight=null,this.rimLight=null,this.ambientLight=null,this.accentLight1=null,this.accentLight2=null,this.accentLight3=null,this.envMap&&(this.envMap.dispose(),this.envMap=null),this._envCubeRenderTarget&&(this._envCubeRenderTarget.dispose(),this._envCubeRenderTarget=null),this._envScene&&(this._envScene.traverse(e=>{e.geometry&&e.geometry.dispose(),e.material&&this.disposeMaterial(e.material)}),this._envScene.clear(),this._envScene=null),this._envCubeCamera&&(this._envCubeCamera=null),this.renderer&&(this.renderer.dispose(),this.renderer=null),this.scene.clear(),this.mixer&&(this.mixer.stopAllAction(),this.mixer=null),this.clock=null,this.camera=null,this._tempColor=null,this._tempColor2=null,this._white=null,this._tempQuat=null,this._tempEuler=null,this._quatX=null,this._quatY=null,this._quatZ=null,this._rollQuat=null,this._meshQuat=null,this._xAxis=null,this._yAxis=null,this._zAxis=null,this._cameraToMesh=null,this._cameraDir=null}}const S="\n/**\n * Apply a single blend mode to two colors\n * @param base - Base color (RGB, 0.0-1.0 range)\n * @param blend - Blend color (RGB, 0.0-1.0 range)\n * @param mode - Blend mode index (0-17)\n * @return Blended color (RGB, 0.0-1.0 range)\n *\n * Blend Mode Reference:\n * 0 = Multiply (darkening)\n * 1 = Linear Burn (darkening, linear)\n * 2 = Color Burn (darkening, intense)\n * 3 = Color Dodge (brightening, intense)\n * 4 = Screen (brightening)\n * 5 = Overlay (contrast, screen/multiply hybrid)\n * 6 = Add (brightening, additive glow)\n * 7 = Soft Light (contrast, gentle)\n * 8 = Hard Light (contrast, strong)\n * 9 = Vivid Light (contrast, saturation boost)\n * 10 = Linear Light (contrast, linear)\n * 11 = Difference (inversion)\n * 12 = Exclusion (soft inversion)\n * 13 = Darken (comparison, darker)\n * 14 = Lighten (comparison, lighter)\n * 15 = Subtract (darkening, deep shadows)\n * 16 = Divide (brightening, ethereal glow)\n * 17 = Pin Light (posterization)\n */\nvec3 applyBlendMode(vec3 base, vec3 blend, int mode) {\n if (mode == 0) {\n // MULTIPLY: base * blend\n return base * blend;\n } else if (mode == 1) {\n // LINEAR BURN: base + blend - 1\n return max(base + blend - vec3(1.0), vec3(0.0));\n } else if (mode == 2) {\n // COLOR BURN: (blend==0.0) ? 0.0 : max((1.0-((1.0-base)/blend)), 0.0)\n return vec3(\n blend.r == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.r) / blend.r), 0.0),\n blend.g == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.g) / blend.g), 0.0),\n blend.b == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.b) / blend.b), 0.0)\n );\n } else if (mode == 3) {\n // COLOR DODGE: (blend==1.0) ? 1.0 : min(base/(1.0-blend), 1.0)\n return vec3(\n blend.r == 1.0 ? 1.0 : min(base.r / (1.0 - blend.r), 1.0),\n blend.g == 1.0 ? 1.0 : min(base.g / (1.0 - blend.g), 1.0),\n blend.b == 1.0 ? 1.0 : min(base.b / (1.0 - blend.b), 1.0)\n );\n } else if (mode == 4) {\n // SCREEN: 1 - (1 - base) * (1 - blend)\n return vec3(1.0) - (vec3(1.0) - base) * (vec3(1.0) - blend);\n } else if (mode == 5) {\n // OVERLAY: base < 0.5 ? (2 * base * blend) : (1 - 2 * (1 - base) * (1 - blend))\n return vec3(\n base.r < 0.5 ? (2.0 * base.r * blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r)),\n base.g < 0.5 ? (2.0 * base.g * blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g)),\n base.b < 0.5 ? (2.0 * base.b * blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b))\n );\n } else if (mode == 6) {\n // ADD (LINEAR DODGE): base + blend\n return min(base + blend, vec3(1.0));\n } else if (mode == 7) {\n // SOFT LIGHT: blend < 0.5 ? (2*base*blend + base^2*(1-2*blend)) : (sqrt(base)*(2*blend-1) + 2*base*(1-blend))\n return vec3(\n blend.r < 0.5 ? (2.0 * base.r * blend.r + base.r * base.r * (1.0 - 2.0 * blend.r)) : (sqrt(base.r) * (2.0 * blend.r - 1.0) + 2.0 * base.r * (1.0 - blend.r)),\n blend.g < 0.5 ? (2.0 * base.g * blend.g + base.g * base.g * (1.0 - 2.0 * blend.g)) : (sqrt(base.g) * (2.0 * blend.g - 1.0) + 2.0 * base.g * (1.0 - blend.g)),\n blend.b < 0.5 ? (2.0 * base.b * blend.b + base.b * base.b * (1.0 - 2.0 * blend.b)) : (sqrt(base.b) * (2.0 * blend.b - 1.0) + 2.0 * base.b * (1.0 - blend.b))\n );\n } else if (mode == 8) {\n // HARD LIGHT: blend < 0.5 ? (2 * base * blend) : (1 - 2 * (1 - base) * (1 - blend))\n return vec3(\n blend.r < 0.5 ? (2.0 * base.r * blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r)),\n blend.g < 0.5 ? (2.0 * base.g * blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g)),\n blend.b < 0.5 ? (2.0 * base.b * blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b))\n );\n } else if (mode == 9) {\n // VIVID LIGHT: blend < 0.5 ? ColorBurn(base, 2*blend) : ColorDodge(base, 2*(blend-0.5))\n return vec3(\n blend.r < 0.5 ? (blend.r == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.r) / (2.0 * blend.r)), 0.0)) : (blend.r == 1.0 ? 1.0 : min(base.r / (2.0 * (1.0 - blend.r)), 1.0)),\n blend.g < 0.5 ? (blend.g == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.g) / (2.0 * blend.g)), 0.0)) : (blend.g == 1.0 ? 1.0 : min(base.g / (2.0 * (1.0 - blend.g)), 1.0)),\n blend.b < 0.5 ? (blend.b == 0.0 ? 0.0 : max(1.0 - ((1.0 - base.b) / (2.0 * blend.b)), 0.0)) : (blend.b == 1.0 ? 1.0 : min(base.b / (2.0 * (1.0 - blend.b)), 1.0))\n );\n } else if (mode == 10) {\n // LINEAR LIGHT: blend < 0.5 ? LinearBurn(base, 2*blend) : LinearDodge(base, 2*(blend-0.5))\n return vec3(\n blend.r < 0.5 ? max(base.r + 2.0 * blend.r - 1.0, 0.0) : min(base.r + 2.0 * (blend.r - 0.5), 1.0),\n blend.g < 0.5 ? max(base.g + 2.0 * blend.g - 1.0, 0.0) : min(base.g + 2.0 * (blend.g - 0.5), 1.0),\n blend.b < 0.5 ? max(base.b + 2.0 * blend.b - 1.0, 0.0) : min(base.b + 2.0 * (blend.b - 0.5), 1.0)\n );\n } else if (mode == 11) {\n // DIFFERENCE: abs(base - blend)\n return abs(base - blend);\n } else if (mode == 12) {\n // EXCLUSION: base + blend - 2 * base * blend\n return base + blend - 2.0 * base * blend;\n } else if (mode == 13) {\n // DARKEN: min(base, blend)\n return min(base, blend);\n } else if (mode == 14) {\n // LIGHTEN: max(base, blend)\n return max(base, blend);\n } else if (mode == 15) {\n // SUBTRACT: max(base - blend, 0)\n return max(base - blend, vec3(0.0));\n } else if (mode == 16) {\n // DIVIDE: base / (blend + epsilon)\n return min(base / (blend + vec3(0.001)), vec3(1.0));\n } else {\n // PIN LIGHT (mode 17): Replaces colors based on blend brightness\n float blendLum = (blend.r + blend.g + blend.b) / 3.0;\n if (blendLum > 0.5) {\n // Lighten: replace pixels darker than blend\n return max(base, 2.0 * blend - vec3(1.0));\n } else {\n // Darken: replace pixels lighter than blend\n return min(base, 2.0 * blend);\n }\n }\n}\n",x=["Multiply","Linear Burn","Color Burn","Color Dodge","Screen","Overlay","Add","Soft Light","Hard Light","Vivid Light","Linear Light","Difference","Exclusion","Darken","Lighten","Subtract","Divide","Pin Light"];function C(e){return x[e]||"Unknown"}function D(e){const t=x.indexOf(e);return-1!==t?t:0}const P=`\n/**\n * Moon Fragment Shader with Blend Layers\n *\n * Supports up to 4 sequential blend mode layers for complex color grading\n * using universal Photoshop-style blend modes\n */\n\nuniform sampler2D colorMap;\nuniform sampler2D normalMap;\nuniform vec2 shadowOffset;\nuniform float shadowCoverage;\nuniform float shadowSoftness;\nuniform vec3 glowColor;\nuniform float glowIntensity;\nuniform float opacity;\n\n// Lunar Eclipse (Blood Moon) uniforms\nuniform float eclipseProgress;\nuniform float eclipseIntensity;\nuniform vec3 bloodMoonColor;\nuniform float emissiveStrength;\nuniform vec2 eclipseShadowPos; // Shadow center position (-2 to 1)\nuniform float eclipseShadowRadius; // Shadow radius\n\n// Eclipse Color Grading (from color pickers)\nuniform vec3 eclipseShadowColor;\nuniform vec3 eclipseMidtoneColor;\nuniform vec3 eclipseHighlightColor;\nuniform vec3 eclipseGlowColor;\n\n// Brightness model toggle (0 = centeredness-based, 1 = edge-based)\nuniform float eclipseBrightnessModel;\n\n// Shadow darkness control (0.0 = no darkening, 1.0 = maximum darkening)\nuniform float shadowDarkness;\n\n// Blend Layer Uniforms (up to 4 layers)\nuniform float layer1Mode;\nuniform float layer1Strength;\nuniform float layer1Enabled;\n\nuniform float layer2Mode;\nuniform float layer2Strength;\nuniform float layer2Enabled;\n\nuniform float layer3Mode;\nuniform float layer3Strength;\nuniform float layer3Enabled;\n\nuniform float layer4Mode;\nuniform float layer4Strength;\nuniform float layer4Enabled;\n\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewNormal;\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// UNIVERSAL BLEND MODES (injected from utils/blendModes.js)\n// ═══════════════════════════════════════════════════════════════════════════\n${S}\n\nvoid main() {\n // DIRECTIONAL SHADOW in VIEW SPACE - camera-relative moon phase\n // Shadow stays fixed relative to screen; rotating moon doesn't change which side is lit\n vec3 viewNormal = normalize(vViewNormal);\n\n float lightX = shadowOffset.x;\n float lightY = shadowOffset.y;\n float offsetMagnitude = length(vec2(lightX, lightY));\n float lightZ = 1.0 - pow(offsetMagnitude, 1.5);\n vec3 lightDir = normalize(vec3(lightX, lightY, lightZ));\n\n // Light direction is in view space (camera-relative)\n float facing = dot(viewNormal, lightDir);\n float edgeWidth = max(fwidth(facing) * 4.0, shadowSoftness * 3.0);\n float shadowFactor = smoothstep(-edgeWidth, edgeWidth, facing);\n\n // Sample moon surface texture\n vec4 texColor = texture2D(colorMap, vUv);\n float brightness = texColor.r + texColor.g + texColor.b;\n if (brightness < 0.03) {\n texColor = vec4(0.5, 0.5, 0.5, 1.0);\n }\n\n // VIEW DIRECTION (for eclipse rim effects only, NOT for general lighting)\n vec3 viewDir = normalize(-vViewPosition);\n float rimFactor = dot(viewNormal, viewDir);\n\n // EARTHSHINE - faint blue glow on shadowed side\n vec3 earthshine = texColor.rgb * 0.01 * vec3(0.35, 0.4, 0.6);\n\n // Apply shadow transition (moon phase only - NOT camera-based)\n // The moon texture is uniformly visible; only the phase shadow creates darkness\n float litFactor = pow(shadowFactor, 2.0);\n vec3 detailEnhanced = texColor.rgb * 1.08;\n float textureLuminance = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));\n detailEnhanced = mix(texColor.rgb * 0.95, texColor.rgb * 1.12, smoothstep(0.3, 0.7, textureLuminance));\n\n // Lit areas show texture; shadowed areas show earthshine\n // NO camera-based limb darkening - moon rotates, texture stays uniformly lit\n vec3 shadowedColor = mix(earthshine, detailEnhanced, litFactor);\n\n vec3 emissive = vec3(0.02, 0.02, 0.02) * shadowFactor;\n vec3 emotionGlow = glowColor * glowIntensity * 0.02 * shadowFactor;\n vec3 finalColor = shadowedColor + emissive + emotionGlow;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LUNAR ECLIPSE EFFECT (Earth's Shadow Sweep)\n // Shadow position drives everything - automatically transitions from dark sharp shadow to red glow\n // ═══════════════════════════════════════════════════════════════════════════\n // Only apply eclipse if shadow is actually near the moon (shadowX > -1.5)\n if (eclipseProgress > 0.001 && eclipseShadowPos.x > -1.5) {\n // Eclipse progress is now pre-modulated by UI based on shadow position\n // No need for shader-side modulation\n float effectiveProgress = eclipseProgress;\n\n // Calculate distance from shadow center using VIEW-SPACE position (3D spherical)\n // This creates a proper circular shadow on the sphere, not a flat UV-based cutoff\n // viewNormal.xy ranges -1 to 1, scale to match UV range (0 to 0.5 from center)\n vec2 shadowCenter = vec2(eclipseShadowPos.x, eclipseShadowPos.y);\n vec2 spherePos = viewNormal.xy * 0.5; // Scale to UV-equivalent range\n float distFromShadow = length(spherePos - shadowCenter);\n\n // TOTALITY FACTOR: Based on how centered the shadow is on the moon\n // When shadowX near 0.0 (centered), we're at totality - brightens and reddens\n // When shadowX far from 0.0 (off to side), we're partial - stays dark and diffuse\n float shadowCenteredness = 1.0 - smoothstep(0.0, 0.6, abs(eclipseShadowPos.x));\n float totalityFactor = shadowCenteredness;\n\n // Earth's umbra (full shadow) - DIFFUSE at partials, sharper at totality\n float umbraRadius = eclipseShadowRadius * 0.7;\n // Edge softness: very diffuse at partials (0.25), sharp at totality (0.05)\n float umbraEdge = mix(0.25, 0.05, totalityFactor);\n float umbra = 1.0 - smoothstep(umbraRadius - umbraEdge, umbraRadius + umbraEdge, distFromShadow);\n\n // Earth's penumbra (partial shadow) - wider and softer\n // Penumbra extends further at partials, tighter at totality\n float penumbraRadius = eclipseShadowRadius * mix(1.4, 1.1, totalityFactor);\n float penumbraEdge = mix(0.3, 0.15, totalityFactor);\n float penumbra = 1.0 - smoothstep(penumbraRadius - penumbraEdge, penumbraRadius + penumbraEdge, distFromShadow);\n\n // UMBRA DARKENING: Much darker at partials, lighter at totality\n // Partials: 85% darkening (very dark shadow)\n // Totality: 30% darkening (blood moon glow visible)\n float baseDarkening = mix(0.85, 0.30, totalityFactor);\n float umbraDarkeningAmount = baseDarkening * shadowDarkness;\n float umbraDarkening = umbra * effectiveProgress;\n\n // Apply base darkening first\n finalColor *= (1.0 - umbraDarkening * umbraDarkeningAmount);\n\n // PENUMBRA: Darker gradient at partials, lighter at totality\n float penumbraDarkening = (penumbra - umbra) * effectiveProgress;\n float penumbraDarkenAmount = mix(0.50, 0.20, totalityFactor); // 50% at partials, 20% at totality\n finalColor *= (1.0 - penumbraDarkening * penumbraDarkenAmount);\n\n // BLOOD MOON COLOR: Applied throughout entire eclipse, not just totality\n // Matches real lunar eclipse behavior - color present at all phases\n // Use totality factor to control BRIGHTNESS, not color presence\n float colorStrength = umbra; // Color appears wherever umbra shadow is present\n vec3 bloodMoonTint = mix(vec3(1.0), eclipseMidtoneColor, colorStrength);\n finalColor *= bloodMoonTint;\n\n // REALISTIC ECLIPSE PROGRESSION (corrected):\n // Shadow sweeps LEFT → RIGHT but NEVER fully covers moon during partials\n // A bright crescent ALWAYS remains visible (shadow stops before covering moon)\n // Just before totality: shadow nearly covers moon, blood moon glow appears\n // The glow spreads FROM the visible bright crescent INTO the shadowed area\n // During totality: shadow finally covers entire moon, full blood moon\n\n // Use view-space normal for spherical position (not UV)\n // Scale to match UV range\n float pixelX = viewNormal.x * 0.5;\n\n // THE LIT CRESCENT: Always visible during partial phases\n // During partials, the moon is partially lit (outside umbra)\n // Only during totality does the shadow fully cover the moon\n\n // Where is the bright crescent? Opposite side from shadow\n // Approaching (shadowX < 0): crescent on RIGHT (positive X)\n // Leaving (shadowX > 0): crescent on LEFT (negative X)\n float crescentSide = -sign(eclipseShadowPos.x);\n\n // CRESCENT EDGE: Where shadow meets lit surface\n // This is always VISIBLE during partials - never goes to zero\n float umbraEdgeX = eclipseShadowPos.x + (umbraRadius * crescentSide);\n\n // Distance from this pixel to the lit crescent edge\n // Positive = inside shadow, negative = in lit crescent\n float distFromLitEdge = (pixelX - umbraEdgeX) * crescentSide;\n\n // GRADIENT: Blood moon glow spreads from the LIT CRESCENT\n // Only pixels INSIDE the shadow get the gradient\n // Gradient is strongest at the umbra edge (where crescent is)\n float crescentGradient = smoothstep(0.5, 0.0, distFromLitEdge);\n\n // BRIGHTNESS CONTROL: Glow only appears near totality\n // When shadow is far from center: stays dark\n // When shadow approaches center: glow spreads from crescent\n float brightnessControl = umbra * crescentGradient * totalityFactor;\n\n // During full totality (shadowX ≈ 0), switch to uniform brightness\n brightnessControl = mix(brightnessControl, umbra * totalityFactor, totalityFactor);\n\n // EMISSIVE GLOW: Blood moon color spreading from crescent\n float glowStrength = mix(0.0, 1.0, brightnessControl);\n vec3 atmosphereGlow = eclipseMidtoneColor * emissiveStrength * glowStrength * umbra;\n finalColor += atmosphereGlow;\n\n // RIM GLOW: Atmospheric limb brightening\n float limbGlowStrength = mix(0.0, 1.5, brightnessControl);\n float limbGlow = pow(1.0 - rimFactor, 3.0) * umbra;\n vec3 rimColor = mix(eclipseGlowColor, eclipseHighlightColor, 0.5);\n finalColor += rimColor * limbGlow * emissiveStrength * limbGlowStrength;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ECLIPSE BLEND LAYERS (Applied AFTER blood moon color)\n // Applied throughout eclipse wherever umbra is present\n // Strength modulated by totality factor for smooth brightness transitions\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Layer 1: Linear Burn @ 0.634\n if (layer1Enabled > 0.5 && effectiveProgress > 0.1) {\n vec3 blendColor1 = vec3(min(layer1Strength, 1.0));\n int mode1 = int(layer1Mode + 0.5);\n vec3 blended1 = clamp(applyBlendMode(finalColor, blendColor1, mode1), 0.0, 1.0);\n // Apply at FULL strength wherever umbra exists\n finalColor = clamp(mix(finalColor, blended1, umbra), 0.0, 1.0);\n }\n\n // Layer 2: Multiply @ 3.086 - Brightness enhancement\n if (layer2Enabled > 0.5 && effectiveProgress > 0.1) {\n // Apply full brightness boost wherever umbra exists\n vec3 brightened = clamp(finalColor * min(layer2Strength, 5.0), 0.0, 1.0);\n finalColor = mix(finalColor, brightened, umbra);\n }\n\n // Layer 3: Hard Light @ 0.351\n if (layer3Enabled > 0.5 && effectiveProgress > 0.1) {\n vec3 blendColor3 = vec3(min(layer3Strength, 1.0));\n int mode3 = int(layer3Mode + 0.5);\n vec3 blended3 = clamp(applyBlendMode(finalColor, blendColor3, mode3), 0.0, 1.0);\n // Apply at FULL strength wherever umbra exists\n finalColor = clamp(mix(finalColor, blended3, umbra), 0.0, 1.0);\n }\n\n // Layer 4: Manual UI layer\n if (layer4Enabled > 0.5 && effectiveProgress > 0.1) {\n vec3 blendColor4 = vec3(min(layer4Strength, 1.0));\n int mode4 = int(layer4Mode + 0.5);\n vec3 blended4 = clamp(applyBlendMode(finalColor, blendColor4, mode4), 0.0, 1.0);\n finalColor = clamp(mix(finalColor, blended4, umbra), 0.0, 1.0);\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // UNIVERSAL BLEND MODE LAYERS (Only applied when eclipse is OFF)\n // These are manual UI-driven color grading tools\n // NOTE: These are DISABLED by default - they're NEVER used since the multiplexer\n // demo doesn't enable them. This section exists for potential future manual control.\n // ═══════════════════════════════════════════════════════════════════════════\n // INTENTIONALLY COMMENTED OUT - these would interfere with eclipse blend layers\n // if (eclipseProgress < 0.001) {\n // // Layer 1 - manual UI control only\n // if (layer1Enabled > 0.5) {\n // vec3 blendColor1 = vec3(layer1Strength);\n // int mode1 = int(layer1Mode + 0.5);\n // finalColor = applyBlendMode(finalColor, blendColor1, mode1);\n // }\n // }\n\n gl_FragColor = vec4(finalColor, opacity);\n}\n`,B=55.5,k=-85,T=-60.5,E={enabled:!0,strength:1,lockedFace:[0,0,1],lerpSpeed:10},I={new:{x:200,y:0,coverage:0},"waxing-crescent":{x:1.5,y:0,coverage:.25},"first-quarter":{x:1,y:0,coverage:.5},"waxing-gibbous":{x:.7,y:0,coverage:.75},full:{x:0,y:0,coverage:1},"waning-gibbous":{x:-.7,y:0,coverage:.75},"last-quarter":{x:-1,y:0,coverage:.5},"waning-crescent":{x:-1.5,y:0,coverage:.25}};function A(){return Object.keys(I)}function R(e){const t=(e%1+1)%1;let i;if(t<=.5){const e=2*t;i=10*Math.pow(1-e,2.5)}else{const e=2*(t-.5);if(e<=.25)i=e/.25*-.3;else if(e<=.5)i=-.3-(e-.25)/.25*.7;else if(e<=.75)i=-1-(e-.5)/.25*2;else{const t=(e-.75)/.25;i=13*Math.pow(t,.4)-3}}return{x:i,y:0,coverage:1-2*Math.abs(t-.5)}}function z(t=64,i=64){const n=new e.SphereGeometry(.5,t,i);return n.userData.tracked=!0,n}function _(e){if(e&&(e.geometry&&e.geometry.dispose(),e.material)){const{material:t}=e;t.userData&&t.userData.pendingTextures&&(t.userData.pendingTextures.forEach(({texture:e})=>{e&&e.dispose()}),t.userData.pendingTextures.clear()),t.map&&t.map.dispose(),t.normalMap&&t.normalMap.dispose(),t.uniforms&&(t.uniforms.colorMap&&t.uniforms.colorMap.value&&t.uniforms.colorMap.value.dispose(),t.uniforms.normalMap&&t.uniforms.normalMap.value&&t.uniforms.normalMap.value.dispose()),t.dispose()}}function O(t,i={}){const n=i.resolution||"2k",a=i.assetBasePath||"/assets",s=`${a}/textures/Moon/moon-color-${n}.jpg`,o=`${a}/textures/Moon/moon-normal-${n}.jpg`,r=new Map;r.set(s,{texture:null});const l=t.load(s,e=>{const t=r.get(s);t&&(t.texture=e),r.delete(s)},void 0,e=>{console.error(`❌ Failed to load moon color texture (${n}):`,e),r.delete(s)});r.set(o,{texture:null});const h=t.load(o,e=>{const t=r.get(o);t&&(t.texture=e),r.delete(o)},void 0,e=>{console.error(`❌ Failed to load moon normal map (${n}):`,e),r.delete(o)});l.wrapS=l.wrapT=e.RepeatWrapping,h.wrapS=h.wrapT=e.RepeatWrapping,l.anisotropy=16,h.anisotropy=16;const c=new e.MeshStandardMaterial({map:l,normalMap:h,normalScale:new e.Vector2(1.5,1.5),roughness:.7,metalness:0,emissive:new e.Color(.3,.3,.3),emissiveIntensity:.5,transparent:!1,side:e.FrontSide});return c.userData.pendingTextures=r,c}function F(t=new e.Color(16777215),i=0){return new e.MeshStandardMaterial({color:15263976,roughness:.9,metalness:0,emissive:t,emissiveIntensity:i})}function L(t,i={}){const n=i.resolution||"2k",a=i.glowColor||new e.Color(1,1,1),s=i.glowIntensity||1,o=i.shadowType||"crescent",r=i.assetBasePath||"/assets";let l,h;if(void 0!==i.shadowOffsetX)({shadowOffsetX:l}=i),h=void 0!==i.shadowOffsetY?i.shadowOffsetY:0;else if(void 0!==i.moonPhase){let e;"string"==typeof i.moonPhase?([e]=[I[i.moonPhase]],e||(console.warn(`Unknown moon phase: ${i.moonPhase}, using waxing-crescent`),e=I["waxing-crescent"])):e="number"==typeof i.moonPhase?R(i.moonPhase):I["waxing-crescent"],l=e.x,h=e.y}else{const e=I["waxing-crescent"];l=e.x,h=e.y}const c=void 0!==i.shadowCoverage?i.shadowCoverage:.85,u=`${r}/textures/Moon/moon-color-${n}.jpg`,d=`${r}/textures/Moon/moon-normal-${n}.jpg`,{vertexShader:m,fragmentShader:p}=function(e){return"crescent"===e||console.warn(`Unknown shadow type: ${e}, defaulting to crescent`),{vertexShader:"\n/**\n * Moon Crescent Vertex Shader\n * Passes world-space normal to fragment shader for realistic lighting\n */\n\nvarying vec3 vPosition; // LOCAL position\nvarying vec3 vWorldPosition;\nvarying vec3 vWorldNormal; // WORLD SPACE normal (rotates with moon)\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n vPosition = position;\n\n // Transform normal to WORLD space (not view space)\n // This makes the shadow rotate with the moon geometry\n vWorldNormal = normalize(mat3(modelMatrix) * normal);\n\n vec4 worldPosition = modelMatrix * vec4(position, 1.0);\n vWorldPosition = worldPosition.xyz;\n vec4 viewPosition = viewMatrix * worldPosition;\n vViewPosition = viewPosition.xyz;\n gl_Position = projectionMatrix * viewPosition;\n}\n",fragmentShader:"\n/**\n * Moon Crescent Fragment Shader\n *\n * Uses directional half-space test in WORLD SPACE to create realistic terminator:\n * - Light direction fixed in world space (like the sun)\n * - Normals rotate with moon geometry (in world space)\n * - dot(normal, lightDir) < 0 = shadow side\n * - dot(normal, lightDir) > 0 = lit side\n * - Smooth terminator with earthshine on dark side\n */\n\nuniform sampler2D colorMap;\nuniform sampler2D normalMap;\nuniform vec2 shadowOffset; // Controls light direction (x=horizontal, y=vertical)\nuniform float shadowCoverage; // Unused for directional shadow\nuniform float shadowSoftness; // Terminator edge softness (default: 0.05)\nuniform vec3 glowColor;\nuniform float glowIntensity;\nuniform float opacity; // Fade in opacity (0-1) to prevent gray flash during texture load\n\n// Lunar Eclipse (Blood Moon) uniforms\nuniform float eclipseProgress; // 0.0 = no eclipse, 1.0 = totality\nuniform float eclipseIntensity; // Darkening strength (0.0-1.0)\nuniform vec3 bloodMoonColor; // Deep reddish-orange for total eclipse\nuniform float blendMode; // 0=Multiply, 1=LinearBurn, 2=ColorBurn, 3=ColorDodge, 4=Screen, 5=Overlay\nuniform float blendStrength; // Blend strength multiplier (0.0-5.0)\nuniform float emissiveStrength; // Emissive glow strength (0.0-1.0)\n\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vWorldNormal; // WORLD SPACE normal (rotates with moon)\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n // DIRECTIONAL SHADOW in WORLD SPACE - realistic moon phase lighting\n // Light direction is fixed in world space, shadow rotates with moon\n\n // Use world-space normal (rotates with moon geometry)\n vec3 worldNormal = normalize(vWorldNormal);\n\n // Light direction in WORLD SPACE\n // shadowOffset.x controls horizontal angle (left/right)\n // shadowOffset.y controls vertical angle (up/down)\n // For thin crescents, we need extreme angles (light from the side or behind)\n\n float lightX = shadowOffset.x;\n float lightY = shadowOffset.y;\n\n // Adaptive Z component with LOGARITHMIC scaling for wider angular range\n // Goal: Spread phases across full 0° to 180° instead of plateauing at 135°\n //\n // Target angles after normalization:\n // - Full moon (x=0): 0° (light from front)\n // - Quarter moon (x=1): 90° (light from side)\n // - Crescent (x=3): 120° (thin crescent)\n // - New moon (x=10): 170° (nearly behind)\n\n float offsetMagnitude = length(vec2(lightX, lightY));\n\n // Use exponential decay for Z to spread angular range\n // Formula: Z = 1.0 - offsetMagnitude^1.5 for better distribution\n float lightZ = 1.0 - pow(offsetMagnitude, 1.5);\n\n // Normalize the light direction vector\n vec3 lightDir = normalize(vec3(lightX, lightY, lightZ));\n\n // Calculate how much this fragment faces the light source\n float facing = dot(worldNormal, lightDir);\n\n // Smooth transition at terminator (shadow boundary)\n // Softer edge for realistic lunar terminator (like real moon photography)\n // Use fwidth() for automatic screen-space anti-aliasing\n float edgeWidth = max(fwidth(facing) * 4.0, shadowSoftness * 3.0);\n float shadowFactor = smoothstep(-edgeWidth, edgeWidth, facing);\n\n // Sample moon surface texture\n vec4 texColor = texture2D(colorMap, vUv);\n\n // Fallback to gray if texture not loaded yet\n float brightness = texColor.r + texColor.g + texColor.b;\n if (brightness < 0.03) {\n texColor = vec4(0.5, 0.5, 0.5, 1.0);\n }\n\n // LIMB DARKENING: Moon gets darker at edges (spherical falloff)\n vec3 viewDir = normalize(-vViewPosition);\n float rimFactor = dot(worldNormal, viewDir);\n float limbDarkening = smoothstep(0.0, 0.6, rimFactor); // Subtle edge darkening\n\n // DIFFUSE LIGHTING: Vary brightness across lit surface (not uniform)\n // More realistic Lambertian diffuse reflection\n float diffuse = max(facing, 0.0);\n float diffuseLighting = mix(0.7, 1.0, diffuse); // Subtle variation\n\n // EARTHSHINE: Almost invisible (~1% for ultimate realism)\n vec3 earthshine = texColor.rgb * 0.01 * vec3(0.35, 0.4, 0.6);\n\n // Apply dramatic shadow transition with maximum contrast\n float litFactor = pow(shadowFactor, 2.0); // Maximum contrast\n\n // TEXTURE ENHANCEMENT: Boost surface detail contrast\n // Slightly darken dark areas, brighten bright areas of texture\n vec3 detailEnhanced = texColor.rgb * 1.08; // Subtle boost\n float textureLuminance = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));\n detailEnhanced = mix(texColor.rgb * 0.95, texColor.rgb * 1.12, smoothstep(0.3, 0.7, textureLuminance));\n\n // Combine enhanced texture with diffuse lighting\n vec3 litColor = detailEnhanced * diffuseLighting;\n vec3 shadowedColor = mix(earthshine, litColor, litFactor);\n\n // Apply limb darkening (slightly stronger for more depth)\n shadowedColor *= mix(0.6, 1.0, limbDarkening);\n\n // Nearly zero emissive for pure realism\n vec3 emissive = vec3(0.02, 0.02, 0.02) * shadowFactor;\n\n // Emotion glow (almost invisible)\n vec3 emotionGlow = glowColor * glowIntensity * 0.02 * shadowFactor;\n\n // Combine all lighting components\n vec3 finalColor = shadowedColor + emissive + emotionGlow;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LUNAR ECLIPSE (BLOOD MOON) EFFECT\n // ═══════════════════════════════════════════════════════════════════════════\n // Simulates Earth's umbral shadow with Rayleigh scattering (reddish glow)\n if (eclipseProgress > 0.001) {\n // Calculate gradient from lit edge to dark center\n // Use rim factor (view angle) to create radial gradient\n float gradientFactor = rimFactor; // 1.0 at edges, 0.0 at center\n\n // Darken the moon (Earth's shadow)\n float darkeningFactor = 1.0 - eclipseIntensity;\n finalColor *= darkeningFactor;\n\n // ═══════════════════════════════════════════════════════════════════\n // PHOTOSHOP-STYLE BLEND MODES: Multiple modes for deep saturation control\n // ═══════════════════════════════════════════════════════════════════\n\n // Define blood moon gradient colors\n vec3 deepRed = vec3(0.6, 0.2, 0.12); // Dark burnt red-orange (center)\n vec3 brightOrange = vec3(0.95, 0.45, 0.22); // Bright burnt orange (edges)\n\n // Create radial gradient from center (dark) to edge (bright)\n vec3 bloodGradient = mix(deepRed, brightOrange, pow(gradientFactor, 1.8));\n\n // Apply blend strength multiplier\n vec3 blendColor = bloodGradient * blendStrength;\n\n // Calculate all blend modes\n vec3 finalBlend;\n int mode = int(blendMode + 0.5); // Round to nearest int\n\n if (mode == 0) {\n // MULTIPLY: base * blend\n finalBlend = finalColor * blendColor;\n } else if (mode == 1) {\n // LINEAR BURN: base + blend - 1\n finalBlend = max(finalColor + blendColor - vec3(1.0), vec3(0.0));\n } else if (mode == 2) {\n // COLOR BURN: (blend==0.0) ? 0.0 : max((1.0-((1.0-base)/blend)), 0.0)\n finalBlend = vec3(\n blendColor.r == 0.0 ? 0.0 : max(1.0 - ((1.0 - finalColor.r) / blendColor.r), 0.0),\n blendColor.g == 0.0 ? 0.0 : max(1.0 - ((1.0 - finalColor.g) / blendColor.g), 0.0),\n blendColor.b == 0.0 ? 0.0 : max(1.0 - ((1.0 - finalColor.b) / blendColor.b), 0.0)\n );\n } else if (mode == 3) {\n // COLOR DODGE: (blend==1.0) ? 1.0 : min(base/(1.0-blend), 1.0)\n finalBlend = vec3(\n blendColor.r == 1.0 ? 1.0 : min(finalColor.r / (1.0 - blendColor.r), 1.0),\n blendColor.g == 1.0 ? 1.0 : min(finalColor.g / (1.0 - blendColor.g), 1.0),\n blendColor.b == 1.0 ? 1.0 : min(finalColor.b / (1.0 - blendColor.b), 1.0)\n );\n } else if (mode == 4) {\n // SCREEN: 1 - (1 - base) * (1 - blend)\n finalBlend = vec3(1.0) - (vec3(1.0) - finalColor) * (vec3(1.0) - blendColor);\n } else {\n // OVERLAY: base < 0.5 ? (2 * base * blend) : (1 - 2 * (1 - base) * (1 - blend))\n finalBlend = vec3(\n finalColor.r < 0.5 ? (2.0 * finalColor.r * blendColor.r) : (1.0 - 2.0 * (1.0 - finalColor.r) * (1.0 - blendColor.r)),\n finalColor.g < 0.5 ? (2.0 * finalColor.g * blendColor.g) : (1.0 - 2.0 * (1.0 - finalColor.g) * (1.0 - blendColor.g)),\n finalColor.b < 0.5 ? (2.0 * finalColor.b * blendColor.b) : (1.0 - 2.0 * (1.0 - finalColor.b) * (1.0 - blendColor.b))\n );\n }\n\n // Apply blood moon effect\n finalColor = mix(finalColor, finalBlend, eclipseProgress);\n\n // Add emissive glow for visibility\n finalColor += bloodGradient * emissiveStrength * eclipseProgress;\n\n // Add bright rim glow during totality (refracted atmosphere light)\n if (eclipseProgress > 0.7) {\n float rimIntensity = pow(gradientFactor, 2.5); // Sharp falloff from edge\n vec3 rimGlow = brightOrange * rimIntensity * (eclipseProgress - 0.7) * 2.5;\n finalColor += rimGlow;\n }\n }\n\n // Apply fade-in opacity to prevent gray flash during texture load\n gl_FragColor = vec4(finalColor, opacity);\n}\n"}}(o),g=new e.ShaderMaterial({uniforms:{colorMap:{value:null},normalMap:{value:null},shadowOffset:{value:new e.Vector2(l,h)},shadowCoverage:{value:c},shadowSoftness:{value:.05},glowColor:{value:a},glowIntensity:{value:s},opacity:{value:0},eclipseProgress:{value:0},eclipseIntensity:{value:0},bloodMoonColor:{value:[.85,.18,.08]},blendMode:{value:0},blendStrength:{value:2},emissiveStrength:{value:.39},eclipseShadowPos:{value:[-2,0]},eclipseShadowRadius:{value:1.2},eclipseShadowColor:{value:[.85,.08,.02]},eclipseMidtoneColor:{value:[1,.12,.03]},eclipseHighlightColor:{value:[1,.35,.08]},eclipseGlowColor:{value:[1,.4,.1]}},vertexShader:m,fragmentShader:p,transparent:!0,side:e.FrontSide}),f=new Map;f.set(u,{texture:null});const y=t.load(u,e=>{g.uniforms.colorMap.value=e;const t=performance.now(),i=()=>{const e=performance.now()-t,n=Math.min(e/300,1);g.uniforms.opacity.value=n,g.needsUpdate=!0,n<1&&requestAnimationFrame(i)};i();const n=f.get(u);n&&(n.texture=e),f.delete(u)},void 0,e=>{console.error("❌ Failed to load moon crescent color texture:",e),f.delete(u)});f.set(d,{texture:null});const v=t.load(d,e=>{g.uniforms.normalMap.value=e,g.needsUpdate=!0;const t=f.get(d);t&&(t.texture=e),f.delete(d)},void 0,e=>{console.error("❌ Failed to load moon crescent normal map:",e),f.delete(d)});return y.wrapS=y.wrapT=e.RepeatWrapping,v.wrapS=v.wrapT=e.RepeatWrapping,y.anisotropy=16,v.anisotropy=16,g.userData.pendingTextures=f,g}function G(e,t={}){return L(e,{...t,shadowType:"crescent"})}function V(e,t){if(!e.uniforms||!e.uniforms.shadowOffset)return console.warn("Material does not have shadowOffset uniform"),!1;let i;if("string"==typeof t){if(i=I[t],!i)return console.warn(`Unknown moon phase: ${t}`),!1}else{if("number"!=typeof t)return console.warn("Phase must be a string or number"),!1;i=R(t)}return e.uniforms.shadowOffset.value.set(i.x,i.y),!0}function q(e,t,i=2e3){let n=null,a=!1;const s=new Promise((s,o)=>{if(!e.uniforms||!e.uniforms.shadowOffset)return void o(new Error("Material does not have shadowOffset uniform"));let r;if("string"==typeof t){if(r=I[t],!r)return void o(new Error(`Unknown moon phase: ${t}`))}else{if("number"!=typeof t)return void o(new Error("Phase must be a string or number"));r=R(t)}const l=e.uniforms.shadowOffset.value.x,h=e.uniforms.shadowOffset.value.y,c=r.x,u=r.y,d=Date.now(),m=()=>{if(a)return void s({cancelled:!0});const t=Date.now()-d,o=Math.min(t/i,1),r=o<.5?4*o*o*o:1-Math.pow(-2*o+2,3)/2,p=l+(c-l)*r,g=h+(u-h)*r;e.uniforms.shadowOffset.value.set(p,g),o<1?n=requestAnimationFrame(m):s({cancelled:!1})};m()});return{promise:s,cancel:()=>{a=!0,null!==n&&(cancelAnimationFrame(n),n=null)}}}function N(e,t,i){e.emissive&&(e.emissive.copy(t),e.emissiveIntensity=i),e.uniforms&&e.uniforms.glowColor&&(e.uniforms.glowColor.value.copy(t),e.uniforms.glowIntensity.value=i)}function j(e,t,i,n){e.uniforms&&e.uniforms.shadowOffset&&(e.uniforms.shadowOffset.value.set(t,i),e.uniforms.shadowCoverage.value=n)}function U(t,i={}){const{resolution:n="2k",glowColor:a=new e.Color(16777215),glowIntensity:s=1,assetBasePath:o="/assets"}=i,{vertexShader:r,fragmentShader:l}={vertexShader:"\n/**\n * Moon Vertex Shader\n * Passes view-space normal for camera-relative moon phase shadows\n */\n\nvarying vec3 vPosition; // LOCAL position (object space)\nvarying vec3 vWorldPosition;\nvarying vec3 vViewNormal; // VIEW SPACE normal (fixed relative to camera)\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n vPosition = position;\n\n // Transform normal to VIEW space (camera-relative)\n // This keeps the moon phase shadow fixed relative to camera view\n // When you rotate the moon, the texture rotates but the phase shadow stays put\n vViewNormal = normalize(normalMatrix * normal);\n\n vec4 worldPosition = modelMatrix * vec4(position, 1.0);\n vWorldPosition = worldPosition.xyz;\n vec4 viewPosition = viewMatrix * worldPosition;\n vViewPosition = viewPosition.xyz;\n gl_Position = projectionMatrix * viewPosition;\n}\n",fragmentShader:P},h=new e.ShaderMaterial({uniforms:{colorMap:{value:null},normalMap:{value:null},shadowOffset:{value:new e.Vector2(0,0)},shadowCoverage:{value:.5},shadowSoftness:{value:.05},glowColor:{value:a},glowIntensity:{value:s},opacity:{value:0},eclipseProgress:{value:0},eclipseIntensity:{value:0},bloodMoonColor:{value:[.85,.18,.08]},emissiveStrength:{value:.39},eclipseShadowPos:{value:[-2,0]},eclipseShadowRadius:{value:1.2},eclipseShadowColor:{value:[1,.58,0]},eclipseMidtoneColor:{value:[.71,.43,.03]},eclipseHighlightColor:{value:[1,.28,.1]},eclipseGlowColor:{value:[.09,.09,.09]},eclipseBrightnessModel:{value:0},shadowDarkness:{value:.53},layer1Mode:{value:9},layer1Strength:{value:.322},layer1Enabled:{value:1},layer2Mode:{value:0},layer2Strength:{value:2.785},layer2Enabled:{value:1},layer3Mode:{value:7},layer3Strength:{value:.199},layer3Enabled:{value:1},layer4Mode:{value:0},layer4Strength:{value:0},layer4Enabled:{value:0}},vertexShader:r,fragmentShader:l,transparent:!0,depthWrite:!0,side:e.FrontSide}),c=`${o}/textures/Moon/moon-color-${n}.jpg`,u=`${o}/textures/Moon/moon-normal-${n}.jpg`;return t.load(c,e=>{h.uniforms.colorMap.value=e;const t=performance.now(),i=()=>{const e=performance.now()-t,n=Math.min(e/300,1);h.uniforms.opacity.value=n,h.needsUpdate=!0,n<1&&requestAnimationFrame(i)};i()}),t.load(u,e=>{h.uniforms.normalMap.value=e}),h}const H=`\n/**\n * Sun Fragment Shader with Blend Layers and Solar Eclipse\n *\n * Supports solar eclipse effects with moon's shadow darkening the sun\n * and up to 4 sequential blend mode layers for eclipse appearance adjustment\n */\n\nuniform float time;\nuniform sampler2D colorMap;\nuniform sampler2D normalMap;\nuniform vec3 baseColor;\nuniform float emissiveIntensity;\nuniform vec2 shadowOffset;\nuniform float shadowCoverage;\nuniform float shadowSoftness;\nuniform float opacity;\n\n// Solar Eclipse uniforms (moon's shadow covering sun)\nuniform float eclipseProgress; // Eclipse progress (0 = no eclipse, 1 = totality)\nuniform vec2 eclipseShadowPos; // Shadow center position in UV space\nuniform float eclipseShadowRadius; // Moon's shadow radius\nuniform float shadowDarkness; // How much to darken the sun (0-1)\n\n// Blend Layer Uniforms (up to 4 layers)\nuniform float layer1Mode;\nuniform float layer1Strength;\nuniform float layer1Enabled;\n\nuniform float layer2Mode;\nuniform float layer2Strength;\nuniform float layer2Enabled;\n\nuniform float layer3Mode;\nuniform float layer3Strength;\nuniform float layer3Enabled;\n\nuniform float layer4Mode;\nuniform float layer4Strength;\nuniform float layer4Enabled;\n\nvarying vec2 vUv;\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition; // View-space position (camera-relative)\n\n// ═══════════════════════════════════════════════════════════════════════════\n// UNIVERSAL BLEND MODES (injected from utils/blendModes.js)\n// ═══════════════════════════════════════════════════════════════════════════\n${S}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// SIMPLEX NOISE (for fire animation - from original sun shader)\n// ═══════════════════════════════════════════════════════════════════════════\nvec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\nvec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }\nvec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\nfloat snoise(vec3 v) {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n vec3 i = floor(v + dot(v, C.yyy));\n vec3 x0 = v - i + dot(i, C.xxx);\n\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min(g.xyz, l.zxy);\n vec3 i2 = max(g.xyz, l.zxy);\n\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy;\n vec3 x3 = x0 - D.yyy;\n\n i = mod289(i);\n vec4 p = permute(permute(permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0));\n\n float n_ = 0.142857142857;\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_);\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4(x.xy, y.xy);\n vec4 b1 = vec4(x.zw, y.zw);\n\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;\n vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;\n\n vec3 p0 = vec3(a0.xy, h.x);\n vec3 p1 = vec3(a0.zw, h.y);\n vec3 p2 = vec3(a1.xy, h.z);\n vec3 p3 = vec3(a1.zw, h.w);\n\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));\n}\n\nvoid main() {\n // ═══════════════════════════════════════════════════════════════════════════\n // BASE SUN RENDERING (photosphere texture + fire animation)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Sample base photosphere texture\n vec4 texColor = texture2D(colorMap, vUv);\n\n // Optimized single-octave noise for subtle fire\n vec3 noiseCoord = vPosition * 30.0 + vec3(0.0, time * 0.025, 0.0);\n float fireNoise = snoise(noiseCoord);\n\n // Simple threshold - fire appears only in specific noise ranges\n float fireMask = fireNoise * 0.5 + 0.5; // Remap -1..1 to 0..1\n fireMask = step(0.45, fireMask) * (1.0 - step(0.55, fireMask)); // Only 0.45-0.55 range\n\n // Almost imperceptible warmth shift\n vec3 fireColor = vec3(1.01, 1.0, 0.99);\n\n // Microscopic blending\n vec3 finalColor = mix(texColor.rgb, fireColor, fireMask * 0.008);\n\n // Apply base color tinting\n finalColor *= baseColor;\n\n // Apply emissive intensity for HDR bloom\n finalColor *= emissiveIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LIMB DARKENING (realistic solar effect - edges appear darker than center)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Calculate distance from center (0 at center, 1 at edge)\n float distFromCenterLimb = length(vWorldPosition.xy) / 0.5; // normalize by sun radius (0.5)\n distFromCenterLimb = clamp(distFromCenterLimb, 0.0, 1.0);\n\n // Limb darkening formula: I(μ) = 1 - u*(1-μ) where μ = cos(viewing angle)\n // Simplified using distance: darker at edges, brighter at center\n float mu = sqrt(1.0 - distFromCenterLimb * distFromCenterLimb); // cos approximation\n // EXTREME limb darkening for visibility\n float limbDarkeningCoeff = 0.98; // 98% darkening at edges\n float limbBrightness = 1.0 - limbDarkeningCoeff * (1.0 - mu);\n limbBrightness = pow(limbBrightness, 0.4); // Very aggressive power curve\n\n // Clamp to prevent over-darkening\n limbBrightness = max(limbBrightness, 0.02); // Edges at least 2% brightness\n\n // Apply limb darkening (BEFORE bloom processing)\n finalColor *= limbBrightness;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // SOLAR ECLIPSE EFFECT (Moon Occulting Sun)\n // ═══════════════════════════════════════════════════════════════════════════\n // Solar eclipse: Moon passes BETWEEN viewer and sun, blocking our view\n // The moon appears as a dark circular disk that covers parts of the sun\n // From Earth, moon and sun appear same angular size (0.5°)\n\n // Only apply eclipse if there's a moon to occlude (radius > 0)\n if (eclipseShadowRadius > 0.01) {\n // Only occlude FRONT-FACING parts of the sun (vViewPosition.z < 0 faces camera in view space)\n // Back of sun should not be affected by moon\n if (vViewPosition.z < 0.1) {\n // Project to screen space - camera-relative, independent of sun rotation\n // vViewPosition.xy is already in camera space, just normalize to sun radius\n // Sun radius in view space is approximately 0.5 at typical camera distance\n vec2 screenPos = vViewPosition.xy;\n\n // Moon center position in screen space (same coordinate system)\n vec2 moonCenter = eclipseShadowPos;\n\n // Distance from this sun point to moon center (2D screen space)\n float distToMoon = length(screenPos - moonCenter);\n\n // Moon's angular size (appears same size as sun from Earth)\n // In normalized screen space, sun radius = 1.0, moon radius = 1.0 for total eclipse\n float moonRadius = eclipseShadowRadius;\n float moonEdge = 0.01; // Sharp edge for moon silhouette\n\n // Check if moon blocks this point (moon is in front of sun)\n float moonOcclusion = 1.0 - smoothstep(moonRadius - moonEdge, moonRadius + moonEdge, distToMoon);\n\n // Only apply if moon is actually occluding something\n if (moonOcclusion > 0.001) {\n // Moon completely blocks sun where it overlaps (no light gets through)\n finalColor *= (1.0 - moonOcclusion);\n\n // Subtle penumbra around moon edge (diffraction)\n float penumbraRadius = moonRadius * 1.02;\n float penumbraEdge = 0.03;\n float penumbra = 1.0 - smoothstep(penumbraRadius - penumbraEdge, penumbraRadius + penumbraEdge, distToMoon);\n float penumbraBlocking = (penumbra - moonOcclusion) * 0.2;\n finalColor *= (1.0 - penumbraBlocking);\n }\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // BLEND LAYERS (Applied globally to entire sun)\n // These allow adjusting the appearance of the sun\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Layer 1\n if (layer1Enabled > 0.5) {\n vec3 blendColor1 = vec3(min(layer1Strength, 1.0));\n int mode1 = int(layer1Mode + 0.5);\n vec3 blended1 = clamp(applyBlendMode(finalColor, blendColor1, mode1), 0.0, 1.0);\n finalColor = clamp(blended1, 0.0, 1.0);\n }\n\n // Layer 2\n if (layer2Enabled > 0.5) {\n vec3 blendColor2 = vec3(min(layer2Strength, 1.0));\n int mode2 = int(layer2Mode + 0.5);\n vec3 blended2 = clamp(applyBlendMode(finalColor, blendColor2, mode2), 0.0, 1.0);\n finalColor = clamp(blended2, 0.0, 1.0);\n }\n\n // Layer 3\n if (layer3Enabled > 0.5) {\n vec3 blendColor3 = vec3(min(layer3Strength, 1.0));\n int mode3 = int(layer3Mode + 0.5);\n vec3 blended3 = clamp(applyBlendMode(finalColor, blendColor3, mode3), 0.0, 1.0);\n finalColor = clamp(blended3, 0.0, 1.0);\n }\n\n // Layer 4\n if (layer4Enabled > 0.5) {\n vec3 blendColor4 = vec3(min(layer4Strength, 1.0));\n int mode4 = int(layer4Mode + 0.5);\n vec3 blended4 = clamp(applyBlendMode(finalColor, blendColor4, mode4), 0.0, 1.0);\n finalColor = clamp(blended4, 0.0, 1.0);\n }\n\n // Apply fade-in opacity to prevent texture flash during load\n gl_FragColor = vec4(finalColor, opacity);\n}\n`,W={baseSpeed:.01,axes:[0,1,0]};function X(t,i={}){const n=i.resolution||"4k",a=i.glowColor||[1,1,1],s=i.glowIntensity||1,o=i.materialVariant||null,r=i.assetBasePath||"/assets",l=`${r}/textures/Sun/sun-photosphere-${n}.jpg`,h=`${r}/textures/Sun/sun-photosphere-normal-${n}.jpg`,c=1+2*s,u=new e.Color(c*a[0],c*a[1],c*a[2]*.95),d=new Map;d.set(l,{texture:null});const m=t.load(l,e=>{v.uniforms?.opacity&&(v.uniforms.opacity.value=1);const t=d.get(l);t&&(t.texture=e),d.delete(l)},void 0,e=>{console.warn(`⚠️ Failed to load sun texture (${n}), using color fallback:`,e),d.delete(l)});d.set(h,{texture:null});const p=t.load(h,e=>{const t=d.get(h);t&&(t.texture=e),d.delete(h)},void 0,e=>{console.warn(`⚠️ Sun normal map not found (${n}), continuing without surface detail:`,e),d.delete(h)});let g,f;m.wrapS=m.wrapT=e.RepeatWrapping,p.wrapS=p.wrapT=e.RepeatWrapping,m.anisotropy=16,p.anisotropy=16;let y={};if("multiplexer"===o){const{vertexShader:e,fragmentShader:t}={vertexShader:"\n/**\n * Sun Vertex Shader\n * Passes view-space position for camera-relative eclipse shadow calculations\n */\n\nvarying vec2 vUv;\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec3 vWorldPosition;\nvarying vec3 vViewPosition; // View-space position (camera-relative)\n\nvoid main() {\n vUv = uv;\n vNormal = normalize(normalMatrix * normal);\n vPosition = position;\n vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n\n // Calculate view-space position (camera-relative, always faces camera)\n vec4 viewPos = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = viewPos.xyz;\n\n gl_Position = projectionMatrix * viewPos;\n}\n",fragmentShader:H};g=e,f=t,y={eclipseProgress:{value:0},eclipseShadowPos:{value:[-2,0]},eclipseShadowRadius:{value:.882},shadowDarkness:{value:1},layer1Mode:{value:0},layer1Strength:{value:.23},layer1Enabled:{value:1},layer2Mode:{value:0},layer2Strength:{value:0},layer2Enabled:{value:0},layer3Mode:{value:0},layer3Strength:{value:0},layer3Enabled:{value:0},layer4Mode:{value:0},layer4Strength:{value:0},layer4Enabled:{value:0}}}else g="\n varying vec2 vUv;\n varying vec3 vNormal;\n varying vec3 vPosition;\n varying vec3 vWorldPosition;\n\n void main() {\n vUv = uv;\n vNormal = normalize(normalMatrix * normal);\n vPosition = position;\n vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",f="\n uniform float time;\n uniform sampler2D colorMap;\n uniform sampler2D normalMap;\n uniform vec3 baseColor;\n uniform float emissiveIntensity;\n uniform vec2 shadowOffset;\n uniform float shadowCoverage;\n uniform float shadowSoftness;\n uniform float opacity; // Fade in opacity (0-1) to prevent texture flash\n\n varying vec2 vUv;\n varying vec3 vNormal;\n varying vec3 vPosition;\n varying vec3 vWorldPosition;\n\n // Simplex noise for fire animation (Ashima Arts)\n vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }\n vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }\n vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }\n\n float snoise(vec3 v) {\n const vec2 C = vec2(1.0/6.0, 1.0/3.0);\n const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);\n\n vec3 i = floor(v + dot(v, C.yyy));\n vec3 x0 = v - i + dot(i, C.xxx);\n\n vec3 g = step(x0.yzx, x0.xyz);\n vec3 l = 1.0 - g;\n vec3 i1 = min(g.xyz, l.zxy);\n vec3 i2 = max(g.xyz, l.zxy);\n\n vec3 x1 = x0 - i1 + C.xxx;\n vec3 x2 = x0 - i2 + C.yyy;\n vec3 x3 = x0 - D.yyy;\n\n i = mod289(i);\n vec4 p = permute(permute(permute(\n i.z + vec4(0.0, i1.z, i2.z, 1.0))\n + i.y + vec4(0.0, i1.y, i2.y, 1.0))\n + i.x + vec4(0.0, i1.x, i2.x, 1.0));\n\n float n_ = 0.142857142857;\n vec3 ns = n_ * D.wyz - D.xzx;\n\n vec4 j = p - 49.0 * floor(p * ns.z * ns.z);\n\n vec4 x_ = floor(j * ns.z);\n vec4 y_ = floor(j - 7.0 * x_);\n\n vec4 x = x_ *ns.x + ns.yyyy;\n vec4 y = y_ *ns.x + ns.yyyy;\n vec4 h = 1.0 - abs(x) - abs(y);\n\n vec4 b0 = vec4(x.xy, y.xy);\n vec4 b1 = vec4(x.zw, y.zw);\n\n vec4 s0 = floor(b0)*2.0 + 1.0;\n vec4 s1 = floor(b1)*2.0 + 1.0;\n vec4 sh = -step(h, vec4(0.0));\n\n vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;\n vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;\n\n vec3 p0 = vec3(a0.xy, h.x);\n vec3 p1 = vec3(a0.zw, h.y);\n vec3 p2 = vec3(a1.xy, h.z);\n vec3 p3 = vec3(a1.zw, h.w);\n\n vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));\n p0 *= norm.x;\n p1 *= norm.y;\n p2 *= norm.z;\n p3 *= norm.w;\n\n vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);\n m = m * m;\n return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));\n }\n\n void main() {\n // Sample base photosphere texture\n vec4 texColor = texture2D(colorMap, vUv);\n\n // Optimized single-octave noise for subtle fire (was 2 FBM calls with 3 octaves each)\n // Using position-based noise with time offset for animation\n vec3 noiseCoord = vPosition * 30.0 + vec3(0.0, time * 0.025, 0.0);\n float fireNoise = snoise(noiseCoord);\n\n // Simple threshold - fire appears only in specific noise ranges\n // Using step functions instead of smoothstep for performance\n float fireMask = fireNoise * 0.5 + 0.5; // Remap -1..1 to 0..1\n fireMask = step(0.45, fireMask) * (1.0 - step(0.55, fireMask)); // Only 0.45-0.55 range\n\n // Almost imperceptible warmth shift (same visual as before)\n vec3 fireColor = vec3(1.01, 1.0, 0.99);\n\n // Microscopic blending - nearly invisible (same blend factor)\n vec3 finalColor = mix(texColor.rgb, fireColor, fireMask * 0.008);\n\n // Apply base color tinting\n finalColor *= baseColor;\n\n // Apply emissive intensity for HDR bloom\n finalColor *= emissiveIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // LIMB DARKENING (realistic solar effect - edges appear darker than center)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Calculate distance from center (0 at center, 1 at edge)\n float distFromCenterLimb = length(vWorldPosition.xy) / 0.5; // normalize by sun radius (0.5)\n distFromCenterLimb = clamp(distFromCenterLimb, 0.0, 1.0);\n\n // Limb darkening formula: I(μ) = 1 - u*(1-μ) where μ = cos(viewing angle)\n // Simplified using distance: darker at edges, brighter at center\n float mu = sqrt(1.0 - distFromCenterLimb * distFromCenterLimb); // cos approximation\n float limbDarkeningCoeff = 0.6; // NASA solar data: ~60% darkening at limb\n float limbBrightness = 1.0 - limbDarkeningCoeff * (1.0 - mu);\n\n // Apply limb darkening (preserves bright core for bloom)\n finalColor *= limbBrightness;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // SHADOW DARKENING (applied AFTER bloom intensity so it doesn't affect bloom)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Sun sphere center (world space origin)\n float sunRadius = 0.5; // Matches geometry radius\n\n // Shadow sphere center (offset from sun center)\n vec3 shadowCenter = vec3(shadowOffset.x, shadowOffset.y, 0.0);\n\n // Calculate distance from fragment to shadow sphere center\n float distToShadow = distance(vWorldPosition, shadowCenter);\n\n // Shadow threshold (shadow sphere radius adjusted by coverage)\n float shadowRadius = sunRadius * shadowCoverage;\n\n // Calculate shadow factor (0 = full shadow, 1 = no shadow)\n float shadowFactor = smoothstep(shadowRadius - shadowSoftness, shadowRadius + shadowSoftness, distToShadow);\n\n // Darken ONLY the final color output (not the bloom calculation)\n float shadowDarkness = 0.05; // How dark the shadow gets (5% brightness)\n finalColor *= mix(shadowDarkness, 1.0, shadowFactor);\n\n // ═══════════════════════════════════════════════════════════════════════════\n // RADIAL CORONA WAVES (applied AFTER shadow, visible around eclipse edge)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Calculate angle from sun center in world space XY plane\n float angle = atan(vWorldPosition.y, vWorldPosition.x);\n\n // Create radial wave pattern (16 petals for finer detail, rotating slowly)\n float wave = sin(angle * 16.0 + time * 0.3) * 0.5 + 0.5;\n\n // Apply waves to visible (non-shadowed) edges\n float distFromCenter = length(vWorldPosition.xy);\n\n // Edge factor: strong at sun's edge where bloom will amplify it\n float edgeFactor = smoothstep(0.35, 0.5, distFromCenter);\n\n // Only apply waves to non-shadowed areas (visible during eclipse)\n // Combine with shadow factor so waves appear around shadow edge\n float waveStrength = edgeFactor * shadowFactor;\n\n // Very strong modulation (2x variation) for dramatic eclipse corona\n float coronaModulation = 1.0 + (wave * 2.0 - 1.0) * waveStrength;\n finalColor *= coronaModulation;\n\n // Apply fade-in opacity to prevent texture flash during load\n gl_FragColor = vec4(finalColor, opacity);\n }\n ";const v=new e.ShaderMaterial({uniforms:{time:{value:0},colorMap:{value:m},normalMap:{value:p},baseColor:{value:u},emissiveIntensity:{value:1.2},glowColor:{value:new e.Color(1,1,1)},glowIntensity:{value:1},shadowOffset:{value:new e.Vector2(200,0)},shadowCoverage:{value:.5},shadowSoftness:{value:.1},opacity:{value:0},...y},vertexShader:g,fragmentShader:f,transparent:!0,toneMapped:!1});return v.userData.uniforms=v.uniforms,v.userData.pendingTextures=d,v}function Y(t=null,i={}){const n=i.glowColor||[1,1,1],a=i.glowIntensity||1,s=i.resolution||"4k",o=i.materialVariant||null,r=new e.SphereGeometry(.5,128,128);let l;if(r.userData.tracked=!0,t)l=X(t,{glowColor:n,glowIntensity:a,resolution:s,materialVariant:o});else{const t=1+2*a,i=new e.Color(t*n[0],t*n[1],t*n[2]*.95);l=new e.MeshBasicMaterial({color:i,toneMapped:!1})}const h=new e.Mesh(r,l);return h.castShadow=!1,h.receiveShadow=!1,h}function $(e,t,i=1,n=0){if(!e||!e.material)return;const{material:a}=e;if(a.uniforms&&a.uniforms.baseColor){const{uniforms:e}=a;n>0&&(e.time.value=(e.time.value+n)%(2*Math.PI));const t=1+2*i;e.baseColor.value.setRGB(t,t,.95*t),e.emissiveIntensity.value=1.2}else if(a.color){const e=1+2*i;a.color.setRGB(e,e,.95*e)}}function Q(e){if(e&&(e.geometry&&e.geometry.dispose(),e.material)){const{material:t}=e;t.userData&&t.userData.pendingTextures&&(t.userData.pendingTextures.forEach(({texture:e})=>{e&&e.dispose()}),t.userData.pendingTextures.clear()),t.uniforms&&(t.uniforms.colorMap&&t.uniforms.colorMap.value&&t.uniforms.colorMap.value.dispose(),t.uniforms.normalMap&&t.uniforms.normalMap.value&&t.uniforms.normalMap.value.dispose()),t.map&&t.map.dispose(),t.normalMap&&t.normalMap.dispose(),t.dispose()}}function Z(){const t=new e.SphereGeometry(.5,32,32),i=t.attributes.position;for(let e=0;e<i.count;e++){let t=i.getX(e);const n=i.getY(e);let a=i.getZ(e);const s=1+.3*Math.max(0,n);if(t*=s,a*=.8*s,n<-.3){const e=(-n-.3)/.2;t*=1-.8*e,a*=1-.8*e}i.setXYZ(e,t,n,a)}return t.computeVertexNormals(),t}function J(){const t=new e.DodecahedronGeometry(.5,0);return t.computeVertexNormals(),t}function K(){const t=new e.BufferGeometry,i=[],n=[];i.push(0,2.3,0);for(let e=0;e<6;e++){const t=e/6*Math.PI*2;i.push(1*Math.cos(t),1.5,1*Math.sin(t))}for(let e=0;e<6;e++){const t=e/6*Math.PI*2;i.push(1*Math.cos(t),-1.5,1*Math.sin(t))}i.push(0,-2.3,0);for(let e=0;e<6;e++){const t=(e+1)%6;n.push(0,1+e,1+t)}for(let e=0;e<6;e++){const t=(e+1)%6;n.push(1+e,7+e,1+t),n.push(1+t,7+e,7+t)}for(let e=0;e<6;e++){const t=(e+1)%6;n.push(13,7+t,7+e)}t.setAttribute("position",new e.Float32BufferAttribute(i,3)),t.setIndex(n);const a=1.6/4.6;return t.scale(a,a,a),t.computeVertexNormals(),t}function ee(t=.4,i=.15,n=32,a=64){return new e.TorusGeometry(t,i,n,a)}function te(t=.5,i=1){return new e.IcosahedronGeometry(t,i)}const ie={sphere:{geometry:function(t=64,i=64){return new e.SphereGeometry(.5,t,i)}(64,64),blink:{type:"vertical-squish",duration:150,scaleAxis:[1,.3,1],curve:"sine",playful:{anticipation:.03,overshoot:.05}}},torus:{geometry:ee(),blink:{type:"vertical-squish",duration:150,scaleAxis:[1,.4,1],rotation:[0,0,Math.PI/8],curve:"sine"}},icosahedron:{geometry:te(.5,1),blink:{type:"geometric-pulse",duration:130,scaleAxis:[.7,.7,.7],curve:"sine"}},octahedron:{geometry:function(t=.5,i=0){return new e.OctahedronGeometry(t,i)}(.5,0),blink:{type:"geometric-pulse",duration:130,scaleAxis:[.7,.7,.7],curve:"sine"}},tetrahedron:{geometry:function(t=.5,i=0){return new e.TetrahedronGeometry(t,i)}(.5,0),blink:{type:"geometric-pulse",duration:110,scaleAxis:[.75,.75,.75],rotation:[Math.PI/6,0,0],curve:"sine"}},dodecahedron:{geometry:function(t=.5,i=0){return new e.DodecahedronGeometry(t,i)}(.5,0),blink:{type:"facet-flash",duration:140,scaleAxis:[.75,.75,.75],glowBoost:.4,curve:"sine"}},"smooth-icosahedron":{geometry:te(.5,2),blink:{type:"geometric-pulse",duration:140,scaleAxis:[.75,.75,.75],curve:"sine"}},"faceted-icosahedron":{geometry:te(.5,0),blink:{type:"facet-flash",duration:120,scaleAxis:[.7,.7,.7],glowBoost:.3,curve:"sine"}},ring:{geometry:ee(.4,.1,16,64),blink:{type:"vertical-squish",duration:140,scaleAxis:[1,.5,1],curve:"sine"}},moon:{geometry:z(64,64),material:"custom",blink:{type:"gentle-pulse",duration:180,scaleAxis:[.95,.95,.95],glowBoost:.2,curve:"sine"},particleRadiusMultiplier:1.4},sun:{geometry:new e.SphereGeometry(.5,64,64),material:"emissive",blink:{type:"radial-pulse",duration:200,scaleAxis:[1.05,1.05,1.05],glowBoost:.5,curve:"sine"},particleRadiusMultiplier:1.5},crystal:{geometry:null,geometryLoader:function(t="/assets"){return new Promise((i,n)=>{(new f).load(`${t}/models/Crystal/crystal.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.6/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.attributes.normal||n.computeVertexNormals(),n.computeBoundingBox();const o=new e.Vector3;n.boundingBox.getSize(o);let r=n;r.computeVertexNormals(),i(r)}else{console.warn("💎 [CRYSTAL] No mesh in OBJ, using fallback");const e=K();i(e)}},e=>{},e=>{console.warn("💎 [CRYSTAL] OBJ load FAILED:",e);const t=K();i(t)})})},material:"custom",blink:{type:"facet-flash",duration:160,scaleAxis:[.95,.95,.95],glowBoost:.4,curve:"sine"},particleRadiusMultiplier:1.4},rough:{geometry:null,geometryLoader:function(t="/assets"){return new Promise(i=>{(new f).load(`${t}/models/Crystal/rough.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.6/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),n.computeBoundingBox(),i(n)}else console.warn("💎 [ROUGH] No mesh in OBJ, using fallback sphere"),i(new e.SphereGeometry(.5,32,32))},void 0,t=>{console.warn("💎 [ROUGH] OBJ load failed:",t),i(new e.SphereGeometry(.5,32,32))})})},material:"custom",blink:{type:"facet-flash",duration:150,scaleAxis:[.95,.95,.95],glowBoost:.5,curve:"sine"},particleRadiusMultiplier:1.3},heart:{geometry:null,geometryLoader:function(t="/assets"){return new Promise(i=>{(new f).load(`${t}/models/Crystal/heart.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.2/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),n.computeBoundingBox(),n.attributes.uv||function(t){t.computeBoundingBox();const i=t.boundingBox,n=t.attributes.position,a=new Float32Array(2*n.count),s=i.max.x-i.min.x,o=i.max.y-i.min.y;for(let e=0;e<n.count;e++){const t=n.getX(e),r=n.getY(e);a[2*e]=(t-i.min.x)/s,a[2*e+1]=(r-i.min.y)/o}t.setAttribute("uv",new e.BufferAttribute(a,2))}(n),i(n)}else console.warn("💗 [HEART] No mesh in OBJ, using fallback"),i(Z())},void 0,e=>{console.warn("💗 [HEART] OBJ load failed:",e),i(Z())})})},material:"custom",blink:{type:"gentle-pulse",duration:180,scaleAxis:[.92,.92,.92],glowBoost:.6,curve:"sine"},particleRadiusMultiplier:1.3},star:{geometry:null,geometryLoader:function(t="/assets"){return new Promise(i=>{(new f).load(`${t}/models/Crystal/star.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z);const a=new e.Vector3;n.boundingBox.getSize(a);const s=1.4/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),n.computeBoundingBox(),n.attributes.uv||function(t){t.computeBoundingBox();const i=t.boundingBox,n=t.attributes.position,a=new Float32Array(2*n.count),s=i.max.x-i.min.x,o=i.max.y-i.min.y;for(let e=0;e<n.count;e++){const t=n.getX(e),r=n.getY(e);a[2*e]=(t-i.min.x)/s,a[2*e+1]=(r-i.min.y)/o}t.setAttribute("uv",new e.BufferAttribute(a,2))}(n),i(n)}else console.warn("⭐ [STAR] No mesh in OBJ, using fallback"),i(J())},void 0,e=>{console.warn("⭐ [STAR] OBJ load failed:",e),i(J())})})},material:"custom",blink:{type:"facet-flash",duration:150,scaleAxis:[.93,.93,.93],glowBoost:.5,curve:"sine"},particleRadiusMultiplier:1.4}};class ne{constructor(){this.currentAnimation=null,this.animations=[],this.time=0}playEmotion(e,t={}){const i=this.createEmotionAnimation(e);this.startAnimation(i,t)}playGesture(e,t={}){const i=this.createGestureAnimation(e);this.startAnimation(i,t)}playMorph(e,t,i={}){const n=this.createMorphAnimation(e,t);this.startAnimation(n,i)}update(e){this.time+=e;for(let e=this.animations.length-1;e>=0;e--){const t=this.animations[e],i=t.duration;Math.min((this.time-t.startTime)/i,1)>=1&&(t.callbacks&&t.callbacks.onComplete&&t.callbacks.onComplete(),this.animations.splice(e,1))}}createEmotionAnimation(e){const t={joy:{duration:.6,evaluate:e=>({scale:1+.15*Math.sin(e*Math.PI),glowIntensity:1+.15*Math.sin(e*Math.PI)})},love:{duration:1.2,evaluate:e=>({scale:1+.08*Math.sin(e*Math.PI*2),glowIntensity:1+.1*Math.sin(e*Math.PI*2)})},curiosity:{duration:.8,evaluate:e=>({rotation:[0,.1*Math.sin(e*Math.PI*4),0],scale:1+.05*Math.sin(e*Math.PI),glowIntensity:1})},sadness:{duration:1.5,evaluate:e=>({scale:1-.1*e,glowIntensity:1-.15*Math.sin(e*Math.PI)})},anger:{duration:.4,evaluate:e=>{const t=.15*Math.sin(e*Math.PI*8);return{rotation:[t,t,0],scale:1.1+.1*Math.sin(e*Math.PI),glowIntensity:1+.15*Math.sin(e*Math.PI*8)}}},fear:{duration:.5,evaluate:e=>{const t=.08*Math.sin(e*Math.PI*10);return{scale:.9+t,rotation:[t,0,t],glowIntensity:1+.1*Math.sin(e*Math.PI*10)}}},surprise:{duration:.4,evaluate:e=>({scale:1+.25*(1-Math.cos(e*Math.PI)),glowIntensity:1+.2*(1-Math.cos(e*Math.PI))})},neutral:{duration:.5,evaluate:e=>({scale:1,glowIntensity:1})}};return t[e]||t.neutral}createGestureAnimation(e){const t={bounce:{duration:.8,evaluate:e=>{const t=Math.abs(Math.sin(e*Math.PI));return{position:[0,.5*t,0],scale:1+.1*t}}},pulse:{duration:.6,evaluate:e=>{const t=Math.sin(e*Math.PI);return{scale:1+.2*t,glowIntensity:1+.5*t}}},spin:{duration:1,evaluate:e=>({rotation:[0,e*Math.PI*2,0]})},wobble:{duration:1,evaluate:e=>{const t=Math.sin(e*Math.PI*3);return{rotation:[.3*t,0,.2*t]}}},float:{duration:2,evaluate:e=>({position:[0,.3*Math.sin(e*Math.PI),0]})},shake:{duration:.5,evaluate:e=>{const t=Math.sin(e*Math.PI*6)*(1-e);return{position:[.2*t,0,0],rotation:[0,0,.1*t]}}},nod:{duration:.8,evaluate:e=>({rotation:[.3*Math.sin(e*Math.PI*2),0,0]})}};return t[e]||t.pulse}createMorphAnimation(e,t){return{duration:1,fromShape:e,toShape:t,evaluate:e=>({morphProgress:e,scale:1+.1*Math.sin(e*Math.PI),rotation:[0,e*Math.PI*.5,0]})}}startAnimation(e,t){this.animations.push({...e,startTime:this.time,callbacks:t||{}}),this.currentAnimation=e}stopAll(){this.animations=[],this.currentAnimation=null}destroy(){this.stopAll(),this.animations=null,this.currentAnimation=null,this.time=0}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}getIdleAnimation(){return{duration:3,loop:!0,evaluate:e=>{const t=Math.sin(e*Math.PI*2),i=Math.sin(e*Math.PI);return{scale:1+.02*t,position:[.05*i,.03*t,0],rotation:[0,.05*i,0],glowIntensity:1+.1*t}}}}isPlaying(){return this.animations.length>0}}class ae{constructor(){this.breathingSpeed=1,this.breathingDepth=.03,this.breathingPhase=0,this.breathRate=1,this.breathDepth=.03,this.breathRateMult=1,this.breathDepthMult=1,this.emotionBreathPatterns={happy:{rate:1.1,depth:1.2},sad:{rate:.8,depth:.7},angry:{rate:1.4,depth:1.3},calm:{rate:.7,depth:.9},excited:{rate:1.5,depth:1.4},focused:{rate:.9,depth:.6},neutral:{rate:1,depth:1},love:{rate:1.2,depth:1.3},surprised:{rate:1.3,depth:1.1},confused:{rate:1.1,depth:.9},amused:{rate:1.2,depth:1.1},bored:{rate:.6,depth:.8},tired:{rate:.5,depth:1.2},anxious:{rate:1.6,depth:.9},determined:{rate:1.1,depth:1},proud:{rate:.9,depth:1.3},content:{rate:.8,depth:1},hopeful:{rate:1,depth:1.1},zen:{rate:.4,depth:1.5},intrigued:{rate:1.1,depth:.8},embarrassed:{rate:1.3,depth:.7},grateful:{rate:.9,depth:1.1},inspired:{rate:1,depth:1.3},silly:{rate:1.4,depth:1.2},sleepy:{rate:.3,depth:1.4}}}update(e,t,i=null){const n=this.emotionBreathPatterns[t]||{rate:1,depth:1};i&&i["3d"]&&i["3d"].scale?(this.breathRateMult=i["3d"].scale.breathRateMultiplier||1,this.breathDepthMult=i["3d"].scale.breathDepthMultiplier||1):(this.breathRateMult=1,this.breathDepthMult=1),this.breathRate=n.rate*this.breathRateMult,this.breathDepth=this.breathingDepth*n.depth*this.breathDepthMult;const a=this.breathingSpeed*this.breathRate*(e/1e3);this.breathingPhase+=a,this.breathingPhase>2*Math.PI&&(this.breathingPhase-=2*Math.PI)}getBreathingScale(){return 1+Math.sin(this.breathingPhase)*this.breathDepth}setEmotion(e,t=null){const i=this.emotionBreathPatterns[e]||{rate:1,depth:1};t&&t["3d"]&&t["3d"].scale?(this.breathRateMult=t["3d"].scale.breathRateMultiplier||1,this.breathDepthMult=t["3d"].scale.breathDepthMultiplier||1):(this.breathRateMult=1,this.breathDepthMult=1),this.breathRate=i.rate*this.breathRateMult,this.breathDepth=this.breathingDepth*i.depth*this.breathDepthMult}reset(){this.breathingPhase=0,this.breathRate=1,this.breathDepth=this.breathingDepth,this.breathRateMult=1,this.breathDepthMult=1}getBreathingInfo(){return{phase:this.breathingPhase,rate:this.breathRate,depth:this.breathDepth,scale:this.getBreathingScale(),rateMult:this.breathRateMult,depthMult:this.breathDepthMult}}destroy(){this.emotionBreathPatterns=null}}class se{constructor(){this.tempEuler=new e.Euler,this.tempQuat=new e.Quaternion,this.accumulatedRotationQuat=new e.Quaternion,this.finalQuaternion=new e.Quaternion}blend(e,t,i,n,a){this.accumulatedRotationQuat.identity();const s={position:[0,0,0],rotationQuat:this.accumulatedRotationQuat,scale:1,glowIntensity:1,glowBoost:0};for(const i of e)if(i.evaluate){const e=t-i.startTime,n=i.duration,a=Math.min(e/n,1),o=i.evaluate(a);o&&(o.position&&(s.position[0]+=o.position[0],s.position[1]+=o.position[1],s.position[2]+=o.position[2]),o.rotation&&(this.tempEuler.set(o.rotation[0],o.rotation[1],o.rotation[2],"XYZ"),this.tempQuat.setFromEuler(this.tempEuler),s.rotationQuat.multiply(this.tempQuat)),void 0!==o.scale&&(s.scale*=o.scale),void 0!==o.glowIntensity&&(s.glowIntensity*=o.glowIntensity),void 0!==o.glowBoost&&(s.glowBoost+=o.glowBoost))}this.finalQuaternion.copy(i).multiply(s.rotationQuat),this.tempEuler.setFromQuaternion(this.finalQuaternion,"XYZ");const o=[this.tempEuler.x,this.tempEuler.y,this.tempEuler.z],r=n*s.scale,l=a*s.glowIntensity;return{position:s.position,rotation:o,scale:r,glowIntensity:l,glowBoost:s.glowBoost,gestureQuaternion:s.rotationQuat}}destroy(){this.tempEuler=null,this.tempQuat=null,this.accumulatedRotationQuat=null,this.finalQuaternion=null}}const oe=new Map;var re=function(e){return oe.get(e)||null},le=function(){return Array.from(oe.keys())},he={name:"suspicion",emoji:"🤨",description:"Paranoid watchfulness with surveillance scanning",visual:{glowColor:"#6B46C1",particleRate:4,minParticles:6,maxParticles:12,particleBehavior:"surveillance",particleSpeed:.2,breathRate:.6,breathDepth:.04,coreJitter:.02,blinkRate:1.1,blinkSpeed:1,particleColors:[{color:"#6B46C1",weight:30},{color:"#4A5568",weight:25},{color:"#8B4789",weight:20},{color:"#9F7AEA",weight:15},{color:"#2D3748",weight:10}],threatLevel:0,getGlowIntensity(){return.3+.7*this.threatLevel},getParticleSpeed(){return.2+.8*this.threatLevel},getGlowColor(){const e=this.threatLevel||0,t=Math.round(107+113*e),i=Math.round(70+-32*e),n=Math.round(193+-66*e),a=e=>e.toString(16).padStart(2,"0");return`#${a(t)}${a(i)}${a(n)}`}},modifiers:{speed:.4,amplitude:.6,intensity:1.2,smoothness:.3,regularity:.2,focus:1.5,addWobble:!0},typicalGestures:["scan","twitch","peek","tilt","hold"],transitions:{duration:500,easing:"linear",priority:4},special:{coreSquint:.6,scanInterval:2e3,scanDuration:1200,scanAngle:60,twitchChance:.02,peekInterval:4e3,maxThreatDistance:300,alertThreshold:.7},"3d":{rotation:{type:"suspicious",speed:1,axes:[0,0,0],musicSync:!1},glow:{color:"#6B46C1",intensity:.85,pulse:{speed:.6,range:[.7,1]}},scale:{base:1,breathe:{enabled:!0,depth:.04,rate:.6}}},soulAnimation:{driftSpeed:.9,shimmerSpeed:1.8,turbulence:.4}},ce={name:"calm",emoji:"😌",description:"Serene, peaceful state with gentle movements",visual:{glowColor:"#66D9CC",particleRate:6,minParticles:10,maxParticles:50,particleBehavior:"zen",breathRate:.4,breathDepth:.12,coreJitter:!1,blinkRate:.8,blinkSpeed:1,particleColors:[{color:"#66D9CC",weight:35},{color:"#99E6D9",weight:25},{color:"#40BFB3",weight:20},{color:"#B3F2E6",weight:15},{color:"#339980",weight:5}]},modifiers:{speed:.5,amplitude:.3,intensity:.4,smoothness:2,regularity:1.5,addWeight:!1,floatHeight:.2,swayAmount:.15,duration:1.5},typicalGestures:["breathe","float","drift","idle"],transitions:{duration:800,easing:"easeInOutSine",priority:1},movement:{floatPattern:"sine_slow",floatPeriod:6e3,floatAmplitude:8,swayPattern:"gentle",swayPeriod:8e3,swayAmplitude:5,microMovements:!1},getCoreParams(e){const t=e.time||Date.now(),i=.5*Math.sin(6e-4*t)+.5;return{scaleX:1-.02*i,scaleY:1-.02*i,eyeOpenness:.85,eyeExpression:"serene",pupilOffset:{x:2*Math.sin(3e-4*t),y:1*Math.cos(4e-4*t)},glowPulse:.95+.05*i}},updateParticle(e,t){e.x+=.1*Math.sin(.001*e.life),e.y-=.02*t,e.opacity=.3*Math.sin(.002*e.life)+.2,e.size=e.baseSize*(1+.2*Math.sin(.001*e.life))},renderCore:(e,t,i,n)=>!1,"3d":{rotation:{type:"gentle",speed:.5,axes:[0,.3,0],musicSync:!0},glow:{color:"#66D9CC",intensity:.6,pulse:{speed:.4,range:[.5,.7]}},scale:{base:1,breathe:{enabled:!0,depth:.12,rate:.4}}},soulAnimation:{driftSpeed:.3,shimmerSpeed:.4,turbulence:.1}};const ue=new Map,de={happy:"joy",peaceful:"calm",curious:"surprise",frustrated:"anger",sad:"sadness",excitement:"excited"};function me(e){const t=de[e]||e,i=ue.get(t);if(i)return i;return re(t)||null}function pe(e){const t=me(e);if(!t)return me("neutral").visual;if(!t.visual)return{};const{visual:i}=t,n={};for(const e in i)"function"!=typeof i[e]&&(n[e]=i[e]);return"function"==typeof i.getGlowIntensity&&(n.glowIntensity=i.getGlowIntensity()),"function"==typeof i.getParticleSpeed&&(n.particleSpeed=i.getParticleSpeed()),"function"==typeof i.getParticleRate&&(n.particleRate=i.getParticleRate()),"function"==typeof i.getGlowColor&&(n.glowColor=i.getGlowColor()),n}function ge(e){const t=me(e);return t?t.modifiers:me("neutral").modifiers}function fe(e,t){const i=me(e),n=me(t);return i&&n?n.transitions&&n.transitions[e]?n.transitions[e]:{duration:1e3,easing:"ease-in-out",gesture:n.transitions?.defaultGesture||null}:{duration:1e3,easing:"ease-in-out"}}[{name:"neutral",emoji:"😐",description:"Calm, balanced emotional state",visual:{glowColor:"#00BCD4",particleRate:2,minParticles:8,maxParticles:10,particleBehavior:"ambient",breathRate:1,breathDepth:.08,coreJitter:!1,blinkRate:1,blinkSpeed:1,particleColors:[{color:"#00BCD4",weight:25},{color:"#00ACC1",weight:20},{color:"#26C6DA",weight:15},{color:"#B2EBF2",weight:15},{color:"#0097A7",weight:10},{color:"#80DEEA",weight:10},{color:"#E0F7FA",weight:5}]},modifiers:{speed:1,amplitude:1,intensity:1,smoothness:1,regularity:1},typicalGestures:["breathe","float","idle","blink"],transitions:{duration:500,easing:"easeInOut",priority:0},getCoreParams:e=>({scaleX:1,scaleY:1,eyeOpenness:1,eyeExpression:"neutral",pupilOffset:{x:0,y:0}}),renderCore:(e,t,i,n)=>!1,"3d":{rotation:{type:"gentle",speed:1,axes:[0,.3,0],musicSync:!1},glow:{color:"#00BCD4",intensity:.9,pulse:{speed:1,range:[.8,1]}},scale:{base:1,breathe:{enabled:!0,depth:.08,rate:1}}},soulAnimation:{driftSpeed:.5,shimmerSpeed:.5,turbulence:.2}},{name:"joy",emoji:"😊",description:"Playful happiness and celebration",visual:{glowColor:"#FFEB3B",particleRate:8,minParticles:0,maxParticles:50,particleBehavior:"popcorn",breathRate:1.5,breathDepth:.1,coreJitter:!1,blinkRate:1.3,blinkSpeed:1.1,particleColors:[{color:"#FFEB3B",weight:25},{color:"#FFC107",weight:20},{color:"#FFFF00",weight:15},{color:"#FFD700",weight:15},{color:"#FFF59D",weight:10},{color:"#FF9800",weight:10},{color:"#FFFDE7",weight:5}]},modifiers:{speed:1.8,amplitude:1.9,intensity:1.1,smoothness:1,regularity:.9,addBounce:!0},typicalGestures:["bounce","spin","wave","expand","shake","float"],transitions:{duration:400,easing:"easeOutBack",priority:5,burstOnEntry:!0},getCoreParams:e=>({scaleX:1,scaleY:1,eyeOpenness:1,eyeExpression:"happy",pupilOffset:{x:0,y:-.1},sparkle:!0}),"3d":{rotation:{type:"rhythmic",speed:1.8,axes:[0,.3,0],musicSync:!0},glow:{color:"#FFEB3B",intensity:1.6,pulse:{speed:1.5,range:[1.2,1.8]}},scale:{base:1,breathe:{enabled:!0,depth:.1,rate:1.5}}},soulAnimation:{driftSpeed:1.2,shimmerSpeed:1.5,turbulence:.3}},{name:"sadness",emoji:"😢",description:"Deep melancholic sorrow",visual:{glowColor:"#4169E1",particleRate:6,minParticles:0,maxParticles:50,particleBehavior:"falling",breathRate:.6,breathDepth:.12,coreJitter:!1,blinkRate:.6,blinkSpeed:.8,particleColors:[{color:"#4169E1",weight:25},{color:"#1E90FF",weight:20},{color:"#6495ED",weight:15},{color:"#B0C4DE",weight:15},{color:"#191970",weight:10},{color:"#87CEEB",weight:10},{color:"#2F4F4F",weight:5}]},modifiers:{speed:.7,amplitude:.6,intensity:.8,smoothness:1.3,regularity:1.1,addGravity:!0},typicalGestures:["droop","sway","contract","drift","sink"],transitions:{duration:800,easing:"easeInOut",priority:3},"3d":{rotation:{type:"gentle",speed:.7,axes:[0,.2,0],musicSync:!1},glow:{color:"#4169E1",intensity:.65,pulse:{speed:.6,range:[.5,.8]}},scale:{base:1,breathe:{enabled:!0,depth:.12,rate:.6}}},soulAnimation:{driftSpeed:.2,shimmerSpeed:.3,turbulence:.1}},{name:"anger",emoji:"😠",description:"Intense rage and aggression",visual:{glowColor:"#DC143C",particleRate:8,minParticles:8,maxParticles:50,particleBehavior:"aggressive",breathRate:2.2,breathDepth:.15,coreJitter:!0,blinkRate:1.6,blinkSpeed:1.3,particleColors:[{color:"#DC143C",weight:25},{color:"#FF0000",weight:20},{color:"#B22222",weight:15},{color:"#FF4500",weight:15},{color:"#8B0000",weight:10},{color:"#FF6347",weight:10},{color:"#660000",weight:5}]},modifiers:{speed:1.5,amplitude:1.4,intensity:1.3,smoothness:.3,regularity:.7,addShake:!0},typicalGestures:["shake","vibrate","expand","pulse","flicker","strike"],transitions:{duration:300,easing:"easeOutExpo",priority:8,shakeOnEntry:!0},special:{screenShake:!0,particleTrails:"fire",glowPulse:!0,temperatureEffect:"hot"},"3d":{rotation:{type:"unstable",speed:1.5,axes:[0,.3,0],shake:{amplitude:.02,frequency:7},eruption:{enabled:!0,interval:3e3,speedMultiplier:3.5,duration:400},musicSync:!1},glow:{color:"#DC143C",intensity:1.8,pulse:{speed:2.2,range:[.8,2]}},scale:{base:1,breathe:{enabled:!0,depth:.15,rate:2.2}}},soulAnimation:{driftSpeed:2,shimmerSpeed:.8,turbulence:.8}},{name:"fear",emoji:"😨",description:"Anxious state with fleeing particles",visual:{glowColor:"#8A2BE2",particleRate:8,minParticles:8,maxParticles:50,particleBehavior:"scattering",breathRate:2.5,breathDepth:.06,coreJitter:!0,blinkRate:1.7,blinkSpeed:1.4,particleColors:[{color:"#8A2BE2",weight:25},{color:"#4B0082",weight:20},{color:"#9400D3",weight:15},{color:"#6B46C1",weight:15},{color:"#9932CC",weight:10},{color:"#E6E6FA",weight:8},{color:"#301934",weight:7}]},modifiers:{speed:1.4,amplitude:.8,intensity:1.2,smoothness:.5,regularity:.5,addJitter:!0},typicalGestures:["shake","vibrate","contract","flicker","retreat"],transitions:{duration:400,easing:"easeOut",priority:7},"3d":{rotation:{type:"unstable",speed:1.4,axes:[0,.3,0],shake:{amplitude:.015,frequency:3.5},musicSync:!1},glow:{color:"#8A2BE2",intensity:.9,pulse:{speed:2.5,range:[.6,1.2]}},scale:{base:1,breathe:{enabled:!0,depth:.06,rate:2.5}}},soulAnimation:{driftSpeed:1.8,shimmerSpeed:2.5,turbulence:.6}},{name:"surprise",emoji:"😲",description:"Sudden shock with explosive particles",visual:{glowColor:"#FFD700",particleRate:5,minParticles:0,maxParticles:15,particleBehavior:"burst",breathRate:.3,breathDepth:.18,coreJitter:!1,blinkRate:1.4,blinkSpeed:1.2,particleColors:[{color:"#FFD700",weight:25},{color:"#FFA500",weight:20},{color:"#FFFF00",weight:15},{color:"#FF6347",weight:15},{color:"#FFE4B5",weight:10},{color:"#FF4500",weight:10},{color:"#FFFACD",weight:5}]},modifiers:{speed:1.6,amplitude:1.5,intensity:1.4,smoothness:.7,regularity:.8,addPop:!0},typicalGestures:["expand","bounce","flash","pulse","pop"],transitions:{duration:200,easing:"easeOutBack",priority:6},"3d":{rotation:{type:"unstable",speed:1.6,axes:[0,.45,0],shake:{amplitude:.01,frequency:3},musicSync:!1},glow:{color:"#FFD700",intensity:1.8,pulse:{speed:.3,range:[1,2.2]}},scale:{base:1,breathe:{enabled:!0,depth:.18,rate:.3}}},soulAnimation:{driftSpeed:1.5,shimmerSpeed:2,turbulence:.5}},{name:"disgust",emoji:"🤢",description:"Revulsion with repelling particles",visual:{glowColor:"#9ACD32",particleRate:4,minParticles:5,maxParticles:12,particleBehavior:"repelling",breathRate:.7,breathDepth:.04,coreJitter:!1,blinkRate:.9,blinkSpeed:.9,particleColors:[{color:"#9ACD32",weight:25},{color:"#ADFF2F",weight:20},{color:"#7FFF00",weight:15},{color:"#BDB76B",weight:15},{color:"#6B8E23",weight:10},{color:"#CCFF00",weight:8},{color:"#556B2F",weight:7}]},modifiers:{speed:.9,amplitude:.7,intensity:.9,smoothness:.8,regularity:1,addRecoil:!0},typicalGestures:["contract","shake","recoil","wobble"],transitions:{duration:600,easing:"easeIn",priority:4},"3d":{rotation:{type:"gentle",speed:.9,axes:[0,.25,0],musicSync:!1},glow:{color:"#9ACD32",intensity:1,pulse:{speed:.7,range:[.7,1.2]}},scale:{base:1,breathe:{enabled:!0,depth:.04,rate:.7}}},soulAnimation:{driftSpeed:.4,shimmerSpeed:.6,turbulence:.35}},{name:"love",emoji:"💕",description:"Warm affection with orbiting particles",visual:{glowColor:"#FF1493",particleRate:6,minParticles:15,maxParticles:50,particleBehavior:"orbiting",breathRate:.75,breathDepth:.15,coreJitter:!1,blinkRate:1.2,blinkSpeed:1,particleColors:[{color:"#FF1493",weight:30},{color:"#FF69B4",weight:25},{color:"#FF007F",weight:15},{color:"#FFB6C1",weight:10},{color:"#FF45A0",weight:10},{color:"#E91E63",weight:5},{color:"#FFC0CB",weight:5}]},modifiers:{speed:.9,amplitude:1.1,intensity:1.2,smoothness:1.4,regularity:1.2,addWarmth:!0},typicalGestures:["pulse","sway","orbit","glow","breathe","float"],transitions:{duration:700,easing:"easeInOut",priority:5},"3d":{rotation:{type:"gentle",speed:.9,axes:[0,.28,0],musicSync:!0},glow:{color:"#FF1493",intensity:1.8,pulse:{speed:.75,range:[1.3,2]}},scale:{base:1,breathe:{enabled:!0,depth:.15,rate:.75}}},soulAnimation:{driftSpeed:.8,shimmerSpeed:1.2,turbulence:.2}},he,{name:"excited",emoji:"🤩",description:"High energy with rapid particles",visual:{glowColor:"#FF6B35",particleRate:8,minParticles:10,maxParticles:50,particleBehavior:"burst",breathRate:2,breathDepth:.14,coreJitter:!0,blinkRate:1.5,blinkSpeed:1.2,particleColors:[{color:"#FF6B35",weight:25},{color:"#FF1744",weight:20},{color:"#FFC107",weight:15},{color:"#FF9100",weight:15},{color:"#FFEB3B",weight:10},{color:"#FF5722",weight:10},{color:"#FFF59D",weight:5}]},modifiers:{speed:1.4,amplitude:1.3,intensity:1.3,smoothness:.8,regularity:.7,addVibration:!0},typicalGestures:["bounce","spin","vibrate","expand","shake","pulse"],transitions:{duration:300,easing:"easeOutElastic",priority:6},"3d":{rotation:{type:"unstable",speed:1.4,axes:[0,.4,0],shake:{amplitude:.01,frequency:4},musicSync:!1},glow:{color:"#FF6B35",intensity:1.5,pulse:{speed:2,range:[1,1.8]}},scale:{base:1,breathe:{enabled:!0,depth:.14,rate:2}}},soulAnimation:{driftSpeed:1.5,shimmerSpeed:2,turbulence:.5}},{name:"resting",emoji:"😴",description:"Deep relaxation with slow drift",visual:{glowColor:"#9370DB",particleRate:1,minParticles:3,maxParticles:5,particleBehavior:"resting",breathRate:.8,breathDepth:.12,coreJitter:!1,blinkRate:.4,blinkSpeed:.7,particleColors:[{color:"#9370DB",weight:30},{color:"#A591C4",weight:20},{color:"#B366FF",weight:20},{color:"#B8A1E6",weight:15},{color:"#674D9B",weight:15}]},modifiers:{speed:.5,amplitude:.4,intensity:.5,smoothness:1.4,regularity:.9,addWeight:!0},typicalGestures:["breathe","drift","sway","float"],transitions:{duration:1e3,easing:"easeInOut",priority:2},"3d":{rotation:{type:"gentle",speed:.5,axes:[0,.15,0],musicSync:!1},glow:{color:"#9370DB",intensity:.8,pulse:{speed:.8,range:[.6,1]}},scale:{base:1,breathe:{enabled:!0,depth:.12,rate:.8}}},soulAnimation:{driftSpeed:.15,shimmerSpeed:.1,turbulence:.05}},{name:"euphoria",emoji:"🌟",description:"Radiant hope and new beginnings",visual:{glowColor:"#FFB6C1",particleRate:6,minParticles:15,maxParticles:30,particleBehavior:"radiant",breathRate:1.3,breathDepth:.25,coreJitter:!1,blinkRate:1.4,blinkSpeed:1.1,particleColors:[{color:"#FFB6C1",weight:20},{color:"#FFD700",weight:18},{color:"#87CEEB",weight:15},{color:"#DDA0DD",weight:15},{color:"#98FB98",weight:12},{color:"#FFA07A",weight:10},{color:"#E6E6FA",weight:8},{color:"#FFFFFF",weight:2}]},modifiers:{speed:1.4,amplitude:1.5,intensity:1.6,smoothness:1.3,regularity:.8,addWarmth:!0,addLift:!0},typicalGestures:["expand","radiate","pulse","glow","float","bloom"],transitions:{duration:600,easing:"easeOutExpo",priority:8},"3d":{rotation:{type:"rhythmic",speed:1.4,axes:[0,.35,0],musicSync:!0},glow:{color:"#FFB6C1",intensity:1.2,pulse:{speed:1.3,range:[.9,1.5]}},scale:{base:1,breathe:{enabled:!0,depth:.25,rate:1.3}}},soulAnimation:{driftSpeed:1.8,shimmerSpeed:2.5,turbulence:.7}},{name:"focused",emoji:"🎯",description:"Intense concentration with directed flow",visual:{glowColor:"#00CED1",particleRate:4,minParticles:5,maxParticles:12,particleBehavior:"directed",breathRate:1.2,breathDepth:.08,coreJitter:!0,blinkRate:.7,blinkSpeed:1,particleColors:[{color:"#00CED1",weight:30},{color:"#4A9FA0",weight:20},{color:"#00FFFF",weight:20},{color:"#5FE5E7",weight:15},{color:"#006B6D",weight:15}],eyeOpenness:.7,microAdjustments:!0},modifiers:{speed:1,amplitude:.9,intensity:1.1,smoothness:1.1,regularity:1.2,addPrecision:!0},typicalGestures:["track","lock","scan","pulse","vibrate"],transitions:{duration:400,easing:"easeIn",priority:5},getCoreParams:e=>({scaleX:1.1,scaleY:.7,eyeOpenness:.7,eyeExpression:"focused",pupilOffset:{x:0,y:0},microAdjustments:!0}),"3d":{rotation:{type:"still",speed:.5,axes:[0,.1,0],musicSync:!1},glow:{color:"#00CED1",intensity:1.2,pulse:{speed:1.2,range:[1,1.3]}},scale:{base:1,breathe:{enabled:!0,depth:.08,rate:1.2}}},soulAnimation:{driftSpeed:.6,shimmerSpeed:.2,turbulence:.1}},{name:"glitch",emoji:"🌈",description:"Surprised sadness with rainbow colors and glitch wiggle",visual:{primaryColor:"#FF6B9D",glowColor:"#4169E1",glowIntensity:1.2,particleRate:5,minParticles:5,maxParticles:15,particleBehavior:"burst",particleSpeed:1,breathRate:.4,breathDepth:.15,coreJitter:!1,coreSize:1,eyeOpenness:.8,blinkRate:1.3,blinkSpeed:1.2,particleColors:[{color:"#FF0080",weight:18},{color:"#00FF80",weight:18},{color:"#8000FF",weight:18},{color:"#FF8000",weight:15},{color:"#0080FF",weight:15},{color:"#FFFF00",weight:10},{color:"#FF6B9D",weight:6}],particleGlitchWiggle:!0,glitchWiggleIntensity:.3,glitchWiggleFrequency:.1},modifiers:{speed:1.1,amplitude:1,intensity:1.1,smoothness:.8,regularity:.7,focus:.6},typicalGestures:["bounce","sway","pulse","drift","flash"],transitions:{duration:300,easing:"easeInOut",priority:5},"3d":{rotation:{type:"unstable",speed:1.1,axes:[0,.35,0],shake:{amplitude:.02,frequency:5},musicSync:!1},glow:{color:"#FF6B9D",intensity:1.2,pulse:{speed:.4,range:[.8,1.6]}},scale:{base:1,breathe:{enabled:!0,depth:.15,rate:.4}}}},ce].forEach(e=>{e&&e.name&&ue.set(e.name,e)});class ye{constructor(e,t={}){this.blinkConfig=e.blink||this.getDefaultBlinkConfig(),this.currentGeometryType=null,this.baseDuration=this.blinkConfig.duration||150,this.baseMinInterval=3e3,this.baseMaxInterval=7e3,this.emotionBlinkRate=1,this.emotionBlinkSpeed=1,this.isBlinking=!1,this.blinkTimer=0,this.nextBlinkTime=this.getRandomBlinkTime(),this.enabled=!0,this.blinkProgress=0}setEmotion(e){const t=me(e);this.emotionBlinkRate=t?.visual?.blinkRate||1,this.emotionBlinkSpeed=t?.visual?.blinkSpeed||1}setGeometry(e){this.blinkConfig=e.blink||this.getDefaultBlinkConfig(),this.baseDuration=this.blinkConfig.duration||150}update(e){if(!this.enabled)return this.getIdleState();if(this.isBlinking){this.blinkTimer+=e;const t=this.baseDuration/this.emotionBlinkSpeed;if(this.blinkTimer>=t)return this.completeBlink(),this.getIdleState();const i=this.blinkTimer/t;return this.blinkProgress=i,this.getBlinkState()}return Date.now()>=this.nextBlinkTime?(this.startBlink(),this.getBlinkState()):this.getIdleState()}startBlink(){this.enabled&&(this.isBlinking=!0,this.blinkTimer=0,this.blinkProgress=0)}completeBlink(){this.isBlinking=!1,this.blinkTimer=0,this.blinkProgress=0,this.nextBlinkTime=Date.now()+this.getRandomBlinkTime()}getRandomBlinkTime(){const e=this.baseMinInterval/this.emotionBlinkRate,t=this.baseMaxInterval/this.emotionBlinkRate;return e+Math.random()*(t-e)}getBlinkState(){const e=this.blinkConfig,t=Math.sin(this.blinkProgress*Math.PI);let i=1;if(e.playful)if(this.blinkProgress<.1){const t=this.blinkProgress/.1;i-=Math.sin(t*Math.PI)*e.playful.anticipation}else if(this.blinkProgress>.8){const t=(this.blinkProgress-.8)/.2;i+=Math.sin(t*Math.PI)*e.playful.overshoot}const n=t*i,a=[1-(1-e.scaleAxis[0])*n,1-(1-e.scaleAxis[1])*n,1-(1-e.scaleAxis[2])*n];let s=null;e.rotation&&(s=[e.rotation[0]*n,e.rotation[1]*n,e.rotation[2]*n]);let o=0;return e.glowBoost&&(o=e.glowBoost*n),{isBlinking:!0,progress:this.blinkProgress,scale:a,rotation:s,glowBoost:o}}getIdleState(){return{isBlinking:!1,progress:0,scale:[1,1,1],rotation:null,glowBoost:0}}getDefaultBlinkConfig(){return{type:"vertical-squish",duration:150,scaleAxis:[1,.3,1],curve:"sine"}}pause(){this.enabled=!1,this.isBlinking&&this.completeBlink()}resume(){this.enabled=!0,this.nextBlinkTime=Date.now()+this.getRandomBlinkTime()}getState(){return{isBlinking:this.isBlinking,enabled:this.enabled,blinkProgress:this.blinkProgress,emotionBlinkRate:this.emotionBlinkRate,emotionBlinkSpeed:this.emotionBlinkSpeed,nextBlinkTime:this.nextBlinkTime}}destroy(){this.blinkConfig=null,this.enabled=!1,this.isBlinking=!1}}let ve;"undefined"!=typeof window&&window.__emotiveRhythmEngine?ve=window.__emotiveRhythmEngine:(ve=new class{constructor(){this.bpm=120,this.timeSignature=[4,4],this.isPlaying=!1,this.startTime=0,this.currentBeat=0,this.currentBar=0,this.beatProgress=0,this.barProgress=0,this.beatDuration=6e4/this.bpm,this.barDuration=this.beatDuration*this.timeSignature[0],this.lastBeatTime=0,this.nextBeatTime=0,this.listeners=new Map,this.beatCallbacks=new Set,this.barCallbacks=new Set,this.subdivisions={sixteenth:0,eighth:0,triplet:0,swing:0},this.audioSync=null,this.syncOffset=0,this.autoSync=!1,this.intensity=1,this.groove=0,this.humanize=.05,this.patterns=new Map,this.currentPattern=null,this.initializePatterns()}initializePatterns(){this.patterns.set("4/4",{name:"4/4",description:"Common time - 4 beats per bar",timeSignature:[4,4],groove:0,accents:[1,.5,.7,.5]}),this.patterns.set("straight",{name:"straight",description:"Straight, even timing",groove:0,accents:[1,.5,.7,.5]}),this.patterns.set("swing",{name:"swing",description:"Swing/shuffle timing",groove:.67,accents:[1,.3,.8,.3]}),this.patterns.set("3/4",{name:"3/4",description:"Waltz time - 3 beats per bar",timeSignature:[3,4],accents:[1,.5,.5]}),this.patterns.set("waltz",{name:"waltz",description:"3/4 waltz timing",timeSignature:[3,4],accents:[1,.5,.5]}),this.patterns.set("6/8",{name:"6/8",description:"Compound duple time",timeSignature:[6,8],accents:[1,.3,.3,.7,.3,.3]}),this.patterns.set("5/4",{name:"5/4",description:"Complex meter - 5 beats per bar",timeSignature:[5,4],accents:[1,.5,.6,.5,.7]}),this.patterns.set("7/8",{name:"7/8",description:"Irregular meter",timeSignature:[7,8],accents:[1,.5,.5,.7,.5,.5,.6]}),this.patterns.set("dubstep",{name:"dubstep",description:"Dubstep half-time feel",accents:[.2,.2,1,.2],subdivisions:{wobble:!0}}),this.patterns.set("breakbeat",{name:"breakbeat",description:"Broken beat pattern",accents:[1,.2,.7,.9,.2,.8,.4,.2]})}start(){this.isPlaying||(this.isPlaying=!0,this.isRunning=!0,this.startTime=performance.now(),this.lastBeatTime=this.startTime,this.nextBeatTime=this.startTime+this.beatDuration,this.currentBeat=0,this.currentBar=0,this.emit("start",{bpm:this.bpm,timeSignature:this.timeSignature,pattern:this.currentPattern}),this.update())}stop(){this.isPlaying&&(this.isPlaying=!1,this.emit("stop",{totalBeats:this.currentBeat,totalBars:this.currentBar}))}update(){if(!this.isPlaying)return;const e=(performance.now()-this.startTime)/this.beatDuration,t=Math.floor(e);this.beatProgress=e%1,t>this.currentBeat&&this.onBeat(t);const i=Math.floor(t/this.timeSignature[0]);i>this.currentBar&&this.onBar(i),this.currentBeat=t,this.currentBar=i,this.barProgress=t%this.timeSignature[0]/this.timeSignature[0],this.updateSubdivisions(),this.emit("update",this.getTimeInfo()),this.isPlaying&&requestAnimationFrame(()=>this.update())}onBeat(e){const t=e%this.timeSignature[0],i=this.getAccent(t),n=this.humanize*(Math.random()-.5)*this.beatDuration,a={beat:e,beatInBar:t,bar:this.currentBar,accent:i,intensity:this.intensity*i,humanTiming:n,timestamp:performance.now()};this.emit("beat",a),this.beatCallbacks.forEach(e=>e(a)),this.lastBeatTime=performance.now(),this.nextBeatTime=this.lastBeatTime+this.beatDuration}onBar(e){const t={bar:e,timeSignature:this.timeSignature,pattern:this.currentPattern,timestamp:performance.now()};this.emit("bar",t),this.barCallbacks.forEach(e=>e(t))}updateSubdivisions(){if(this.subdivisions.sixteenth=4*this.beatProgress%1,this.subdivisions.eighth=2*this.beatProgress%1,this.subdivisions.triplet=3*this.beatProgress%1,this.groove>0){const e=.5+.17*this.groove;this.subdivisions.eighth<.5?this.subdivisions.swing=this.subdivisions.eighth/e:this.subdivisions.swing=.5+(this.subdivisions.eighth-.5)/(1-e)}else this.subdivisions.swing=this.subdivisions.eighth}getAccent(e){if(this.currentPattern&&this.patterns.has(this.currentPattern)){const t=this.patterns.get(this.currentPattern);if(t.accents&&void 0!==t.accents[e])return t.accents[e]}return 0===e?1:2===e&&4===this.timeSignature[0]?.7:.5}getTimeInfo(){return{elapsed:performance.now()-this.startTime,beat:this.currentBeat,bar:this.currentBar,beatInBar:this.currentBeat%this.timeSignature[0],beatProgress:this.beatProgress,barProgress:this.barProgress,subdivisions:{...this.subdivisions},bpm:this.bpm,beatDuration:this.beatDuration,timeSignature:[...this.timeSignature],intensity:this.intensity,groove:this.groove,pattern:this.currentPattern,nextBeatIn:this.nextBeatTime-performance.now(),accent:this.getAccent(this.currentBeat%this.timeSignature[0])}}setBPM(e){this.bpm=Math.max(20,Math.min(360,e)),this.beatDuration=6e4/this.bpm,this.barDuration=this.beatDuration*this.timeSignature[0],this.emit("tempoChange",{bpm:this.bpm})}setTimeSignature(e,t){this.timeSignature=[e,t],this.barDuration=this.beatDuration*e,this.emit("timeSignatureChange",{timeSignature:this.timeSignature})}setPattern(e){if(!this.patterns.has(e))return;const t=this.patterns.get(e);this.currentPattern=e,t.timeSignature&&this.setTimeSignature(...t.timeSignature),void 0!==t.groove&&(this.groove=t.groove),this.emit("patternChange",{pattern:e})}onBeatCallback(e){return this.beatCallbacks.add(e),()=>this.beatCallbacks.delete(e)}onBarCallback(e){return this.barCallbacks.add(e),()=>this.barCallbacks.delete(e)}emit(e,t){this.listeners.has(e)&&this.listeners.get(e).forEach(e=>e(t))}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>{this.listeners.has(e)&&this.listeners.get(e).delete(t)}}syncToAudio(e,t){this.audioSync={context:e,source:t}}getAdapter(){return{getTimeInfo:()=>this.getTimeInfo(),isOnBeat:(e=.1)=>this.beatProgress<e||this.beatProgress>1-e,isOnSubdivision:(e,t=.1)=>{const i=this.subdivisions[e]||0;return i<t||i>1-t},getBeatSync:(e=0,t=1,i="linear")=>{let n=this.beatProgress;switch(i){case"ease":n=.5-Math.cos(n*Math.PI)/2;break;case"bounce":n=Math.abs(Math.sin(n*Math.PI));break;case"pulse":n=Math.pow(Math.sin(n*Math.PI),2)}return e+(t-e)*n},getAccentedValue:(e,t=2)=>e*(1+(this.getAccent(this.currentBeat%this.timeSignature[0])-.5)*t),onBeat:e=>this.onBeatCallback(e),onBar:e=>this.onBarCallback(e),beatsToMs:e=>e*this.beatDuration,msToBeats:e=>e/this.beatDuration,isPlaying:()=>this.isPlaying,getBPM:()=>this.bpm,getPattern:()=>this.currentPattern}}},"undefined"!=typeof window&&(window.__emotiveRhythmEngine=ve));class be{constructor(){this.enabled=!1,this.adapter=null,this.beatProgress=0,this.barProgress=0,this.accent=.5,this.intensity=1,this.bpm=120,this.isOnBeat=!1,this.pattern=null,this.grooveEnabled=!0,this.grooveTime=0,this._lastBeatProgress=0,this._staleFrameCount=0,this.modulation={scaleMultiplier:1,glowMultiplier:1,positionMultiplier:1,rotationMultiplier:1,accentBoost:0,grooveOffset:[0,0,0],grooveScale:1,grooveRotation:[0,0,0]},this._target={scaleMultiplier:1,glowMultiplier:1,positionMultiplier:1,rotationMultiplier:1,accentBoost:0,grooveOffset:[0,0,0],grooveScale:1,grooveRotation:[0,0,0]},this.config={beatSyncStrength:.3,accentMultiplier:1.5,grooveBounceAmount:.02,grooveSwayAmount:.015,groovePulseAmount:.03,grooveRotationAmount:.02,smoothingSpeed:8,grooveSmoothingSpeed:6}}_lerp(e,t,i,n){return e+(t-e)*(1-Math.exp(-i*n))}_lerpArray(e,t,i,n){const a=1-Math.exp(-i*n);return e.map((e,i)=>e+(t[i]-e)*a)}initialize(){this.adapter=ve.getAdapter(),this.enabled=!0,this.adapter.onBeat(e=>{this.accent=e.accent,this.isOnBeat=!0,setTimeout(()=>{this.isOnBeat=!1},100)})}start(e=120,t="straight"){this.enabled||this.initialize(),e&&ve.setBPM(e),t&&ve.setPattern(t),ve.start()}stop(){ve.stop()}setBPM(e){ve.setBPM(e),this.bpm=e}setPattern(e){ve.setPattern(e),this.pattern=e}update(e){const t=e/1e3;if(this.adapter||(this.adapter=ve.getAdapter()),!this.adapter)return void this.resetModulation(t);if(!this.adapter.isPlaying())return void this.resetModulation(t);this.enabled=!0;const i=this.adapter.getTimeInfo();if(Math.abs(i.beatProgress-this._lastBeatProgress)<.001?this._staleFrameCount++:(this._staleFrameCount=0,this._lastBeatProgress=i.beatProgress),this._staleFrameCount>10){const e=(i.bpm||this.bpm||120)/60;this.grooveTime+=t,this.beatProgress=this.grooveTime*e%1,this.barProgress=this.grooveTime*e/4%1}else this.beatProgress=i.beatProgress,this.barProgress=i.barProgress,this.grooveTime+=t;this.intensity=i.intensity,this.bpm=i.bpm||this.bpm,this.pattern=i.pattern,this.computeModulation(),this.applySmoothing(t)}computeModulation(){const{beatSyncStrength:e,accentMultiplier:t}=this.config,i=this.beatProgress*Math.PI*2,n=.5*(Math.cos(i)+1);this._target.scaleMultiplier=1+n*e*.4,this._target.glowMultiplier=1+n*e*.8,this._target.positionMultiplier=1+n*e*.2,this._target.rotationMultiplier=1+n*e*.15,this._target.accentBoost=this.isOnBeat?(this.accent-.5)*t:0,this.grooveEnabled?this.computeGroove():(this._target.grooveOffset=[0,0,0],this._target.grooveScale=1,this._target.grooveRotation=[0,0,0])}computeGroove(){const{grooveBounceAmount:e,grooveSwayAmount:t,groovePulseAmount:i,grooveRotationAmount:n}=this.config,a=this.beatProgress*Math.PI*2,s=Math.sin(a)*e,o=this.barProgress*Math.PI*2,r=Math.sin(o)*t,l=1+Math.sin(a)*i,h=Math.sin(o)*n;this._target.grooveOffset=[r,s,0],this._target.grooveScale=l,this._target.grooveRotation=[0,0,h]}applySmoothing(e){const{smoothingSpeed:t,grooveSmoothingSpeed:i}=this.config;this.modulation.scaleMultiplier=this._lerp(this.modulation.scaleMultiplier,this._target.scaleMultiplier,t,e),this.modulation.glowMultiplier=this._lerp(this.modulation.glowMultiplier,this._target.glowMultiplier,t,e),this.modulation.positionMultiplier=this._lerp(this.modulation.positionMultiplier,this._target.positionMultiplier,t,e),this.modulation.rotationMultiplier=this._lerp(this.modulation.rotationMultiplier,this._target.rotationMultiplier,t,e),this.modulation.accentBoost=this._lerp(this.modulation.accentBoost,this._target.accentBoost,.5*t,e),this.modulation.grooveOffset=this._lerpArray(this.modulation.grooveOffset,this._target.grooveOffset,i,e),this.modulation.grooveScale=this._lerp(this.modulation.grooveScale,this._target.grooveScale,i,e),this.modulation.grooveRotation=this._lerpArray(this.modulation.grooveRotation,this._target.grooveRotation,i,e)}resetModulation(e=.016){this._target.scaleMultiplier=1,this._target.glowMultiplier=1,this._target.positionMultiplier=1,this._target.rotationMultiplier=1,this._target.accentBoost=0,this._target.grooveOffset=[0,0,0],this._target.grooveScale=1,this._target.grooveRotation=[0,0,0],this.modulation.scaleMultiplier=this._lerp(this.modulation.scaleMultiplier,1,4,e),this.modulation.glowMultiplier=this._lerp(this.modulation.glowMultiplier,1,4,e),this.modulation.positionMultiplier=this._lerp(this.modulation.positionMultiplier,1,4,e),this.modulation.rotationMultiplier=this._lerp(this.modulation.rotationMultiplier,1,4,e),this.modulation.accentBoost=this._lerp(this.modulation.accentBoost,0,4,e),this.modulation.grooveOffset=this._lerpArray(this.modulation.grooveOffset,[0,0,0],4,e),this.modulation.grooveScale=this._lerp(this.modulation.grooveScale,1,4,e),this.modulation.grooveRotation=this._lerpArray(this.modulation.grooveRotation,[0,0,0],4,e)}getModulation(){return this.modulation}getMusicalDuration(e,t=null){if(!this.enabled||!this.adapter||!this.adapter.isPlaying())return e;if(t?.durationSync){const e=t.durationSync;if("beats"===e.mode&&e.beats)return this.adapter.beatsToMs(e.beats);if("bars"===e.mode&&e.bars)return this.adapter.beatsToMs(4*e.bars)}return e}isOnBeatNow(e=.1){return!(!this.enabled||!this.adapter)&&this.adapter.isOnBeat(e)}isOnAccent(e=.7){return this.isOnBeat&&this.accent>=e}getBeatSync(e,t,i="pulse"){return this.enabled&&this.adapter?this.adapter.getBeatSync(e,t,i):e}getAccentedValue(e,t=2){return this.enabled&&this.adapter?this.adapter.getAccentedValue(e,t):e}setGrooveEnabled(e){this.grooveEnabled=e,e||(this._target.grooveOffset=[0,0,0],this._target.grooveScale=1,this._target.grooveRotation=[0,0,0])}setGrooveConfig(e){Object.assign(this.config,e)}setBeatSyncStrength(e){this.config.beatSyncStrength=Math.max(0,Math.min(1,e))}isPlaying(){return this.enabled&&this.adapter&&this.adapter.isPlaying()}getBPM(){return this.bpm}getPattern(){return this.pattern}destroy(){this.enabled=!1,this.adapter=null,this.resetModulation()}}const we=new be;class Me{constructor(){this.isTransitioning=!1,this.currentGeometryType=null,this.targetGeometryType=null,this.morphStartTime=0,this.morphDuration=1e3,this.morphProgress=0,this.visualProgress=0,this.hasSwappedGeometry=!1,this.isPausedAtSwap=!1,this.pausedAtTime=0,this.easing="easeInOutCubic"}startMorph(e,t,i=1e3){if(e===t&&!this.isTransitioning)return!1;if(this.isTransitioning&&this.targetGeometryType===t)return!1;if(this.isTransitioning){const e=this.calculateScaleMultiplier(this.visualProgress);if(this.hasSwappedGeometry){this.morphStartTime=Date.now(),this.morphDuration=i;const n=e>0?Math.sqrt(1-Math.min(e,1))/2:.5;this.morphProgress=n,this.visualProgress=n,this.hasSwappedGeometry=!1,this.targetGeometryType=t,this._interruptedTarget=t,this.isPausedAtSwap=!1,this.isGrowIn=!1;const a=n*i;return this.morphStartTime=Date.now()-a,!0}return this.targetGeometryType=t,this._interruptedTarget=t,!0}return this.currentGeometryType=e,this.targetGeometryType=t,this.morphStartTime=Date.now(),this.morphDuration=i,this.morphProgress=0,this.visualProgress=0,this.isTransitioning=!0,this.hasSwappedGeometry=!1,this.isPausedAtSwap=!1,this.pausedAtTime=0,this.isGrowIn=!1,this._interruptedTarget=null,!0}getInterruptedTarget(){const e=this._interruptedTarget;return this._interruptedTarget=null,e}growIn(e,t=500){return!this.isTransitioning&&(this.currentGeometryType=e,this.targetGeometryType=e,this.morphStartTime=Date.now(),this.morphDuration=t,this.morphProgress=0,this.visualProgress=0,this.isTransitioning=!0,this.hasSwappedGeometry=!0,this.isPausedAtSwap=!1,this.pausedAtTime=0,this.isGrowIn=!0,!0)}pauseAtSwap(){this.isTransitioning&&!this.isPausedAtSwap&&(this.isPausedAtSwap=!0,this.pausedAtTime=Date.now())}resumeFromSwap(){if(this.isPausedAtSwap){const e=Date.now()-this.pausedAtTime;this.morphStartTime+=e,this.isPausedAtSwap=!1,this.pausedAtTime=0}}update(e){if(!this.isTransitioning)return{isTransitioning:!1,progress:0,visualProgress:0,scaleMultiplier:1};if(this.isPausedAtSwap)return{isTransitioning:!0,progress:.5,visualProgress:.5,scaleMultiplier:0,waitingForGeometry:!0};const t=Date.now()-this.morphStartTime,i=Math.min(t/this.morphDuration,1);this.morphProgress=this.applyEasing(i),this.visualProgress=.6*this.visualProgress+.4*this.morphProgress,Math.abs(this.visualProgress-this.morphProgress)<.01&&(this.visualProgress=this.morphProgress);const n=this.calculateScaleMultiplier(this.visualProgress);let a=!1;return!this.hasSwappedGeometry&&this.morphProgress>=.5&&(this.hasSwappedGeometry=!0,a=!0),this.morphProgress>=1?(this.completeMorph(),{isTransitioning:!1,progress:1,visualProgress:1,scaleMultiplier:1,completed:!0}):{isTransitioning:!0,progress:this.morphProgress,visualProgress:this.visualProgress,scaleMultiplier:n,shouldSwapGeometry:a}}calculateScaleMultiplier(e){if(this.isGrowIn){const t=1.70158,i=1+(t+1)*Math.pow(e-1,3)+t*Math.pow(e-1,2);return Math.max(0,i)}if(e<=.5){const t=2*e;return 1-t*t}{const t=2*(e-.5);return t*(2-t)}}completeMorph(){this.currentGeometryType=this.targetGeometryType,this.targetGeometryType=null,this.isTransitioning=!1,this.morphProgress=0,this.visualProgress=0}applyEasing(e){switch(this.easing){case"linear":return e;case"easeInQuad":return e*e;case"easeOutQuad":return e*(2-e);case"easeInOutQuad":return e<.5?2*e*e:(4-2*e)*e-1;case"easeInOutSine":return-(Math.cos(Math.PI*e)-1)/2;default:return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}}getState(){return{isTransitioning:this.isTransitioning,currentGeometryType:this.currentGeometryType,targetGeometryType:this.targetGeometryType,progress:this.morphProgress,visualProgress:this.visualProgress}}cancel(){this.isTransitioning=!1,this.targetGeometryType=null,this.morphProgress=0,this.visualProgress=0}}class Se{constructor(e={},t=null,i=null){if(this.config=e,this.rhythmEngine=t,this.geometryRotation=i,this.type=e.type||"gentle",this.speed=e.speed||1,i&&void 0!==i.baseSpeed){const e=i.baseSpeed,t=i.axes||[0,1,0];this.axes=[t[0]*e*this.speed,t[1]*e*this.speed,t[2]*e*this.speed]}else this.axes=e.axes||[0,.01,0];this.shake=e.shake||{amplitude:0,frequency:0},this.wobbleEnabled=!0,this.eruption=e.eruption||{enabled:!1},this.eruption.enabled&&(this.eruption.interval=this.eruption.interval||3e3,this.eruption.speedMultiplier=this.eruption.speedMultiplier||3,this.eruption.duration=this.eruption.duration||400,this.eruption.nextEruptionTime=this.eruption.interval,this.eruption.eruptionStartTime=-1),this.musicSync=void 0!==e.musicSync&&e.musicSync,this.time=0,this.episodicWobble={enabled:!1,minInterval:2e3,maxInterval:5e3,amplitude:.05,duration:200,nextWobbleTime:0,wobbleStartTime:-1,wobbleTarget:[0,0,0]}}update(e,t){switch(this.time+=e,this.episodicWobble.enabled&&this.wobbleEnabled&&this._applyEpisodicWobble(e,t),this.type){case"gentle":default:return this._evaluateGentle(e,t);case"unstable":return this._evaluateUnstable(e,t);case"rhythmic":return this._evaluateRhythmic(e,t);case"orbital":return this._evaluateOrbital(e,t);case"still":return this._evaluateStill(e,t);case"suspicious":return this._evaluateSuspicious(e,t)}}_evaluateGentle(e,t){const i=.001*e;return t[0]+=this.axes[0]*this.speed*i,t[1]+=this.axes[1]*this.speed*i,t[2]+=this.axes[2]*this.speed*i,t}_evaluateUnstable(e,t){const i=.001*e;let n=1;if(this.eruption.enabled&&(this.eruption.eruptionStartTime<0&&this.time>=this.eruption.nextEruptionTime&&(this.eruption.eruptionStartTime=this.time),this.eruption.eruptionStartTime>=0)){const e=this.time-this.eruption.eruptionStartTime;if(e<this.eruption.duration){const t=e/this.eruption.duration,i=Math.sin(t*Math.PI);n=1+(this.eruption.speedMultiplier-1)*i}else this.eruption.eruptionStartTime=-1,this.eruption.nextEruptionTime=this.time+this.eruption.interval}const a=this.speed*n;if(t[0]+=this.axes[0]*a*i,t[1]+=this.axes[1]*a*i,t[2]+=this.axes[2]*a*i,this.wobbleEnabled){const e=.001*this.time,i=this.shake.frequency||8,n=this.shake.amplitude||.02,a=.02,s=Math.min(n,a),o=Math.sin(e*i*Math.PI*2)*s*.7,r=Math.sin(e*i*Math.PI*2*1.3)*s*.5,l=Math.sin(e*i*Math.PI*2*.9)*s*.8;t[0]+=o,t[1]+=r,t[2]+=l}return t}_evaluateRhythmic(e,t){const i=.001*e;if(!this.musicSync||!this.rhythmEngine)return this._evaluateGentle(e,t);{const e=60/(this.rhythmEngine.bpm||120),n=.001*this.time%e,a=1+.3*Math.sin(n/e*Math.PI*2);t[0]+=this.axes[0]*this.speed*a*i,t[1]+=this.axes[1]*this.speed*a*i,t[2]+=this.axes[2]*this.speed*a*i}return t}_evaluateOrbital(e,t){const i=.001*e,n=.001*this.time,a=.5*this.speed,s=.1*Math.sin(n*a*Math.PI*2),o=.05*Math.sin(n*a*Math.PI*2*.5);return t[0]+=s*i,t[1]+=this.axes[1]*this.speed*i,t[2]+=o*i,t}_evaluateStill(e,t){const i=.001*e;return t[0]+=.1*this.axes[0]*i,t[1]+=.1*this.axes[1]*i,t[2]+=.1*this.axes[2]*i,t}_evaluateSuspicious(e,t){const i=.001*e,n=.001*this.time,a=4/this.speed,s=n%a/a;let o;if(s<.85)o=s/.85*Math.PI;else{const e=(s-.85)/.15;o=Math.PI*(1-e)}const r=o-t[1];return t[1]+=3*r*i,t}reset(){this.time=0}_applyEpisodicWobble(e,t){const i=this.episodicWobble;if(-1===i.wobbleStartTime&&this.time>=i.nextWobbleTime){i.wobbleStartTime=this.time,i.wobbleTarget=[(Math.random()-.5)*i.amplitude,(Math.random()-.5)*i.amplitude,(Math.random()-.5)*i.amplitude];const e=i.minInterval+Math.random()*(i.maxInterval-i.minInterval);i.nextWobbleTime=this.time+e}if(-1!==i.wobbleStartTime){const e=this.time-i.wobbleStartTime,n=Math.min(e/i.duration,1);if(n<1){const e=Math.sin(n*Math.PI);t[0]+=i.wobbleTarget[0]*e,t[1]+=i.wobbleTarget[1]*e,t[2]+=i.wobbleTarget[2]*e}else i.wobbleStartTime=-1}}updateConfig(e){if(this.config=e,this.type=e.type||"gentle",this.speed=e.speed||1,this.geometryRotation&&void 0!==this.geometryRotation.baseSpeed){const e=this.geometryRotation.baseSpeed,t=this.geometryRotation.axes||[0,1,0];this.axes=[t[0]*e*this.speed,t[1]*e*this.speed,t[2]*e*this.speed]}else this.axes=e.axes||[0,.01,0];this.shake=e.shake||{amplitude:0,frequency:0},this.musicSync=void 0!==e.musicSync&&e.musicSync}applyUndertoneMultipliers(e){if(void 0!==e.speedMultiplier&&(this.speed*=e.speedMultiplier),void 0!==e.shakeMultiplier&&this.shake.amplitude&&(this.shake.amplitude*=e.shakeMultiplier),void 0!==e.enableEpisodicWobble&&(this.episodicWobble.enabled=e.enableEpisodicWobble,this.episodicWobble.enabled&&0===this.episodicWobble.nextWobbleTime)){const e=this.episodicWobble.minInterval+Math.random()*(this.episodicWobble.maxInterval-this.episodicWobble.minInterval);this.episodicWobble.nextWobbleTime=this.time+e}}setWobbleEnabled(e){this.wobbleEnabled=e}}class xe{constructor(e={}){this.config=e,this.strength=void 0!==e.strength?e.strength:.5,this.damping=void 0!==e.damping?e.damping:.8,this.centerOfMass=e.centerOfMass||[0,-.3,0],this.axes=e.axes||{pitch:!0,roll:!0,yaw:!1},this.angularVelocity={x:0,y:0,z:0}}update(e,t){if(0===this.strength)return t;const i=.001*e,n=t[0],a=t[1],s=t[2];if(this.axes.pitch){const e=-n*this.strength;this.angularVelocity.x+=e*i,this.angularVelocity.x*=1-this.damping,t[0]+=this.angularVelocity.x*i}if(this.axes.roll){const e=-s*this.strength;this.angularVelocity.z+=e*i,this.angularVelocity.z*=1-this.damping,t[2]+=this.angularVelocity.z*i}if(this.axes.yaw){const e=-a*this.strength;this.angularVelocity.y+=e*i,this.angularVelocity.y*=1-this.damping,t[1]+=this.angularVelocity.y*i}return t}reset(){this.angularVelocity={x:0,y:0,z:0}}updateConfig(e){this.config=e,this.strength=void 0!==e.strength?e.strength:this.strength,this.damping=void 0!==e.damping?e.damping:this.damping,this.centerOfMass=e.centerOfMass||this.centerOfMass,this.axes=e.axes||this.axes}applyUndertoneMultipliers(e){void 0!==e.strengthMultiplier&&(this.strength*=e.strengthMultiplier)}}class Ce{constructor(t={},i=null){this.config=t,this.camera=i,this.strength=void 0!==t.strength?t.strength:1,this.lockedFace=t.lockedFace||[0,0,1],this.calibrationRotation=t.calibrationRotation||[0,0,0],this.lerpSpeed=void 0!==t.lerpSpeed?t.lerpSpeed:1,this.tempVector=new e.Vector3,this.tempQuaternion=new e.Quaternion,this.targetQuaternion=new e.Quaternion,this.calibrationQuaternion=new e.Quaternion,this.currentQuaternion=new e.Quaternion,this._lockedFaceVec=new e.Vector3,this._targetMatrix=new e.Matrix4,this._lookAtOrigin=new e.Vector3(0,0,0),this._upVector=new e.Vector3(0,1,0),this._tempEuler=new e.Euler(0,0,0,"XYZ"),this._defaultPosition=new e.Vector3(0,0,0)}update(e,t,i){if(0===this.strength||!this.camera)return t;const n=i||this._defaultPosition,a=.001*e;this.tempVector.copy(this.camera.position).sub(n),this.tempVector.lengthSq()<1e-4&&this.tempVector.set(0,0,1),this.tempVector.normalize(),this._lockedFaceVec.set(this.lockedFace[0],this.lockedFace[1],this.lockedFace[2]).normalize(),this._targetMatrix.lookAt(this.tempVector,this._lookAtOrigin,this._upVector),this.targetQuaternion.setFromRotationMatrix(this._targetMatrix),0===this.calibrationRotation[0]&&0===this.calibrationRotation[1]&&0===this.calibrationRotation[2]||(this._tempEuler.set(this.calibrationRotation[0],this.calibrationRotation[1],this.calibrationRotation[2],"XYZ"),this.calibrationQuaternion.setFromEuler(this._tempEuler),this.targetQuaternion.multiply(this.calibrationQuaternion)),this._tempEuler.set(t[0],t[1],t[2],"XYZ"),this.currentQuaternion.setFromEuler(this._tempEuler);const s=Math.min(1,this.strength*this.lerpSpeed*a*60);return this.currentQuaternion.slerp(this.targetQuaternion,s),this._tempEuler.setFromQuaternion(this.currentQuaternion,"XYZ"),t[0]=this._tempEuler.x,t[1]=this._tempEuler.y,t[2]=this._tempEuler.z,t}setCamera(e){this.camera=e}setCalibrationRotation(e){this.calibrationRotation=e}updateConfig(e){this.config=e,this.strength=void 0!==e.strength?e.strength:this.strength,this.lockedFace=e.lockedFace||this.lockedFace,this.calibrationRotation=e.calibrationRotation||this.calibrationRotation,this.lerpSpeed=void 0!==e.lerpSpeed?e.lerpSpeed:this.lerpSpeed}dispose(){this.camera=null,this.tempVector=null,this.tempQuaternion=null,this.targetQuaternion=null,this.calibrationQuaternion=null,this.currentQuaternion=null}}const De=new Map;var Pe=function(e){return De.get(e)||null},Be={name:"bounce",emoji:"⬆️",type:"blending",description:"Vertical oscillation with smooth easing",config:{duration:800,musicalDuration:{musical:!0,beats:2},amplitude:30,frequency:2,axis:"vertical",damping:!0,easing:"sine",strength:.6,particleMotion:{type:"bounce",axis:"vertical",strength:.6,frequency:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:3,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.8,offBeat:.6,curve:"bounce"},frequencySync:{mode:"tempo",multiplier:1},durationSync:{mode:"beats",beats:4},accentResponse:{enabled:!0,multiplier:1.5},patternOverrides:{waltz:{frequencySync:{multiplier:.75},durationSync:{beats:3}},swing:{amplitudeSync:{onBeat:2,offBeat:.4,curve:"ease"}},dubstep:{amplitudeSync:{onBeat:1.5,dropBeat:3,curve:"pulse"}},breakbeat:{frequencySync:{multiplier:1.5},amplitudeSync:{onBeat:2.2,offBeat:.3}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.bounce={startY:e.y,startX:e.x,startVx:e.vx,startVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.bounce?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=this.easeInOutCubic(t);let{frequency:h}=o;const c=i.phase||0;let u=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(u*=i.rhythmModulation.amplitudeMultiplier||1,u*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(h*=i.rhythmModulation.frequencyMultiplier));const d=Math.sin((l+c)*Math.PI*2*h);if(o.damping&&t>.7&&(u*=1-(t-.7)/.3*.8),"vertical"===o.axis?(e.vy+=d*u*.01*n,t>.9&&(e.vx*=.98)):"horizontal"===o.axis&&(e.vx+=d*u*.01*n,t>.9&&(e.vy*=.98)),t>.9){const i=1-10*(t-.9);e.vx=e.vx*(.95+.05*i),e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.bounce&&delete e.gestureData.bounce},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||30,a=i.frequency||2,s=.003*n*(i.strength||.6),o=(e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2)*Math.PI*a,r=Math.abs(Math.sin(o));let l=s;return e>.7&&(l*=1-(e-.7)/.3*.8),{position:[0,r*l,0],rotation:[0,0,0],scale:1+.08*r}}}},ke={name:"pulse",emoji:"💗",type:"blending",description:"Radial expansion and contraction from center",config:{duration:600,amplitude:30,frequency:1,holdPeak:.1,easing:"sine",scaleAmount:.2,glowAmount:.3,strength:.15,direction:"outward",particleMotion:{type:"pulse",strength:.15,direction:"outward",frequency:1}},rhythm:{enabled:!0,syncMode:"beat",amplitudeSync:{onBeat:1.6,offBeat:.8,curve:"pulse"},frequencySync:{mode:"locked",subdivision:"quarter"},durationSync:{mode:"beats",beats:1},accentResponse:{enabled:!0,multiplier:2},patternOverrides:{waltz:{amplitudeSync:{onBeat:2,offBeat:.5},durationSync:{beats:3}},swing:{amplitudeSync:{onBeat:1.8,offBeat:.6,curve:"ease"},frequencySync:{subdivision:"swing"}},dubstep:{amplitudeSync:{onBeat:1.2,dropBeat:4,curve:"pulse"}},breakbeat:{frequencySync:{mode:"random",range:[.5,2]},amplitudeSync:{onBeat:2.5,offBeat:.3}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.sqrt(a*a+s*s),r=Math.atan2(s,a);e.gestureData.pulse={baseDistance:o,angle:r,startX:e.x,startY:e.y,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.pulse?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.pulse,r={...this.config,...i},l=i.strength||1,h=this.easeInOutSine(t);let c,{frequency:u}=r,{amplitude:d}=r;i.rhythmModulation&&(d*=i.rhythmModulation.amplitudeMultiplier||1,d*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(u*=i.rhythmModulation.frequencyMultiplier));const m=h*u*2%2;c=r.holdPeak>0&&m>1-r.holdPeak&&m<1+r.holdPeak?1:Math.sin(h*Math.PI*2*u);const p=c*d*l*e.scaleFactor,g=o.baseDistance+p,f=a+Math.cos(o.angle)*g,y=s+Math.sin(o.angle)*g,v=.15*n;if(e.vx+=(f-e.x)*v*.1,e.vy+=(y-e.y)*v*.1,t>.9){const i=1-10*(t-.9);e.vx*=.9+.1*i,e.vy*=.9+.1*i}},cleanup(e){e.gestureData?.pulse&&delete e.gestureData.pulse},easeInOutSine:e=>-(Math.cos(Math.PI*e)-1)/2,"3d":{evaluate(e,t){const i=t||{},n=i.frequency||1,a=i.strength||.15,s=i.scaleAmount||.2,o=i.glowAmount||.3,r=-(Math.cos(Math.PI*e)-1)/2,l=Math.sin(r*Math.PI*2*n);return{position:[0,0,0],rotation:[0,0,0],scale:1+l*s*a,glowIntensity:1+Math.max(-.3,Math.min(.3,l*o*a*2)),glowBoost:Math.max(0,.8*l)}}}},Te={name:"shake",emoji:"🫨",type:"blending",description:"Random jitter movement for vibration effects",config:{duration:400,amplitude:15,frequency:15,decay:.9,smoothing:.1,axes:"both",easing:"linear",strength:3,particleMotion:{type:"shake",strength:3,frequency:15,decay:!1}},rhythm:{enabled:!0,syncMode:"subdivision",amplitudeSync:{subdivision:"sixteenth",onBeat:2.5,offBeat:.7,curve:"pulse"},frequencySync:{mode:"tempo",baseFrequency:15,scaling:"linear"},durationSync:{mode:"beats",beats:2},patternOverrides:{breakbeat:{amplitudeSync:{onBeat:3,offBeat:.2},frequencySync:{mode:"random",range:[8,20]}},dubstep:{amplitudeSync:{subdivision:"eighth",onBeat:4,dropBeat:6,curve:"pulse"}},swing:{amplitudeSync:{onBeat:1.8,offBeat:1,curve:"ease"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.shake={originalX:e.x,originalY:e.y,randomAngle:Math.random()*Math.PI*2,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.shake?.initialized||this.initialize(e,i);const o=e.gestureData.shake,r={...this.config,...i},l=r.strength||this.config.strength||1;let{amplitude:h}=r,{frequency:c}=r;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(c*=i.rhythmModulation.frequencyMultiplier));const u=r.decay?1-t:1,d=Math.sin(t*Math.PI*c)*h*u*l*e.scaleFactor,m=d*Math.cos(o.randomAngle),p=d*Math.sin(o.randomAngle);e.x=o.originalX+m,e.y=o.originalY+p},pseudoRandom(e){const t=1e4*Math.sin(e);return t-Math.floor(t)},cleanup(e){e.gestureData?.shake&&(e.x=e.gestureData.shake.originalX,e.y=e.gestureData.shake.originalY,delete e.gestureData.shake)},"3d":{evaluate(e,t){const i=t||{},n=.015*(i.amplitude||15),a=i.frequency||15,s=i.strength||1,o=i.decay?1-e:1,r=Math.sin(e*Math.PI*a)*n*o*s,l=Math.floor(e*a);return{position:[r*(1e4*Math.sin(l)%1-.5)*2,0,r*(1e4*Math.sin(1.3*l)%1-.5)*2],rotation:[0,0,r*(1e4*Math.sin(1.7*l)%1-.5)*.5],scale:1}}}},Ee={name:"nod",emoji:"🙂",type:"blending",description:"Vertical nodding motion",config:{duration:500,amplitude:15,frequency:2,easing:"sine",strength:.4,particleMotion:{type:"bounce",axis:"vertical",strength:.4,frequency:2,phase:0}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!1,priority:5,blendable:!1,minDuration:"halfBar",frequencySync:{mode:"subdivision",subdivision:"half",multiplier:1},amplitudeSync:{onBeat:1.4,offBeat:.8,curve:"ease"},durationSync:{mode:"beats",beats:2},patternOverrides:{waltz:{frequencySync:{subdivision:"quarter"},amplitudeSync:{onBeat:1.6,curve:"ease"}},swing:{amplitudeSync:{onBeat:1.5,offBeat:.9}},dubstep:{amplitudeSync:{onBeat:1.2,dropBeat:3,curve:"pulse"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.nod={startY:e.y,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.nod?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1;let{frequency:l}=o,{amplitude:h}=o;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(l*=i.rhythmModulation.frequencyMultiplier));const c=Math.sin(t*Math.PI*2*l);h=h*r*e.scaleFactor,e.vy+=c*h*.01*n,t>.9&&(e.vy*=.95)},cleanup(e){e.gestureData?.nod&&delete e.gestureData.nod},"3d":{evaluate(e,t){const i={...this.config,...t};let{frequency:n}=i,{amplitude:a}=i;t.rhythmModulation&&(a*=t.rhythmModulation.amplitudeMultiplier||1,a*=t.rhythmModulation.accentMultiplier||1,t.rhythmModulation.frequencyMultiplier&&(n*=t.rhythmModulation.frequencyMultiplier));const s=Math.sin(e*Math.PI),o=e>.9?.95:1;return{position:[0,0,s*(.1*a)*.015*o],rotation:[s*(.08*a)*o,0,0],scale:1}}}},Ie={name:"vibrate",emoji:"📳",type:"blending",description:"High frequency vibration",config:{duration:500,frequency:20,amplitude:8,easing:"linear",strength:2,particleMotion:{type:"shake",strength:2,frequency:20,amplitude:8}},rhythm:{enabled:!0,syncMode:"subdivision",frequencySync:{subdivision:"thirty-second",baseFrequency:20,tempoScaling:!0},amplitudeSync:{onBeat:1.5,offBeat:.8,curve:"pulse"},durationSync:{mode:"beats",beats:1},patternOverrides:{dubstep:{frequencySync:{subdivision:"sixteenth"},amplitudeSync:{onBeat:2,dropBeat:3}},breakbeat:{frequencySync:{mode:"random",range:[15,30]}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.vibrate={timer:0,seed:1e3*Math.random(),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.vibrate?.initialized||this.initialize(e,i);const o=e.gestureData.vibrate,r={...this.config,...i},l=r.strength||this.config.strength||1;let{amplitude:h}=r,{frequency:c}=r;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(c*=i.rhythmModulation.frequencyMultiplier)),o.timer+=n*c;const u=(Math.random()-.5)*h*l,d=(Math.random()-.5)*h*l;if(e.vx+=.5*u*n,e.vy+=.5*d*n,e.vx*=.9,e.vy*=.9,t>.8){const i=1-5*(t-.8);e.vx*=i,e.vy*=i}},cleanup(e){e.gestureData?.vibrate&&delete e.gestureData.vibrate},"3d":{evaluate(e,t){const i={...this.config,...t};let{amplitude:n}=i;const a=i.strength||this.config.strength||1;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const s=Math.sin(e*Math.PI),o=n*a*.003*s;return{position:[(Math.random()-.5)*o,(Math.random()-.5)*o,(Math.random()-.5)*o],rotation:[.01*(Math.random()-.5)*s,.01*(Math.random()-.5)*s,.01*(Math.random()-.5)*s],scale:1+.01*(Math.random()-.5)*s}}}},Ae={name:"orbit",emoji:"🪐",description:"3D orbital motion around center",type:"override",config:{speed:1,rotations:1,zRotations:1,smoothness:.15,verticalOscillation:0,centripetal:!1},rhythm:{enabled:!0,syncMode:"bar",speedSync:{mode:"tempo",baseSpeed:1,scaling:"linear"},rotationSync:{mode:"bars",rotationsPerBar:1,zSync:!0},radiusSync:{subdivision:"quarter",pulsAmount:.1,curve:"ease"},patternOverrides:{waltz:{rotationSync:{rotationsPerBar:.75},radiusSync:{pulsAmount:.15}},swing:{speedSync:{mode:"swing",ratio:.67},verticalOscillation:.2},dubstep:{radiusSync:{subdivision:"eighth",pulsAmount:.3,dropMultiplier:2}},breakbeat:{speedSync:{mode:"random",range:[.5,2]},centripetal:!0}}},apply:function(e,t,i,n,a,s){e.gestureData||(e.gestureData={});const o=e.gestureData,r=i,l=i.amplitude||1;if(!o.initialized){o.originalX=e.x,o.originalY=e.y,o.originalZ=e.z||0,o.originalVx=e.vx||0,o.originalVy=e.vy||0;const t=e.x-a,i=e.y-s;o.radius=Math.sqrt(t*t+i*i),o.radius<50&&(o.radius=50+100*Math.random()),o.initialAngle=Math.atan2(i,t),o.orbitSpeed=r.speed*(.8+.4*Math.random()),o.orbitTilt=.3*Math.random(),o.initialized=!0}let{rotations:h}=r,c=.05;r.rhythmModulation&&(r.rhythmModulation.speedMultiplier&&(o.orbitSpeed*=r.rhythmModulation.speedMultiplier),r.rhythmModulation.rotationMultiplier&&(h*=r.rhythmModulation.rotationMultiplier),r.rhythmModulation.radiusPulse&&(c=r.rhythmModulation.radiusPulse));let u=1,d=1;t<.15?(u=t/.15,u=u*u*(3-2*u),d=u):t>.85&&(u=(1-t)/.15,u=u*u*(3-2*u),d=u);const m=o.initialAngle+t*Math.PI*2*h*u,p=1+Math.sin(t*Math.PI*4)*c*u,g=o.radius*l*p*u,f=a+Math.cos(m)*g,y=s+Math.sin(m)*g,v=m*r.zRotations;if(e.z=.8*Math.sin(v)*u+o.originalZ*(1-u),t<.15){const t=.3*u;e.x=o.originalX+(f-o.originalX)*t,e.y=o.originalY+(y-o.originalY)*t;const i=-Math.sin(m)*g*o.orbitSpeed,n=Math.cos(m)*g*o.orbitSpeed;e.vx=o.originalVx+(i-o.originalVx)*d,e.vy=o.originalVy+(n-o.originalVy)*d}else if(t>.85){e.x=f+(o.originalX-f)*(1-u),e.y=y+(o.originalY-y)*(1-u);const t=-Math.sin(m)*g*o.orbitSpeed,i=Math.cos(m)*g*o.orbitSpeed;e.vx=t*d+o.originalVx*(1-d),e.vy=i*d+o.originalVy*(1-d)}else{if(r.verticalOscillation>0){const t=Math.sin(2*m)*r.verticalOscillation*l;e.y=y+t,e.x=f}else{const t=r.smoothness||.1;e.x+=(f-e.x)*t,e.y+=(y-e.y)*t}e.vx=-Math.sin(m)*g*o.orbitSpeed,e.vy=Math.cos(m)*g*o.orbitSpeed}if(r.centripetal){const i=1+.3*(1-Math.abs(e.z)),n=o.initialAngle+t*Math.PI*2*r.rotations*i;e.x=a+Math.cos(n)*g,e.y=s+Math.sin(n)*g}},emotions:["zen","love","excited","surprise"],features:{uses3D:!0,smooth:!0,looping:!0,dramatic:!0},"3d":{evaluate(e,t){const i={...this.config,...t};let{rotations:n}=i;const{zRotations:a}=i;t.rhythmModulation&&t.rhythmModulation.rotationMultiplier&&(n*=t.rhythmModulation.rotationMultiplier);let s=1;e<.15?(s=e/.15,s=s*s*(3-2*s)):e>.85&&(s=(1-e)/.15,s=s*s*(3-2*s));const o=e*Math.PI*2*n*s,r=o*a,l=.1*Math.sin(o)*s,h=.05*Math.cos(o)*s,c=.05*Math.sin(r)*s;return{position:[0,0,.2*Math.sin(r)*s],rotation:[h,l,c],scale:1+.03*Math.sin(2*o)*s}}}},Re={name:"twitch",emoji:"⚡",type:"blending",description:"Nervous, paranoid twitching",config:{intensity:8,frequency:.08,duration:100,recovery:200,maxOffset:15,sharpness:.9},rhythm:{enabled:!0,syncMode:"subdivision",probabilitySync:{subdivision:"sixteenth",onBeat:.3,offBeat:.05,accentBoost:2},intensitySync:{onBeat:2,offBeat:.8,curve:"pulse"},patternOverrides:{breakbeat:{probabilitySync:{onBeat:.5,offBeat:.1},intensitySync:{onBeat:3,offBeat:.5}},dubstep:{intensitySync:{onBeat:1.5,dropBeat:5,curve:"pulse"}}}},apply(e,t,i,n,a,s){e.gestureData||(e.gestureData={}),e.gestureData.twitch||(e.gestureData.twitch={twitchOffset:{x:0,y:0},targetOffset:{x:0,y:0},isTwitching:!1,twitchTimer:0,cooldownTimer:0,lastTwitch:0});const o=e.gestureData.twitch,{config:r}=this;let l=i.intensity||r.intensity;i.rhythmModulation&&(l*=i.rhythmModulation.amplitudeMultiplier||1,l*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.probabilityMultiplier);const h=Date.now();if(!o.isTwitching&&o.cooldownTimer<=0&&Math.random()<(i.frequency||r.frequency)){o.isTwitching=!0,o.twitchTimer=r.duration,o.cooldownTimer=r.recovery;const e=Math.random()*Math.PI*2,t=.5*r.maxOffset+Math.random()*(.5*r.maxOffset);o.targetOffset={x:Math.cos(e)*t*l/8,y:Math.sin(e)*t*l/8},o.lastTwitch=h}if(o.cooldownTimer>0&&(o.cooldownTimer-=16*n),o.isTwitching)if(o.twitchTimer-=16*n,o.twitchTimer>0){const{sharpness:e}=r;o.twitchOffset.x+=(o.targetOffset.x-o.twitchOffset.x)*e,o.twitchOffset.y+=(o.targetOffset.y-o.twitchOffset.y)*e}else o.isTwitching=!1;else o.twitchOffset.x*=.85,o.twitchOffset.y*=.85;e.vx+=o.twitchOffset.x*n*.5,e.vy+=o.twitchOffset.y*n*.5,Math.random()<.1&&(e.vx+=(Math.random()-.5)*l*.3,e.vy+=(Math.random()-.5)*l*.3)},cleanup(e){e.gestureData?.twitch&&delete e.gestureData.twitch},"3d":{evaluate(e,t){const i=t.config||{};let n=i.intensity||8;const a=i.maxOffset||15,s=i.frequency||.08;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const o=9999*Math.floor(10*e),r=e=>{const t=1e4*Math.sin(o+e);return t-Math.floor(t)};if(r(0)<3*s){const e=r(1)*Math.PI*2,t=a*n/8*.005;return{position:[Math.cos(e)*t*r(2),Math.sin(e)*t*r(3),(r(4)-.5)*t],rotation:[.2*(r(5)-.5),.2*(r(6)-.5),.2*(r(7)-.5)],scale:1+.1*(r(8)-.5)}}{const e=.5;return{position:[(r(10)-.5)*e,(r(11)-.5)*e,(r(12)-.5)*e],rotation:[.01*(r(13)-.5),.01*(r(14)-.5),.01*(r(15)-.5)],scale:1}}}}},ze={name:"sway",type:"blending",emoji:"🌊",description:"Gentle side-to-side swaying motion",config:{duration:2e3,amplitude:20,frequency:1,strength:.5},rhythm:{enabled:!0,syncMode:"bar",amplitudeSync:{onBeat:1.2,offBeat:.9,curve:"ease"},durationSync:{mode:"bars",bars:1},patternOverrides:{waltz:{durationSync:{bars:1},amplitudeSync:{onBeat:1.5,curve:"ease"}},swing:{amplitudeSync:{onBeat:1.3,offBeat:.7,curve:"bounce"}}}},apply(e,t,i,n,a,s){const o={...this.config,...i},r=o.amplitude||this.config.amplitude,l=o.frequency||this.config.frequency,h=o.strength||this.config.strength,c=Math.sin(t*Math.PI*2*l)*r;e.vx+=.01*c*n*h,e.vy+=.5*Math.cos(t*Math.PI*4)*n*h},cleanup(e){},"3d":{evaluate(e,t){const i={...this.config,...t};let n=i.amplitude||this.config.amplitude;const a=i.frequency||this.config.frequency,s=i.strength||this.config.strength;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const o=Math.sin(e*Math.PI*2*a),r=n*s*.3*.01,l=.15*o*s,h=.08*o*s;return{position:[o*r,.3*Math.cos(e*Math.PI*4)*r,Math.sin(e*Math.PI*a)*r*.5],rotation:[0,h,l],scale:1}}}},_e={name:"float",type:"blending",emoji:"🎈",description:"Gentle floating upward motion",config:{duration:2e3,amplitude:80,wobbleAmount:20,strength:1},rhythm:{enabled:!0,syncMode:"beat",amplitudeSync:{onBeat:1.5,offBeat:.8,curve:"bounce"},wobbleSync:{subdivision:"eighth",intensity:.7},durationSync:{mode:"bars",bars:2},accentResponse:{enabled:!0,multiplier:1.3},patternOverrides:{waltz:{wobbleSync:{subdivision:"quarter",intensity:.9}},dubstep:{amplitudeSync:{onBeat:2,curve:"pulse"}}}},apply(e,t,i,n,a,s){e.gestureData||(e.gestureData={}),e.gestureData.float||(e.gestureData.float={originalSize:e.size,originalOpacity:e.opacity||1});const o={...this.config,...i};let r=o.amplitude||this.config.amplitude,l=o.wobbleAmount||this.config.wobbleAmount;const h=o.strength||this.config.strength;i.rhythmModulation&&(r*=i.rhythmModulation.amplitudeMultiplier||1,r*=i.rhythmModulation.accentMultiplier||1,l*=i.rhythmModulation.wobbleMultiplier||1);const c=Math.sin(t*Math.PI*4)*l;e.vy-=.01*r*n*h*(1-.5*t),e.vx+=.01*c*n*h,e.size=e.baseSize*(1+.1*t),e.opacity=1-.3*t},cleanup(e){e.gestureData?.float?(e.opacity=e.gestureData.float.originalOpacity,e.size=e.gestureData.float.originalSize,delete e.gestureData.float):(e.opacity=1,e.size=e.baseSize),e.vx*=.5,e.vy*=.5},"3d":{evaluate(e,t){const i={...this.config,...t};let n=i.amplitude||this.config.amplitude,a=i.wobbleAmount||this.config.wobbleAmount;const s=i.strength||this.config.strength;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1,a*=t.rhythmModulation.wobbleMultiplier||1);const o=Math.sin(e*Math.PI),r=n*o*s*.005,l=Math.sin(e*Math.PI*4)*a*.3*.005,h=Math.sin(e*Math.PI)*Math.PI*.5*s,c=Math.sin(e*Math.PI);return{position:[l,r,0],rotation:[c*Math.sin(e*Math.PI*2)*.1,h,c*Math.cos(e*Math.PI*3)*.08],scale:1+.1*o}}}},Oe={name:"jitter",type:"blending",emoji:"🫨",description:"Nervous jittery movement",config:{duration:1e3,intensity:15,frequency:30,strength:1},rhythm:{enabled:!0,syncMode:"beat",amplitudeSync:{onBeat:2,offBeat:.5,curve:"pulse"},patternOverrides:{breakbeat:{amplitudeSync:{onBeat:3,offBeat:.3}},dubstep:{amplitudeSync:{onBeat:5,offBeat:.1,curve:"pulse"}}}},apply(e,t,i,n,a,s){e.gestureData||(e.gestureData={}),e.gestureData.jitter||(e.gestureData.jitter={originalSize:e.size});const o={...this.config,...i};let r=o.intensity||this.config.intensity;const l=o.strength||this.config.strength;i.rhythmModulation&&(r*=i.rhythmModulation.amplitudeMultiplier||1,r*=i.rhythmModulation.accentMultiplier||1);const h=(Math.random()-.5)*r*l,c=(Math.random()-.5)*r*l,u=1-.5*t;e.vx+=.1*h*n*u,e.vy+=.1*c*n*u,e.size=e.baseSize*(1+.1*(Math.random()-.5))},cleanup(e){e.gestureData?.jitter?(e.size=e.gestureData.jitter.originalSize,delete e.gestureData.jitter):e.size=e.baseSize,e.vx*=.7,e.vy*=.7},"3d":{evaluate(e,t){const i={...this.config,...t};let n=i.intensity||this.config.intensity;const a=i.strength||this.config.strength;t.rhythmModulation&&(n*=t.rhythmModulation.amplitudeMultiplier||1,n*=t.rhythmModulation.accentMultiplier||1);const s=Math.sin(e*Math.PI),o=n*a*.002*s;return{position:[(Math.random()-.5)*o,(Math.random()-.5)*o,(Math.random()-.5)*o],rotation:[.005*(Math.random()-.5)*s,.005*(Math.random()-.5)*s,.005*(Math.random()-.5)*s],scale:1+.02*(Math.random()-.5)*s}}}},Fe={name:"wiggle",emoji:"〰️",type:"additive",description:"Rapid side-to-side oscillation",config:{duration:600,musicalDuration:{musical:!0,beats:1},amplitude:15,frequency:6,strength:1,damping:.3,easing:"linear",particleMotion:{type:"wiggle",strength:1,amplitude:15,frequency:6}},rhythm:{enabled:!0,syncMode:"beat",frequencySync:{subdivision:"sixteenth",wigglePerBeat:4},amplitudeSync:{onBeat:1.5,offBeat:.8,curve:"bounce"},durationSync:{mode:"beats",beats:1}},apply(e,t,i,n,a,s,o){const r=(i.amplitude||this.config.amplitude)*a,l=i.frequency||this.config.frequency,h=1-n*(i.damping||this.config.damping),c=Math.sin(n*Math.PI*l)*r*h;e.vx+=.5*c;const u=Math.cos(n*Math.PI*l*2)*r*.1*h;e.vy+=.3*u},"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||1,a=i.amplitude||15,s=i.frequency||6,o=i.damping||.3,r=Math.sin(e*Math.PI*s),l=1-e*o;return{position:[r*a*.008*n*l,0,0],rotation:[0,.25*r*n*l,0],scale:1}}}},Le={name:"headBob",emoji:"🎧",type:"additive",description:"Rhythmic vertical bobbing to music",config:{duration:600,musicalDuration:{musical:!0,beats:1},amplitude:12,frequency:2,strength:1,damping:.1,easing:"linear",particleMotion:{type:"headBob",strength:1,amplitude:12,frequency:2}},rhythm:{enabled:!0,syncMode:"beat",frequencySync:{subdivision:"eighth",bobsPerBeat:2},amplitudeSync:{onBeat:1.3,offBeat:1,curve:"pulse"},durationSync:{mode:"beats",beats:1}},apply(e,t,i,n,a,s,o){const r=(i.amplitude||this.config.amplitude)*a,l=i.frequency||this.config.frequency,h=1-n*(i.damping||this.config.damping),c=Math.sin(n*Math.PI*2*l)*r*h;e.vy+=.5*c;const u=Math.cos(n*Math.PI*2*l*1.5)*r*.05*h;e.vx+=.2*u},"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||1,a=i.amplitude||12,s=i.frequency||2,o=i.damping||.1,r=Math.sin(e*Math.PI*2*s),l=1-e*o;return{position:[0,-r*a*.008*n*l,0],rotation:[r*(.045*a)*n*l,0,0],scale:1}}}},Ge={name:"lean",emoji:"↗️",type:"blending",description:"Diagonal tilting motion with smooth return",config:{duration:1200,musicalDuration:{musical:!0,beats:2},amplitude:10,frequency:1,direction:"right",strength:.7,particleMotion:{type:"lean",direction:"right",strength:.7,frequency:1}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:3,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.3,offBeat:.8,curve:"ease"},durationSync:{mode:"beats",beats:2},accentResponse:{enabled:!0,multiplier:1.4},patternOverrides:{waltz:{durationSync:{beats:3},amplitudeSync:{onBeat:1.5,offBeat:.6}},swing:{amplitudeSync:{onBeat:1.6,offBeat:.5,curve:"bounce"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.lean={startX:e.x,startY:e.y,startVx:e.vx,startVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.lean?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=this.easeInOutCubic(t),h=o.frequency||this.config.frequency;let c=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(c*=i.rhythmModulation.amplitudeMultiplier||1,c*=i.rhythmModulation.accentMultiplier||1);const u=Math.sin(l*Math.PI*h),d="left"===o.direction?-1:1;if(e.vx+=u*c*.015*n*d,e.vy+=u*c*.01*n*d*.5,t>.9){const i=1-10*(t-.9);e.vx=e.vx*(.95+.05*i),e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.lean&&delete e.gestureData.lean},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||10,a=i.frequency||1,s=i.strength||.7,o=i.direction||"right",r=.003*n*s,l=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,h=Math.sin(l*Math.PI*a),c="left"===o?-1:1;return{position:[h*r*c,0,0],rotation:[0,0,.35*h*c],scale:1}}}},Ve={name:"point",emoji:"👉",type:"blending",description:"Directional pointing motion with forward momentum",config:{duration:1e3,musicalDuration:{musical:!0,beats:2},amplitude:15,direction:"right",strength:.8,particleMotion:{type:"point",direction:"right",strength:.8}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:4,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.5,offBeat:.7,curve:"ease"},durationSync:{mode:"beats",beats:2},accentResponse:{enabled:!0,multiplier:1.6},patternOverrides:{march:{amplitudeSync:{onBeat:2,offBeat:.5,curve:"pulse"}},swing:{amplitudeSync:{onBeat:1.4,offBeat:.8,curve:"bounce"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.point={startX:e.x,startY:e.y,startVx:e.vx,startVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.point?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=this.easeInOutCubic(t);let h=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(h*=i.rhythmModulation.amplitudeMultiplier||1,h*=i.rhythmModulation.accentMultiplier||1);const c=Math.sin(l*Math.PI);let u=0,d=0;switch(o.direction||"right"){case"right":u=1;break;case"left":u=-1;break;case"up":d=-1;break;case"down":d=1}if(e.vx+=c*h*.02*n*u,e.vy+=c*h*.02*n*d,t>.9){const i=1-10*(t-.9);e.vx=e.vx*(.95+.05*i),e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.point&&delete e.gestureData.point},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||15,a=i.strength||.8,s=i.direction||"right",o=.005*n*a,r=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,l=Math.sin(r*Math.PI);let h=0,c=0;switch(s){case"right":h=l*o,c=.25*l;break;case"left":h=-l*o,c=.25*-l;break;case"up":case"down":c=0}return{position:[h,0,0],rotation:[0,c,0],scale:1}}}},qe={name:"reach",emoji:"🙌",type:"blending",description:"Upward reaching motion with scale increase",config:{duration:1400,musicalDuration:{musical:!0,beats:2},amplitude:25,strength:.9,scaleMax:1.05,particleMotion:{type:"reach",strength:.9,scaleMax:1.05}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:4,blendable:!0,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.4,offBeat:.9,curve:"ease"},durationSync:{mode:"beats",beats:2},accentResponse:{enabled:!0,multiplier:1.5},patternOverrides:{uplifting:{amplitudeSync:{onBeat:1.8,offBeat:.7,curve:"ease"},durationSync:{beats:3}},ambient:{amplitudeSync:{onBeat:1.2,offBeat:1,curve:"linear"}}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.reach={startY:e.y,startVy:e.vy,originalSize:e.size,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.reach?.initialized||this.initialize(e,i);const o={...this.config,...i},r=o.strength||this.config.strength||1,l=o.scaleMax||this.config.scaleMax||1.05,h=this.easeInOutCubic(t);let c=o.amplitude*r*e.scaleFactor;i.rhythmModulation&&(c*=i.rhythmModulation.amplitudeMultiplier||1,c*=i.rhythmModulation.accentMultiplier||1);const u=Math.sin(h*Math.PI);e.vy-=u*c*.015*n;const d=1+u*(l-1);if(e.size=e.baseSize*d,t>.9){const i=1-10*(t-.9);e.vy=e.vy*(.95+.05*i)}},cleanup(e){e.gestureData?.reach&&(e.gestureData.reach.originalSize?e.size=e.gestureData.reach.originalSize:e.size=e.baseSize,delete e.gestureData.reach)},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t||{},n=i.amplitude||25,a=i.strength||.9,s=i.scaleMax||1.05,o=.004*n*a,r=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,l=Math.sin(r*Math.PI);return{position:[0,l*o,0],rotation:[.1*l,0,0],scale:1+l*(s-1)}}}},Ne={name:"spin",emoji:"🌀",type:"override",description:"Orbital rotation around center point",config:{duration:600,musicalDuration:{musical:!0,beats:1},rotations:1,direction:"random",radiusMultiplier:1,spiralOut:!1,accelerate:!0,maintainDistance:!0,scaleAmount:.1,easing:"linear",strength:.7,particleMotion:{type:"spin",strength:.7,rotations:1,radius:1}},rhythm:{enabled:!0,syncMode:"bar",rotationSync:{mode:"bars",rotationsPerBar:1,accelerateOnBeat:!0},radiusSync:{subdivision:"quarter",expandOnBeat:1.2,contractOffBeat:.9,curve:"bounce"},durationSync:{mode:"beats",beats:4},patternOverrides:{waltz:{rotationSync:{rotationsPerBar:.75},radiusSync:{curve:"ease"}},swing:{rotationSync:{accelerateOnBeat:!1},direction:"alternating"},dubstep:{radiusSync:{subdivision:"eighth",expandOnBeat:1.5,dropMultiplier:2},spiralOut:!0},breakbeat:{rotationSync:{mode:"random",range:[.5,2]},direction:"random"}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;let o=t.direction||this.config.direction;"random"===o&&(o=Math.random()<.5?"clockwise":"counter-clockwise"),e.gestureData.spin={startAngle:Math.atan2(s,a),startRadius:Math.sqrt(a*a+s*s)||30,originalX:e.x,originalY:e.y,originalVx:e.vx,originalVy:e.vy,direction:o,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.spin?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.spin,r={...this.config,...i},l=i.strength||1;let{rotations:h}=r,{radiusMultiplier:c}=r;i.rhythmModulation&&(i.rhythmModulation.rotationMultiplier&&(h*=i.rhythmModulation.rotationMultiplier),i.rhythmModulation.radiusMultiplier&&(c*=i.rhythmModulation.radiusMultiplier));let u=t;r.accelerate&&(u=t<.5?.5*this.easeInQuad(2*t):.5+.5*this.easeOutQuad(2*(t-.5)));const d=h*Math.PI*2*l,m="counter-clockwise"===o.direction?-1:1,p=o.startAngle+d*u*m;let g=o.startRadius;r.spiralOut&&(g*=1+.5*t),1!==c&&(g*=1+(c-1)*Math.sin(t*Math.PI));const f=a+Math.cos(p)*g,y=s+Math.sin(p)*g;if(e.x+=.25*(f-e.x),e.y+=.25*(y-e.y),e.vx=.5*(f-e.x),e.vy=.5*(y-e.y),t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.spin){const t=e.gestureData.spin;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.spin}},easeInQuad:e=>e*e,easeOutQuad:e=>e*(2-e),"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.spin)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.spin,a=t.config||{},s=t.strength||1;let o=e;a.accelerate&&(o=e<.5?e*e*4*.5:.5+(e-.5)*(2-(e-.5))*.5);const r=(a.rotations||1)*Math.PI*2*s,l="counter-clockwise"===n.direction?-1:1;return{position:[0,0,0],rotation:[0,r*Math.sin(o*Math.PI)*l,0],scale:1+(a.scaleAmount||.1)*Math.sin(e*Math.PI)*s}}}},je={name:"jump",emoji:"🦘",type:"override",description:"Squash, leap, and land with classic animation principles",config:{duration:800,jumpHeight:60,squashAmount:.8,stretchAmount:1.2,anticipation:.2,hangTime:.1,landingImpact:!0,driftOutward:!0,easing:"quad",particleMotion:{type:"jump",strength:.9,jumpHeight:60,squash:.8,stretch:1.2}},rhythm:{enabled:!0,syncMode:"beat",phaseSync:{anticipation:"eighth",jump:"beat",landing:"sixteenth"},heightSync:{onBeat:1.5,offBeat:.8,accent:2,curve:"exponential"},deformationSync:{squashOnBeat:.6,stretchOnBeat:1.4,timing:"anticipatory"},hangTimeSync:{mode:"tempo",baseDuration:.1,scaling:"inverse"},dynamics:{forte:{jumpHeight:80,stretch:1.3},piano:{jumpHeight:30,stretch:1.1}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={}),e.gestureData.jump={startX:e.x,startY:e.y,startSize:e.size,originalVx:e.vx,originalVy:e.vy,driftDirection:.1*(e.x-i),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.jump?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.jump,r={...this.config,...i},l=i.strength||1,h=r.jumpHeight*l*e.scaleFactor,c=r.squashAmount,u=r.stretchAmount,d=r.anticipation,m=1-.5*r.anticipation;if(t<d){const i=t/d,n=this.easeOutQuad(i);e.size=o.startSize*(1-(1-c)*n),e.y=o.startY+5*n*e.scaleFactor,e.vx=0,e.vy=0}else if(t<m){const i=(t-d)/(m-d);let n=Math.sin(i*Math.PI);if(r.hangTime>0&&i>.4&&i<.6){const e=(i-.4)/.2;n=.95+.05*this.easeInOutCubic(e)}if(e.y=o.startY-n*h,r.driftOutward&&(e.x=o.startX+n*o.driftDirection),i<.5){const t=2*i;e.size=o.startSize*(c+(u-c)*t)}else{const t=2*(i-.5);e.size=o.startSize*(u-(u-1)*t*.8)}e.vx=.5*o.driftDirection,e.vy=-Math.cos(i*Math.PI)*h*.1}else{const i=(t-m)/(1-m),n=this.easeOutBounce(i);if(e.y=o.startY,r.landingImpact)if(i<.3){const t=i/.3;e.size=o.startSize*(1-(1-.8*c)*(1-t))}else{const t=(i-.3)/.7;e.size=o.startSize*(.8*c+(1-.8*c)*t)}else e.size=o.startSize*(c+(1-c)*n);e.vx=o.originalVx*n,e.vy=o.originalVy*n}},cleanup(e){if(e.gestureData?.jump){const t=e.gestureData.jump;e.size=t.startSize,e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.jump}},easeOutQuad:e=>e*(2-e),easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutBounce(e){const t=7.5625,i=2.75;return e<1/i?t*e*e:e<2/i?t*(e-=1.5/i)*e+.75:e<2.5/i?t*(e-=2.25/i)*e+.9375:t*(e-=2.625/i)*e+.984375},"3d":{evaluate(e,t){const i=t.config||t||{},n=t.strength||1,a=.004*(i.jumpHeight||60)*n,s=i.squashAmount||.8,o=i.stretchAmount||1.2,r=i.anticipation||.2,l=1-.5*r;let h=0,c=1,u=0;if(e<r){const t=e/r,i=t*(2-t);c=1-(1-s)*i,h=.02*-i}else if(e<l){const t=(e-r)/(l-r);h=Math.sin(t*Math.PI)*a,c=t<.5?s+2*t*(o-s):o-2*(t-.5)*(o-1)*.8,u=.05*Math.sin(t*Math.PI)}else{const t=(e-l)/(1-l);if(t<.5){const e=2*t;h=-Math.sin(e*Math.PI)*a*.15}else h=0;c=!1!==i.landingImpact?t<.3?1-(1-.8*s)*(1-t/.3):.8*s+(t-.3)/.7*(1-.8*s):s+(1-s)*t}return{position:[0,h,0],rotation:[u,0,0],scale:c}}}},Ue={name:"morph",emoji:"✨",type:"override",description:"Form geometric patterns and shapes",config:{musicalDuration:{musical:!0,beats:2,minBeats:1,maxBeats:8},phases:[{name:"gather",beats:.25},{name:"form",beats:.75},{name:"hold",beats:.5},{name:"dissolve",beats:.5}],morphType:"fluid",pattern:"star",points:5,innerRadius:.4,size:80,amplitude:20,rotation:0,smooth:!0,randomizeOrder:!1,easing:"sine",strength:1.2,particleMotion:{type:"morph",pattern:"star",strength:1.2,smooth:!0,points:5}},rhythm:{enabled:!0,syncMode:"phrase",patternSync:{verse:"circle",chorus:"star",bridge:"heart",drop:"explosion"},timingSync:{formationBeat:1,holdBeats:2,dissolveBeat:4,curve:"anticipatory"},sizeSync:{onBeat:1.2,offBeat:.95,subdivision:"quarter",curve:"elastic"},rotationSync:{mode:"continuous",degreesPerBar:90,direction:"clockwise"},dynamics:{forte:{points:8,size:100},piano:{points:3,size:60}}},initialize(e,t,i,n,a){e.gestureData||(e.gestureData={});const s={...this.config,...t},o=e.x,r=e.y,l=Math.atan2(e.y-n,e.x-i),h=Math.random()<.5?1:-1;let c,u;const d=s.size*e.scaleFactor,m=(s.rotation||0)*Math.PI/180*h;switch(s.pattern){case"star":c=i,u=n,this.calculateStarPosition(e,l,d,s.points,s.innerRadius,m,i,n);break;case"heart":this.calculateHeartPosition(e,l,d,m,i,n);break;case"square":this.calculateSquarePosition(e,l,d,m,i,n);break;case"triangle":this.calculateTrianglePosition(e,l,d,m,i,n);break;default:{const e=d;c=i+Math.cos(l+m)*e,u=n+Math.sin(l+m)*e;break}}e.gestureData.morph={startX:o,startY:r,targetX:e.gestureData.morphTargetX||c,targetY:e.gestureData.morphTargetY||u,originalVx:e.vx,originalVy:e.vy,rotationDirection:h,initialized:!0}},calculateStarPosition(e,t,i,n,a,s,o,r){const l=((t+Math.PI)%(2*Math.PI)+2*Math.PI)%(2*Math.PI),h=Math.floor(l/(2*Math.PI)*10),c=h%2==0,u=Math.floor(h/2);let d;d=c?72*u*Math.PI/180:(72*u+36)*Math.PI/180,d+=s;const m=c?i:i*a;e.gestureData.morphTargetX=o+Math.cos(d)*m,e.gestureData.morphTargetY=r+Math.sin(d)*m},calculateHeartPosition(e,t,i,n,a,s){const o=(t+Math.PI)/(2*Math.PI),r=.05*i,l=16*Math.pow(Math.sin(o*Math.PI*2),3),h=-(13*Math.cos(o*Math.PI*2)-5*Math.cos(2*o*Math.PI*2)-2*Math.cos(3*o*Math.PI*2)-Math.cos(4*o*Math.PI*2)),c=Math.cos(n),u=Math.sin(n),d=l*c-h*u,m=l*u+h*c;e.gestureData.morphTargetX=a+d*r,e.gestureData.morphTargetY=s+m*r},calculateSquarePosition(e,t,i,n,a,s){const o=((t+n)%(2*Math.PI)+2*Math.PI)%(2*Math.PI);let r,l;const h=i;o<Math.PI/4||o>=7*Math.PI/4?(r=h,l=h*Math.tan(o)):o<3*Math.PI/4?(r=h/Math.tan(o),l=h):o<5*Math.PI/4?(r=-h,l=-h*Math.tan(o)):(r=-h/Math.tan(o),l=-h);const c=Math.cos(n),u=Math.sin(n),d=r*c-l*u,m=r*u+l*c;e.gestureData.morphTargetX=a+d,e.gestureData.morphTargetY=s+m},calculateTrianglePosition(e,t,i,n,a,s){const o=[{x:0,y:-i},{x:.866*-i,y:.5*i},{x:.866*i,y:.5*i}],r=Math.floor((t+Math.PI)/(2*Math.PI)*3)%3,l=(r+1)%3,h=Math.random(),c=o[r].x+(o[l].x-o[r].x)*h,u=o[r].y+(o[l].y-o[r].y)*h,d=Math.cos(n),m=Math.sin(n),p=c*d-u*m,g=c*m+u*d;e.gestureData.morphTargetX=a+p,e.gestureData.morphTargetY=s+g},apply(e,t,i,n,a,s){e.gestureData?.morph?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.morph,r={...this.config,...i};let l,h,c=t;if(r.holdTime>0){const e=.5-r.holdTime/2,i=.5+r.holdTime/2;c=t<e?t/e*.5:t<i?.5:.5+(t-i)/(1-i)*.5}if(c<=.5){const e=2*c;l=o.startX+(o.targetX-o.startX)*this.easeOutQuad(e),h=o.startY+(o.targetY-o.startY)*this.easeOutQuad(e)}else{const e=2*(c-.5);l=o.targetX+(o.startX-o.targetX)*this.easeInQuad(e),h=o.targetY+(o.startY-o.targetY)*this.easeInQuad(e)}if(r.smooth){const t=.2;e.x+=(l-e.x)*t,e.y+=(h-e.y)*t}else e.x=l,e.y=h;if(e.vx=.5*(l-e.x),e.vy=.5*(h-e.y),t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.morph){const t=e.gestureData.morph;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.morph,delete e.gestureData.morphTargetX,delete e.gestureData.morphTargetY}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutQuad:e=>e*(2-e),easeInQuad:e=>e*e,"3d":{evaluate(e,t){const i=t?.strength||1,n=Math.sin(e*Math.PI);let a;if(e<=.5){const t=2*e;a=1+t*(2-t)*.25*i}else{const t=2*(e-.5);a=1.25*i+t*t*(1-1.25*i),a=Math.max(1,a)}return{position:[0,0,0],rotation:[0,n*Math.PI*.3*i,.1*Math.sin(e*Math.PI*2)*i],scale:a,glowIntensity:1+.4*n*i,glowBoost:1.5*n*i}}}},He={name:"stretch",emoji:"↔️",type:"override",description:"Scale particles along X and Y axes",config:{duration:2e3,scaleX:1.3,scaleY:.9,alternate:!1,elastic:!0,overshoot:.1,frequency:1,easing:"sine",strength:1,particleMotion:{type:"stretch",scaleX:1.8,scaleY:.6,strength:1},centerBased:!0,preserveArea:!1},rhythm:{enabled:!0,syncMode:"beat",scaleSync:{onBeat:{x:1.5,y:.7},offBeat:{x:.8,y:1.3},subdivision:"eighth",curve:"elastic"},alternateSync:{pattern:"XYXY",beatsPerChange:1,overlap:.1},overshootSync:{normal:.1,accent:.3,downbeat:.2,curve:"spring"},preservationSync:{verse:!0,chorus:!1,bridge:!0},dynamics:{forte:{scaleX:2,scaleY:.5,overshoot:.4},piano:{scaleX:1.1,scaleY:.95,overshoot:.05}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.stretch={offsetX:a,offsetY:s,startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.stretch?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.stretch,r={...this.config,...i},l=i.strength||1;let h,c,{scaleX:u}=r,{scaleY:d}=r;if(r.preserveArea&&1!==u&&1!==d){const e=u*d,t=Math.sqrt(1/e);u*=t,d*=t}if(r.alternate)if(t<.5){const e=2*t;u=1+(u-1)*this.getElasticProgress(e,r),d=1+(1/u-1)*(r.preserveArea?1:0)}else{const e=2*(t-.5);u+=(1-u)*this.getElasticProgress(e,r),d=1+(d-1)*this.getElasticProgress(e,r)}else{const e=this.getElasticProgress(t,r);u=1+(u-1)*e*l,d=1+(d-1)*e*l}if(r.centerBased?(h=a+o.offsetX*u,c=s+o.offsetY*d):(h=o.startX*u,c=o.startY*d),e.x=h,e.y=c,e.vx=o.offsetX*(u-1)*l*.1,e.vy=o.offsetY*(d-1)*l*.1,t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},getElasticProgress(e,t){if(!t.elastic)return this.easeInOutCubic(e);if(0===e)return 0;if(1===e)return 1;const i=t.overshoot||.1;if(e<.5){const t=2*e;return.5*this.easeInElastic(t,i)}{const t=2*(e-.5);return.5+.5*this.easeOutElastic(t,i)}},cleanup(e){if(e.gestureData?.stretch){const t=e.gestureData.stretch;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.stretch}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeInElastic:(e,t)=>0===e?0:1===e?1:-Math.pow(2,10*(e-1))*Math.sin((e-1-.075)*(2*Math.PI)/.3)*(1+t),easeOutElastic:(e,t)=>0===e?0:1===e?1:Math.pow(2,-10*e)*Math.sin((e-.075)*(2*Math.PI)/.3)*(1+t)+1,"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.stretch)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=t.config||{},a=t.strength||1;let s,o=n.scaleX||1.3,r=n.scaleY||.9;if(n.preserveArea&&1!==o&&1!==r){const e=o*r,t=Math.sqrt(1/e);o*=t,r*=t}if(n.elastic){const t=n.overshoot||.1;if(e<.5){const i=2*e,n=.3,a=n/4;s=-Math.pow(2,10*(i-1))*Math.sin((i-1-a)*(2*Math.PI)/n)*(1+t)*.5}else{const i=2*(e-.5),n=.3,a=n/4;s=.5+.5*(Math.pow(2,-10*i)*Math.sin((i-a)*(2*Math.PI)/n)*(1+t)+1)}}else s=e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2;let l,h=1;if(e>.8){const t=(e-.8)/(1-.8);h=1-t*t*t}l=n.alternate?e<.5?2*e*.8:.8-2*(e-.5)*1.4:1*s*a;const c=1+l*h;return{position:[0,0,0],rotation:[0,0,.1*Math.sin(e*Math.PI*4)*s*h],scale:c}}}},We={name:"tilt",emoji:"🤔",type:"override",description:"Gather particles then tilt as unified group",config:{duration:500,gatherPhase:.2,tiltAngle:45,swayAmount:80,liftAmount:60,frequency:3,homeRadius:20,easing:"sine",strength:2.5,particleMotion:{type:"tilt",strength:2.5,frequency:3,swayAmount:80,liftAmount:60},smoothness:.25},rhythm:{enabled:!0,syncMode:"swing",angleSync:{onBeat:45,offBeat:-30,swing:15,subdivision:"triplet",curve:"ease-in-out"},gatherSync:{beatsBefore:.5,releaseAfter:.25,intensity:"dynamic"},swaySync:{verse:60,chorus:100,bridge:80,syncopated:!0},liftSync:{upOnTilt:!0,heightOnAccent:80,normalHeight:40,curve:"bounce"},dynamics:{forte:{tiltAngle:60,swayAmount:120,frequency:4},piano:{tiltAngle:20,swayAmount:40,frequency:2}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.atan2(s,a),r=Math.sqrt(a*a+s*s),l=Math.random(),h=({...this.config,...t}.homeRadius+20*Math.random())*e.scaleFactor;e.gestureData.tilt={startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,angle:o,distance:r,homeRadius:h,homeX:i+Math.cos(o)*h,homeY:n+Math.sin(o)*h,role:l,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.tilt?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.tilt,r={...this.config,...i},l=i.strength||1;let h,c;if(t<r.gatherPhase){const i=t/r.gatherPhase,n=this.easeInOutCubic(i);h=o.startX+(o.homeX-o.startX)*n,c=o.startY+(o.homeY-o.startY)*n;const a=.6;e.x+=(h-e.x)*a,e.y+=(c-e.y)*a}else{const i=(t-r.gatherPhase)/(1-r.gatherPhase)*Math.PI*r.frequency,n=Math.sin(i),u=r.tiltAngle*Math.PI/180*l,d=o.angle+n*u,m=Math.abs(n)*r.liftAmount*e.scaleFactor,p=o.homeRadius+m;h=a+Math.cos(d)*p,c=s+Math.sin(d)*p-.3*m;const g=r.smoothness+.1*o.role;e.x+=(h-e.x)*g,e.y+=(c-e.y)*g;const f=-Math.sin(d),y=Math.cos(d);e.vx=f*n*2,e.vy=y*n*2}if(t<r.gatherPhase&&(e.vx=.25*(h-e.x),e.vy=.25*(c-e.y)),t>.9){const i=10*(1-t),n=o.startX+(e.x-o.startX)*i,a=o.startY+(e.y-o.startY)*i;e.x=n,e.y=a,e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.tilt){const t=e.gestureData.tilt;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.tilt}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||1,a=i.gatherPhase||.2,s=i.frequency||3,o=i.tiltAngle||45;let r=0;if(e>=a){const t=(e-a)/(1-a)*Math.PI*s;r=Math.sin(t)*(o*Math.PI/180*n*.4)}return{position:[0,0,0],rotation:[0,0,r],scale:1}}}},Xe={name:"orbital",emoji:"🪐",type:"override",description:"Orbital motion around center",config:{speed:.02,maintainRadius:!0,elliptical:!1,use3D:!0,zPhaseOffset:0,verticalOscillation:0,duration:3e3,particleMotion:{type:"orbital",strength:1}},rhythm:{enabled:!0,syncMode:"harmonic",speedSync:{tonic:.02,fifth:.03,octave:.04,third:.025,curve:"smooth"},radiusSync:{bass:150,mid:100,treble:50,scaling:"logarithmic"},depthSync:{major:{z:1,phase:0},minor:{z:-1,phase:Math.PI},diminished:{z:.5,phase:Math.PI/2},augmented:{z:.8,phase:-Math.PI/2}},phaseSync:{mode:"harmonic",intervals:[1,1.5,2],drift:.05},dynamics:{forte:{speed:.04,maintainRadius:!1},piano:{speed:.01,maintainRadius:!0}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.sqrt(a*a+s*s),r=Math.random()<.5?1:-1,l=Math.max(o,100+180*Math.random()),h=o<5?Math.random()*Math.PI*2:Math.atan2(s,a);e.gestureData.orbital={radius:l,targetRadius:l,angle:h,initialAngle:h,originalVx:e.vx,originalVy:e.vy,originalZ:e.z||0,zPhase:Math.random()*Math.PI*2,direction:r}},apply(e,t,i,n,a,s){e.gestureData?.orbital||this.initialize(e,i,a,s);const o=e.gestureData.orbital,r=(i.speed||this.config.speed)*(i.strength||1);o.angle+=r*n*o.direction;let{radius:l}=o;if(i.maintainRadius||(l=o.radius*(1+.1*Math.sin(t*Math.PI*2))),e.x=a+Math.cos(o.angle)*l,e.y=s+Math.sin(o.angle)*l,!1!==i.use3D){const t=o.angle+o.zPhase+(i.zPhaseOffset||0);if(e.z=.8*Math.sin(t),i.verticalOscillation){const n=Math.cos(t)*i.verticalOscillation*l*.1;e.y+=n}}if(e.vx=-Math.sin(o.angle)*l*r,e.vy=Math.cos(o.angle)*l*r,t>.9){const i=10*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i)}},cleanup(e){if(e.gestureData?.orbital){const t=e.gestureData.orbital;e.vx=t.originalVx,e.vy=t.originalVy,e.z=t.originalZ,delete e.gestureData.orbital}},"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.orbital)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.orbital;t.config;let a=1;e<.15?(a=e/.15,a=Math.sin(a*Math.PI*.5)):e>.85&&(a=(1-e)/.15,a=Math.sin(a*Math.PI*.5));const s=n.initialAngle+e*Math.PI*2*n.direction,o=.3*Math.cos(s)*a,r=.3*Math.sin(s)*a,l=(s+Math.PI/2-(n.initialAngle+Math.PI/2))*a,h=i.z||0;return{position:[o,0,r+.1*h*a],rotation:[0,l,0],scale:1+.15*h*a}}}},Ye={name:"hula",emoji:"🌀",type:"override",description:"Hula-hoop motion with vertical waves",config:{speed:.015,maintainRadius:!1,elliptical:!0,use3D:!0,zPhaseOffset:Math.PI/4,verticalOscillation:.3,wobbleAmount:.15,duration:2500,particleMotion:{type:"hula",strength:1,verticalOscillation:.3}},rhythm:{enabled:!0,syncMode:"bar",speedSync:{mode:"tempo",baseSpeed:.015,scaling:"proportional"},wobbleSync:{onBeat:.25,offBeat:.1,curve:"sine"},verticalSync:{subdivision:"quarter",amplitude:.4,phase:"sequential"},dynamics:{forte:{wobbleAmount:.3,speed:1.2},piano:{wobbleAmount:.05,speed:.8}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.sqrt(a*a+s*s),r=Math.random()<.5?1:-1,l=Math.max(o,100+180*Math.random()),h=o<5?Math.random()*Math.PI*2:Math.atan2(s,a);e.gestureData.hula={radius:l,angle:h,initialAngle:h,originalVx:e.vx,originalVy:e.vy,originalZ:e.z||0,zPhase:Math.random()*Math.PI*2,wobblePhase:Math.random()*Math.PI*2,direction:r}},apply(e,t,i,n,a,s){e.gestureData?.hula||this.initialize(e,i,a,s);const o=e.gestureData.hula,r=(i.speed||this.config.speed)*(i.strength||1);let l=1;t<.1?(l=t/.1,l=Math.sin(l*Math.PI*.5)):t>.9&&(l=(1-t)/.1,l=Math.sin(l*Math.PI*.5)),o.angle+=r*n*o.direction*l;const h=Math.sin(2*o.angle+o.wobblePhase)*(i.wobbleAmount||this.config.wobbleAmount)*l,c=o.radius*(1+h)*l,u=o.radius*(.7+h)*l,d=a+Math.cos(o.angle)*c,m=s+Math.sin(o.angle)*u;if(t<.1){const t=e.x-a,i=e.y-s;Math.sqrt(t*t+i*i)<50?(e.x=a+Math.cos(o.angle)*c,e.y=s+Math.sin(o.angle)*u):(e.x=e.x+(d-e.x)*l*.5,e.y=e.y+(m-e.y)*l*.5)}else e.x=d,e.y=m;const p=o.angle+o.zPhase+(i.zPhaseOffset||this.config.zPhaseOffset);e.z=.9*Math.sin(p)*l;const g=i.verticalOscillation||this.config.verticalOscillation,f=Math.cos(2*p)*g*o.radius*.2*l;e.y+=f;const y=e.z*o.radius*.1;e.y-=y;const v=-Math.sin(o.angle)*c*r,b=Math.cos(o.angle)*u*r;t<.1?(e.vx=o.originalVx+(v-o.originalVx)*l,e.vy=o.originalVy+(b-o.originalVy)*l):t>.9?(e.vx=v*l+o.originalVx*(1-l),e.vy=b*l+o.originalVy*(1-l),e.z=e.z*l+o.originalZ*(1-l)):(e.vx=v,e.vy=b)},cleanup(e){if(e.gestureData?.hula){const t=e.gestureData.hula;e.vx=t.originalVx,e.vy=t.originalVy,e.z=t.originalZ,delete e.gestureData.hula}},"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.hula)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.hula,a=t.config||{};let s=1;e<.15?(s=e/.15,s=Math.sin(s*Math.PI*.5)):e>.85&&(s=(1-e)/.15,s=Math.sin(s*Math.PI*.5));const o=n.initialAngle+e*Math.PI*2*n.direction,r=.25*Math.cos(o)*s,l=.25*Math.sin(o)*s,h=a.verticalOscillation||.3;return{position:[r,Math.sin(2*o+n.wobblePhase)*h*s,l],rotation:[0,(o-n.initialAngle)*s,0],scale:1+.15*Math.abs(Math.sin(o))*s}}}},$e={name:"twist",emoji:"🌀",type:"override",description:"Twisting dance motion with alternating rotation",config:{duration:1200,rotationAngle:45,contractionFactor:.8,twistFrequency:2,easing:"smooth",strength:.8,particleMotion:{type:"twist",rotationAngle:45,contractionFactor:.8,twistFrequency:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",interruptible:!0,priority:4,blendable:!1,crossfadePoint:"anyBeat",amplitudeSync:{onBeat:1.5,offBeat:.7,curve:"elastic"},patternOverrides:{funk:{rotationAngle:60,contractionFactor:.7},disco:{twistFrequency:3,rotationAngle:50},latin:{rotationAngle:35,contractionFactor:.85,twistFrequency:2.5}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.twist={startX:e.x,startY:e.y,startAngle:Math.atan2(e.y-t.centerY,e.x-t.centerX),startDistance:Math.sqrt(Math.pow(e.x-t.centerX,2)+Math.pow(e.y-t.centerY,2)),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.twist?.initialized||this.initialize(e,{...i,centerX:a,centerY:s});const o={...this.config,...i},r=e.gestureData.twist,l=o.strength||this.config.strength||1,h=t*o.twistFrequency*Math.PI*2,c=Math.sin(h)*l;let{rotationAngle:u}=o,{contractionFactor:d}=o;i.rhythmModulation&&(u*=i.rhythmModulation.amplitudeMultiplier||1,d=1-(1-d)*(i.rhythmModulation.amplitudeMultiplier||1));const m=u*Math.PI/180*c,p=1-(1-d)*Math.abs(c),g=r.startAngle+m,f=r.startDistance*p,y=a+Math.cos(g)*f,v=s+Math.sin(g)*f,b=.15*l;e.x+=(y-e.x)*b,e.y+=(v-e.y)*b,e.vx=.05*(y-e.x),e.vy=.05*(v-e.y);const w=5*Math.sin(t*Math.PI*4)*l;if(e.y+=.1*w,t>.9){const i=1-10*(t-.9);e.vx*=i,e.vy*=i}},cleanup(e){e.gestureData?.twist&&delete e.gestureData.twist},"3d":{evaluate(e,t){const{particle:i}=t;if(!i||!i.gestureData?.twist)return{position:[0,0,0],rotation:[0,0,0],scale:1};const n=i.gestureData.twist,a=t.config||{},s=a.strength||1,o=e>.85?(1-e)/.15:1,r=e*(a.twistFrequency||2)*Math.PI*2,l=Math.sin(r)*s*o,h=l*((a.rotationAngle||45)*Math.PI/180),c=n.startAngle+h,u=(a.contractionFactor||.8)*n.startDistance;return{position:[Math.cos(c)*u*.1*o*.01,0,Math.sin(c)*u*.1*o*.01],rotation:[.1*Math.cos(r)*s*o,h,.15*Math.sin(.5*r)*s*o],scale:1-(1-(a.contractionFactor||.8))*Math.abs(l)}}}},Qe={name:"wave",emoji:"🌊",type:"override",description:"Infinity pattern flow with phasing",config:{musicalDuration:{musical:!0,bars:1,minBeats:4,maxBeats:16},phases:[{name:"gather",beats:.5},{name:"rise",beats:.5},{name:"waveLeft",beats:1},{name:"waveRight",beats:1},{name:"settle",beats:1}],amplitude:40,frequency:1,phaseShift:.3,liftHeight:20,fadeInOut:!0,smoothness:.1,easing:"sine",strength:1,particleMotion:{type:"wave",strength:1,amplitude:50}},rhythm:{enabled:!0,syncMode:"wave",amplitudeSync:{onWave:65,onStatic:25,curve:"flowing"},frequencySync:{mode:"phrase",slow:.7,fast:1.8,curve:"melodic"},durationSync:{mode:"bars",adaptToPhrase:!0,sustain:!0},phaseSync:{enabled:!0,multiplier:.5,type:"ensemble"},melodicResponse:{enabled:!0,multiplier:1.4,type:"amplitude"},patternOverrides:{ambient:{amplitudeSync:{onWave:80,onStatic:40,curve:"hypnotic"},frequencySync:{slow:.5,fast:1.2},durationSync:{minBeats:16,maxBeats:64}},ocean:{amplitudeSync:{onWave:90,onStatic:20,curve:"natural"},phaseSync:{multiplier:.8},melodicResponse:{multiplier:1.8}},electronic:{amplitudeSync:{onWave:70,onStatic:30,curve:"digital"},frequencySync:{slow:.8,fast:2.5,curve:"precise"}},orchestral:{amplitudeSync:{onWave:75,onStatic:35},phaseSync:{multiplier:.7},melodicResponse:{multiplier:2}}},dynamics:{forte:{amplitudeSync:{onWave:{multiplier:1.8},onStatic:{multiplier:1.4}},frequencySync:{multiplier:1.3},melodicResponse:{multiplier:2.2}},piano:{amplitudeSync:{onWave:{multiplier:.6},onStatic:{multiplier:.4}},frequencySync:{multiplier:.7},melodicResponse:{multiplier:1.1}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n,o=Math.atan2(s,a),r=Math.sqrt(a*a+s*s),l=Math.random()<.5?1:-1;e.gestureData.wave={startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,baseOpacity:e.opacity||e.life||1,angle:o,radius:r,offset:Math.random()*Math.PI*2,role:Math.random(),direction:l,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.wave?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.wave,r={...this.config,...i},l=i.strength||1,h=this.easeInOutSine(t),c=o.role*r.phaseShift,u=Math.max(0,h-c),d=u*Math.PI*2*r.frequency*o.direction+o.offset,m=.5+o.radius/100*.5,p=r.amplitude*m*l*e.scaleFactor,g=a+Math.sin(d)*p,f=s+Math.sin(2*d)*p*.3+-Math.abs(Math.sin(h*Math.PI))*r.liftHeight*e.scaleFactor,y=r.smoothness+.12*o.role;if(e.x+=(g-e.x)*y,e.y+=(f-e.y)*y,e.vx=.3*(g-e.x),e.vy=.3*(f-e.y),r.fadeInOut){let t;t=u<.1?u/.1:u>.9?(1-u)/.1:.5+.5*Math.sin(u*Math.PI),e.opacity=o.baseOpacity*(.3+.7*t),void 0!==e.life&&(e.life=e.opacity)}if(t>=.95){const i=20*(1-t);e.vx=e.vx*i+o.originalVx*(1-i),e.vy=e.vy*i+o.originalVy*(1-i),r.fadeInOut&&(e.opacity=o.baseOpacity*i,void 0!==e.life&&(e.life=e.opacity))}},cleanup(e){if(e.gestureData?.wave){const t=e.gestureData.wave;e.vx=t.originalVx,e.vy=t.originalVy,e.opacity=t.baseOpacity,void 0!==e.life&&(e.life=t.baseOpacity),delete e.gestureData.wave}},easeInOutSine:e=>-(Math.cos(Math.PI*e)-1)/2,"3d":{evaluate(e,t){const i=t?.strength||1,n=t?.frequency||1,a=-(Math.cos(Math.PI*e)-1)/2,s=a*Math.PI*2*n,o=.12*Math.sin(s)*i,r=.06*Math.sin(2*s)*i,l=.03*Math.sin(s)*i,h=.08*Math.sin(2*s)*i,c=.05*Math.sin(s)*i,u=1+.08*Math.abs(Math.sin(a*Math.PI))*i,d=Math.abs(Math.sin(s));return{position:[o,r,l],rotation:[h,0,c],scale:u,glowIntensity:1+.3*d*i,glowBoost:.6*d*i}}}},Ze={name:"drift",emoji:"☁️",type:"override",description:"Controlled floating with fade effects",config:{duration:800,distance:50,angle:45,returnToOrigin:!0,fadeOut:!1,holdTime:.2,turbulence:.1,angleSpread:45,smoothness:.08,easing:"ease",strength:1,particleMotion:{type:"drift",strength:1,distance:60}},rhythm:{enabled:!0,syncMode:"ambient",distanceSync:{quiet:30,loud:80,crescendo:"expand",diminuendo:"contract"},angleSync:{major:45,minor:225,modulation:"smooth",cadence:"return"},holdSync:{shortPhrase:.1,longPhrase:.4,fermata:"sustain"},accentResponse:{enabled:!0,multiplier:1.3,type:"distance"},patternOverrides:{ambient:{distanceSync:{quiet:40,loud:100},holdSync:{shortPhrase:.3,longPhrase:.6}},classical:{angleSync:{major:30,minor:210},distanceSync:{quiet:25,loud:60}},jazz:{angleSync:{major:60,minor:240,swing:!0,syncopated:!0}},new_age:{distanceSync:{quiet:35,loud:70},holdSync:{shortPhrase:.4,longPhrase:.8},angleSync:{modulation:"gradual"}}},dynamics:{forte:{distanceSync:{quiet:{multiplier:1.5},loud:{multiplier:1.8}},holdSync:{multiplier:1.2},accentResponse:{multiplier:1.6}},piano:{distanceSync:{quiet:{multiplier:.6},loud:{multiplier:.8}},holdSync:{multiplier:.8},accentResponse:{multiplier:1.1}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;let o=Math.atan2(s,a);const r={...this.config,...t}.angleSpread*Math.PI/180,l=(Math.random()-.5)*r;o+=l;const h=30+30*Math.random();e.gestureData.drift={startX:e.x,startY:e.y,originalVx:e.vx,originalVy:e.vy,baseOpacity:e.opacity||e.life||1,driftAngle:o,angleOffset:l,homeRadius:h*e.scaleFactor,homeX:i+Math.cos(o)*h,homeY:n+Math.sin(o)*h,role:Math.random(),turbulencePhase:Math.random()*Math.PI*2,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.drift?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.drift,r={...this.config,...i},l=i.strength||1,h=this.easeInOutCubic(t),c=Math.max(0,h-.1*o.role);let u,d,m;if(r.returnToOrigin)if(c<.4){const e=c/.4,t=this.easeOutQuad(e);u=o.startX+(o.homeX-o.startX)*t,d=o.startY+(o.homeY-o.startY)*t}else if(c<.6+r.holdTime){const t=(c-.4)/(.2+r.holdTime);m=o.homeRadius+Math.sin(t*Math.PI*.5)*r.distance*l*e.scaleFactor}else{const t=(c-.6-r.holdTime)/(.4-r.holdTime);m=o.homeRadius+Math.cos(t*Math.PI*.5)*r.distance*l*e.scaleFactor}else{const t=c;m=o.homeRadius+t*r.distance*l*e.scaleFactor}if(void 0!==m){o.turbulencePhase+=r.turbulence*n;const e=Math.sin(o.turbulencePhase)*r.turbulence*10,t=Math.cos(1.3*o.turbulencePhase)*r.turbulence*10,i=o.driftAngle+o.angleOffset;u=a+Math.cos(i)*m+e,d=s+Math.sin(i)*m+t}const p=r.smoothness+.08*o.role;if(e.x+=(u-e.x)*p,e.y+=(d-e.y)*p,e.vx=.25*(u-e.x),e.vy=.25*(d-e.y),r.fadeOut){let i;i=t<.25?.3+t/.25*.7:t<.75?.7+.3*Math.sin((t-.25)*Math.PI/.5):4*(1-t),e.opacity=o.baseOpacity*i,void 0!==e.life&&(e.life=e.opacity)}t>=.99&&(e.vx=.1*o.originalVx,e.vy=.1*o.originalVy,r.fadeOut&&(e.opacity=o.baseOpacity,void 0!==e.life&&(e.life=o.baseOpacity)))},cleanup(e){if(e.gestureData?.drift){const t=e.gestureData.drift;e.vx=t.originalVx,e.vy=t.originalVy,e.opacity=t.baseOpacity,void 0!==e.life&&(e.life=t.baseOpacity),delete e.gestureData.drift}},easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutQuad:e=>e*(2-e),"3d":{evaluate(e,t){const i={...this.config,...t},n=t.strength||1,a=(i.angle||45)*Math.PI/180,s=i.returnToOrigin?e<.5?2*e:2*(1-e):e;return{position:[Math.cos(a)*s*.3*n,Math.sin(a)*s*.3*n,.15*Math.sin(e*Math.PI)*n],rotation:[0,10*s*n,0],scale:1+.03*Math.sin(e*Math.PI),glowIntensity:1-.1*s}}}},Je={name:"flicker",emoji:"⚡",type:"blending",description:"Rapid opacity changes with motion jitter",config:{duration:800,flickerRate:15,frequency:6,minOpacity:.3,maxOpacity:1,jitterAmount:2,colorShift:!1,strobe:!1,pulseMode:!1,groupFlicker:.3,easing:"linear",strength:.7,particleMotion:{type:"flicker",strength:.7,frequency:6}},rhythm:{enabled:!0,syncMode:"subdivision",rateSync:{subdivision:"sixteenth",onBeat:30,offBeat:10,triplet:20,curve:"step"},opacitySync:{pattern:"HLMH",subdivision:"eighth",onAccent:.1,regular:.5},jitterSync:{onBeat:5,offBeat:1,accent:10,curve:"random"},strobeSync:{verse:!1,chorus:!0,drop:"intense",pattern:"XOXO"},dynamics:{forte:{flickerRate:25,jitterAmount:5,minOpacity:.1},piano:{flickerRate:8,jitterAmount:1,minOpacity:.5}}},initialize(e,t){e.gestureData||(e.gestureData={});const i={...this.config,...t},n=Math.random()<i.groupFlicker;e.gestureData.flicker={baseOpacity:e.opacity||e.life||1,baseColor:e.color,baseX:e.x,baseY:e.y,flickerTimer:0,lastFlicker:0,flickerState:!0,isGrouped:n,groupId:n?Math.floor(3*Math.random()):-1,phase:Math.random()*Math.PI*2,colorHue:0,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.flicker?.initialized||this.initialize(e,i);const o=e.gestureData.flicker,r={...this.config,...i},l=i.strength||1;let h;if(o.flickerTimer+=n*r.flickerRate,r.strobe)h=(o.flickerTimer+o.phase)%1<.5?1:r.minOpacity;else if(r.pulseMode){const e=o.flickerTimer+o.phase;h=r.minOpacity+(r.maxOpacity-r.minOpacity)*(.5*Math.sin(e)+.5)}else{if(o.flickerTimer-o.lastFlicker>1)if(o.lastFlicker=o.flickerTimer,o.isGrouped){const e=Math.floor(o.flickerTimer)%3;o.flickerState=e===o.groupId}else o.flickerState=Math.random()>.3;const t=o.flickerState?r.maxOpacity:r.minOpacity+.3*Math.random(),i=e.opacity/o.baseOpacity;h=i+.3*(t-i)}const c=o.baseOpacity*(1+(h-1)*l);if(e.opacity=Math.max(0,Math.min(1,c)),void 0!==e.life&&(e.life=e.opacity),r.jitterAmount>0&&h>r.minOpacity){const t=r.jitterAmount*l*e.scaleFactor,i=(Math.random()-.5)*t*h,a=(Math.random()-.5)*t*h;e.vx+=.1*i*n,e.vy+=.1*a*n}if(r.colorShift&&e.color){o.colorHue+=.01*n;const t=30*Math.sin(o.colorHue);e.color=this.shiftHue(o.baseColor,t*l)}let u=1;t<.1?u=t/.1:t>.9&&(u=(1-t)/.1),e.opacity*=u,void 0!==e.life&&(e.life=e.opacity),t>.8&&(e.vx*=.95,e.vy*=.95)},shiftHue(e,t){if(!e||!e.startsWith("#"))return e;const i=e.slice(1),n=parseInt(i.substr(0,2),16)/255,a=parseInt(i.substr(2,2),16)/255,s=parseInt(i.substr(4,2),16)/255,o=t*Math.PI/180,r=Math.cos(o),l=Math.sin(o),h=n*l+a*r,c=s,u=e=>Math.max(0,Math.min(255,Math.round(255*e))).toString(16).padStart(2,"0");return`#${u(n*r-a*l)}${u(h)}${u(c)}`},cleanup(e){if(e.gestureData?.flicker){const t=e.gestureData.flicker;e.opacity=t.baseOpacity,e.color=t.baseColor,void 0!==e.life&&(e.life=t.baseOpacity),delete e.gestureData.flicker}},"3d":{evaluate(e,t){const i=t.config||{},n=t.strength||.7,a=i.flickerRate||15;i.minOpacity;const s=e*a,o=Math.sin(s*Math.PI*2),r=Math.floor(10*s),l=.3*o+.5*(Math.sin(123.456*r)+1)*.7,h=.6+.8*l,c=i.jitterAmount||2,u=.003*n*h,d=(Math.random()-.5)*c*u,m=(Math.random()-.5)*c*u,p=.03*(Math.random()-.5)*n*h;return{position:[d,m,0],rotation:[.5*p,0,p],scale:1+.08*(h-1),glowIntensity:h,glowBoost:1.2*l}}}},Ke={name:"burst",emoji:"💥",type:"blending",description:"Explosive outward burst from center",config:{decay:.5,strength:2},rhythm:{enabled:!0,syncMode:"beat",strengthSync:{onBeat:3.5,offBeat:1,curve:"explosion"},decaySync:{mode:"tempo",fast:.8,slow:.3,curve:"exponential"},durationSync:{mode:"beats",beats:.5,sustain:!1},accentResponse:{enabled:!0,multiplier:2.5,type:"strength"},patternOverrides:{rock:{strengthSync:{onBeat:4,offBeat:1.5},decaySync:{fast:.6,slow:.4}},electronic:{strengthSync:{onBeat:3.8,offBeat:.8,curve:"sharp"},decaySync:{fast:.9,slow:.7}},jazz:{strengthSync:{onBeat:2.8,offBeat:1.8,swing:!0},decaySync:{fast:.5,slow:.2}},orchestral:{strengthSync:{onBeat:3.2,offBeat:.5},accentResponse:{multiplier:3}}},dynamics:{forte:{strengthSync:{onBeat:{multiplier:2},offBeat:{multiplier:1.5}},decaySync:{multiplier:.7},accentResponse:{multiplier:3.5}},piano:{strengthSync:{onBeat:{multiplier:.6},offBeat:{multiplier:.3}},decaySync:{multiplier:1.3},accentResponse:{multiplier:1.8}}}},apply(e,t,i,n,a,s){const o=i.decay||this.config.decay,r=(i.strength||this.config.strength)*(1-t*o),l=e.x-a,h=e.y-s,c=Math.sqrt(l*l+h*h);c>1&&(e.vx+=l/c*r*2*n,e.vy+=h/c*r*2*n)},"3d":{evaluate(e,t){const i={...this.config,...t}.decay||.5,n=e<.3?.3-e:0;return{position:[0,0,0],rotation:[0,0,0],scale:1+(e<.2?5*e:1.5*(1-e))*((t.strength||2)*(1-e*i)),glowIntensity:1+Math.min(1*n,.3),glowBoost:2.5*n}}}},et={name:"directional",emoji:"➡️",type:"blending",description:"Move particles in a specific direction",config:{angle:0,returnToOrigin:!1,strength:1},rhythm:{enabled:!0,syncMode:"flow",angleSync:{verse:0,chorus:90,bridge:180,outro:270,transition:"smooth"},strengthSync:{onBeat:1.8,offBeat:.6,curve:"wave"},returnSync:{enabled:!0,onSectionChange:!0,duration:"transition",strength:1.2},accentResponse:{enabled:!0,multiplier:2,type:"strength"},patternOverrides:{march:{angleSync:{verse:0,chorus:0},strengthSync:{onBeat:2.5,offBeat:1}},waltz:{angleSync:{verse:45,chorus:135,bridge:225,outro:315,transition:"circular"}},swing:{strengthSync:{onBeat:1.6,offBeat:1.4,swing:!0}},electronic:{angleSync:{transition:"instant"},strengthSync:{onBeat:2.2,offBeat:.4,curve:"sharp"}}},dynamics:{forte:{strengthSync:{onBeat:{multiplier:1.6},offBeat:{multiplier:1.2}},angleSync:{transition:"sharp"},accentResponse:{multiplier:2.5}},piano:{strengthSync:{onBeat:{multiplier:.7},offBeat:{multiplier:.8}},angleSync:{transition:"gradual"},accentResponse:{multiplier:1.4}}}},initialize(e){e.gestureData||(e.gestureData={}),e.gestureData.directional={initialX:e.x,initialY:e.y}},apply(e,t,i,n,a,s){e.gestureData?.directional||this.initialize(e);const o=(i.angle||this.config.angle)*Math.PI/180,r=i.strength||this.config.strength;if(e.vx+=Math.cos(o)*r*.3*n,e.vy+=Math.sin(o)*r*.3*n,i.returnToOrigin&&t>.5){const i=2*(t-.5),a=e.gestureData.directional,s=a.initialX-e.x,o=a.initialY-e.y;e.vx+=s*i*.02*n,e.vy+=o*i*.02*n}},"3d":{evaluate(e,t){const i={...this.config,...t},n=(i.angle||0)*Math.PI/180,a=t.strength||1,s=i.returnToOrigin?e<.5?2*e:2*(1-e):e;return{position:[Math.cos(n)*s*.4*a,Math.sin(n)*s*.4*a,0],rotation:[0,0,0],scale:1,glowIntensity:1}}}},tt={name:"settle",emoji:"🍃",type:"blending",description:"Gradually settle particles to rest",config:{damping:.02,threshold:.01},rhythm:{enabled:!0,syncMode:"resolution",dampingSync:{onResolution:.035,onTension:.015,curve:"gradual"},thresholdSync:{mode:"dynamics",forte:.02,piano:.005,curve:"exponential"},durationSync:{mode:"phrase",minBeats:2,maxBeats:12,sustain:!0},cadenceResponse:{enabled:!0,multiplier:1.6,type:"damping"},patternOverrides:{ambient:{dampingSync:{onResolution:.025,onTension:.008,curve:"atmospheric"},durationSync:{minBeats:8,maxBeats:32}},jazz:{dampingSync:{onResolution:.04,onTension:.02},cadenceResponse:{multiplier:1.8}},classical:{dampingSync:{onResolution:.045,onTension:.012,curve:"expressive"},cadenceResponse:{multiplier:2}},minimalist:{dampingSync:{onResolution:.02,onTension:.005},durationSync:{minBeats:16,maxBeats:64}}},dynamics:{forte:{dampingSync:{onResolution:{multiplier:1.4},onTension:{multiplier:.8}},thresholdSync:{multiplier:2},cadenceResponse:{multiplier:2.2}},piano:{dampingSync:{onResolution:{multiplier:.7},onTension:{multiplier:1.2}},thresholdSync:{multiplier:.5},cadenceResponse:{multiplier:1.3}}}},apply(e,t,i,n,a,s){const o=i.damping||this.config.damping,r=i.threshold||this.config.threshold;e.vx*=Math.max(0,1-o*n*60),e.vy*=Math.max(0,1-o*n*60),Math.abs(e.vx)<r&&(e.vx=0),Math.abs(e.vy)<r&&(e.vy=0)},"3d":{evaluate(e,t){const i=1-Math.pow(1-e,2),n=.01*(1-i);return{position:[Math.sin(e*Math.PI*2)*n,Math.cos(e*Math.PI*3)*n*.5,0],rotation:[0,0,0],scale:1-.03*i,glowIntensity:1-.15*i}}}},it={name:"fade",emoji:"👻",type:"blending",description:"Fade particle opacity",config:{duration:2e3,fadeIn:!0,fadeOut:!0,minOpacity:0,maxOpacity:1},rhythm:{enabled:!0,syncMode:"dynamic",opacitySync:{onBeat:.9,offBeat:.3,subdivision:"eighth",curve:"exponential"},fadePhaseSync:{verse:{fadeIn:!0,fadeOut:!1},chorus:{fadeIn:!1,fadeOut:!1},bridge:{fadeIn:!0,fadeOut:!0},outro:{fadeIn:!1,fadeOut:!0}},pulseSync:{enabled:!0,frequency:"quarter",intensity:.2,onAccent:.4},dynamics:{forte:{minOpacity:.5,maxOpacity:1},piano:{minOpacity:0,maxOpacity:.4}}},initialize(e){e.gestureData||(e.gestureData={}),e.gestureData.fade={baseOpacity:e.opacity||e.life||1}},apply(e,t,i,n,a,s){e.gestureData?.fade||this.initialize(e);const o=e.gestureData.fade,r={...this.config,...i};let l;l=r.fadeIn&&!r.fadeOut?r.minOpacity+(r.maxOpacity-r.minOpacity)*t:r.fadeOut&&!r.fadeIn?r.maxOpacity-(r.maxOpacity-r.minOpacity)*t:t<.5?r.minOpacity+(r.maxOpacity-r.minOpacity)*(2*t):r.maxOpacity-(r.maxOpacity-r.minOpacity)*(2*(t-.5)),e.opacity=o.baseOpacity*l,void 0!==e.life&&(e.life=e.opacity)},cleanup(e){e.gestureData?.fade&&(e.opacity=e.gestureData.fade.baseOpacity,void 0!==e.life&&(e.life=e.opacity),delete e.gestureData.fade)},"3d":{evaluate(e,t){const i={...this.config,...t};let n;const a=i.minOpacity??0,s=i.maxOpacity??1;return n=i.fadeIn&&!i.fadeOut?a+(s-a)*e:i.fadeOut&&!i.fadeIn?s-(s-a)*e:e<.5?s-2*e*(s-a):a+2*(e-.5)*(s-a),{position:[0,0,0],rotation:[0,0,0],scale:1,glowIntensity:n}}}},nt={name:"hold",emoji:"⏸️",type:"override",description:"Hold particles in current position",config:{holdStrength:.95,allowDrift:!1},rhythm:{enabled:!0,syncMode:"rest",holdSync:{onRest:.98,onSound:.8,curve:"immediate"},durationSync:{mode:"rests",minBeats:.5,maxBeats:8,sustain:!0},pauseResponse:{enabled:!0,multiplier:1.5,type:"strength"},patternOverrides:{classical:{holdSync:{onRest:.99,onSound:.75,curve:"dramatic"},pauseResponse:{multiplier:2}},minimal:{holdSync:{onRest:.95,onSound:.85},durationSync:{minBeats:2,maxBeats:16}},jazz:{holdSync:{onRest:.9,onSound:.7},allowDrift:!0},electronic:{holdSync:{onRest:.99,onSound:.6,curve:"digital"},pauseResponse:{multiplier:1.2}}},dynamics:{forte:{holdSync:{onRest:{multiplier:1.02},onSound:{multiplier:.9}},pauseResponse:{multiplier:2.2}},piano:{holdSync:{onRest:{multiplier:.97},onSound:{multiplier:.85}},pauseResponse:{multiplier:1.3}}}},initialize(e){e.gestureData||(e.gestureData={}),e.gestureData.hold={holdX:e.x,holdY:e.y,originalVx:e.vx,originalVy:e.vy}},apply(e,t,i,n,a,s){e.gestureData?.hold||this.initialize(e);const o=e.gestureData.hold,r=i.holdStrength||this.config.holdStrength;if(i.allowDrift?(e.vx*=r,e.vy*=r):(e.x+=(o.holdX-e.x)*(1-r),e.y+=(o.holdY-e.y)*(1-r),e.vx=0,e.vy=0),t>.9){const i=10*(t-.9);e.vx=e.vx*(1-i)+o.originalVx*i,e.vy=e.vy*(1-i)+o.originalVy*i}},cleanup(e){if(e.gestureData?.hold){const t=e.gestureData.hold;e.vx=t.originalVx,e.vy=t.originalVy,delete e.gestureData.hold}},"3d":{evaluate:(e,t)=>({position:[0,0,0],rotation:[0,0,0],scale:1,glowIntensity:1})}},at={name:"breathe",emoji:"🫁",type:"blending",description:"Breathing rhythm with inhale and exhale",config:{musicalDuration:{musical:!0,bars:1,minBeats:2,maxBeats:16},phases:[{name:"inhale",beats:1.5},{name:"hold_in",beats:.5},{name:"exhale",beats:1.5},{name:"hold_out",beats:.5}],inhaleRadius:1.5,exhaleRadius:.3,breathRate:.3,spiralStrength:.002,scaleAmount:.25,glowAmount:.4,frequency:1,easing:"sine",strength:.8,particleMotion:{type:"breathe",strength:.8,inhaleRadius:1.5,exhaleRadius:.3}},rhythm:{enabled:!0,syncMode:"phrase",breathRateSync:{mode:"tempo",bpm:"auto",subdivision:"whole",curve:"sine"},radiusSync:{inhale:{onUpbeat:1.8,onDownbeat:1.4,curve:"ease-in"},exhale:{onUpbeat:.2,onDownbeat:.4,curve:"ease-out"}},durationSync:{mode:"phrases",phrases:2,hold:"fermata"},accentResponse:{enabled:!0,multiplier:1.5,type:"expansion"},patternOverrides:{ballad:{breathRateSync:{subdivision:"double-whole"},radiusSync:{inhale:{onUpbeat:2.2,onDownbeat:1.8},exhale:{onUpbeat:.1,onDownbeat:.2}}},uptempo:{breathRateSync:{subdivision:"half"},radiusSync:{inhale:{onUpbeat:1.4,onDownbeat:1.2},exhale:{onUpbeat:.3,onDownbeat:.4}}},ambient:{breathRateSync:{subdivision:"whole",curve:"ease"},radiusSync:{inhale:{onUpbeat:1.6,onDownbeat:1.6},exhale:{onUpbeat:.2,onDownbeat:.2}}}},dynamics:{forte:{radiusSync:{inhale:{multiplier:1.8},exhale:{multiplier:.5}},spiralStrength:.004,scaleAmount:.4},piano:{radiusSync:{inhale:{multiplier:1.2},exhale:{multiplier:.8}},spiralStrength:.001,scaleAmount:.1}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.breathe={startX:e.x,startY:e.y,angle:Math.atan2(s,a),baseRadius:Math.sqrt(a*a+s*s),phaseOffset:.2*Math.random()-.1}},apply(e,t,i,n,a,s){e.gestureData?.breathe||this.initialize(e,i,a,s);const o={...this.config,...i},r=(Math.sin(t*Math.PI*2*o.breathRate)+1)/2,l=100*(e.scaleFactor||1),h=o.inhaleRadius*l,c=o.exhaleRadius*l,u=c+(h-c)*r,d=e.x-a,m=e.y-s,p=Math.sqrt(d*d+m*m),g=u-p,f=.05*(i.strength||.8)*n;if(p>0){const t=d/p*g*f,a=m/p*g*f;e.vx+=t,e.vy+=a;const s=o.spiralStrength*n*(i.strength||1),l=-m/p,h=d/p;e.vx+=l*s*r,e.vy+=h*s*r}e.vx*=.98,e.vy*=.98},cleanup(e){e.gestureData?.breathe&&delete e.gestureData.breathe},"3d":{evaluate(e,t){const i=(t.config||{}).breathRate||.3,n=Math.sin(e*Math.PI*2*i);let a=1;if(e>.8){const t=(e-.8)/(1-.8);a=1-t*t*t}const s=.2*n*a;return{position:[0,.05*n*a,0],rotation:[0,0,0],scale:1+.35*n*a,glowIntensity:1+s,glowBoost:Math.max(0,2*s)}}}},st={name:"expand",emoji:"💫",type:"blending",description:"Radial expansion from center",config:{duration:600,scaleAmount:3,scaleTarget:3,glowAmount:.5,easing:"back",strength:3,particleMotion:{type:"pulse",strength:3,direction:"outward",persist:!0}},rhythm:{enabled:!0,syncMode:"crescendo",strengthSync:{pianissimo:1.5,fortissimo:5,crescendo:"build",sforzando:"burst"},scaleTargetSync:{verse:2,chorus:4.5,climax:6,curve:"exponential"},durationSync:{mode:"phrases",build:1.2,release:.8,sustain:"hold"},accentResponse:{enabled:!0,multiplier:2.8,type:"strength"},patternOverrides:{orchestral:{strengthSync:{pianissimo:2,fortissimo:6.5,crescendo:"dramatic"},scaleTargetSync:{climax:8}},rock:{strengthSync:{pianissimo:1.8,fortissimo:5.5,curve:"power"},accentResponse:{multiplier:3.2}},ambient:{strengthSync:{pianissimo:1.2,fortissimo:3.5,crescendo:"organic"},durationSync:{build:1.8,release:1.2}},electronic:{strengthSync:{pianissimo:1.6,fortissimo:4.8,curve:"digital"},scaleTargetSync:{curve:"linear"}}},dynamics:{forte:{strengthSync:{pianissimo:{multiplier:1.4},fortissimo:{multiplier:1.8}},scaleTargetSync:{multiplier:1.6},accentResponse:{multiplier:3.5}},piano:{strengthSync:{pianissimo:{multiplier:.8},fortissimo:{multiplier:1.2}},scaleTargetSync:{multiplier:.7},accentResponse:{multiplier:2}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.expand={startX:e.x,startY:e.y,angle:Math.atan2(s,a),baseRadius:Math.sqrt(a*a+s*s),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.expand?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.expand,r={...this.config,...i},l=r.strength||1,h=1+(r.scaleTarget-1)*t*l,c=o.baseRadius*h,u=a+Math.cos(o.angle)*c,d=s+Math.sin(o.angle)*c,m=u-e.x,p=d-e.y;e.vx+=.8*m*n,e.vy+=.8*p*n,e.vx*=.95,e.vy*=.95},cleanup(e){e.gestureData?.expand&&delete e.gestureData.expand},"3d":{evaluate(e,t){const i={...this.config,...t},n=i.strength||3;return{position:[0,0,0],rotation:[0,0,0],scale:1+e*(i.scaleAmount||3)*(n/3),glowIntensity:1+.25*e,glowBoost:.8*e}}}},ot={name:"contract",emoji:"🌀",type:"blending",description:"Radial contraction toward center",config:{duration:600,scaleAmount:.2,scaleTarget:.2,glowAmount:-.2,easing:"cubic",strength:2.5,particleMotion:{type:"pulse",strength:2.5,direction:"inward",persist:!0}},rhythm:{enabled:!0,syncMode:"tension",strengthSync:{onTension:4,onRelease:1.5,curve:"magnetic"},scaleTargetSync:{forte:.1,piano:.4,crescendo:"gradual",diminuendo:"ease"},durationSync:{mode:"phrases",shortPhrase:.8,longPhrase:1.5,hold:"sustain"},accentResponse:{enabled:!0,multiplier:2.2,type:"strength"},patternOverrides:{classical:{strengthSync:{onTension:3.5,onRelease:1.8},scaleTargetSync:{forte:.15,piano:.35}},metal:{strengthSync:{onTension:5,onRelease:2,curve:"sharp"},scaleTargetSync:{forte:.05,piano:.25}},ambient:{strengthSync:{onTension:2.8,onRelease:1.2,curve:"ease"},durationSync:{shortPhrase:1.2,longPhrase:2}},trap:{strengthSync:{onTension:4.5,onRelease:1,dropBeat:6},scaleTargetSync:{forte:.08,piano:.3}}},dynamics:{forte:{strengthSync:{onTension:{multiplier:1.8},onRelease:{multiplier:1.4}},scaleTargetSync:{multiplier:.6},accentResponse:{multiplier:2.8}},piano:{strengthSync:{onTension:{multiplier:.7},onRelease:{multiplier:.8}},scaleTargetSync:{multiplier:1.4},accentResponse:{multiplier:1.6}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={});const a=e.x-i,s=e.y-n;e.gestureData.contract={startX:e.x,startY:e.y,angle:Math.atan2(s,a),baseRadius:Math.sqrt(a*a+s*s),initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.contract?.initialized||this.initialize(e,i,a,s);const o=e.gestureData.contract,r={...this.config,...i},l=r.strength||1,h=1-(1-r.scaleTarget)*t*l,c=o.baseRadius*h,u=a+Math.cos(o.angle)*c,d=s+Math.sin(o.angle)*c,m=u-e.x,p=d-e.y;e.vx+=.5*m*n,e.vy+=.5*p*n,e.vx*=.95,e.vy*=.95},cleanup(e){e.gestureData?.contract&&delete e.gestureData.contract},"3d":{evaluate(e,t){const i={...this.config,...t},n=i.strength||2.5,a=i.scaleTarget||.2,s=1-e*(1-a)*(n/2.5),o=1-.15*e;return{position:[0,0,0],rotation:[0,0,0],scale:Math.max(a,s),glowIntensity:o}}}},rt={name:"flash",emoji:"⚡",type:"blending",description:"Bright flash burst effect",config:{duration:400,glowAmount:2.5,glowPeak:3,scalePeak:1.1,easing:"cubic",strength:1,particleMotion:{type:"burst",strength:1,decay:.3}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"immediate",interruptible:!0,priority:8,blendable:!0,intensitySync:{onBeat:3.5,offBeat:1,accent:5,subdivision:"quarter",curve:"exponential"},durationSync:{mode:"tempo",baseDuration:400,scaling:"inverse"},scaleSync:{onBeat:1.2,offBeat:1,accent:1.4,curve:"elastic"},strobeSync:{enabled:!1,pattern:"XXOX",subdivision:"sixteenth"},dynamics:{forte:{glowPeak:4,scalePeak:1.3,duration:300},piano:{glowPeak:2,scalePeak:1.05,duration:500}}},initialize(e,t){e.gestureData||(e.gestureData={}),e.gestureData.flash={originalOpacity:e.opacity,originalSize:e.size,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.flash?.initialized||this.initialize(e,i);const o=e.gestureData.flash,r={...this.config,...i},l=r.strength||1;let h;if(h=t<.3?t/.3*r.glowPeak:r.glowPeak*(1-(t-.3)/.7),e.opacity=Math.min(1,o.originalOpacity*(1+h*l)),e.size=o.originalSize*(1+(r.scalePeak-1)*h*l*.1),t<.2){const i=(1-t/.2)*l,o=Math.atan2(e.y-s,e.x-a);e.vx+=Math.cos(o)*i*2*n,e.vy+=Math.sin(o)*i*2*n}e.vx*=1-.1*r.particleMotion.decay,e.vy*=1-.1*r.particleMotion.decay},cleanup(e){e.gestureData?.flash&&(e.opacity=e.gestureData.flash.originalOpacity,e.size=e.gestureData.flash.originalSize,delete e.gestureData.flash)},"3d":{evaluate(e,t){const i={...this.config,...t};let n;t.strength,n=e<.3?e/.3:1-(e-.3)/.7;const a=1+.4*n;return{position:[0,0,0],rotation:[0,0,0],scale:1+n*((i.scalePeak||1.1)-1),glowIntensity:a,glowBoost:2*n}}}},lt={name:"glow",emoji:"✨",type:"blending",description:"Pure luminous glow without movement",config:{duration:1500,amplitude:0,frequency:1,holdPeak:.3,easing:"sine",scaleAmount:.1,glowAmount:.8,strength:0,direction:"none",particleMotion:{type:"glow",strength:0,direction:"none",frequency:1}},rhythm:{enabled:!0,syncMode:"phrase",amplitudeSync:{onBeat:2,offBeat:1.2,curve:"smooth"},frequencySync:{mode:"phrase",subdivision:"bar"},durationSync:{mode:"bars",bars:2},accentResponse:{enabled:!0,multiplier:2.5},patternOverrides:{ambient:{amplitudeSync:{onBeat:2.5,offBeat:1.8},durationSync:{bars:4}},electronic:{amplitudeSync:{onBeat:3,offBeat:.5,curve:"sharp"},frequencySync:{subdivision:"quarter"}}}},initialize(e,t,i,n){e.gestureData||(e.gestureData={}),e.gestureData.glow={startOpacity:e.opacity,startGlow:e.glowSizeMultiplier||0,initialized:!0}},apply(e,t,i,n,a,s){e.gestureData?.glow?.initialized||this.initialize(e,i,a,s);const o={...this.config,...i},r=this.easeInOutSine(t);let l,{frequency:h}=o,{glowAmount:c}=o;i.rhythmModulation&&(c*=i.rhythmModulation.amplitudeMultiplier||1,c*=i.rhythmModulation.accentMultiplier||1,i.rhythmModulation.frequencyMultiplier&&(h*=i.rhythmModulation.frequencyMultiplier));const u=r*h*2%2;l=o.holdPeak>0&&u>1-o.holdPeak&&u<1+o.holdPeak?1:Math.sin(r*Math.PI*2*h);let d=1;t>.9&&(d=.5+.5*(1-10*(t-.9))),e.glowIntensity=1+l*c*d},cleanup(e){e.gestureData?.glow&&(e.glowIntensity=1,delete e.gestureData.glow)},easeInOutSine:e=>-(Math.cos(Math.PI*e)-1)/2,"3d":{evaluate(e,t){const i={...this.config,...t},n=-(Math.cos(Math.PI*e)-1)/2,a=Math.sin(n*Math.PI);let s=i.glowAmount||.8;t.rhythmModulation&&(s*=t.rhythmModulation.amplitudeMultiplier||1,s*=t.rhythmModulation.accentMultiplier||1);const o=1+a*s;return{position:[0,0,0],rotation:[0,0,0],scale:1+a*(i.scaleAmount||.1)*.5,glowIntensity:o,glowBoost:1.5*a}}}},ht={name:"peek",emoji:"👀",type:"effect",description:"Quick peek and hide motion",config:{peekDistance:40,peekSpeed:.15,holdDuration:200,hideSpeed:.25,stagger:!0,duration:1500},rhythm:{enabled:!0,syncMode:"accent",distanceSync:{onAccent:60,offAccent:25,curve:"quick"},speedSync:{mode:"tempo",fast:.25,slow:.1,hideMultiplier:1.8},durationSync:{mode:"subdivision",beats:.25,staggerBeats:.125,sustain:!1},syncopationResponse:{enabled:!0,multiplier:1.8,type:"distance"},patternOverrides:{funk:{distanceSync:{onAccent:70,offAccent:35,curve:"funky"},syncopationResponse:{multiplier:2.2}},latin:{speedSync:{fast:.3,slow:.12},durationSync:{beats:.5,staggerBeats:.25}},breakbeat:{distanceSync:{onAccent:55,offAccent:40},syncopationResponse:{multiplier:2.5}},classical:{distanceSync:{onAccent:45,offAccent:20,curve:"elegant"},speedSync:{fast:.18,slow:.08}}},dynamics:{forte:{distanceSync:{onAccent:{multiplier:1.6},offAccent:{multiplier:1.3}},speedSync:{multiplier:1.4},syncopationResponse:{multiplier:2.8}},piano:{distanceSync:{onAccent:{multiplier:.6},offAccent:{multiplier:.4}},speedSync:{multiplier:.7},syncopationResponse:{multiplier:1.2}}}},apply(e,t,i,n,a,s){if(e.gestureData||(e.gestureData={}),!e.gestureData.peek){const t=e.x-a,i=e.y-s,n=Math.atan2(i,t),o=Math.sqrt(t*t+i*i);e.gestureData.peek={originalX:e.x,originalY:e.y,peekAngle:n,originalDistance:o,staggerDelay:this.config.stagger?.3*Math.random():0,phase:"waiting",phaseTimer:0,peekOffset:{x:0,y:0}}}const o=e.gestureData.peek,{config:r}=this,l=Math.max(0,Math.min(1,(t-o.staggerDelay)/(1-o.staggerDelay)));0===l?o.phase="waiting":l<.3?o.phase="peeking":l<.6?o.phase="holding":l<1&&(o.phase="hiding");let h=0;switch(o.phase){case"peeking":{const e=l/.3;h=this.easeOutCubic(e)*r.peekDistance;break}case"holding":h=r.peekDistance,Math.random()<.1&&(o.peekOffset.x+=2*(Math.random()-.5),o.peekOffset.y+=2*(Math.random()-.5));break;case"hiding":{const e=(l-.6)/.4;h=(1-this.easeInCubic(e))*r.peekDistance;break}}if("waiting"!==o.phase){const t=Math.cos(o.peekAngle)*h,i=Math.sin(o.peekAngle)*h;o.peekOffset.x+=(t-o.peekOffset.x)*r.peekSpeed,o.peekOffset.y+=(i-o.peekOffset.y)*r.peekSpeed,e.x=o.originalX+o.peekOffset.x,e.y=o.originalY+o.peekOffset.y}void 0!==e.alpha&&("peeking"===o.phase||"holding"===o.phase?e.alpha=.7+.3*Math.random():e.alpha=1)},easeOutCubic:e=>1-Math.pow(1-e,3),easeInCubic:e=>e*e*e,cleanup(e){e.gestureData?.peek&&(e.x=e.gestureData.peek.originalX,e.y=e.gestureData.peek.originalY,void 0!==e.alpha&&(e.alpha=1),delete e.gestureData.peek)},"3d":{evaluate(e,t){const i=.01*({...this.config,...t}.peekDistance||40);let n=0,a=1;if(e<.3){const t=e/.3;n=(1-Math.pow(1-t,3))*i}else if(e<.6)n=i,a=.7+.3*Math.random();else{const t=(e-.6)/.4;n=(1-Math.pow(t,3))*i}return{position:[n,0,0],rotation:[0,0,0],scale:1,glowIntensity:a}}}},ct={name:"runningman",emoji:"🏃",type:"effect",description:"Hip-hop running man shuffle",config:{duration:2e3,slideDistance:30,stepHeight:15,speed:1.2,strength:.8,particleMotion:{type:"runningman",strength:.7}},rhythm:{enabled:!0,syncToBeat:!0,beatMultiplier:1,accentBeats:[1,3]},apply:(e,t,i,n,a,s)=>!1,blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i={...this.config,...t}.strength||.8;return{position:[.1*Math.sin(e*Math.PI*4)*i,.05*Math.abs(Math.sin(e*Math.PI*8))*i,0],rotation:[0,0,.035*Math.sin(e*Math.PI*4)*i],scale:1-.035*Math.abs(Math.sin(e*Math.PI*8))*i,glowIntensity:1+.25*Math.abs(Math.sin(e*Math.PI*8)),glowBoost:.35*Math.max(0,Math.abs(Math.sin(e*Math.PI*8)))}}}},ut={name:"charleston",emoji:"🕺",type:"effect",description:"Hip-hop Charleston shuffle with crisscross",config:{duration:2500,kickDistance:35,swivelRange:40,bounceHeight:12,strength:.9,particleMotion:{type:"charleston",strength:.8}},rhythm:{enabled:!0,syncToBeat:!0,beatMultiplier:2,accentBeats:[1,2.5,3,4.5]},apply:(e,t,i,n,a,s)=>!1,blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i={...this.config,...t}.strength||.9;return{position:[.12*Math.sin(e*Math.PI*8)*i,.05*Math.abs(Math.sin(e*Math.PI*8))*i,0],rotation:[0,0,.05*Math.sin(e*Math.PI*8)*i],scale:1-.04*Math.abs(Math.sin(e*Math.PI*8))*i,glowIntensity:1+.3*Math.abs(Math.sin(e*Math.PI*8)),glowBoost:.4*Math.max(0,Math.abs(Math.sin(e*Math.PI*8)))}}}};const dt=[Be,ke,Te,Ee,Ie,Ae,Re,ze,_e,Oe,{name:"sparkle",emoji:"✨",type:"blending",description:"Bright twinkling sparkle bursts",config:{duration:800,musicalDuration:{musical:!0,beats:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",durationSync:{mode:"beats",beats:2},interruptible:!0,priority:5,blendable:!0},apply:(e,t,i)=>!1,blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i=t?.strength||1,n=Math.pow(Math.max(0,Math.sin(e*Math.PI*6)),3),a=Math.pow(Math.max(0,Math.sin(e*Math.PI*8+1)),3),s=Math.pow(Math.max(0,Math.sin(e*Math.PI*10+2)),3),o=Math.max(n,a,s)*Math.sin(e*Math.PI);return{position:[0,0,0],rotation:[0,0,0],scale:1+.08*o*i,glowIntensity:1+.5*o*i,glowBoost:2*o*i}}}},{name:"shimmer",emoji:"🌟",type:"particle",description:"Shimmer effect with sparkling particles",config:{duration:2e3,musicalDuration:{musical:!0,bars:1},particleMotion:"radiant"},rhythm:{enabled:!0,syncType:"beat",durationSync:{mode:"bars",bars:1},intensity:.8},override:(e,t,i)=>(e.shimmerEffect=!0,e.shimmerProgress=t,!0),blend:(e,t,i)=>!1,"3d":{evaluate(e,t){const i=t?.strength||1,n=(.4*Math.sin(e*Math.PI*4)+.35*Math.sin(e*Math.PI*6+.5)+.25*Math.sin(e*Math.PI*10+1)+1)/2;return{position:[0,0,0],rotation:[0,0,0],scale:1+.05*n*i,glowIntensity:1+.3*n*i,glowBoost:1*n*i}}}},Fe,((e,t="✨")=>({name:e,emoji:t,type:"blending",description:`${e} animation`,config:{duration:1e3,musicalDuration:{musical:!0,beats:2}},rhythm:{enabled:!0,syncMode:"beat",timingSync:"nextBeat",durationSync:{mode:"beats",beats:2},interruptible:!0,priority:3,blendable:!0,crossfadePoint:"anyBeat",maxQueue:3},apply:(e,t,i)=>!1,blend:(e,t,i)=>!1}))("groove","🎵"),Ve,Ge,qe,Le,{name:"rain",emoji:"🌧️",type:"particle",description:"Rain effect with falling particles",config:{duration:3e3,musicalDuration:{musical:!0,bars:2},particleMotion:"falling"},rhythm:{enabled:!0,syncType:"off-beat",durationSync:{mode:"bars",bars:2},intensity:.8},apply:(e,t,i)=>(e.rainEffect=!0,e.rainProgress=t,!0),blend:(e,t,i)=>!1}],mt=[Ne,je,Ue,He,We,Xe,Ye,$e],pt=[Qe,Ze,Je,Ke,et,tt,it,nt,at,st,ot,rt,lt,ht,ct,ut],gt={};function ft(e){if(gt[e])return gt[e];return Pe(e)||null}[...dt,...mt,...pt].forEach(e=>{gt[e.name]=e}),dt.map(e=>e.name),mt.map(e=>e.name),pt.map(e=>e.name);const yt={none:{speed:1,amplitude:1,intensity:1,smoothness:1,regularity:1,"3d":{rotation:{speedMultiplier:1,shakeMultiplier:1},glow:{intensityMultiplier:1,pulseSpeedMultiplier:1},scale:{breathDepthMultiplier:1,breathRateMultiplier:1},righting:{strengthMultiplier:1}}},clear:{speed:1,amplitude:1,intensity:1,smoothness:1,regularity:1,"3d":{rotation:{speedMultiplier:1,shakeMultiplier:1},glow:{intensityMultiplier:1,pulseSpeedMultiplier:1},scale:{breathDepthMultiplier:1,breathRateMultiplier:1},righting:{strengthMultiplier:1}}},nervous:{speed:1.2,amplitude:.9,intensity:1.1,smoothness:.7,regularity:.6,addFlutter:!0,addMicroShake:!0,"3d":{rotation:{speedMultiplier:1.5,shakeMultiplier:3.5,enableEpisodicWobble:!0},glow:{intensityMultiplier:1.25,pulseSpeedMultiplier:2},scale:{breathDepthMultiplier:.5,breathRateMultiplier:1.8},righting:{strengthMultiplier:.7}}},confident:{speed:.9,amplitude:1.3,intensity:1.2,smoothness:1.1,regularity:1.2,addPower:!0,addHold:!0,"3d":{rotation:{speedMultiplier:.7,shakeMultiplier:.2},glow:{intensityMultiplier:1.4,pulseSpeedMultiplier:.7},scale:{breathDepthMultiplier:1.5,breathRateMultiplier:.7},righting:{strengthMultiplier:1.6}}},tired:{speed:.7,amplitude:.7,intensity:.8,smoothness:1.3,regularity:.8,addDroop:!0,addPause:!0,"3d":{rotation:{speedMultiplier:.4,shakeMultiplier:.15},glow:{intensityMultiplier:.5,pulseSpeedMultiplier:.5},scale:{breathDepthMultiplier:1.3,breathRateMultiplier:.5},righting:{strengthMultiplier:.6}}},intense:{speed:1.3,amplitude:1.2,intensity:1.4,smoothness:.6,regularity:.9,addPulse:!0,addFocus:!0,"3d":{rotation:{speedMultiplier:1.6,shakeMultiplier:2.5},glow:{intensityMultiplier:1.8,pulseSpeedMultiplier:2.2},scale:{breathDepthMultiplier:1.6,breathRateMultiplier:1.8},righting:{strengthMultiplier:1.3}}},subdued:{speed:.8,amplitude:.8,intensity:.7,smoothness:1.2,regularity:1.1,addSoftness:!0,addFade:!0,"3d":{rotation:{speedMultiplier:.5,shakeMultiplier:.1},glow:{intensityMultiplier:.55,pulseSpeedMultiplier:.6},scale:{breathDepthMultiplier:.7,breathRateMultiplier:.6},righting:{strengthMultiplier:1.4}}}};function vt(e){return e&&""!==e&&"clear"!==e&&yt[e]||yt.clear}function bt(e){return 3===(e=e.replace("#","")).length&&(e=e.split("").map(e=>e+e).join("")),{r:parseInt(e.substr(0,2),16),g:parseInt(e.substr(2,2),16),b:parseInt(e.substr(4,2),16)}}const wt={intense:1.6,confident:1.3,nervous:1.15,clear:1,tired:.8,subdued:.5};function Mt(e,t){if(!t||"clear"===t)return e;const i=wt[t.toLowerCase()];return i&&1!==i?function(e,t){const i=bt(e),n=function(e,t,i){e/=255,t/=255,i/=255;const n=Math.max(e,t,i),a=Math.min(e,t,i),s=(n+a)/2;let o,r;if(n===a)o=r=0;else{const l=n-a;switch(r=s>.5?l/(2-n-a):l/(n+a),n){case e:o=(t-i)/l+(t<i?6:0);break;case t:o=(i-e)/l+2;break;case i:o=(e-t)/l+4}o/=6}return{h:360*o,s:100*r,l:100*s}}(i.r,i.g,i.b);n.s=Math.max(0,Math.min(100,n.s*t));const a=function(e,t,i){e/=360,i/=100;const n=(e,t,i)=>(i<0&&(i+=1),i>1&&(i-=1),i<1/6?e+6*(t-e)*i:i<.5?t:i<2/3?e+(t-e)*(2/3-i)*6:e);let a,s,o;if(0==(t/=100))a=s=o=i;else{const r=i<.5?i*(1+t):i+t-i*t,l=2*i-r;a=n(l,r,e+1/3),s=n(l,r,e),o=n(l,r,e-1/3)}return{r:Math.round(255*a),g:Math.round(255*s),b:Math.round(255*o)}}(n.h,n.s,n.l);return function(e,t,i){const n=e=>{const t=Math.round(Math.max(0,Math.min(255,e))).toString(16);return 1===t.length?`0${t}`:t};return`#${n(e)}${n(t)}${n(i)}`}(a.r,a.g,a.b)}(e,i):e}Object.fromEntries(Object.entries({neutral:"#B0B0B0",joy:"#FFD700",sadness:"#4169E1",anger:"#DC143C",fear:"#8B008B",surprise:"#FF8C00",disgust:"#9ACD32",love:"#FF69B4"}).map(([e,t])=>{const i=bt(t);return[e,`${i.r}, ${i.g}, ${i.b}`]}));const St=new class{constructor(){this.enabled=!1,this.adapter=null,this.subsystemConfigs=new Map,this.activeModulations=new Map}initialize(){this.adapter=ve.getAdapter(),this.enabled=!0,this.adapter.onBeat(this.handleBeat.bind(this)),this.adapter.onBar(this.handleBar.bind(this))}updateBPM(e){if(e>=60&&e<=220){if(window.rhythmManuallyStoppedForCurrentAudio)return;if(!ve.isRunning)return this.start(e,"straight"),void(window.rhythmSyncVisualizer&&!window.rhythmSyncVisualizer.state.active&&window.rhythmSyncVisualizer.start());ve.setBPM(e)}}registerConfig(e,t,i){if(!i.rhythm||!i.rhythm.enabled)return;const n=`${e}:${t}`;this.subsystemConfigs.set(n,{type:e,name:t,rhythmConfig:i.rhythm,originalConfig:i})}applyGestureRhythm(e,t,i,n){if(!this.enabled||!e.rhythm?.enabled)return{};const a=e.rhythm,s={};if(a.amplitudeSync){const e=a.amplitudeSync,t=this.adapter.getBeatSync(e.offBeat||.8,e.onBeat||1.5,e.curve||"linear");s.amplitudeMultiplier=t}if(a.wobbleSync){const e=a.wobbleSync;this.adapter.isOnSubdivision(e.subdivision,.1)?s.wobbleMultiplier=1+e.intensity:s.wobbleMultiplier=1}if(a.accentResponse?.enabled){const e=this.adapter.getAccentedValue(1,a.accentResponse.multiplier||1.5);s.accentMultiplier=e}const o=this.adapter.getPattern();return o&&a.patternOverrides?.[o]&&Object.assign(s,a.patternOverrides[o]),s}applyParticleRhythm(e,t){if(!this.enabled||!e.rhythm?.enabled)return{};const i=this.adapter.getTimeInfo(),n=e.rhythm,a={};if(n.particleEmission){const e=n.particleEmission;"beat"===e.syncMode&&this.adapter.isOnBeat(.1)?a.emitBurst=e.burstSize||3:void 0!==e.offBeatRate&&(a.emissionRate=e.offBeatRate)}if(n.glowSync){const e=n.glowSync,t=this.adapter.getBeatSync(e.intensityRange[0]||1,e.intensityRange[1]||2,"pulse");a.glowIntensity=t}if("bars"===n.breathSync?.mode){const e=n.breathSync,t=i.bar%e.barsPerBreath/e.barsPerBreath;a.breathPhase=t*Math.PI*2}return a}applyBehaviorRhythm(e,t,i){if(!this.enabled||!e.rhythm?.enabled)return{};const n=this.adapter.getTimeInfo(),a=e.rhythm,s={};if(a.glitchTiming){const e=a.glitchTiming;if(this.adapter.isOnSubdivision(e.subdivision,.05)&&Math.random()<e.probability){const t=this.adapter.isOnBeat()?e.intensityOnBeat:e.intensityOffBeat;s.triggerGlitch=!0,s.glitchIntensity=t}}if(a.orbitRhythm){const e=a.orbitRhythm;"tempo"===e.baseSpeed&&(s.speedMultiplier=this.adapter.getBPM()/120),e.beatAcceleration&&this.adapter.isOnBeat(.1)&&(s.speedBoost=e.beatAcceleration),e.barReset&&0===n.beatInBar&&(s.resetOrbit=!0)}if(a.stutterSync){const e=a.stutterSync,t=this.adapter.getPattern();if(t&&e.patterns?.[t]){const i=e.patterns[t];i.freezeOnDrop&&2===n.beatInBar?(s.freeze=!0,s.freezeDuration=i.dropDuration):i.randomFreeze&&Math.random()<i.randomFreeze&&(s.freeze=!0,s.freezeDuration=i.duration)}}return s}handleBeat(e){this.lastBeatInfo=e}handleBar(e){this.lastBarInfo=e}getMusicalDuration(e,t){if(!this.enabled||!e?.durationSync)return t;const i=e.durationSync;return"bars"===i.mode?this.adapter.beatsToMs(4*i.bars):"beats"===i.mode?this.adapter.beatsToMs(i.beats):t}isEnabled(){return this.enabled&&this.adapter.isPlaying()}start(e=120,t="straight"){e&&ve.setBPM(e),t&&ve.setPattern(t),ve.start(),this.enabled=!0}stop(){ve.stop(),this.enabled=!1,this.bpmLocked=!1,this.lockedBPM=null}setPattern(e){ve.setPattern(e)}setBPM(e){ve.setBPM(e),this.bpmLocked&&(this.lockedBPM=e)}resampleBPM(){this.bpmLocked=!1,this.lockedBPM=null}setTimeSignature(e){this.timeSignature=e;const t=document.getElementById("time-sig-display");t&&(t.textContent=e),"3/4"===e&&ve.getPattern()}syncToAudio(e,t){ve.syncToAudio(e,t)}},xt=new class{constructor(){this.emotionCache=new Map,this.visualParamsCache=new Map,this.modifiersCache=new Map,this.transitionCache=new Map,this.stats={hits:0,misses:0,loadTime:0,cacheSize:0},this.isInitialized=!1,this.loadStartTime=0,this.initialize()}initialize(){this.loadStartTime=performance.now();try{const e=[...Array.from(ue.keys()),...le()];e.forEach(e=>{this.cacheEmotion(e)}),this.cacheCommonTransitions(e),this.isInitialized=!0,this.stats.loadTime=performance.now()-this.loadStartTime,this.stats.cacheSize=this.emotionCache.size}catch(e){console.error("[EmotionCache] Initialization failed:",e),this.isInitialized=!1}}cacheEmotion(e){try{const t=me(e);t&&this.emotionCache.set(e,t);const i=pe(e);this.visualParamsCache.set(e,i);const n=ge(e);this.modifiersCache.set(e,n)}catch(t){console.warn(`[EmotionCache] Failed to cache emotion '${e}':`,t)}}cacheCommonTransitions(e){[["neutral","joy"],["neutral","sadness"],["neutral","anger"],["joy","sadness"],["sadness","joy"],["anger","calm"],["calm","anger"]].forEach(([t,i])=>{if(e.includes(t)&&e.includes(i))try{const e=fe(t,i),n=`${t}->${i}`;this.transitionCache.set(n,e)}catch(e){console.warn(`[EmotionCache] Failed to cache transition '${t}->${i}':`,e)}})}getEmotion(e){if(!this.isInitialized)return console.warn("[EmotionCache] Cache not initialized, falling back to direct access"),me(e);const t=this.emotionCache.get(e);return t?(this.stats.hits++,t):(this.stats.misses++,console.warn(`[EmotionCache] Cache miss for emotion '${e}', consider adding to pre-cache`),me(e))}getVisualParams(e){if(!this.isInitialized)return pe(e);const t=this.visualParamsCache.get(e);return t?(this.stats.hits++,t):(this.stats.misses++,pe(e))}getModifiers(e){if(!this.isInitialized)return ge(e);const t=this.modifiersCache.get(e);return t?(this.stats.hits++,t):(this.stats.misses++,ge(e))}getTransitionParams(e,t){if(!this.isInitialized)return fe(e,t);const i=`${e}->${t}`,n=this.transitionCache.get(i);return n?(this.stats.hits++,n):(this.stats.misses++,fe(e,t))}hasEmotion(e){return this.emotionCache.has(e)}getStats(){const e=this.stats.hits+this.stats.misses,t=e>0?(this.stats.hits/e*100).toFixed(2):0;return{isInitialized:this.isInitialized,loadTime:this.stats.loadTime,cacheSize:this.stats.cacheSize,hits:this.stats.hits,misses:this.stats.misses,hitRate:`${t}%`,emotions:this.emotionCache.size,visualParams:this.visualParamsCache.size,modifiers:this.modifiersCache.size,transitions:this.transitionCache.size}}clear(){this.emotionCache.clear(),this.visualParamsCache.clear(),this.modifiersCache.clear(),this.transitionCache.clear(),this.isInitialized=!1,this.stats={hits:0,misses:0,loadTime:0,cacheSize:0}}reinitialize(){this.clear(),this.initialize()}};function Ct(e){if(!e||0===e.length)return"#FFFFFF";let t=0,i=0;const n=[];for(const a of e)"string"==typeof a?(n.push({color:a,weight:null}),i++):a&&"object"==typeof a&&a.color&&(n.push({color:a.color,weight:a.weight||null}),a.weight?t+=a.weight:i++);const a=Math.max(0,100-t),s=i>0?a/i:0,o=[];let r=0;for(const e of n)r+=null!==e.weight?e.weight:s,o.push({color:e.color,threshold:r});const l=Math.random()*r;for(const e of o)if(l<=e.threshold)return e.color;return n[n.length-1].color}var Dt={name:"ambient",emoji:"☁️",description:"Gentle upward drift like smoke",initialize:function(e){e.vx=0,e.vy=-.04-.02*Math.random(),e.lifeDecay=.002,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={upwardSpeed:5e-4,waviness:0,friction:.998}},update:function(e,t,i,n){const a=e.behaviorData;e.vy*=Math.pow(a.friction,t),e.vy-=a.upwardSpeed*t,e.vx=0}};const Pt=2*Math.PI;var Bt={name:"orbiting",emoji:"💕",description:"Romantic firefly dance around the orb",initialize:function(e){e.lifeDecay=.001+.002*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.isSparkle="#FFE4E1"===e.color||"#FFCCCB"===e.color||"#FFC0CB"===e.color;const t=40*(e.scaleFactor||1)*(1.3+.9*Math.random());e.blinkPhase=Math.random()*Pt,e.blinkSpeed=.3+1.2*Math.random(),e.blinkIntensity=.6+.4*Math.random(),e.fadePhase=Math.random()*Pt,e.fadeSpeed=.1+.3*Math.random(),e.minOpacity=.2+.2*Math.random(),e.maxOpacity=.8+.2*Math.random(),e.isSparkle&&(e.blinkSpeed*=2,e.blinkIntensity=1,e.minOpacity=0,e.maxOpacity=1),e.behaviorData={angle:Math.random()*Pt,radius:t,baseRadius:t,angularVelocity:8e-4+.0017*Math.random(),swayAmount:3+7*Math.random(),swaySpeed:.2+.5*Math.random(),floatOffset:Math.random()*Pt,floatSpeed:.3+.7*Math.random(),floatAmount:2+6*Math.random(),twinklePhase:Math.random()*Pt,twinkleSpeed:2+3*Math.random()}},update:function(e,t,i,n){const a=e.behaviorData;a.angle+=a.angularVelocity*t;const s=Math.sin(a.angle*a.swaySpeed)*a.swayAmount,o=6*Math.sin(1.5*a.angle),r=(a.radius||a.baseRadius)+o+.2*s,l=i+Math.cos(a.angle)*r,h=n+Math.sin(a.angle)*r;a.floatOffset+=a.floatSpeed*t*.001;const c=Math.sin(a.floatOffset)*a.floatAmount;e.vx=.1*(l-e.x),e.vy=.1*(h+c-e.y),e.fadePhase+=e.fadeSpeed*t*.001;const u=.5*Math.sin(e.fadePhase)+.5,d=e.minOpacity+(e.maxOpacity-e.minOpacity)*u;let m;e.blinkPhase+=e.blinkSpeed*t*.002,e.isSparkle?(a.twinklePhase+=a.twinkleSpeed*t*.001,m=.7*Math.pow(Math.sin(a.twinklePhase),16)+.2*Math.sin(5*e.blinkPhase)+.1):m=.4*Math.sin(e.blinkPhase)+.3*Math.sin(3*e.blinkPhase)+.2*Math.sin(7*e.blinkPhase)+.1*Math.sin(11*e.blinkPhase);const p=.5*(m+1),g=.2+p*e.blinkIntensity*.8;e.opacity=e.baseOpacity*d*g,e.isSparkle?e.size=e.baseSize*(.5+1*p):e.size=e.baseSize*(.8+.3*p),e.isSparkle&&(e.tempColor=p>.85?"#FFFFFF":e.color)}},kt={name:"rising",emoji:"🎈",description:"Buoyant upward movement like balloons",initialize:function(e){e.vx=.02*(Math.random()-.5),e.vy=-.05-.03*Math.random(),e.lifeDecay=.002,e.baseOpacity=.7+.3*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={buoyancy:.001,driftAmount:.005}},update:function(e,t,i,n){const a=e.behaviorData;e.vy-=a.buoyancy*t,e.vx+=(Math.random()-.5)*a.driftAmount*t,e.vx*=Math.pow(.995,t),e.vy*=Math.pow(.998,t)}},Tt={name:"falling",emoji:"💧",description:"Heavy downward drift like tears",initialize:function(e){e.vx=0,e.vy=.04+.02*Math.random(),e.lifeDecay=.002,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors));const t=Math.random(),i=Math.random(),n=t*Math.PI*2,a=2*i-1,s=Math.sqrt(1-a*a);e.behaviorData={downwardSpeed:5e-4,friction:.998,fallingDir:{x:s*Math.cos(n),y:a,z:s*Math.sin(n)},orbitDistanceRatio:.7+.4*Math.random()}},update:function(e,t,i,n){const a=e.behaviorData;e.vy*=Math.pow(a.friction,t),e.vy+=a.downwardSpeed*t,e.vx=0}};const Et=2e3,It=3,At=8,Rt=.7;var zt={name:"popcorn",emoji:"🍿",description:"Spontaneous popping with gravity and bounces",initialize:function(e){if(e.vx=.1*(Math.random()-.5),e.vy=.1*(Math.random()-.5),e.lifeDecay=.008+.012*Math.random(),e.emotionColors&&e.emotionColors.length>0)e.color=Ct(e.emotionColors);else{const t=["#FFFFFF","#FFFACD","#FFF8DC","#FFFFE0","#FAFAD2"];e.color=Ct(t)}e.size=Math.random()<.3?(8+4*Math.random())*e.scaleFactor*e.particleSizeMultiplier:(2+4*Math.random())*e.scaleFactor*e.particleSizeMultiplier,e.baseSize=e.size,e.hasGlow=Math.random()<.2,e.glowSizeMultiplier=e.hasGlow?1.2:0,e.behaviorData={popDelay:Math.random()*Et,hasPopped:!1,popStrength:It+Math.random()*(At-It),gravity:.098,bounceDamping:Rt,bounceCount:0,maxBounces:2+Math.floor(2*Math.random()),spinRate:10*(Math.random()-.5),lifetime:0}},update:function(e,t,i,n){const a=e.behaviorData;if(a.lifetime+=16.67*t,!a.hasPopped&&a.lifetime>a.popDelay){a.hasPopped=!0;const t=Math.random()*Math.PI*2;e.vx=Math.cos(t)*a.popStrength*1.5,e.vy=Math.sin(t)*a.popStrength-.3,e.size=1.25*e.baseSize}if(a.hasPopped){e.vy+=a.gravity*t;const i=n+100*e.scaleFactor;e.y>i&&a.bounceCount<a.maxBounces&&(e.y=i,e.vy=-Math.abs(e.vy)*a.bounceDamping,e.vx*=.9,a.bounceCount++,e.size=e.baseSize*(1.5-.1*a.bounceCount)),a.bounceCount>=a.maxBounces&&(e.lifeDecay=.03+.02*Math.random(),e.size*=.95),Math.sqrt(e.vx*e.vx+e.vy*e.vy)<.5&&(e.lifeDecay*=1.5)}}},_t={name:"burst",emoji:"💥",description:"Explosive expansion from center",initialize:function(e){const t="suspicion"===e.emotion,i="surprise"===e.emotion,n="glitch"===e.emotion,a=Math.random()*Pt,s=t?1+.8*Math.random():i?7+5*Math.random():n?2+1.5*Math.random():3.5+2.5*Math.random();e.vx=Math.cos(a)*s,e.vy=Math.sin(a)*s,e.lifeDecay=t?.01:i?.006+.008*Math.random():n?.012:.015,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),t&&(e.size=(6+4*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1),e.baseSize=e.size,e.opacity=1,e.baseOpacity=e.opacity),e.behaviorData={isSuspicion:t,isSurprise:i,isGlitch:n,age:0,fadeStart:t?.3:.2,glitchPhase:Math.random()*Math.PI*2,glitchIntensity:n?.3:0,glitchFrequency:n?.1:0}},update:function(e,t,i,n){const a=e.behaviorData;if(a.isSurprise)if(a.age+=.016*t,a.age<.15){const i=.98;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t)}else if(a.age<.25){const i=.85;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t)}else{const i=.99;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t),e.vx+=.01*(Math.random()-.5)*t,e.vy+=.01*(Math.random()-.5)*t}else{const i=a.isSuspicion?.99:a.isGlitch?.97:.95;e.vx*=Math.pow(i,t),e.vy*=Math.pow(i,t)}if(a.isSuspicion){const i=.001*Date.now();e.vx+=.01*Math.sin(2*i+e.id)*t}if(a.isGlitch){a.age+=.016*t,a.glitchPhase+=a.glitchFrequency*t;const i=Math.sin(a.glitchPhase)*a.glitchIntensity*t,n=Math.cos(1.3*a.glitchPhase)*a.glitchIntensity*t;if(e.vx+=i,e.vy+=n,Math.random()<.02){const t=Math.random()*Math.PI*2,i=.5+.5*Math.random();e.vx+=Math.cos(t)*i,e.vy+=Math.sin(t)*i}}}},Ot={name:"aggressive",emoji:"⚡",description:"Sharp, chaotic movement with violent bursts",initialize:function(e){const t=Math.random()*Pt,i=1.5+2*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.015,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={acceleration:.05,jitter:.3,speedDecay:.95}},update:function(e,t,i,n){const a=e.behaviorData;if(e.vx+=(Math.random()-.5)*a.jitter*t,e.vy+=(Math.random()-.5)*a.jitter*t,e.vx*=Math.pow(a.speedDecay,t),e.vy*=Math.pow(a.speedDecay,t),Math.random()<Math.min(.05*t,.5)){const t=Math.random()*Pt;e.vx+=Math.cos(t)*a.acceleration,e.vy+=Math.sin(t)*a.acceleration}}},Ft={name:"scattering",emoji:"😨",description:"Particles flee from center in panic",initialize:function(e){e.vx=0,e.vy=0,e.lifeDecay=.008,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={fleeSpeed:2,panicFactor:1.2,initialized:!1}},update:function(e,t,i,n){const a=e.behaviorData;if(!a.initialized){const t=e.x-i,s=e.y-n,o=Math.sqrt(t*t+s*s);if(o>0)e.vx=t/o*a.fleeSpeed,e.vy=s/o*a.fleeSpeed;else{const t=Math.random()*Pt;e.vx=Math.cos(t)*a.fleeSpeed,e.vy=Math.sin(t)*a.fleeSpeed}a.initialized=!0}const s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);r>0&&(e.vx+=s/r*a.panicFactor*.01*t,e.vy+=o/r*a.panicFactor*.01*t),e.vx+=.1*(Math.random()-.5)*t,e.vy+=.1*(Math.random()-.5)*t,e.vx*=Math.pow(.98,t),e.vy*=Math.pow(.98,t)}},Lt={name:"repelling",emoji:"🚫",description:"Particles pushed away from center, maintaining distance",initialize:function(e){e.vx=0,e.vy=0,e.lifeDecay=.01,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={repelStrength:.8,minDistance:50,initialized:!1}},update:function(e,t,i,n){const a=e.behaviorData,s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);if(!a.initialized||r<a.minDistance){if(r>0){const i=a.repelStrength/Math.max(r,5);e.vx+=s/r*i*t,e.vy+=o/r*i*t}a.initialized=!0}e.vx*=Math.pow(.99,t),e.vy*=Math.pow(.99,t)}},Gt={name:"connecting",emoji:"🔗",description:"Chaotic movement with center attraction for social states",initialize:function(e){const t=Math.random()*Pt,i=2+5*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.012,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={attractionForce:.008,chaosFactor:1,friction:.95}},update:function(e,t,i,n){const a=e.behaviorData;e.vx*=Math.pow(a.friction,t),e.vy*=Math.pow(a.friction,t);const s=(i-e.x)*a.attractionForce,o=(n-e.y)*a.attractionForce,r=(Math.random()-.5)*a.chaosFactor,l=(Math.random()-.5)*a.chaosFactor;e.vx+=s+r,e.vy+=o+l}},Vt={name:"resting",emoji:"😴",description:"Ultra-slow vertical drift for deep rest states",initialize:function(e){e.vx=0,e.vy=-.01,e.lifeDecay=.001,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={upwardSpeed:2e-5,friction:.999}},update:function(e,t,i,n){const a=e.behaviorData;e.vy*=Math.pow(a.friction,t),e.vy-=a.upwardSpeed*t,e.vx=0}},qt={name:"radiant",emoji:"☀️",description:"Particles radiate outward like sunbeams",initialize:function(e){const t=Math.random()*Pt,i=.8+.4*Math.random();if(e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.006,e.emotionColors&&e.emotionColors.length>0)e.color=Ct(e.emotionColors);else{const t=["#FFD700","#FFB347","#FFA500","#FF69B4"];e.color=Ct(t)}e.hasGlow=Math.random()<.7,e.glowSizeMultiplier=e.hasGlow?1.5+.5*Math.random():0,e.behaviorData={radialSpeed:.02,shimmer:Math.random()*Pt,shimmerSpeed:.1,friction:.99}},update:function(e,t,i,n){const a=e.behaviorData,s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);if(r>0){const i=s/r,n=o/r;e.vx+=i*a.radialSpeed*t,e.vy+=n*a.radialSpeed*t}a.shimmer+=a.shimmerSpeed*t;const l=Math.sin(a.shimmer);e.size=e.baseSize*(1+.2*l),e.opacity=e.baseOpacity*(1+.3*l),e.vx*=Math.pow(a.friction,t),e.vy*=Math.pow(a.friction,t)}};function Nt(e){e.vx=.02*(Math.random()-.5),e.vy=-.03-.02*Math.random(),e.lifeDecay=8e-4,e.size=(6+6*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1)*1.33,e.baseSize=e.size,e.baseOpacity=.2+.2*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={ascensionSpeed:3e-4,waveFactor:.5,waveFrequency:.001,friction:.998,fadeStartDistance:100}}var jt={name:"ascending",emoji:"🧘",description:"Slow steady upward float like incense smoke",initialize:Nt,update:function(e,t,i,n){const a=e.behaviorData;if(!a)return void Nt(e);e.vx*=Math.pow(a.friction,t),e.vy*=Math.pow(a.friction,t),e.vy-=a.ascensionSpeed*t;const s=Math.sin(e.age*a.waveFrequency*1e3)*a.waveFactor;e.vx+=.001*s*t,void 0===e.initialY&&(e.initialY=e.y);const o=e.initialY-e.y;if(o>a.fadeStartDistance){const t=(o-a.fadeStartDistance)/100,i=Math.max(0,1-t);e.baseOpacity*=.995,i<.5&&(e.lifeDecay*=1.02)}Math.abs(e.vx)>.05&&(e.vx*=Math.pow(.95,t)),e.vy<-.1&&(e.vy=-.1)}},Ut={name:"erratic",emoji:"😰",description:"Nervous jittery movement for anxious states",initialize:function(e){const t=Math.random()*Pt,i=.1+.15*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.004,e.size=(2+4*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1),e.baseSize=e.size,e.baseOpacity=.4+.3*Math.random(),e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={jitterStrength:.02,directionChangeRate:.1,speedVariation:.3,spinRate:.05+.1*Math.random()}},update:function(e,t){const i=e.behaviorData;if(e.vx+=(Math.random()-.5)*i.jitterStrength*t,e.vy+=(Math.random()-.5)*i.jitterStrength*t,Math.random()<Math.min(i.directionChangeRate*t,.5)){const t=Math.random()*Pt,i=Math.sqrt(e.vx*e.vx+e.vy*e.vy);e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i}const n=1+(Math.random()-.5)*i.speedVariation*t;e.vx*=n,e.vy*=n;const a=e.age*i.spinRate*1e3;e.size=e.baseSize*(1+.2*Math.sin(a)),e.opacity=e.baseOpacity*(.8+.4*Math.random()),e.vx*=Math.pow(.98,t),e.vy*=Math.pow(.98,t);const s=Math.sqrt(e.vx*e.vx+e.vy*e.vy);s>.5&&(e.vx=e.vx/s*.5,e.vy=e.vy/s*.5)}},Ht={name:"cautious",emoji:"🤨",description:"Slow careful movement with watchful pauses",initialize:function(e){const t=Math.random()*Pt,i=.02+.03*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,e.lifeDecay=.001,e.life=1,e.size=(4+4*Math.random())*(e.scaleFactor||1)*(e.particleSizeMultiplier||1),e.baseSize=e.size,e.baseOpacity=.8+.2*Math.random(),e.opacity=e.baseOpacity,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={pauseTimer:2*Math.random(),pauseDuration:.5+.5*Math.random(),moveDuration:1+.5*Math.random(),isMoving:Math.random()>.5,moveTimer:0,originalVx:e.vx,originalVy:e.vy,watchRadius:50+30*Math.random()}},update:function(e,t,i,n){const a=e.behaviorData;if(a.moveTimer+=t,a.isMoving)a.moveTimer>a.moveDuration?(a.isMoving=!1,a.moveTimer=0,e.vx=0,e.vy=0):(e.vx=a.originalVx,e.vy=a.originalVy);else if(a.moveTimer>a.pauseDuration){a.isMoving=!0,a.moveTimer=0;const t=Math.random()*Pt,i=.02+.03*Math.random();e.vx=Math.cos(t)*i,e.vy=Math.sin(t)*i,a.originalVx=e.vx,a.originalVy=e.vy}const s=e.x-i,o=e.y-n,r=Math.sqrt(s*s+o*o);if(r>a.watchRadius){const i=.02;e.vx-=s/r*i*t,e.vy-=o/r*i*t}e.vx*=Math.pow(.995,t),e.vy*=Math.pow(.995,t),a.isMoving?e.opacity=e.baseOpacity:e.opacity=e.baseOpacity*(.9+.1*Math.sin(5*e.age))}},Wt={name:"surveillance",emoji:"👁️",description:"Searchlight scanning with paranoid watchfulness",initialize(e,t){e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorState={scanAngle:Math.random()*Math.PI-Math.PI/2,scanDirection:Math.random()<.5?1:-1,scanSpeed:.3+.2*Math.random(),scanRange:Math.PI/3+Math.random()*Math.PI/4,scanCenter:Math.random()*Math.PI*2,pauseTimer:0,pauseDuration:500+500*Math.random(),mode:"scanning",modeTimer:0,nextModeChange:2e3+3e3*Math.random(),dartTarget:{x:0,y:0},dartSpeed:0,patrolRadius:150+100*Math.random(),patrolAngle:Math.random()*Math.PI*2,alertLevel:0,lastPosition:{x:e.x,y:e.y}};const i=Math.random();i<.7?e.behaviorState.primaryRole="scanner":i<.9?(e.behaviorState.primaryRole="patroller",e.behaviorState.mode="patrolling"):(e.behaviorState.primaryRole="watcher",e.behaviorState.mode="frozen")},update(e,t,i){const n=e.behaviorState;if(n){switch(n.modeTimer+=16*t,n.modeTimer>n.nextModeChange&&(this.changeMode(e,n,i),n.modeTimer=0,n.nextModeChange=2e3+4e3*Math.random()),n.mode){case"scanning":this.updateScanning(e,t,n,i);break;case"darting":this.updateDarting(e,t,n,i);break;case"frozen":this.updateFrozen(e,t,n,i);break;case"patrolling":this.updatePatrolling(e,t,n,i)}e.vy+=.05*t,e.x+=e.vx*t,e.y+=e.vy*t,n.lastPosition.x=e.x,n.lastPosition.y=e.y}},updateScanning(e,t,i,n){i.pauseTimer>0?(i.pauseTimer-=16*t,e.vx*=.9,e.vy*=.9):(i.scanAngle+=i.scanDirection*i.scanSpeed*t*.02,Math.abs(i.scanAngle)>i.scanRange/2&&(i.scanDirection*=-1,i.pauseTimer=i.pauseDuration,i.scanAngle=Math.sign(i.scanAngle)*i.scanRange/2));const a=i.scanCenter+i.scanAngle,s=.8+.5*i.alertLevel;e.vx=Math.cos(a)*s,e.vy=Math.sin(a)*s*.3},updateDarting(e,t,i,n){const a=i.dartTarget.x-e.x,s=i.dartTarget.y-e.y,o=Math.sqrt(a*a+s*s);o>5?(e.vx=a/o*i.dartSpeed,e.vy=s/o*i.dartSpeed):(i.mode="scanning",i.modeTimer=0)},updateFrozen(e,t,i,n){e.vx*=.95,e.vy*=.95,Math.random()<.01&&(e.vx+=.5*(Math.random()-.5),e.vy+=.5*(Math.random()-.5))},updatePatrolling(e,t,i,n){i.patrolAngle+=.01*t;const a=n.corePosition?.x??n.canvasWidth/2,s=n.corePosition?.y??n.canvasHeight/2,o=a+Math.cos(i.patrolAngle)*i.patrolRadius,r=s+Math.sin(i.patrolAngle)*i.patrolRadius,l=o-e.x,h=r-e.y;e.vx=.02*l,e.vy=.02*h},changeMode(e,t,i){const n=Math.random(),a=i?.corePosition?.x??(i?.canvasWidth/2||e.x),s=i?.corePosition?.y??(i?.canvasHeight/2||e.y);"scanner"===t.primaryRole?n<.1?(t.mode="darting",t.dartTarget={x:a+200*(Math.random()-.5),y:s+200*(Math.random()-.5)},t.dartSpeed=3+2*Math.random()):t.mode=n<.2?"frozen":"scanning":"patroller"===t.primaryRole?t.mode=n<.1?"frozen":"patrolling":t.mode=n<.3?"scanning":"frozen"}},Xt={name:"glitchy",emoji:"⚡",description:"Digital glitch with stuttering orbits and corruption",rhythm:{enabled:!0,glitchTiming:{mode:"subdivision",subdivision:"sixteenth",probability:.3,intensityOnBeat:2,intensityOffBeat:.5},stutterSync:{mode:"pattern",patterns:{dubstep:{freezeOnDrop:!0,dropDuration:100},breakbeat:{randomFreeze:.1,duration:50}}},orbitRhythm:{baseSpeed:"tempo",wobbleSync:"eighth",beatAcceleration:1.5,barReset:!0},rgbSync:{enabled:!0,amount:"intensity",direction:"beat",maxSplit:10},noiseRhythm:{trigger:"accent",duration:50,intensity:"drop"}},initialize(e,t,i,n){e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorState={orbitAngle:Math.random()*Math.PI*2,orbitRadius:300+400*Math.random(),orbitSpeed:.01+.02*Math.random(),glitchTimer:0,nextGlitch:500*Math.random()+100,isGlitching:!1,glitchDuration:0,glitchOffset:{x:0,y:0},stutterTimer:0,nextStutter:200*Math.random()+50,isFrozen:!1,frozenPosition:{x:0,y:0},frozenVelocity:{x:0,y:0},hasGhost:Math.random()<.3,ghostOffset:20*Math.random()+10,ghostAngle:Math.random()*Math.PI*2,rgbSplit:Math.random()<.4,rgbPhase:Math.random()*Math.PI*2,noiseLevel:0,noiseBurst:!1,beatPhase:Math.random()*Math.PI*2,beatFrequency:.05+.03*Math.random(),dropIntensity:0},e.lifeDecay=.0015,e.hasGlow=!0,e.glowSizeMultiplier=3+2*Math.random()},update(e,t,i,n){const a=e.behaviorState;if(!a)return;a.glitchTimer+=16*t,a.stutterTimer+=16*t,a.stutterTimer>a.nextStutter&&(a.isFrozen?(a.isFrozen=!1,a.stutterTimer=0,a.nextStutter=100+300*Math.random(),Math.random()<.3&&(e.x+=60*(Math.random()-.5),e.y+=60*(Math.random()-.5))):(a.isFrozen=!0,a.frozenPosition={x:e.x,y:e.y},a.frozenVelocity={x:e.vx,y:e.vy},a.stutterTimer=0,a.nextStutter=20+40*Math.random())),a.glitchTimer>a.nextGlitch&&!a.isGlitching&&(a.isGlitching=!0,a.glitchDuration=50+100*Math.random(),a.glitchOffset={x:80*(Math.random()-.5),y:80*(Math.random()-.5)},a.glitchTimer=0,Math.random()<.5&&e.emotionColors&&(e.color=Ct(e.emotionColors))),a.isGlitching&&a.glitchTimer>a.glitchDuration&&(a.isGlitching=!1,a.glitchTimer=0,a.nextGlitch=200+800*Math.random(),a.glitchOffset={x:0,y:0}),a.beatPhase+=a.beatFrequency*t;const s=.5*Math.sin(a.beatPhase)+.5;if(a.beatPhase%(4*Math.PI)<.5*Math.PI?a.dropIntensity=Math.min(1,a.dropIntensity+.1*t):a.dropIntensity=Math.max(0,a.dropIntensity-.05*t),a.isFrozen)e.vx=.5*(Math.random()-.5),e.vy=.5*(Math.random()-.5);else{a.orbitAngle+=a.orbitSpeed*t*(1+.5*s);const o=a.orbitRadius*(1+.3*a.dropIntensity*Math.sin(4*a.beatPhase));let r=i+Math.cos(a.orbitAngle)*o,l=n+Math.sin(a.orbitAngle)*o*.6;if(a.isGlitching&&(r+=a.glitchOffset.x*Math.random()*.8,l+=a.glitchOffset.y*Math.random()*.8),a.rgbSplit){const e=3*(1+a.dropIntensity);r+=Math.sin(a.rgbPhase)*e,l+=Math.cos(a.rgbPhase)*e,a.rgbPhase+=.1*t}a.dropIntensity>.8&&Math.random()<.1&&(r+=30*(Math.random()-.5),l+=30*(Math.random()-.5));const h=a.isGlitching?.02:.03;e.vx=(r-e.x)*h,e.vy=(l-e.y)*h,e.vx+=(Math.random()-.5)*s*2,e.vy+=(Math.random()-.5)*s*2}e.x+=e.vx*t,e.y+=e.vy*t,Math.random()<.02&&(e.opacity=.1+.9*Math.random()),e.size=e.baseSize*(1+.3*s+.5*a.dropIntensity)}},Yt={name:"spaz",description:"Ultra-aggressive particles with explosive spread and chaotic motion",initialize(e,t,i,n){e.x=i,e.y=n,e.life=1,e.size=3+4*Math.random();const a=Math.random()*Math.PI*2,s=200+300*Math.random();e.vx=Math.cos(a)*s,e.vy=Math.sin(a)*s,e.behaviorState={explosionPhase:0,explosionTimer:0,explosionDuration:1e3+2e3*Math.random(),chaosTimer:0,nextChaosChange:100+200*Math.random(),chaosAngle:a,chaosSpeed:50+100*Math.random(),spazIntensity:.8+.4*Math.random(),zigzagPattern:Math.random()<.5,spiralPattern:Math.random()<.3,teleportChance:.02,sizePulse:!0,sizePulseSpeed:.1+.05*Math.random(),sizePulsePhase:Math.random()*Math.PI*2,colorShift:Math.random()<.3,colorShiftSpeed:.05+.03*Math.random()},e.lifeDecay=8e-4,e.hasGlow=!0,e.glowSizeMultiplier=4+3*Math.random(),e.glowIntensity=1.5+.5*Math.random()},update(e,t,i,n){const a=e.behaviorState;if(a.explosionTimer+=t,a.chaosTimer+=t,0===a.explosionPhase&&a.explosionTimer<500)e.vx*=.98,e.vy*=.98,Math.random()<.1&&(e.vx+=100*(Math.random()-.5),e.vy+=100*(Math.random()-.5));else if(0===a.explosionPhase&&a.explosionTimer>=500)a.explosionPhase=1,a.chaosAngle=Math.random()*Math.PI*2,a.chaosSpeed=30+70*Math.random();else if(1===a.explosionPhase){a.chaosTimer>=a.nextChaosChange&&(a.chaosAngle=Math.random()*Math.PI*2,a.chaosSpeed=20+80*Math.random(),a.nextChaosChange=50+150*Math.random(),a.chaosTimer=0);const t=Math.cos(a.chaosAngle)*a.chaosSpeed,i=Math.sin(a.chaosAngle)*a.chaosSpeed;if(e.vx=.7*e.vx+.3*t,e.vy=.7*e.vy+.3*i,a.zigzagPattern){const t=.01*a.chaosTimer;e.vx+=20*Math.sin(t),e.vy+=20*Math.cos(t)}if(a.spiralPattern){const t=.005*a.chaosTimer,i=50+30*Math.sin(.003*a.chaosTimer);e.vx+=Math.cos(t)*i*.1,e.vy+=Math.sin(t)*i*.1}}if(Math.random()<a.teleportChance){const t=Math.random()*Math.PI*2,a=200+400*Math.random();e.x=i+Math.cos(t)*a,e.y=n+Math.sin(t)*a,e.vx=200*(Math.random()-.5),e.vy=200*(Math.random()-.5)}if(e.x+=e.vx*(t/1e3),e.y+=e.vy*(t/1e3),a.sizePulse){a.sizePulsePhase+=a.sizePulseSpeed*t;const i=1+.5*Math.sin(a.sizePulsePhase);e.size=(3+4*Math.random())*i}a.colorShift&&(a.colorShiftPhase=(a.colorShiftPhase||0)+a.colorShiftSpeed*t),e.vx*=.995,e.vy*=.995,e.life-=e.lifeDecay*t,(e.life<=0||Math.abs(e.x-i)>2e3||Math.abs(e.y-n)>2e3)&&(e.life=0)},getSpawnPosition(e,t){const i=Math.random()*Math.PI*2,n=100+200*Math.random();return{x:e+Math.cos(i)*n,y:t+Math.sin(i)*n}},getVisualProperties:()=>({glowColor:"#FF00AA",glowIntensity:2,particleColors:[{color:"#FF00AA",weight:30},{color:"#00FFAA",weight:25},{color:"#FFAA00",weight:20},{color:"#AA00FF",weight:15},{color:"#00AAFF",weight:10}]})},$t={name:"directed",emoji:"🎯",description:"Focused, straight-line movement toward target",config:{speed:3,acceleration:.15,focusStrength:.8,randomness:.1,edgeBuffer:50},initialize(e,t,i,n,a){const s=t-e.x,o=i-e.y,r=Math.sqrt(s*s+o*o);if(r>0)e.vx=s/r*this.config.speed,e.vy=o/r*this.config.speed;else{const t=Math.random()*Math.PI*2;e.vx=Math.cos(t)*this.config.speed,e.vy=Math.sin(t)*this.config.speed}e.targetX=t,e.targetY=i,e.directedPhase=0},update(e,t,i,n,a,s){e.directedPhase+=.05*t;const o=e.targetX-e.x,r=e.targetY-e.y,l=Math.sqrt(o*o+r*r);if(l>10){const i=o/l*this.config.speed,n=r/l*this.config.speed;e.vx+=(i-e.vx)*this.config.acceleration*t,e.vy+=(n-e.vy)*this.config.acceleration*t,e.vx+=(Math.random()-.5)*this.config.randomness,e.vy+=(Math.random()-.5)*this.config.randomness}else{const t=Math.random()*Math.PI*2,o=100+200*Math.random();e.targetX=i+Math.cos(t)*o,e.targetY=n+Math.sin(t)*o,e.targetX=Math.max(this.config.edgeBuffer,Math.min(a-this.config.edgeBuffer,e.targetX)),e.targetY=Math.max(this.config.edgeBuffer,Math.min(s-this.config.edgeBuffer,e.targetY))}e.x+=e.vx*t,e.y+=e.vy*t,(e.x<=0||e.x>=a)&&(e.vx*=-.8,e.x=Math.max(0,Math.min(a,e.x)),e.targetX=i+300*(Math.random()-.5)),(e.y<=0||e.y>=s)&&(e.vy*=-.8,e.y=Math.max(0,Math.min(s,e.y)),e.targetY=n+300*(Math.random()-.5))},visuals:{trailLength:"medium",opacity:.9,sizeMultiplier:1,blurAmount:.2}},Qt={name:"fizzy",emoji:"🫧",description:"Bubbly, effervescent movement like carbonation",config:{baseRiseSpeed:2.5,wobbleAmplitude:30,wobbleFrequency:.15,popChance:.002,popForce:8,fizziness:.3,gravity:-.05},initialize(e,t,i,n,a){e.vx=2*(Math.random()-.5),e.vy=-this.config.baseRiseSpeed-2*Math.random(),e.wobblePhase=Math.random()*Math.PI*2,e.wobbleSpeed=this.config.wobbleFrequency*(.8+.4*Math.random()),e.bubbleSize=.5+.5*Math.random(),e.popTimer=0,e.isFizzing=!0},update(e,t,i,n,a,s){e.wobblePhase+=e.wobbleSpeed*t;const o=Math.sin(e.wobblePhase)*this.config.wobbleAmplitude;if(e.vx=.05*o+(Math.random()-.5)*this.config.fizziness,e.vy+=this.config.gravity*t,e.vy+=(Math.random()-.5)*this.config.fizziness,Math.random()<this.config.popChance){const t=Math.random()*Math.PI*2;e.vx=Math.cos(t)*this.config.popForce,e.vy=Math.sin(t)*this.config.popForce*.7,e.popTimer=1,e.bubbleSize=.3+.7*Math.random()}e.popTimer>0&&(e.popTimer-=.05*t,e.vx*=.95,e.vy*=.95),e.x+=e.vx*t,e.y+=e.vy*t,e.y<-50&&(e.y=s+50,e.x=i+300*(Math.random()-.5),e.vy=-this.config.baseRiseSpeed-2*Math.random(),e.bubbleSize=.5+.5*Math.random()),(e.x<=0||e.x>=a)&&(e.vx*=-.5,e.x=Math.max(0,Math.min(a,e.x))),e.y>s+50&&(e.y=s,e.vy=1.5*-this.config.baseRiseSpeed),e.size=e.baseSize*e.bubbleSize*(1+.1*Math.sin(2*e.wobblePhase))},visuals:{trailLength:"short",opacity:.6,sizeMultiplier:1.2,blurAmount:.5,sparkle:!0}};var Zt={name:"zen",emoji:"☯️",description:"Peaceful orbital movement like a hovering aura",initialize:function(e){e.vx=.5*(Math.random()-.5),e.vy=.5*(Math.random()-.5),e.lifeDecay=.003,e.emotionColors&&e.emotionColors.length>0&&(e.color=Ct(e.emotionColors)),e.behaviorData={orbitAngle:Math.random()*Math.PI*2,orbitRadius:40+60*Math.random(),orbitSpeed:8e-4+6e-4*Math.random(),floatOffset:Math.random()*Math.PI*2,breathingOffset:Math.random()*Math.PI*2,lifetime:0}},update:function(e,t,i,n){const a=e.behaviorData;if(!a)return;a.lifetime+=t;const s=(a.lifetime+8e3*a.breathingOffset)/8e3,o=.5*Math.sin(s*Math.PI*2)+.5;e.size=e.baseSize*(.95+.05*o),a.orbitAngle+=a.orbitSpeed*t;const r=10*Math.sin(1e-4*a.lifetime+a.floatOffset),l=a.orbitRadius+r,h=i+Math.cos(a.orbitAngle)*l,c=n+Math.sin(a.orbitAngle)*l,u=15*Math.sin(3e-4*a.lifetime+a.breathingOffset),d=h-e.x,m=c+u-e.y;e.vx=.03*d,e.vy=.03*m,e.vx+=.02*(Math.random()-.5),e.vy+=.02*(Math.random()-.5),e.vx*=.98,e.vy*=.98}};const Jt=new Map;var Kt=function(e){return Jt.get(e)||null},ei=function(){return Array.from(Jt.keys())};const ti={};function ii(e){if(ti[e])return ti[e];return Kt(e)||null}function ni(e,t){const i=ii(t);return i&&i.initialize?(i.initialize(e),!0):"ambient"!==t&&(console.warn(`⚠️ Behavior '${t}' not found, falling back to ambient`),ni(e,"ambient"))}function ai(e,t,i,n,a){const s=ii(t);return!(!s||!s.update||(s.update(e,i,n,a),0))}[Dt,$t,Qt,Bt,kt,Tt,zt,_t,Ot,Ft,Lt,Gt,Vt,qt,jt,Ut,Ht,Wt,Xt,Yt,Zt].forEach(e=>{ti[e.name]=e}),"undefined"!=typeof window&&window.DEBUG_PARTICLES&&(window.ParticleBehaviors={registry:ti,list:function(){return[...Object.values(ti).map(e=>({name:e.name,emoji:e.emoji||"🎯",description:e.description||"No description",type:"core"})),...ei().map(e=>{const t=Kt(e);return{name:t.name,emoji:t.emoji||"🔌",description:t.description||"Plugin behavior",type:"plugin"}})]},get:ii});class si{constructor(e,t,i="ambient",n=1,a=1,s=null){const o=Math.random();this.z=o<1/13?.5+.5*Math.random():.9*Math.random()-1;const r=this.z>0?(20+20*Math.random())*n:3*n,l=Math.random()*Math.PI*2;this.x=e+Math.cos(l)*r,this.y=t+Math.sin(l)*r,this.vx=0,this.vy=0,this.vz=0,this.life=0,this.maxLife=1,this.lifeDecay=.01,this.fadeInTime=.15,this.fadeOutTime=.3,this.isFadingOut=!1,this.age=0,this.scaleFactor=n,this.particleSizeMultiplier=a,this.size=(4+6*Math.random())*n*a,this.baseSize=this.size,this.emotionColors=s,this.color="#ffffff",this.opacity=1,this.hasGlow=Math.random()<.333,this.glowSizeMultiplier=this.hasGlow?1.33+.33*Math.random():0,this.isCellShaded=Math.random()<.333,this.baseOpacity=.3+.4*Math.random(),this.cachedColors=new Map,this.maxCachedColors=20,this.colorAccessOrder=[],this.lastColor=null,this.lastOpacity=-1,this.behavior=i,this.behaviorData={},this.gestureData={initialX:e,initialY:t},ni(this,i)}update(e,t,i,n=null,a=null,s=0,o=null){const r=Math.min(e,50)/16.67,l=a&&a.type&&s>0&&function(e){const t=ft(e);return!!t&&"override"===t.type}(a.type);let h,c;if(l?this.applyGestureMotion(a,s,r,t,i):"falling"===this.gestureBehavior?ai(this,"falling",r,t,i):"radiant"===this.gestureBehavior?ai(this,"radiant",r,t,i):(ai(this,this.behavior,r,t,i),a&&s>0&&this.applyGestureMotion(a,s,r,t,i)),l||(this.x+=this.vx*r,this.y+=this.vy*r),o)h=o.width,c=o.height;else{const e=document.getElementById("card-mascot")||document.getElementById("cherokee-guide-mascot")||document.querySelector("canvas");h=e?e.width:2*t,c=e?e.height:2*i}const u=t-h/2+20,d=t+h/2-20,m=i-c/2+20,p=i+c/2-20;this.x-this.size<u?(this.x=u+this.size,this.vx=.5*Math.abs(this.vx)):this.x+this.size>d&&(this.x=d-this.size,this.vx=.5*-Math.abs(this.vx)),this.y-this.size<m?(this.y=m+this.size,this.vy=.5*Math.abs(this.vy)):this.y+this.size>p&&(this.y=p-this.size,this.vy=.5*-Math.abs(this.vy)),this.age+=this.lifeDecay*r,this.age<this.fadeInTime?this.life=this.age/this.fadeInTime:this.age<1-this.fadeOutTime?this.life=1:(this.life=(1-this.age)/this.fadeOutTime,this.isFadingOut=!0,"popcorn"===this.behavior&&(this.size=this.baseSize*(.5+.5*this.life))),this.life=Math.max(0,Math.min(1,this.life)),"falling"===this.behavior?this.opacity=this.life:this.opacity=this.easeInOutCubic(this.life),"burst"===this.behavior&&this.behaviorData&&this.life<this.behaviorData.fadeStart&&(this.size=this.baseSize*(this.life/this.behaviorData.fadeStart))}applyUndertoneModifier(e,t){}applyGestureMotion(e,t,i,n,a){!function(e,t,i,n,a,s){if(!i||!i.type||n>=1)return;e.gestureData||(e.gestureData={originalVx:e.vx,originalVy:e.vy,initialX:e.x,initialY:e.y,startAngle:Math.atan2(e.y-s,e.x-a),startRadius:Math.sqrt(Math.pow(e.x-a,2)+Math.pow(e.y-s,2))});const o=ft(i.type);if(!o)return;let r=i;if(St.isEnabled()&&o.rhythm?.enabled){const a=St.applyGestureRhythm(o,e,n,t);r={...i,amplitude:(i.amplitude||1)*(a.amplitudeMultiplier||1)*(a.accentMultiplier||1),wobbleAmount:(i.wobbleAmount||0)*(a.wobbleMultiplier||1),rhythmModulation:a}}o.apply&&o.apply(e,n,r,t,a,s),n>=.99&&o.cleanup&&(o.cleanup(e),e.gestureData=null)}(this,i,e,t,n,a)}isOutOfBounds(e,t){return this.x<-50||this.x>e+50||this.y<-50||this.y>t+50}isAlive(){return this.life>0}setOutwardVelocity(e){if(this.behaviorData&&void 0!==this.behaviorData.outwardSpeed){const t=this.behaviorData.outwardSpeed;this.vx=Math.cos(e)*t,this.vy=Math.sin(e)*t+(this.behaviorData.upwardBias||0)}}getDepthAdjustedSize(){const e=1+.2*this.z;return this.size*e}getState(){return{position:{x:this.x,y:this.y,z:this.z},velocity:{x:this.vx,y:this.vy,z:this.vz},life:this.life,behavior:this.behavior,size:this.size,opacity:this.opacity}}reset(e,t,i="ambient",n=1,a=1,s=null){const o=Math.random();this.z=o<1/13?.5+.5*Math.random():.9*Math.random()-1;const r=this.z>0?(20+20*Math.random())*n:3*n,l=Math.random()*Math.PI*2;if(this.x=e+Math.cos(l)*r,this.y=t+Math.sin(l)*r,this.vx=0,this.vy=0,this.vz=0,this.life=0,this.age=0,this.scaleFactor=n,this.particleSizeMultiplier=a,this.size=(4+6*Math.random())*n*a,this.baseSize=this.size,this.emotionColors=s,this.cachedColors.clear(),this.colorAccessOrder=[],this.opacity=0,this.isFadingOut=!1,this.baseOpacity=.3+.4*Math.random(),this.color="#ffffff",this.behavior=i,this.gestureData=null,this.behaviorData)for(const e in this.behaviorData)delete this.behaviorData[e];else this.behaviorData={};ni(this,i)}getCachedColor(e,t){const i=Math.round(100*t)/100,n=`${e}_${i}`;if(this.cachedColors.has(n)){const e=this.colorAccessOrder.indexOf(n);-1!==e&&this.colorAccessOrder.splice(e,1),this.colorAccessOrder.push(n)}else{if(this.cachedColors.size>=this.maxCachedColors){const e=this.colorAccessOrder.shift();this.cachedColors.delete(e)}this.cachedColors.set(n,this.hexToRgba(e,i)),this.colorAccessOrder.push(n)}return this.cachedColors.get(n)}hexToRgba(e,t){const i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return i?`rgba(${parseInt(i[1],16)}, ${parseInt(i[2],16)}, ${parseInt(i[3],16)}, ${t})`:`rgba(255, 255, 255, ${t})`}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}render(e,t="#ffffff"){if(this.life<=0)return;if(!isFinite(this.x)||!isFinite(this.y))return;const i=this.x,n=this.y,a=Math.max(.1,this.size),s=this.tempColor||this.color||t;if(e.save(),this.isCellShaded){e.strokeStyle=this.getCachedColor(s,.9*this.opacity),e.lineWidth=2,e.beginPath(),e.arc(i,n,a,0,2*Math.PI),e.stroke();const t=Math.floor(3*this.opacity)/3;e.fillStyle=this.getCachedColor(s,t*(this.baseOpacity||.5)*.5),e.beginPath(),e.arc(i,n,Math.max(.1,a-1),0,2*Math.PI),e.fill(),t>.5&&(e.fillStyle=this.getCachedColor("#FFFFFF",.3),e.beginPath(),e.arc(i-.3*a,n-.3*a,.3*a,0,2*Math.PI),e.fill())}else{const t=e.createRadialGradient(i,n,0,i,n,a);if(t.addColorStop(0,this.getCachedColor(s,this.opacity*(this.baseOpacity||.5))),t.addColorStop(.5,this.getCachedColor(s,this.opacity*(this.baseOpacity||.5)*.5)),t.addColorStop(1,this.getCachedColor(s,0)),e.fillStyle=t,e.beginPath(),e.arc(i,n,a,0,2*Math.PI),e.fill(),this.hasGlow&&this.glowSizeMultiplier>0){const t=a*this.glowSizeMultiplier,o=e.createRadialGradient(i,n,.5*a,i,n,t),r=.3,l=Math.max(r,this.opacity),h=Math.min(1,this.glowSizeMultiplier/3);o.addColorStop(0,this.getCachedColor(s,Math.max(.5,.8*l)*h)),o.addColorStop(.25,this.getCachedColor(s,Math.max(.3,.6*l)*h)),o.addColorStop(.5,this.getCachedColor(s,Math.max(.2,.4*l)*h)),o.addColorStop(.75,this.getCachedColor(s,Math.max(.1,.2*l)*h)),o.addColorStop(1,this.getCachedColor(s,0)),e.save(),e.globalCompositeOperation="screen",e.fillStyle=o,e.beginPath(),e.arc(i,n,t,0,2*Math.PI),e.fill(),e.restore()}}e.restore()}}class oi{constructor(e=50){this.poolSize=Math.min(e,50),this.pool=[],this.totalParticlesCreated=0,this.totalParticlesDestroyed=0,this.poolHits=0,this.poolMisses=0}getParticle(e,t,i,n,a,s,o,r=null){let l;return this.pool.length>0?(l=this.pool.pop(),l.reset(e,t,i,n,a,s),this.poolHits++):(l=new si(e,t,i,n,a,s),this.poolMisses++,this.totalParticlesCreated++),l.emotion=o,r&&(l.gestureBehavior=r),l}returnParticle(e){if(this.pool.length<this.poolSize){if(e.cachedGradient=null,e.cachedGradientKey=null,e.behaviorData)for(const t in e.behaviorData)delete e.behaviorData[t];this.pool.push(e)}else this.totalParticlesDestroyed++}refreshPool(){const e=this.pool.length-this.poolSize;e>0&&(this.pool.splice(this.poolSize),this.totalParticlesDestroyed+=e)}getStats(){return{poolSize:this.pool.length,poolHits:this.poolHits,poolMisses:this.poolMisses,totalCreated:this.totalParticlesCreated,totalDestroyed:this.totalParticlesDestroyed}}clear(){this.pool=[],this.poolHits=0,this.poolMisses=0,this.totalParticlesCreated=0,this.totalParticlesDestroyed=0}}class ri{constructor(){this.spawnAccumulator=0}getSpawnPosition(e,t,i,n,a,s=null){const o=Math.min(n,a)/12,r=2.5*o,l=1.1*r,h=Math.min(t-30,n-t-30),c=Math.min(i-30,a-i-30),u=Math.min(1.5*r,h,c);switch(e){case"ambient":case"resting":{const e=Math.random()*Math.PI*2,n=.9*r;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n,angle:e}}case"rising":{const e=Math.random()*Math.PI*2,n=l+Math.random()*(u-l);return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"falling":{const e=Math.random()*Math.PI*2,n=.9*r;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n,angle:e}}case"aggressive":{const e=Math.random()*Math.PI*2,n=r+Math.random()*o;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"scattering":default:return{x:t,y:i};case"burst":{const e=Math.random()*Math.PI*2;if("suspicion"===s){const n=1.5*o;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}if("surprise"===s){const n=1.2*o;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}return{x:t,y:i}}case"repelling":{const e=Math.random()*Math.PI*2,n=.9*r;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"orbiting":{const e=Math.random()*Math.PI*2,n=1.2*r+Math.random()*r*.5;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"glitchy":{const e=Math.random()*Math.PI*2,n=3*r+Math.random()*r*4;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}case"spaz":{const e=Math.random()*Math.PI*2,n=2*r+Math.random()*r*3;return{x:t+Math.cos(e)*n,y:i+Math.sin(e)*n}}}}clampToCanvas(e,t,i,n,a=30){return{x:Math.max(a,Math.min(i-a,e)),y:Math.max(a,Math.min(n-a,t))}}calculateSpawnRate(e,t){if(e<=0)return 0;const i=Math.min(t,50),n=e/1e3;this.spawnAccumulator+=n*i,this.spawnAccumulator=Math.min(this.spawnAccumulator,3);let a=0;for(;this.spawnAccumulator>=1;)a++,this.spawnAccumulator-=1;return a}resetAccumulator(){this.spawnAccumulator=0}}class li{render(e,t,i="#ffffff",n=null){const a=[];for(const e of t)e.life<=0||a.push(e);this._renderParticles(e,a,i,n)}renderLayer(e,t,i="#ffffff",n=!1,a=null){const s=[],o=e.canvas.width,r=e.canvas.height;for(const e of t)e.z>=0===n&&(e.x<-50||e.x>o+50||e.y<-50||e.y>r+50||e.life<=0||s.push(e));return s.sort((e,t)=>e.isCellShaded!==t.isCellShaded?e.isCellShaded?-1:1:e.hasGlow!==t.hasGlow?e.hasGlow?-1:1:0),this._renderParticles(e,s,i,a),s}_renderParticles(e,t,i,n=null){e.save();let a=null;for(const s of t)if(s.isCellShaded)s.render(e,i),a=null;else{const t=s.color||i;if(t!==a&&(e.fillStyle=t,a=t),!isFinite(s.x)||!isFinite(s.y))continue;const o=s.getDepthAdjustedSize?s.getDepthAdjustedSize():s.size;let r=Math.max(.1,o),l=1;if(n&&n.fireflyEffect){const e=(.01*s.x+.01*s.y+.1*s.size)%(2*Math.PI),t=n.fireflyTime||.001*Date.now(),i=n.particleGlow||2;l=.3+Math.max(0,Math.sin(3*t+e))*i}if(n&&n.flickerEffect){const e=(.02*s.x+.02*s.y)%(2*Math.PI),t=n.flickerTime||.001*Date.now(),i=n.particleGlow||2;l=.5+Math.sin(12*t+e)*i*.5}if(n&&n.shimmerEffect){const t=s.x-e.canvas.width/2,i=s.y-e.canvas.height/2,a=Math.sqrt(t*t+i*i)/200,o=n.shimmerTime||.001*Date.now(),r=n.shimmerWave||0,h=n.particleGlow||1.2;l=1+.15*Math.sin(3*o-a+r)*h}if(n&&n.glowEffect){const t=n.glowProgress||0,i=n.particleGlow||2,a=s.x-e.canvas.width/2,o=s.y-e.canvas.height/2,l=Math.sqrt(a*a+o*o)/300,h=Math.min(.3*l,.5),c=Math.max(0,(t-h)/(1-h)),u=Math.sin(c*Math.PI);s._originalGlow||(s._originalGlow={hasGlow:s.hasGlow,glowSizeMultiplier:s.glowSizeMultiplier||0}),s.hasGlow=!0,s.glowSizeMultiplier=Math.max(3,s._originalGlow.glowSizeMultiplier)+u*i*3,r*=1+.3*u,t>=.99&&s._originalGlow&&(s.hasGlow=s._originalGlow.hasGlow,s.glowSizeMultiplier=s._originalGlow.glowSizeMultiplier,delete s._originalGlow)}if(s.hasGlow||l>1){const t=Math.max(.1,r*(s.glowSizeMultiplier||1.5)*l),i=e.globalCompositeOperation;e.globalCompositeOperation="screen",e.globalAlpha=.15*s.opacity*l,e.beginPath(),e.arc(s.x,s.y,t,0,2*Math.PI),e.fill(),e.globalAlpha=.25*s.opacity*l,e.beginPath(),e.arc(s.x,s.y,.6*t,0,2*Math.PI),e.fill(),e.globalCompositeOperation=i}e.globalAlpha=s.opacity*(s.baseOpacity||.5)*.6*Math.min(2,l),e.beginPath(),e.arc(s.x,s.y,r,0,2*Math.PI),e.fill()}e.restore()}}class hi{constructor(e=50,t=null){this.errorBoundary=t,this.maxParticles=e,this.absoluteMaxParticles=2*e,this.particles=[],this.particlePool=new oi(e),this.particleSpawner=new ri,this.particleRenderer=new li,this.containmentBounds=null,this.stateChangeCount=0,this.lastMemoryCheck=Date.now(),this.lastLeakedCount=0,this.particleCount=0,this.cleanupTimer=0,this.cleanupInterval=5e3}get pool(){return this.particlePool.pool}get poolSize(){return this.particlePool.poolSize}get poolHits(){return this.particlePool.poolHits}get poolMisses(){return this.particlePool.poolMisses}get totalParticlesCreated(){return this.particlePool.totalParticlesCreated}get totalParticlesDestroyed(){return this.particlePool.totalParticlesDestroyed}get spawnAccumulator(){return this.particleSpawner.spawnAccumulator}set spawnAccumulator(e){this.particleSpawner.spawnAccumulator=e}getParticleFromPool(e,t,i){return this.particlePool.getParticle(e,t,i,this.scaleFactor||1,this.particleSizeMultiplier||1,this.currentEmotionColors,this.currentEmotion,this.gestureBehavior)}returnParticleToPool(e){this.particlePool.returnParticle(e)}spawn(e,t,i,n,a,s,o=null,r=0,l=10,h=1,c=1,u=null,d=null){if(this.scaleFactor=h,this.particleSizeMultiplier=c,this.errorBoundary)return this.errorBoundary.wrap(()=>{this._spawn(e,t,i,n,a,s,o,r,l,u,d)},"particle-spawn")();this._spawn(e,t,i,n,a,s,o,r,l,u,d)}resetAccumulator(){this.particleSpawner.resetAccumulator()}_spawn(e,t,i,n,a,s,o,r=0,l=10,h=null,c=null){this.currentEmotion=t,this.baseEmotionColors=h,this.currentUndertone=c,this.currentEmotionColors=h&&c?function(e,t){return e&&Array.isArray(e)&&t&&"clear"!==t?e.map(e=>"string"==typeof e?Mt(e,t):e&&"object"==typeof e&&e.color?{...e,color:Mt(e.color,t)}:e):e}(h,c):h;let u=i;if(St.isEnabled()){const i=xt&&xt.isInitialized?xt.getEmotion(t):me(t);if(i){const t=St.applyParticleRhythm(i,this);if(t.emitBurst)for(let i=0;i<t.emitBurst&&this.particles.length<l;i++)this.spawnSingleParticle(e,n,a);void 0!==t.emissionRate&&(u*=t.emissionRate)}}if(null!==o){for(let t=0;t<o&&this.particles.length<this.maxParticles;t++)this.spawnSingleParticle(e,n,a);return}if(this.skipSpawnThisFrame)return;for(;this.particles.length<r&&this.particles.length<this.maxParticles;)this.spawnSingleParticle(e,n,a);if(this.particles.length>=l)return;if(u<=0)return;const d=this.particleSpawner.calculateSpawnRate(u,s);for(let t=0;t<d&&this.particles.length<l;t++)this.spawnSingleParticle(e,n,a)}getSpawnPosition(e,t,i,n,a){return this.particleSpawner.getSpawnPosition(e,t,i,n,a,this.currentEmotion)}clampToCanvas(e,t,i,n,a=30){return this.particleSpawner.clampToCanvas(e,t,i,n,a)}spawnSingleParticle(e,t,i){if(this.particles.length>=this.absoluteMaxParticles)return;const n=this.canvasWidth||2*t,a=this.canvasHeight||2*i,s=this.particleSpawner.getSpawnPosition(e,t,i,n,a,this.currentEmotion),o=this.particleSpawner.clampToCanvas(s.x,s.y,n,a);s.x=o.x,s.y=o.y;const r=this.getParticleFromPool(s.x,s.y,e);"meditation_swirl"===e&&s.palmCenter&&(r.palmCenter=s.palmCenter,r.swirlAngle=s.swirlAngle),this.particles.push(r),this.particleCount++}update(e,t,i,n=null,a=0,s=null){if(this.errorBoundary)return this.errorBoundary.wrap((e,t,i,n,a,s)=>this._update(e,t,i,n,a,s),"particle-update")(e,t,i,n,a,s);this._update(e,t,i,n,a,s)}_update(e,t,i,n=null,a=0,s=null){for(this.particles=this.particles.filter(o=>(o.update(e,t,i,s,n,a,this.containmentBounds),o.isAlive()));this.particles.length>this.maxParticles;)this.removeParticle(0)}setGestureBehavior(e,t){this.gestureBehavior=t?e:null,t?this.particles.forEach(t=>{t.gestureBehavior=e}):this.particles.forEach(e=>{e.gestureBehavior=null})}removeParticle(e){if(e>=0&&e<this.particles.length){const t=this.particles.splice(e,1)[0];t.cachedGradient=null,t.cachedGradientKey=null,this.returnParticleToPool(t),this.particleCount=Math.max(0,this.particleCount-1)}}render(e,t="#ffffff",i=null){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._render(e,t,i)},"particle-render")();this._render(e,t,i)}renderBackground(e,t="#ffffff",i=null){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._renderLayer(e,t,!1,i)},"particle-render-bg")();this._renderLayer(e,t,!1,i)}renderForeground(e,t="#ffffff",i=null){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._renderLayer(e,t,!0,i)},"particle-render-fg")();this._renderLayer(e,t,!0,i)}_renderLayer(e,t,i,n=null){this.particleRenderer.renderLayer(e,this.particles,t,i,n)}_render(e,t,i=null){this.particleRenderer.render(e,this.particles,t,i)}clear(){for(this.stateChangeCount++;this.particles.length>0;){const e=this.particles.pop();if(e.cachedColors&&e.cachedColors.clear(),e.behaviorData)for(const t in e.behaviorData)delete e.behaviorData[t];this.pool.length<this.poolSize&&!this.pool.includes(e)&&this.pool.push(e)}if(this.particles.length=0,this.particleCount=0,this.spawnAccumulator=0,this.pool.length>this.poolSize){const e=this.pool.length-this.poolSize;this.pool.splice(this.poolSize,e)}}burst(e,t,i,n){if(this.errorBoundary)return this.errorBoundary.wrap(()=>{this._burst(e,t,i,n)},"particle-burst")();this._burst(e,t,i,n)}_burst(e,t,i,n){const a=Math.min(e,this.maxParticles-this.particles.length);for(let e=0;e<a;e++)this.spawnSingleParticle(t,i,n)}performCleanup(){if(this.pool.length>this.poolSize){const e=this.pool.length-this.poolSize;for(let t=0;t<e;t++){const e=this.pool.pop();e&&(e.cachedGradient=null,e.cachedGradientKey=null,e.behaviorData=null)}}for(const e of this.particles)e.cachedGradient&&e.life<.5&&(e.cachedGradient=null,e.cachedGradientKey=null)}getStats(){return{activeParticles:this.particles.length,maxParticles:this.maxParticles,poolSize:this.pool.length,poolHits:this.poolHits,poolMisses:this.poolMisses,poolEfficiency:this.poolHits/Math.max(1,this.poolHits+this.poolMisses),spawnAccumulator:this.spawnAccumulator}}setMaxParticles(e){for(this.originalMaxParticles=this.originalMaxParticles||this.maxParticles,this.maxParticles=Math.max(1,e);this.particles.length>this.maxParticles;)this.removeParticle(0)}cleanupDeadParticles(){const e=this.particles.length;this.particles=this.particles.filter(e=>e.isAlive());const t=e-this.particles.length;return this.pool.length>20&&(this.pool.length=20),t}getParticlesByBehavior(e){return this.particles.filter(t=>t.behavior===e)}validateParticles(){for(const e of this.particles)if(!e.isAlive()||e.life<0||e.life>1)return!1;return!0}cleanup(){for(let e=this.particles.length-1;e>=0;e--)this.particles[e].isAlive()||this.removeParticle(e)}refreshPool(){this.particlePool.clear();for(const e of this.particles)e.life=0}setContainmentBounds(e){this.containmentBounds=e}destroy(){this.clear(),this.particlePool.clear()}}class ci{constructor(t={}){this.worldScale=t.worldScale||.2,this.baseRadius=t.baseRadius||.15,this.depthScale=t.depthScale||.75,this.verticalScale=t.verticalScale||1,this.coreRadius3D=t.coreRadius3D||1,this.tempVec3=new e.Vector3,this.tempVec3_2=new e.Vector3,this.behaviorTranslators=this._initBehaviorTranslators(),this.currentGestureData=null}setCoreRadius3D(e){this.coreRadius3D=e}updateRotationState(e,t,i=null){this.rotationState=e,this.deltaTime=t,this.currentGestureData=i}_initBehaviorTranslators(){return{ambient:this._translateAmbient.bind(this),orbiting:this._translateOrbiting.bind(this),rising:this._translateRising.bind(this),falling:this._translateFalling.bind(this),popcorn:this._translatePopcorn.bind(this),burst:this._translateBurst.bind(this),aggressive:this._translateAggressive.bind(this),scattering:this._translateScattering.bind(this),repelling:this._translateRepelling.bind(this),connecting:this._translateConnecting.bind(this),resting:this._translateResting.bind(this),radiant:this._translateRadiant.bind(this),ascending:this._translateAscending.bind(this),erratic:this._translateErratic.bind(this),cautious:this._translateCautious.bind(this),surveillance:this._translateSurveillance.bind(this),glitchy:this._translateGlitchy.bind(this),spaz:this._translateSpaz.bind(this),directed:this._translateDirected.bind(this),fizzy:this._translateFizzy.bind(this),zen:this._translateZen.bind(this),gravitationalAccretion:this._translateGravitationalAccretion.bind(this)}}translate2DTo3D(e,t,i){const n=(this.behaviorTranslators[e.behavior]||this._translateDefault.bind(this))(e,t,i);return this.currentGestureData&&"spin"===this.currentGestureData.gestureName?this._applySpinRotation(n,t,this.currentGestureData.progress):n}_applySpinRotation(e,t,i){const n=e.x-t.x,a=e.y-t.y,s=e.z-t.z,o=Math.sin(i*Math.PI)*Math.PI*2,r=Math.cos(o),l=Math.sin(o),h=n*r-s*l,c=n*l+s*r;return this.tempVec3.set(t.x+h,t.y+a,t.z+c)}_canvasToWorld(e,t,i,n,a,s){const o=(e-n)/n,r=-(t-a)/a,l=1+i*this.depthScale,h=o*this.worldScale*l+s.x,c=r*this.worldScale*this.verticalScale*l+s.y,u=i*this.worldScale*.5+s.z;return this.tempVec3.set(h,c,u)}_hash(e){const t=43758.5453123*Math.sin(e);return t-Math.floor(t)}_getUniformDirection3D(e){const t=e.behaviorData||{};if(t.direction3D)return t.direction3D;const i=127.1*e.x+311.7*e.y+74.7*(e.vx||0)+159.3*(e.vy||0),n=this._hash(i),a=this._hash(i+1),s=n*Math.PI*2,o=2*a-1,r=Math.sqrt(1-o*o),l=r*Math.cos(s),h=o,c=r*Math.sin(s);return t.direction3D={x:l,y:h,z:c},t.direction3D}_toSpherical(e,t,i,n){const a=e-n.x,s=t-n.y,o=i-n.z,r=Math.sqrt(a*a+s*s+o*o);return{radius:r,theta:Math.atan2(o,a),phi:Math.acos(s/(r||1))}}_toCartesian(e,t,i,n){const a=e*Math.sin(i)*Math.cos(t)+n.x,s=e*Math.cos(i)+n.y,o=e*Math.sin(i)*Math.sin(t)+n.z;return this.tempVec3_2.set(a,s,o)}_translateDefault(e,t,i){return this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t)}_translateAmbient(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.6*this.coreRadius3D,c=h+l*(1.2*this.coreRadius3D-h),u=.5*e.age,d=.03*this.coreRadius3D,m=Math.cos(u)*d,p=Math.sin(u)*d;return this.tempVec3.set(t.x+n.x*c+m,t.y+n.y*c*this.verticalScale,t.z+n.z*c+p)}_translateOrbiting(e,t,i){const n=e.behaviorData||{};if(!n.orbitPlane){const t=e.x+.5*e.y,i=.7*e.x+e.y;n.orbitPlane={inclination:.5*(Math.sin(.1*t)+1)*Math.PI,rotation:.5*(Math.sin(.1*i)+1)*Math.PI*2}}const{inclination:a,rotation:s}=n.orbitPlane,o=n.angle||0,r=.01*(n.radius||100)*this.baseRadius*.25*(1+e.z*this.depthScale),l=Math.cos(o)*r,h=Math.sin(o)*r,c=Math.cos(a),u=Math.sin(a),d=Math.cos(s),m=Math.sin(s),p=l*d-h*c*m,g=h*u,f=l*m+h*c*d;return this.tempVec3.set(t.x+p,t.y+g*this.verticalScale,t.z+f)}_translateRising(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=-.01*e.vy;return n.y+=a,n}_translateFalling(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.6*this.coreRadius3D,c=h+l*(1.2*this.coreRadius3D-h),u=.6*e.age*this.coreRadius3D;return this.tempVec3.set(t.x+n.x*c,t.y+n.y*c*this.verticalScale-u,t.z+n.z*c)}_translatePopcorn(e,t,i){const n=i.width/2,a=i.height/2,s=e.behaviorData||{},o=this._getUniformDirection3D(e);if(!s.hasPopped){const e=.7*this.coreRadius3D;return this.tempVec3.set(t.x+o.x*e,t.y+o.y*e*this.verticalScale,t.z+o.z*e)}const r=e.x-n,l=e.y-a,h=Math.sqrt(r*r+l*l),c=Math.min(h/n,1.5),u=1.2*this.coreRadius3D,d=u+c*(4*this.coreRadius3D-u);return this.tempVec3.set(t.x+o.x*d,t.y+o.y*d*this.verticalScale,t.z+o.z*d)}_translateBurst(e,t,i){const n=this._getUniformDirection3D(e),a=1-e.life,s=this.coreRadius3D*(1+1*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateAggressive(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.3*this.coreRadius3D,c=h+l*(.55*this.coreRadius3D-h),u=.04*this.coreRadius3D,d=Math.sin(10*e.age+.1*e.x)*u,m=Math.cos(12*e.age+.1*e.y)*u,p=Math.sin(8*e.age+.1*e.vx)*u;return this.tempVec3.set(t.x+n.x*c+d,t.y+n.y*c*this.verticalScale+m,t.z+n.z*c+p)}_translateScattering(e,t,i){const n=this._getUniformDirection3D(e),a=Math.min(.8*e.age,1),s=this.coreRadius3D*(.3+.3*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateRepelling(e,t,i){const n=this._getUniformDirection3D(e),a=Math.min(.6*e.age,1),s=this.coreRadius3D*(.3+.3*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateConnecting(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=.3*(1-e.life),s=this.tempVec3_2.set(t.x-n.x,t.y-n.y,t.z-n.z).normalize();return n.add(s.multiplyScalar(a)),n}_translateResting(e,t,i){const n=this._getUniformDirection3D(e),a=i.width/2,s=i.height/2,o=e.x-a,r=e.y-s,l=Math.sqrt(o*o+r*r)/a,h=.25*this.coreRadius3D,c=h+l*(.45*this.coreRadius3D-h),u=.3*e.age,d=Math.sin(u)*this.coreRadius3D*.01;return this.tempVec3.set(t.x+n.x*c,t.y+n.y*c*this.verticalScale+d,t.z+n.z*c)}_translateRadiant(e,t,i){const n=this._getUniformDirection3D(e),a=1-e.life,s=this.coreRadius3D*(1+.8*a);return this.tempVec3.set(t.x+n.x*s,t.y+n.y*s*this.verticalScale,t.z+n.z*s)}_translateAscending(e,t,i){const n=e.behaviorData||{},a=n.spiralAngle||0,s=.01*(n.spiralRadius||50)*this.coreRadius3D,o=e.age*this.coreRadius3D*.5,r=Math.cos(a)*s+t.x,l=o+t.y,h=Math.sin(a)*s+t.z;return this.tempVec3.set(r,l,h)}_translateErratic(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=10*e.age;return n.x+=.1*Math.sin(1.1*a),n.y+=.1*Math.cos(1.3*a),n.z+=.1*Math.sin(1.7*a),n}_translateCautious(e,t,i){return this._translateAmbient(e,t,i)}_translateSurveillance(e,t,i){const n=this._getUniformDirection3D(e),a=.5*e.age,s=1.2*this.coreRadius3D,o={x:0*n.y-1*n.z,y:0*n.z-0*n.x,z:1*n.x-0*n.y},r=Math.sqrt(o.x*o.x+o.y*o.y+o.z*o.z);r>0&&(o.x/=r,o.y/=r,o.z/=r);const l=Math.cos(a)*n.x+Math.sin(a)*o.x,h=Math.cos(a)*n.y+Math.sin(a)*o.y,c=Math.cos(a)*n.z+Math.sin(a)*o.z;return this.tempVec3.set(t.x+l*s,t.y+h*s*this.verticalScale,t.z+c*s)}_translateGlitchy(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t);return Math.floor(10*e.age)%3==0&&(n.x+=.3*(Math.random()-.5),n.y+=.3*(Math.random()-.5),n.z+=.3*(Math.random()-.5)),n}_translateSpaz(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=.15,s=20*e.age;return n.x+=Math.sin(2.1*s)*a,n.y+=Math.cos(2.3*s)*a,n.z+=Math.sin(2.7*s)*a,n}_translateDirected(e,t,i){const n=e.behaviorData||{};if(void 0!==n.targetX&&void 0!==n.targetY){const a=this._canvasToWorld(n.targetX,n.targetY,e.z,i.width/2,i.height/2,t),s=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),o=1-e.life;return this.tempVec3.lerpVectors(s,a,o)}const a=this._getUniformDirection3D(e),s=i.width/2,o=i.height/2,r=e.x-s,l=e.y-o,h=Math.sqrt(r*r+l*l)/s,c=1*this.coreRadius3D,u=c+h*(1.6*this.coreRadius3D-c);return this.tempVec3.set(t.x+a.x*u,t.y+a.y*u*this.verticalScale,t.z+a.z*u)}_translateFizzy(e,t,i){const n=this._canvasToWorld(e.x,e.y,e.z,i.width/2,i.height/2,t),a=.05*Math.sin(8*e.age);return n.x+=a,n.z+=.05*Math.cos(8*e.age),n.y+=.5*e.age,n}_translateZen(e,t,i){const n=this._getUniformDirection3D(e),a=.2*e.age,s=1.4*this.coreRadius3D,o={x:0*n.y-1*n.z,y:0*n.z-0*n.x,z:1*n.x-0*n.y},r=Math.sqrt(o.x*o.x+o.y*o.y+o.z*o.z);r>0&&(o.x/=r,o.y/=r,o.z/=r);const l=Math.cos(a)*n.x+Math.sin(a)*o.x,h=Math.cos(a)*n.y+Math.sin(a)*o.y,c=Math.cos(a)*n.z+Math.sin(a)*o.z;return this.tempVec3.set(t.x+l*s,t.y+h*s*this.verticalScale,t.z+c*s)}_translateGravitationalAccretion(e,t,i){const n=e.behaviorData||{},a=.25;if(n.orbitRadius||(e.x,e.y,n.orbitRadius=a*(2.5+5.5*Math.random()),n.orbitAngle=Math.PI+Math.random()*Math.PI,n.diskInclination=.1*(Math.random()-.5),n.angularVelocity=.5/Math.sqrt(n.orbitRadius/a),n.tidalStretch={x:1,y:1,z:1}),n.orbitRadius-=1e-4*this.baseRadius,n.angularVelocity=.5/Math.sqrt(n.orbitRadius/a),n.orbitAngle+=n.angularVelocity*(this.deltaTime||16)*.001,n.orbitAngle=n.orbitAngle%(2*Math.PI),n.orbitAngle<0&&(n.orbitAngle+=2*Math.PI),n.orbitAngle<Math.PI)return e.isAlive=!1,e.life=0,this.tempVec3.set(t.x,t.y,t.z);const s=n.orbitRadius/a;if(s<=1)e.isAlive=!1,e.life=0;else if(s<=1.5)n.tidalStretch.x=.3,n.tidalStretch.y=3,n.tidalStretch.z=.3;else if(s<=2.5){const e=(2.5-s)/1;n.tidalStretch.x=1-.7*e,n.tidalStretch.y=1+2*e,n.tidalStretch.z=1-.7*e}else n.tidalStretch.x=1,n.tidalStretch.y=1,n.tidalStretch.z=1;const o=Math.cos(n.orbitAngle)*n.orbitRadius,r=Math.sin(n.orbitAngle)*n.orbitRadius,l=.025*Math.sin(3*n.orbitAngle+e.x)*Math.sin(n.diskInclination),h=o*n.tidalStretch.x,c=l*n.tidalStretch.y,u=r*n.tidalStretch.z,d=.25;return this.tempVec3.set(t.x+h*d,t.y+c*d,t.z+u*d)}setWorldScale(e){this.worldScale=e}setBaseRadius(e){this.baseRadius=e}cleanupParticleCaches(e){for(const t of e)!t.isAlive&&t.behaviorData&&(t.behaviorData.direction3D&&(t.behaviorData.direction3D=null),t.behaviorData.orbitPlane&&(t.behaviorData.orbitPlane=null),t.behaviorData.orbitPath&&(t.behaviorData.orbitPath=null),t.behaviorData.orbitRadius&&(t.behaviorData.orbitRadius=null,t.behaviorData.orbitAngle=null,t.behaviorData.diskInclination=null,t.behaviorData.angularVelocity=null,t.behaviorData.tidalStretch=null))}dispose(){this.tempVec3=null,this.tempVec3_2=null,this.rotationState=null,this.currentGestureData=null}}let ui=null,di=null;const mi=`\n uniform float time;\n uniform vec3 emotionColor;\n uniform float energyIntensity;\n uniform float driftEnabled;\n uniform float driftSpeed;\n uniform float crossWaveEnabled;\n uniform float crossWaveSpeed;\n uniform float ghostMode; // 0.0 = solid, 1.0 = ghost (only visible through bloom)\n uniform float baseOpacity; // Base opacity when not in ghost mode (default 1.0)\n uniform float phaseOffset1; // Phase offset for primary drift (radians)\n uniform float phaseOffset2; // Phase offset for secondary drift (radians)\n uniform float phaseOffset3; // Phase offset for crosswave (radians)\n\n // Blend layer uniforms\n uniform float blendLayer1Mode;\n uniform float blendLayer1Strength;\n uniform float blendLayer1Enabled;\n uniform float blendLayer2Mode;\n uniform float blendLayer2Strength;\n uniform float blendLayer2Enabled;\n\n varying vec3 vPosition;\n varying vec3 vNormal;\n\n // Blend modes (injected from blendModesGLSL)\n ${S}\n\n // Smooth noise function\n float noise3D(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n float n = i.x + i.y * 157.0 + i.z * 113.0;\n vec4 v = fract(sin(vec4(n, n+1.0, n+157.0, n+158.0)) * 43758.5453);\n return mix(mix(v.x, v.y, f.x), mix(v.z, v.w, f.x), f.y);\n }\n\n void main() {\n // Drifting energy clouds - slow, ethereal movement\n // Start with zero energy - only effects add to it\n float driftEnergy = 0.0;\n float crossWaveEnergy = 0.0;\n\n // Spatially triangulated fire bands - each owns a 120° wedge of the geometry\n // Bands can never overlap because they're physically separated\n float angle = atan(vPosition.x, vPosition.z); // -π to π\n float normalizedAngle = (angle + 3.14159) / 6.28318; // 0 to 1\n\n // Determine which zone this fragment belongs to (0, 1, or 2)\n float zone = floor(normalizedAngle * 3.0);\n float zonePos = fract(normalizedAngle * 3.0); // Position within zone (0-1)\n\n // Time-based phase for each zone (120° offset in time)\n float phaseSpeed = 0.15;\n float t = time * phaseSpeed;\n float phase1Time = sin(t + phaseOffset1) * 0.5 + 0.5;\n float phase2Time = sin(t + phaseOffset2) * 0.5 + 0.5;\n float phase3Time = sin(t + phaseOffset3) * 0.5 + 0.5;\n\n // Only ONE phase affects this fragment - the one that owns this spatial zone\n float activePhase = zone < 1.0 ? phase1Time : (zone < 2.0 ? phase2Time : phase3Time);\n\n float primaryDrift = 0.0;\n float secondaryDrift = 0.0;\n\n if (driftEnabled > 0.5) {\n float t = time * driftSpeed;\n // Primary drift - moving in one direction\n float drift1 = noise3D(vPosition * 2.0 + vec3(t, t * 0.7, t * 0.3));\n float drift2 = noise3D(vPosition * 3.0 - vec3(t * 0.5, t, t * 0.8));\n // Use max instead of multiply to avoid near-zero products\n primaryDrift = max(drift1, drift2);\n primaryDrift = max(0.0, primaryDrift - 0.4) * 2.0; // Rescale after threshold\n\n // Secondary drift - offset in opposite direction to fill gaps\n float drift3 = noise3D(vPosition * 2.5 - vec3(t * 0.8, t * 0.4, t));\n float drift4 = noise3D(vPosition * 1.8 + vec3(t * 0.6, t * 0.9, t * 0.2));\n secondaryDrift = max(drift3, drift4);\n secondaryDrift = max(0.0, secondaryDrift - 0.4) * 2.0;\n\n driftEnergy = primaryDrift + secondaryDrift;\n }\n\n // Horizontal cross wave - thin bands sweeping across\n float rawCrossWave = 0.0;\n if (crossWaveEnabled > 0.5) {\n float t = time * crossWaveSpeed;\n float wave = sin(vPosition.x * 4.0 + vPosition.z * 2.0 - t) * 0.5 + 0.5;\n // pow(4) for thin bright bands\n rawCrossWave = pow(wave, 4.0);\n crossWaveEnergy = rawCrossWave;\n }\n\n // Mix the effects - normalize to prevent blowout\n // driftEnergy can be 0-2 (two drifts), rawCrossWave is 0-1\n float normalizedDrift = min(1.0, driftEnergy * 0.5);\n float normalizedWave = rawCrossWave;\n\n // activePhase is 0-1, remap to visibility range\n // 0.53 floor (just above 0.52 threshold), 0.58 ceiling (subtle glow)\n float remappedPhase = 0.53 + activePhase * 0.05;\n\n // Effects add subtle variation (max 0.05)\n float effectContrib = (normalizedDrift * 0.03) + (normalizedWave * 0.02);\n float phasedActivity = remappedPhase + effectContrib;\n\n // Keep unclamped for visibility threshold check (ghost mode needs full range)\n float rawEffectActivity = phasedActivity;\n // Clamp for color intensity (floor: guaranteed visible, ceiling: no blowout)\n float effectActivity = clamp(phasedActivity, 0.53, 0.60);\n\n // Total energy for color calculation (reduced for subtler bloom)\n float totalEnergy = 0.25 + effectActivity * 0.55; // Base glow + effect contribution\n\n // Edge glow - adds rim lighting\n vec3 viewDir = normalize(-vPosition);\n float edgeGlow = 1.0 - abs(dot(vNormal, viewDir));\n edgeGlow = pow(edgeGlow, 2.0) * 0.4;\n\n // Final color before blend layers\n vec3 coreColor = emotionColor * totalEnergy * energyIntensity;\n coreColor += emotionColor * edgeGlow * 0.3;\n\n // Apply blend layers to the entire soul color\n if (blendLayer1Enabled > 0.5) {\n int mode = int(blendLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(coreColor, emotionColor * blendLayer1Strength, mode);\n coreColor = mix(coreColor, blendResult, blendLayer1Strength);\n }\n if (blendLayer2Enabled > 0.5) {\n int mode = int(blendLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(coreColor, emotionColor * blendLayer2Strength, mode);\n coreColor = mix(coreColor, blendResult, blendLayer2Strength);\n }\n\n // Ghost mode: ONLY the traveling fire bands are visible\n // Everything below the threshold is completely invisible\n float alpha = baseOpacity;\n if (ghostMode > 0.01) {\n // High threshold - only the peaks of the thin bands pass through\n float threshold = 0.4 + ghostMode * 0.4; // 0.4-0.8 range\n float visibility = smoothstep(threshold, threshold + 0.05, rawEffectActivity);\n\n // Hard cutoff - only bright fire bands visible\n alpha = visibility * baseOpacity;\n\n // Discard everything that isn't a bright fire band\n if (alpha < 0.05) {\n discard;\n }\n\n // Boost color intensity for visible fire\n coreColor *= 1.2 + visibility * 0.6;\n }\n\n // Output the computed core color\n gl_FragColor = vec4(coreColor, alpha);\n }\n`;class pi{constructor(e={}){this.radius=e.radius||.15,this.detail=e.detail||1,this.geometryType=e.geometryType||"crystal",this.renderer=e.renderer||null,this.assetBasePath=e.assetBasePath||"/assets",this.mesh=null,this.material=null,this.parentMesh=null,this.baseScale=1,this._pendingParent=null,this._disposed=!1,this._createMesh()}static _loadInclusionGeometry(t="/assets"){return ui?Promise.resolve(ui.clone()):di?di.then(e=>e.clone()):(di=new Promise(i=>{(new f).load(`${t}/models/Crystal/inclusion.obj`,t=>{let n=null;if(t.traverse(e=>{e.isMesh&&e.geometry&&({geometry:n}=e)}),n){n.computeBoundingBox();const t=new e.Vector3;n.boundingBox.getCenter(t),n.translate(-t.x,-t.y,-t.z),n.rotateX(Math.PI/2),n.computeBoundingBox();const a=new e.Vector3;n.boundingBox.getSize(a);const s=.3/Math.max(a.x,a.y,a.z);n.scale(s,s,s),n.computeVertexNormals(),ui=n,i(n.clone())}else console.warn("[🔮 SOUL] No mesh in inclusion.obj, using fallback"),i(null)},void 0,e=>{console.warn("[🔮 SOUL] Failed to load inclusion.obj:",e),i(null)})}),di)}_createMesh(){let t;console.log(`[CrystalSoul] _createMesh() START, inclusionGeometryCache=${!!ui}`),this.material=new e.ShaderMaterial({uniforms:{time:{value:0},emotionColor:{value:new e.Color(1,1,1)},energyIntensity:{value:1.5},driftEnabled:{value:1},driftSpeed:{value:.5},crossWaveEnabled:{value:1},crossWaveSpeed:{value:.4},ghostMode:{value:.36},baseOpacity:{value:1},phaseOffset1:{value:0},phaseOffset2:{value:2.094},phaseOffset3:{value:4.189},blendLayer1Mode:{value:2},blendLayer1Strength:{value:2.3},blendLayer1Enabled:{value:1},blendLayer2Mode:{value:0},blendLayer2Strength:{value:1},blendLayer2Enabled:{value:1}},vertexShader:"\n varying vec3 vPosition;\n varying vec3 vNormal;\n\n void main() {\n vPosition = position;\n vNormal = normalize(normalMatrix * normal);\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n",fragmentShader:mi,transparent:!0,depthWrite:!0,depthTest:!0,side:e.FrontSide}),t=ui?ui.clone():new e.OctahedronGeometry(this.radius,this.detail),this.mesh=new e.Mesh(t,this.material),this.mesh.name="crystalSoul",this.mesh.renderOrder=0,this.mesh.layers.set(2)}attachTo(e,t){this._disposed||(e?this.mesh?(this.mesh.parent&&this.mesh.parent.remove(this.mesh),this.parentMesh=e,this._scene=t,t&&!this.mesh.parent&&t.add(this.mesh),this._syncPosition(),this.mesh.visible=!0):console.warn("[CrystalSoul] Cannot attach - mesh is null"):console.warn("[CrystalSoul] Cannot attach to null parent"))}_syncPosition(){this.parentMesh&&this.mesh&&(this.parentMesh.getWorldPosition(this.mesh.position),this.parentMesh.getWorldQuaternion(this.mesh.quaternion))}detach(){this.mesh&&(this.mesh.visible=!1,this.parentMesh=null)}update(e,t,i=1){if(!this.material||!this.material.uniforms)return;this._syncPosition();const{uniforms:n}=this.material;n.time&&(n.time.value+=e/1e3),n.emotionColor&&t&&n.emotionColor.value.setRGB(t[0],t[1],t[2]),n.energyIntensity&&(n.energyIntensity.value=.8),this.mesh&&this.mesh.scale.setScalar(this.baseScale*i)}setSize(e){if(!this.mesh)return;const t=.05+.95*e;this.baseScale=t,this.mesh.scale.setScalar(t)}setEffects(e={}){if(!this.material||!this.material.uniforms)return;const{uniforms:t}=this.material;void 0!==e.driftEnabled&&t.driftEnabled&&(t.driftEnabled.value=e.driftEnabled?1:0),void 0!==e.driftSpeed&&t.driftSpeed&&(t.driftSpeed.value=Math.max(.1,Math.min(3,e.driftSpeed))),void 0!==e.crossWaveEnabled&&t.crossWaveEnabled&&(t.crossWaveEnabled.value=e.crossWaveEnabled?1:0),void 0!==e.crossWaveSpeed&&t.crossWaveSpeed&&(t.crossWaveSpeed.value=Math.max(.1,Math.min(3,e.crossWaveSpeed))),void 0!==e.phaseOffset1&&t.phaseOffset1&&(t.phaseOffset1.value=e.phaseOffset1),void 0!==e.phaseOffset2&&t.phaseOffset2&&(t.phaseOffset2.value=e.phaseOffset2),void 0!==e.phaseOffset3&&t.phaseOffset3&&(t.phaseOffset3.value=e.phaseOffset3)}setColor(e){this.material&&this.material.uniforms&&this.material.uniforms.emotionColor&&this.material.uniforms.emotionColor.value.setRGB(e[0],e[1],e[2])}setBlendLayers(e){if(!this.material||!this.material.uniforms)return;const t=this.material.uniforms;e[0]?(t.blendLayer1Mode&&(t.blendLayer1Mode.value=e[0].mode??0),t.blendLayer1Strength&&(t.blendLayer1Strength.value=e[0].strength??0),t.blendLayer1Enabled&&(t.blendLayer1Enabled.value=e[0].enabled?1:0)):t.blendLayer1Enabled&&(t.blendLayer1Enabled.value=0),e[1]?(t.blendLayer2Mode&&(t.blendLayer2Mode.value=e[1].mode??0),t.blendLayer2Strength&&(t.blendLayer2Strength.value=e[1].strength??0),t.blendLayer2Enabled&&(t.blendLayer2Enabled.value=e[1].enabled?1:0)):t.blendLayer2Enabled&&(t.blendLayer2Enabled.value=0)}isAttached(){return null!==this.parentMesh&&null!==this.mesh&&null!==this.mesh.parent}setVisible(e){this.mesh&&(this.mesh.visible=e)}setGhostMode(e){this.material&&this.material.uniforms&&this.material.uniforms.ghostMode&&(this.material.uniforms.ghostMode.value=e?1:0)}setBaseOpacity(e){this.material&&this.material.uniforms&&this.material.uniforms.baseOpacity&&(this.material.uniforms.baseOpacity.value=Math.max(0,Math.min(1,e)))}dispose(){if(this._disposed)return;this._disposed=!0,this.mesh&&(this.mesh.visible=!1);const e=this.mesh,t=this.material;e?.parent&&e.parent.remove(e),this.mesh=null,this.material=null,this.parentMesh=null,requestAnimationFrame(()=>{e?.geometry&&e.geometry.dispose(),t&&t.dispose()})}}class gi{constructor(e=50,t={}){this.maxParticles=e,this.options=t,this.geometry=null,this.material=null,this.points=null,this.positions=null,this.sizes=null,this.colors=null,this.alphas=null,this.glowIntensities=null,this.depths=null,this.styles=null,this.particleCount=0,this.gestureEffects={firefly:!1,flicker:!1,shimmer:!1,glow:!1,time:0},this._initGeometry(),this._initMaterial(),this._initPoints()}_initGeometry(){this.geometry=new e.BufferGeometry;const{maxParticles:t}=this;this.positions=new Float32Array(3*t),this.sizes=new Float32Array(t),this.colors=new Float32Array(3*t),this.alphas=new Float32Array(t),this.glowIntensities=new Float32Array(t),this.depths=new Float32Array(t),this.styles=new Float32Array(t),this.geometry.setAttribute("position",new e.BufferAttribute(this.positions,3)),this.geometry.setAttribute("size",new e.BufferAttribute(this.sizes,1)),this.geometry.setAttribute("customColor",new e.BufferAttribute(this.colors,3)),this.geometry.setAttribute("alpha",new e.BufferAttribute(this.alphas,1)),this.geometry.setAttribute("glowIntensity",new e.BufferAttribute(this.glowIntensities,1)),this.geometry.setAttribute("depth",new e.BufferAttribute(this.depths,1)),this.geometry.setAttribute("style",new e.BufferAttribute(this.styles,1)),this.geometry.attributes.position.setUsage(e.DynamicDrawUsage),this.geometry.attributes.size.setUsage(e.DynamicDrawUsage),this.geometry.attributes.customColor.setUsage(e.DynamicDrawUsage),this.geometry.attributes.alpha.setUsage(e.DynamicDrawUsage),this.geometry.attributes.glowIntensity.setUsage(e.DynamicDrawUsage),this.geometry.attributes.depth.setUsage(e.DynamicDrawUsage),this.geometry.attributes.style.setUsage(e.DynamicDrawUsage),this.geometry.setDrawRange(0,0)}_initMaterial(){this.material=new e.ShaderMaterial({uniforms:{coreScale:{value:1},viewportHeight:{value:600},pixelRatio:{value:1}},vertexShader:"\n/**\n * Particle Vertex Shader - Simple 2D-style particles in 3D space\n * Matches the 2D canvas particle appearance\n */\n\n// Per-particle attributes\nattribute float size;\nattribute vec3 customColor;\nattribute float alpha;\nattribute float glowIntensity;\nattribute float style; // 0.0 = solid/gradient, 1.0 = cell-shaded (ring with transparent center)\n\n// Uniforms\nuniform float coreScale;\nuniform float viewportHeight;\nuniform float pixelRatio;\n\n// Varying to fragment shader\nvarying vec3 vColor;\nvarying float vAlpha;\nvarying float vGlowIntensity;\nvarying float vStyle;\n\nvoid main() {\n // Pass attributes to fragment shader\n vColor = customColor;\n vAlpha = alpha;\n vGlowIntensity = glowIntensity;\n vStyle = style;\n\n // Calculate position in clip space\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n\n // Calculate point size with perspective scaling\n float perspectiveScale = coreScale * (75.0 / length(mvPosition.xyz)) * (viewportHeight / 600.0) / pixelRatio;\n gl_PointSize = size * perspectiveScale;\n\n // Final position\n gl_Position = projectionMatrix * mvPosition;\n}\n",fragmentShader:"\n/**\n * Particle Fragment Shader - Solid colored circles matching 2D appearance\n * Uses premultiplied alpha for proper blending\n */\n\nvarying vec3 vColor;\nvarying float vAlpha;\nvarying float vGlowIntensity;\nvarying float vStyle;\n\nvoid main() {\n // Distance from center (0 at center, 0.5 at edge)\n vec2 center = gl_PointCoord - vec2(0.5);\n float dist = length(center);\n\n // Hard circle cutoff - discard everything outside\n if (dist > 0.45) {\n discard;\n }\n\n vec3 finalColor = vColor;\n\n // Base opacity from particle (already includes baseOpacity variation)\n float alpha = vAlpha;\n\n // Gesture glow boost\n if (vGlowIntensity >= 2.0) {\n float gestureBoost = (vGlowIntensity - 2.0) / 13.0;\n finalColor *= (1.0 + gestureBoost * 0.5);\n alpha = min(alpha * (1.0 + gestureBoost * 0.3), 1.0);\n }\n\n // Cell-shaded particles are slightly more opaque\n float opacityBoost = vStyle > 0.5 ? 1.0 : 0.85;\n alpha *= opacityBoost;\n\n // Output with proper alpha for blending\n // Premultiply alpha for correct compositing\n gl_FragColor = vec4(finalColor * alpha, alpha);\n}\n",transparent:!0,blending:e.CustomBlending,blendSrc:e.OneFactor,blendDst:e.OneMinusSrcAlphaFactor,blendSrcAlpha:e.OneFactor,blendDstAlpha:e.OneMinusSrcAlphaFactor,depthWrite:!1,depthTest:!0})}_initPoints(){this.points=new e.Points(this.geometry,this.material),this.points.frustumCulled=!0}updateParticles(e,t,i,n,a,s,o,r,l){this.particleCount=Math.min(e.length,this.maxParticles),void 0!==r&&(this.material.uniforms.coreScale.value=r),n&&n.height&&(this.material.uniforms.viewportHeight.value=n.height),this.options.renderer&&(this.material.uniforms.pixelRatio.value=this.options.renderer.getPixelRatio()),this.gestureEffects.time+=.016,this.gestureEffects.time>2*Math.PI&&(this.gestureEffects.time=this.gestureEffects.time%(2*Math.PI)),a&&s&&t.updateRotationState(a,s,o);for(let a=0;a<this.particleCount;a++){const s=e[a];if(!s.isAlive()){this.alphas[a]=0;continue}const o=t.translate2DTo3D(s,i,n);if(("crystal"===l||"heart"===l||"rough"===l)&&o.z>.15){this.alphas[a]=0;continue}const r=3*a;this.positions[r+0]=o.x,this.positions[r+1]=o.y,this.positions[r+2]=o.z;const h=s.getDepthAdjustedSize?s.getDepthAdjustedSize():s.size,c="popcorn"===s.behavior?1.2:.85;this.sizes[a]=h*c;const u=this._parseColor(s.color||"#ffffff"),d=3*a;this.colors[d+0]=u.r,this.colors[d+1]=u.g,this.colors[d+2]=u.b,this.alphas[a]=s.opacity*(s.baseOpacity||1);let m=s.hasGlow?1*(s.glowSizeMultiplier||1.5):0;m=this._applyGestureEffects(s,m,a),this.glowIntensities[a]=m;const p=.5*(1-s.z);this.depths[a]=Math.max(0,Math.min(1,p)),this.styles[a]=s.isCellShaded?1:0}this.geometry.attributes.position.needsUpdate=!0,this.geometry.attributes.size.needsUpdate=!0,this.geometry.attributes.customColor.needsUpdate=!0,this.geometry.attributes.alpha.needsUpdate=!0,this.geometry.attributes.glowIntensity.needsUpdate=!0,this.geometry.attributes.depth.needsUpdate=!0,this.geometry.attributes.style.needsUpdate=!0,this.geometry.setDrawRange(0,this.particleCount)}_applyGestureEffects(e,t,i){let n=t;if(this.gestureEffects.firefly){const t=(.01*e.x+.01*e.y+.1*e.size)%(2*Math.PI),i=2+.5*(Math.sin(3*this.gestureEffects.time+t)+1)*10;n=Math.max(n,i)}if(this.gestureEffects.flicker){const t=(.02*e.x+.02*e.y)%(2*Math.PI),a=15*this.gestureEffects.time,s=.5*(Math.sin(a+t)+1),o=Math.floor(10*a+i),r=2+10*(.3*s+.5*(Math.sin(123.456*o)+1)*.7);n=Math.max(n,r)}if(this.gestureEffects.shimmer){const t=e.x-(this.gestureEffects.centerX||0),i=e.y-(this.gestureEffects.centerY||0),a=Math.sqrt(t*t+i*i)/200,s=2+.5*(Math.sin(3*this.gestureEffects.time-a)+1)*8;n=Math.max(n,s)}if(this.gestureEffects.glow){const e=this.gestureEffects.glowProgress||0,t=3+12*Math.sin(e*Math.PI);n=Math.max(n,t)}return n}_parseColor(e){const t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?{r:parseInt(t[1],16)/255,g:parseInt(t[2],16)/255,b:parseInt(t[3],16)/255}:{r:1,g:1,b:1}}setGestureEffects(e){if(!e)return this.gestureEffects.firefly=!1,this.gestureEffects.flicker=!1,this.gestureEffects.shimmer=!1,void(this.gestureEffects.glow=!1);this.gestureEffects.firefly=e.fireflyEffect||!1,this.gestureEffects.flicker=e.flickerEffect||!1,this.gestureEffects.shimmer=e.shimmerEffect||!1,this.gestureEffects.glow=e.glowEffect||!1,this.gestureEffects.glowProgress=e.glowProgress,this.gestureEffects.centerX=e.centerX,this.gestureEffects.centerY=e.centerY}getPoints(){return this.points}setVisible(e){this.points.visible=e}resize(e){e!==this.maxParticles&&(this.geometry&&this.geometry.dispose(),this.maxParticles=e,this._initGeometry(),this.points&&(this.points.geometry=this.geometry))}cleanupParticleStates(e){for(const t of e)!t.isAlive()&&t.behaviorData&&(t.behaviorData.direction3D&&(t.behaviorData.direction3D=null),t.behaviorData.orbitPlane&&(t.behaviorData.orbitPlane=null),t.behaviorData.orbitPath&&(t.behaviorData.orbitPath=null),t.behaviorData=null)}dispose(){this.geometry&&this.geometry.dispose(),this.material&&this.material.dispose(),this.positions=null,this.sizes=null,this.colors=null,this.alphas=null,this.glowIntensities=null,this.depths=null,this.styles=null}}class fi{constructor(){this.cachedConfigs=new Map,this.maxCacheSize=100}calculate(e,t=null){const i=`${e}:${t||"none"}`;if(this.cachedConfigs.has(i))return this.cachedConfigs.get(i);const n=me(e);if(!n)return console.warn(`[ParticleEmotionCalculator] Unknown emotion: ${e}`),this._getDefaultConfig();const a=this._extractBaseConfig(n,e),s=this._applyUndertoneModifiers(a,t),o=this._applySpecialBehaviors(s,e);if(this.cachedConfigs.size>=this.maxCacheSize){const e=this.cachedConfigs.keys().next().value;this.cachedConfigs.delete(e)}return this.cachedConfigs.set(i,o),o}_extractBaseConfig(e,t){const i=e.visual||{};return{behavior:i.particleBehavior||"ambient",rate:i.particleRate||1,min:void 0!==i.minParticles?i.minParticles:0,max:void 0!==i.maxParticles?i.maxParticles:10,colors:i.particleColors||null,emotion:t}}_applyUndertoneModifiers(e,t){if(!t)return e;const i=vt(t);if(!i||!i.particles)return e;const n=i.particles,a={...e};return n.behaviorOverride&&(a.behavior=n.behaviorOverride),n.rateMultiplier&&(a.rate=e.rate*n.rateMultiplier,a.max=Math.floor(e.max*n.rateMultiplier)),void 0!==n.minParticles&&(a.min=n.minParticles),void 0!==n.maxParticles&&(a.max=n.maxParticles),a}_applySpecialBehaviors(e,t){return"zen"===t?{...e,specialBehavior:"zen-mixing"}:e}selectZenBehavior(){return Math.random()<.6?"falling":"orbiting"}_getDefaultConfig(){return{behavior:"ambient",rate:1,min:0,max:10,colors:null,emotion:"neutral"}}clearCache(){this.cachedConfigs.clear()}getCacheSize(){return this.cachedConfigs.size}}class yi{constructor(){this.previousGesture=null}extract(e,t){if(!e||0===e.length)return this.previousGesture=null,null;const i=e[0],n=this._calculateProgress(i,t);if(n>=1)return this.previousGesture=null,null;const a=this._extractGestureName(i);if(!a)return null;const s=this._buildGestureMotion(i,a);return this.previousGesture=a,{motion:s,progress:n,config:i.config||{},gestureName:a,animation:i}}_calculateProgress(e,t){const i=(t-e.startTime)/e.duration;return Math.max(0,Math.min(1,i))}_extractGestureName(e){return e.gestureName||e.name||e.config?.gestureName||null}_buildGestureMotion(e,t){const i=e.config||{};return{type:t,amplitude:i.amplitude||1,strength:i.strength||1,wobbleAmount:i.wobbleAmount||0,duration:e.duration}}hasGestureChanged(e){return!(!e&&!this.previousGesture||(e||!this.previousGesture)&&(!e||this.previousGesture)&&e.gestureName===this.previousGesture)}extractAll(e,t){if(!e||0===e.length)return[];const i=[];for(const n of e){const e=this._calculateProgress(n,t);if(e>=1)continue;const a=this._extractGestureName(n);if(!a)continue;const s=this._buildGestureMotion(n,a);i.push({motion:s,progress:e,config:n.config||{},gestureName:a,animation:n})}return i}reset(){this.previousGesture=null}}class vi{constructor(){this.effectMap={sparkle:this.buildFireflyEffect.bind(this),twinkle:this.buildFireflyEffect.bind(this),flicker:this.buildFlickerEffect.bind(this),shimmer:this.buildShimmerEffect.bind(this),glow:this.buildGlowEffect.bind(this),burst:this.buildGlowEffect.bind(this),flash:this.buildFlickerEffect.bind(this)}}build(e,t,i){if(!e||!e.motion)return null;const{gestureName:n}=e,a=this.effectMap[n];return a?a(e,t,i):null}buildFireflyEffect(e,t,i){const n=e.config||{};return{fireflyEffect:!0,fireflyTime:.001*Date.now(),particleGlow:n.particleGlow||2,centerX:t,centerY:i}}buildFlickerEffect(e,t,i){const n=e.config||{};return{flickerEffect:!0,flickerTime:.001*Date.now(),particleGlow:n.particleGlow||2,centerX:t,centerY:i}}buildShimmerEffect(e,t,i){const n=e.config||{},a=e.progress||0;return{shimmerEffect:!0,shimmerTime:.001*Date.now(),shimmerWave:a*Math.PI*2,particleGlow:n.particleGlow||1.2,centerX:t,centerY:i}}buildGlowEffect(e,t,i){const n=e.config||{};return{glowEffect:!0,glowProgress:e.progress||0,particleGlow:n.particleGlow||2,centerX:t,centerY:i}}registerEffect(e,t){this.effectMap[e]=t.bind(this)}hasEffect(e){return!!this.effectMap[e]}getEffectGestures(){return Object.keys(this.effectMap)}buildAll(e,t,i){if(!e||0===e.length)return[];const n=[];for(const a of e){const e=this.build(a,t,i);e&&n.push(e)}return n}mergeEffects(e){if(!e||0===e.length)return null;if(1===e.length)return e[0];const t={};for(const i of e)Object.assign(t,i);return t}destroy(){this.effectMap=null}}class bi{constructor(e,t,i){this.particleSystem=e,this.translator=t,this.renderer=i,this.emotionCalculator=new fi,this.gestureExtractor=new yi,this.effectsBuilder=new vi,this.currentEmotion=null,this.currentUndertone=null,this.currentConfig=null}update(e,t,i,n,a,s,o,r,l,h){void 0!==h&&this.translator.setCoreRadius3D(h);const c=this._updateEmotionConfig(t,i),u=this.gestureExtractor.extract(n,a);this._spawnParticles(c,e,o),this._updatePhysics(c,u,e,o,i),this._updateRendering(u,s,o,r,e,l)}_updateEmotionConfig(e,t){return this.currentEmotion===e&&this.currentUndertone===t||(this.currentEmotion=e,this.currentUndertone=t,this.currentConfig=this.emotionCalculator.calculate(e,t),this.particleSystem.clear()),this.currentConfig}_spawnParticles(e,t,i){const n=i.width/2,a=i.height/2;let s=e.behavior;"zen-mixing"===e.specialBehavior&&(s=this.emotionCalculator.selectZenBehavior()),this.particleSystem.spawn(s,e.emotion,e.rate,n,a,t,null,e.min,e.max,1,1,e.colors,this.currentUndertone)}_updatePhysics(e,t,i,n,a){const s=n.width/2,o=n.height/2,r=a?{undertone:a}:null;this.particleSystem.update(i,s,o,t?t.motion:null,t?t.progress:0,r)}_updateRendering(e,t,i,n,a,s){const o=i.width/2,r=i.height/2,l=e?this.effectsBuilder.build(e,o,r):null;this.renderer.updateParticles(this.particleSystem.particles,this.translator,t,i,n,a,e,s,this.geometryType),this.renderer.setGestureEffects(l)}setEmotion(e,t=null){this.currentEmotion=null,this.currentUndertone=null}setGeometryType(e){this.geometryType=e}clear(){this.particleSystem.clear()}setEnabled(e){this.renderer.setVisible(e),e||this.clear()}getParticleCount(){return this.particleSystem.particles.length}getCurrentConfig(){return this.currentConfig}registerEffect(e,t){this.effectsBuilder.registerEffect(e,t)}destroy(){this.particleSystem.destroy(),this.renderer.dispose(),this.translator&&(this.translator.dispose?.(),this.translator=null),this.emotionCalculator.clearCache(),this.emotionCalculator=null,this.gestureExtractor.reset(),this.gestureExtractor=null,this.effectsBuilder&&(this.effectsBuilder.destroy?.(),this.effectsBuilder=null)}}const wi="off",Mi="annular",Si="total",xi={[wi]:{shadowCoverage:0,coronaIntensity:1,coronaRaysEnabled:!1,baileyBeadsEnabled:!1,baileyBeadsCount:0,baileyBeadsSize:0},[Mi]:{shadowCoverage:.95,coronaIntensity:.8,coronaRaysEnabled:!1,baileyBeadsEnabled:!0,baileyBeadsCount:12,baileyBeadsSize:.015},[Si]:{shadowCoverage:1.019,coronaIntensity:4,coronaRaysEnabled:!0,baileyBeadsEnabled:!0,baileyBeadsCount:6,baileyBeadsSize:.025}};function Ci(e){return xi[e]||xi[wi]}class Di{constructor(t,i){this.scene=t,this.sunRadius=i,this.heroBeadCount=3,this.supportBeadCount=15,this.beadCount=this.heroBeadCount+this.supportBeadCount,this.beads=[],this.visible=!1,this._directionToCamera=new e.Vector3,this._up=new e.Vector3(0,1,0),this._right=new e.Vector3,this._upVector=new e.Vector3,this._beadOffset=new e.Vector3,this._tempColor=new e.Color,this.sharedTexture=null,this.createBeads()}createBeads(){const t=document.createElement("canvas");t.width=64,t.height=64;const i=t.getContext("2d"),n=i.createRadialGradient(32,32,0,32,32,32);n.addColorStop(0,"rgba(255, 255, 255, 1.0)"),n.addColorStop(.1,"rgba(255, 255, 255, 0.9)"),n.addColorStop(.3,"rgba(255, 240, 200, 0.6)"),n.addColorStop(.6,"rgba(255, 220, 150, 0.2)"),n.addColorStop(1,"rgba(255, 200, 100, 0.0)"),i.fillStyle=n,i.fillRect(0,0,64,64);const a=new e.CanvasTexture(t);a.needsUpdate=!0,this.sharedTexture=a;const s=this.generateLunarValleys();for(let t=0;t<this.beadCount;t++){const i=new e.Group,n=new e.SpriteMaterial({map:a.clone(),blending:e.AdditiveBlending,transparent:!0,depthWrite:!1,opacity:0,color:this._tempColor.setRGB(1,.3,.3)}),o=new e.Sprite(n);o.scale.set(.08,.08,1),i.add(o);const r=new e.SpriteMaterial({map:a.clone(),blending:e.AdditiveBlending,transparent:!0,depthWrite:!1,opacity:0,color:this._tempColor.setRGB(.8,1,.8)}),l=new e.Sprite(r);l.scale.set(.08,.08,1),i.add(l);const h=new e.SpriteMaterial({map:a,blending:e.AdditiveBlending,transparent:!0,depthWrite:!1,opacity:0,color:this._tempColor.setRGB(.3,.5,1)}),c=new e.Sprite(h);c.scale.set(.08,.08,1),i.add(c),i.userData={angle:s[t].angle,depth:s[t].depth,baseIntensity:s[t].baseIntensity,isHero:s[t].isHero,sizeMultiplier:s[t].isHero?1.5:1,targetOpacity:0,currentOpacity:0,redSprite:o,greenSprite:l,blueSprite:c},this.beads.push(i),this.scene.add(i)}}generateLunarValleys(){const e=[];let t=12345;const i=()=>(t=(9301*t+49297)%233280,t/233280),n=i()*Math.PI*2;for(let t=0;t<this.heroBeadCount;t++){const a=n+t*Math.PI*2/3;e.push({angle:a,depth:.8+.2*i(),baseIntensity:.8+.2*i(),isHero:!0})}for(let t=0;t<this.supportBeadCount;t++){const a=n+Math.floor(t/(this.supportBeadCount/3))*Math.PI*2/3,s=1.2*(i()-.5);e.push({angle:a+s,depth:.3+.5*i(),baseIntensity:.4+.4*i(),isHero:!1})}return e}update(e,t,i,n,a=1){const s=this.sunRadius*a*1,o=e.position;this._directionToCamera.subVectors(o,t).normalize(),this._right.crossVectors(this._directionToCamera,this._up).normalize(),this._upVector.crossVectors(this._right,this._directionToCamera).normalize();for(const e of this.beads){const{angle:i,redSprite:n,greenSprite:o,blueSprite:r,sizeMultiplier:l}=e.userData,h=Math.cos(i)*s,c=Math.sin(i)*s;this._beadOffset.set(0,0,0),this._beadOffset.addScaledVector(this._right,h),this._beadOffset.addScaledVector(this._upVector,c),this._beadOffset.addScaledVector(this._directionToCamera,.01*s);const u=t.x+this._beadOffset.x,d=t.y+this._beadOffset.y,m=t.z+this._beadOffset.z,p=.008*a,g=Math.cos(i)*p,f=Math.sin(i)*p;n.position.set(g,f,.001),o.position.set(0,0,0),r.position.set(-g,-f,-.001),e.position.set(u,d,m),e.updateMatrixWorld(!0);const y=.15*a*l;n.scale.set(y,y,1),o.scale.set(y,y,1),r.scale.set(y,y,1)}if(this.visible){const e=.9,t=.97,n=1;for(const a of this.beads){let s=0;if(i>=e&&i<n){const o=(i-e)/(n-e)*Math.PI*2,r=Math.abs((a.userData.angle-o+Math.PI)%(2*Math.PI)-Math.PI);let l=1;i<t&&(l=(i-e)/(t-e)),s=Math.max(0,1-r/1)*a.userData.baseIntensity*l*a.userData.depth,s*=200}a.userData.targetOpacity=s}}else for(const e of this.beads)e.userData.targetOpacity=0;for(const e of this.beads){const{redSprite:t,greenSprite:i,blueSprite:a}=e.userData,s=e.userData.targetOpacity-e.userData.currentOpacity;e.userData.currentOpacity+=3*s*(n/1e3),e.userData.currentOpacity<.001&&(e.userData.currentOpacity=0),t.material.opacity=.7*e.userData.currentOpacity,i.material.opacity=1*e.userData.currentOpacity,a.material.opacity=.7*e.userData.currentOpacity}}setVisible(e){this.visible=e}dispose(){for(const e of this.beads){const{redSprite:t,greenSprite:i,blueSprite:n}=e.userData;t.material.map&&t.material.map.dispose(),t.material.dispose(),i.material.map&&i.material.map.dispose(),i.material.dispose(),n.material.map&&n.material.map.dispose(),n.material.dispose(),this.scene.remove(e)}this.beads=[],this.sharedTexture&&(this.sharedTexture.dispose(),this.sharedTexture=null),this._directionToCamera=null,this._up=null,this._right=null,this._upVector=null,this._beadOffset=null,this._tempColor=null,this.scene=null}}class Pi{constructor(t,i,n=null){this.scene=t,this.sunRadius=i,this.sunMesh=n,this.eclipseType=wi,this.previousEclipseType=wi,this.enabled=!1,this.time=0,this.randomSeed=12345,this.isTransitioning=!1,this.transitionProgress=0,this.transitionDuration=400,this.transitionDirection="in",this.manualControl=!1,this.customShadowCoverage=void 0,this._directionToCamera=new e.Vector3,this._up=new e.Vector3(0,1,0),this._right=new e.Vector3,this._upVector=new e.Vector3,this._tempOffset=new e.Vector3,this._tempColor=new e.Color,this.createShadowDisk(),this.createCoronaDisk(),this.createCounterCoronaDisk(),this.sunMesh&&(this.scene.remove(this.coronaDisk),this.scene.remove(this.counterCoronaDisk),this.sunMesh.add(this.coronaDisk),this.sunMesh.add(this.counterCoronaDisk)),this.baileysBeads=new Di(t,i)}createShadowDisk(){const t=this.sunRadius,i=new e.CircleGeometry(t,256),n=new e.MeshBasicMaterial({color:0,transparent:!0,opacity:1,blending:e.MultiplyBlending,premultipliedAlpha:!0,side:e.DoubleSide,depthWrite:!1,depthTest:!1,fog:!1});this.shadowDisk=new e.Mesh(i,n),this.shadowDisk.renderOrder=1e4,this.shadowDisk.position.set(200,0,0),this.scene.add(this.shadowDisk)}createCoronaDisk(){const t=2.05*this.sunRadius,i=.6*this.sunRadius,n=new e.RingGeometry(i,t,256),a=new e.ShaderMaterial({uniforms:{time:{value:0},glowColor:{value:new e.Color(.9,.95,1)},intensity:{value:2.4},randomSeed:{value:this.randomSeed},uvRotation:{value:0},rayElongation:{value:1},uberHeroElongation:{value:1},isTotalEclipse:{value:0},layer1Mode:{value:11},layer1Strength:{value:2.155},layer1Enabled:{value:1},layer2Mode:{value:5},layer2Strength:{value:.695},layer2Enabled:{value:1},layer3Mode:{value:0},layer3Strength:{value:1},layer3Enabled:{value:0},layer4Mode:{value:0},layer4Strength:{value:1},layer4Enabled:{value:0}},vertexShader:"\n uniform float uvRotation;\n varying vec2 vUv;\n\n void main() {\n // Rotate UVs around center (0.5, 0.5)\n vec2 centeredUV = uv - 0.5;\n float cosRot = cos(uvRotation);\n float sinRot = sin(uvRotation);\n mat2 rotMatrix = mat2(cosRot, -sinRot, sinRot, cosRot);\n vec2 rotatedUV = rotMatrix * centeredUV;\n vUv = rotatedUV + 0.5;\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }\n ",fragmentShader:`\n uniform float time;\n uniform vec3 glowColor;\n uniform float intensity;\n uniform float randomSeed;\n uniform float rayElongation;\n uniform float uberHeroElongation;\n uniform float isTotalEclipse;\n\n // Blend Layer Uniforms (up to 4 layers)\n uniform float layer1Mode;\n uniform float layer1Strength;\n uniform float layer1Enabled;\n\n uniform float layer2Mode;\n uniform float layer2Strength;\n uniform float layer2Enabled;\n\n uniform float layer3Mode;\n uniform float layer3Strength;\n uniform float layer3Enabled;\n\n uniform float layer4Mode;\n uniform float layer4Strength;\n uniform float layer4Enabled;\n\n varying vec2 vUv;\n\n // ═══════════════════════════════════════════════════════════════════════════\n // UNIVERSAL BLEND MODES (injected from utils/blendModes.js)\n // ═══════════════════════════════════════════════════════════════════════════\n ${S}\n\n // Hash function for pseudo-random variation\n float hash(float n) {\n return fract(sin(n) * 43758.5453123);\n }\n\n // 2D hash for more variation\n float hash2(vec2 p) {\n return fract(sin(dot(p, vec2(12.9898 + randomSeed, 78.233 + randomSeed))) * 43758.5453);\n }\n\n void main() {\n // Calculate distance and angle from center\n vec2 center = vec2(0.5, 0.5);\n vec2 toCenter = vUv - center;\n float dist = length(toCenter) * 2.0; // Normalize to 0-1 range\n float angle = atan(toCenter.y, toCenter.x); // UVs are already rotated in vertex shader\n\n // Shadow edge - where corona rays start\n // Ring inner edge is at (sunRadius*0.85)/coronaRadius = 0.765/1.845 = 0.415\n // Start rays at sun's geometric edge (0.488) so they don't show inside sun\n float shadowEdge = 0.488;\n\n // Varied radial streamer pattern with artistic composition\n float rayIntensity = 0.0;\n\n // RULE OF THIRDS: Place 3 hero rays at compositionally strong points\n // Golden angles based on rule of thirds: 1/3, 2/3, and offset positions\n float heroAngles[3];\n heroAngles[0] = hash(randomSeed * 1.234) * 6.28318; // First hero ray (random rotation)\n heroAngles[1] = heroAngles[0] + 2.0944; // 120° apart (1/3 circle)\n heroAngles[2] = heroAngles[0] + 4.1888; // 240° apart (2/3 circle)\n\n // Process hero rays first (3 extra-long dramatic rays)\n for (int h = 0; h < 3; h++) {\n float rayAngle = heroAngles[h];\n float angleDiff = abs(mod(angle - rayAngle + 3.14159, 6.28318) - 3.14159);\n\n // Hero rays: extra long and prominent (fit within 0.535 normalized space)\n float baseHeroLength = 0.45 + hash(float(h) * 31.415 + randomSeed) * 0.08; // 0.45 to 0.53 (max available, longer!)\n\n // Apply UBER elongation: hero rays ALWAYS get extreme elongation (regardless of angle)\n // This creates 3 dramatic streamers that extend far in their respective directions\n float heroLength = baseHeroLength * uberHeroElongation;\n\n // Uber hero rays: keep them narrow but visible for dramatic pointy effect\n // Width scales with elongation to stay sharp but visible\n float baseHeroWidth = 0.15 + hash(float(h) * 27.183 + randomSeed) * 0.15; // 0.15 to 0.3 base width\n float narrowingFactor = mix(1.0, 0.3, (uberHeroElongation - 1.0) / max(uberHeroElongation, 1.0)); // 1.0 → 0.3 (70% narrower at max elongation)\n float heroWidth = baseHeroWidth * narrowingFactor; // Narrow when elongated = pointy!\n\n float distFromEdge = dist - shadowEdge;\n\n // Ghostly ethereal taper - very gradual falloff\n float taper = pow(1.0 - clamp(distFromEdge / max(heroLength, 0.001), 0.0, 1.0), 3.0);\n float rayWidth = heroWidth * taper;\n\n // Soft feathered edges instead of hard cutoff\n float edgeSoftness = 0.15; // Wider feather for smooth edges\n float angularMask = smoothstep(rayWidth + edgeSoftness, rayWidth - edgeSoftness, angleDiff);\n\n // Very gentle radial falloff for ethereal look\n float radialFalloff = pow(taper, 0.8);\n\n // Soft radial range with feathered ends\n float radialMask = smoothstep(-0.1, 0.05, distFromEdge) *\n smoothstep(heroLength + 0.15, heroLength - 0.05, distFromEdge);\n\n float heroIntensity = angularMask * radialFalloff * radialMask * 0.7; // Reduced intensity for ghostly effect\n rayIntensity = max(rayIntensity, heroIntensity);\n }\n\n // 20 supporting rays with rule-of-thirds-aware distribution\n for (float i = 0.0; i < 20.0; i++) {\n // Cluster more rays around hero ray positions (rule of thirds)\n float clusterTarget = mod(i, 3.0); // Which hero ray to cluster near\n float clusterAngle = heroAngles[int(clusterTarget)];\n\n // Base distribution with clustering tendency\n float spreadAngle = (i / 20.0) * 6.28318;\n float clusterPull = (hash(i * 13.579 + randomSeed) - 0.5) * 1.5; // Stronger variation\n float rayAngle = spreadAngle + clusterPull;\n\n float angleDiff = abs(mod(angle - rayAngle + 3.14159, 6.28318) - 3.14159);\n\n // Unique random values per ray\n float random1 = hash(i * 12.9898 + randomSeed);\n float random2 = hash(i * 78.233 + randomSeed);\n float random3 = hash(i * 37.719 + randomSeed);\n float random4 = hash(i * 93.989 + randomSeed);\n\n // Varied lengths following power law distribution (more short, fewer long)\n float lengthVariation = random1 * random1; // Squared for naturalistic distribution\n float baseRayLength = 0.1 + lengthVariation * 0.7; // 0.1 to 0.8\n\n // 20% chance of long streamers (supporting the hero rays)\n float isLong = step(0.80, random2);\n baseRayLength = mix(baseRayLength, 0.7 + random3 * 0.6, isLong); // 0.7 to 1.3\n\n // Apply directional elongation: rays pointing up/down (vertical) get elongated\n float verticalWeight = abs(sin(rayAngle));\n float elongationFactor = mix(1.0, rayElongation, verticalWeight);\n float rayLength = baseRayLength * elongationFactor;\n\n // EQUATORIAL ASYMMETRY (total eclipse only): rays along equator are more prominent\n // Solar minimum: streamers cluster along equatorial plane\n float equatorialWeight = abs(cos(rayAngle)); // 1.0 at horizontal, 0.0 at vertical\n float asymmetryBoost = mix(1.0, 1.0 + equatorialWeight * 0.5, isTotalEclipse);\n rayLength *= asymmetryBoost;\n\n // Varied widths with power law (more thin, fewer thick)\n float baseWidth = 0.03 + (random4 * random4) * 0.2; // 0.03 to 0.23 (naturally varied)\n\n // Taper: wide at base, narrow at tip\n float distFromEdge = dist - shadowEdge;\n\n // Ghostly ethereal taper - very gradual falloff\n float taper = pow(1.0 - clamp(distFromEdge / max(rayLength, 0.001), 0.0, 1.0), 3.5);\n float rayWidth = baseWidth * taper;\n\n // Soft feathered edges for ethereal wisps\n float edgeSoftness = 0.10; // Wider feather for smooth edges\n float angularMask = smoothstep(rayWidth + edgeSoftness, rayWidth - edgeSoftness, angleDiff);\n\n // Very gentle radial falloff for ghostly appearance\n float radialFalloff = pow(taper, 1.0);\n\n // Soft radial range with feathered ends\n float radialMask = smoothstep(-0.08, 0.03, distFromEdge) *\n smoothstep(rayLength + 0.12, rayLength - 0.03, distFromEdge);\n\n float streamerIntensity = angularMask * radialFalloff * radialMask * 0.5; // Reduced for ethereal wisps\n rayIntensity = max(rayIntensity, streamerIntensity);\n }\n\n // Base corona glow - thinner during total eclipse for realism\n float baseGlowWidth = mix(0.04, 0.015, isTotalEclipse); // Thinner during totality\n float baseGlow = smoothstep(shadowEdge - 0.01, shadowEdge, dist) *\n (1.0 - smoothstep(shadowEdge + baseGlowWidth * 0.5, shadowEdge + baseGlowWidth, dist));\n\n // Enhanced gradient: white → cool blue-white → deep blue with distance\n // Distance normalized to corona extent (0 = shadow edge, 1 = far corona)\n float coronaDist = clamp((dist - shadowEdge) / 0.6, 0.0, 1.0);\n\n // ═══════════════════════════════════════════════════════════════════════════\n // TOTAL ECLIPSE ENHANCEMENTS (scaled continuously by isTotalEclipse 0.0-1.0)\n // ═══════════════════════════════════════════════════════════════════════════\n\n // 1. CHROMOSPHERE RED RIM - thin pink/red ring at sun's edge (hydrogen emission)\n float rimStart = shadowEdge;\n float rimEnd = shadowEdge + 0.025;\n float chromosphereRim = smoothstep(rimStart - 0.005, rimStart, dist) *\n (1.0 - smoothstep(rimEnd - 0.01, rimEnd, dist));\n chromosphereRim *= 0.6 * isTotalEclipse; // Scale by eclipse progress\n vec3 chromosphereColor = vec3(1.0, 0.3, 0.4); // Pink-red (H-alpha emission)\n\n // 2. STRONGER BRIGHTNESS FALLOFF - inner corona much brighter\n // Mix between 1.0 (normal) and enhanced falloff based on isTotalEclipse\n float enhancedFalloff = mix(3.0, 0.3, pow(coronaDist, 0.7));\n float brightnessMultiplier = mix(1.0, enhancedFalloff, isTotalEclipse);\n\n // 3. F-CORONA OUTER GLOW - faint diffuse glow from interplanetary dust\n float fCoronaDist = clamp((dist - shadowEdge) / 1.2, 0.0, 1.0);\n float fCorona = (1.0 - fCoronaDist) * 0.08;\n fCorona *= smoothstep(0.3, 0.5, coronaDist);\n fCorona *= isTotalEclipse; // Scale by eclipse progress\n\n // 4. WISPY TENDRILS - add fine detail noise to ray intensity\n float noiseAngle = angle * 8.0 + time * 0.1;\n float noiseRadius = dist * 15.0;\n float wispyDetail = hash(noiseAngle + noiseRadius + randomSeed * 3.0) * 0.15;\n wispyDetail *= rayIntensity * isTotalEclipse; // Scale by eclipse progress\n\n // Combine: base glow + streamers + wispy detail\n float finalIntensity = (baseGlow * 0.6 + rayIntensity + wispyDetail) * intensity;\n finalIntensity *= brightnessMultiplier;\n\n // Multi-stage color gradient for realistic corona\n vec3 innerGlow = vec3(1.0, 1.0, 1.0); // Pure white at base\n vec3 middleGlow = vec3(0.9, 0.95, 1.0); // Cool white\n vec3 outerGlow = vec3(0.6, 0.75, 0.95); // Pale blue\n vec3 farGlow = vec3(0.3, 0.5, 0.8); // Deep blue\n\n // Three-stage color mix\n vec3 coronaColor;\n if (coronaDist < 0.3) {\n // Inner: white → cool white\n coronaColor = mix(innerGlow, middleGlow, coronaDist / 0.3);\n } else if (coronaDist < 0.7) {\n // Middle: cool white → pale blue\n coronaColor = mix(middleGlow, outerGlow, (coronaDist - 0.3) / 0.4);\n } else {\n // Outer: pale blue → deep blue\n coronaColor = mix(outerGlow, farGlow, (coronaDist - 0.7) / 0.3);\n }\n\n vec3 finalColor = coronaColor * finalIntensity;\n\n // Add chromosphere red rim (total eclipse only)\n finalColor += chromosphereColor * chromosphereRim * intensity;\n\n // Add F-corona outer glow (total eclipse only)\n finalColor += vec3(0.9, 0.85, 0.8) * fCorona * intensity; // Slightly warm white\n\n // ═══════════════════════════════════════════════════════════════════════════\n // BLEND LAYERS (Applied globally to entire corona)\n // These allow adjusting the appearance of the corona to prevent black edges\n // ═══════════════════════════════════════════════════════════════════════════\n\n // Layer 1\n if (layer1Enabled > 0.5) {\n vec3 blendColor1 = vec3(min(layer1Strength, 1.0));\n int mode1 = int(layer1Mode + 0.5);\n vec3 blended1 = clamp(applyBlendMode(finalColor, blendColor1, mode1), 0.0, 1.0);\n finalColor = clamp(blended1, 0.0, 1.0);\n }\n\n // Layer 2\n if (layer2Enabled > 0.5) {\n vec3 blendColor2 = vec3(min(layer2Strength, 1.0));\n int mode2 = int(layer2Mode + 0.5);\n vec3 blended2 = clamp(applyBlendMode(finalColor, blendColor2, mode2), 0.0, 1.0);\n finalColor = clamp(blended2, 0.0, 1.0);\n }\n\n // Layer 3\n if (layer3Enabled > 0.5) {\n vec3 blendColor3 = vec3(min(layer3Strength, 1.0));\n int mode3 = int(layer3Mode + 0.5);\n vec3 blended3 = clamp(applyBlendMode(finalColor, blendColor3, mode3), 0.0, 1.0);\n finalColor = clamp(blended3, 0.0, 1.0);\n }\n\n // Layer 4\n if (layer4Enabled > 0.5) {\n vec3 blendColor4 = vec3(min(layer4Strength, 1.0));\n int mode4 = int(layer4Mode + 0.5);\n vec3 blended4 = clamp(applyBlendMode(finalColor, blendColor4, mode4), 0.0, 1.0);\n finalColor = clamp(blended4, 0.0, 1.0);\n }\n\n // Sharp alpha falloff to prevent black bleeding in bloom\n // Higher power = sharper cutoff at edges (less semi-transparent area)\n float alphaFalloff = pow(1.0 - coronaDist, 3.0);\n float alpha = finalIntensity * alphaFalloff * 0.95;\n\n gl_FragColor = vec4(finalColor, alpha);\n }\n `,transparent:!0,blending:e.AdditiveBlending,depthWrite:!1,side:e.DoubleSide});this.coronaDisk=new e.Mesh(n,a),this.coronaDisk.position.set(0,0,0),this.coronaDisk.renderOrder=9998,this.scene.add(this.coronaDisk)}createCounterCoronaDisk(){const t=this.coronaDisk.geometry,i=this.randomSeed+5e3,n=new e.ShaderMaterial({uniforms:{time:{value:0},glowColor:{value:new e.Color(.9,.95,1)},intensity:{value:2.4},randomSeed:{value:i},uvRotation:{value:0},rayElongation:{value:1},uberHeroElongation:{value:1},isTotalEclipse:{value:0},layer1Mode:{value:11},layer1Strength:{value:2.155},layer1Enabled:{value:1},layer2Mode:{value:5},layer2Strength:{value:.695},layer2Enabled:{value:1},layer3Mode:{value:0},layer3Strength:{value:1},layer3Enabled:{value:0},layer4Mode:{value:0},layer4Strength:{value:1},layer4Enabled:{value:0}},vertexShader:this.coronaDisk.material.vertexShader,fragmentShader:this.coronaDisk.material.fragmentShader,transparent:!0,blending:e.AdditiveBlending,depthWrite:!1,side:e.DoubleSide});this.counterCoronaDisk=new e.Mesh(t,n),this.counterCoronaDisk.position.set(0,0,0),this.counterCoronaDisk.renderOrder=9997,this.scene.add(this.counterCoronaDisk)}setShadowCoverage(e){this.customShadowCoverage=e}setCoronaBlendLayer(e,t){if(e<1||e>4)return void console.error(`❌ Invalid corona layer number: ${e} (must be 1-4)`);const{mode:i=0,strength:n=1,enabled:a=!1}=t;this.coronaDisk?.material?.uniforms&&(this.coronaDisk.material.uniforms[`layer${e}Mode`].value=i,this.coronaDisk.material.uniforms[`layer${e}Strength`].value=n,this.coronaDisk.material.uniforms[`layer${e}Enabled`].value=a?1:0),this.counterCoronaDisk?.material?.uniforms&&(this.counterCoronaDisk.material.uniforms[`layer${e}Mode`].value=i,this.counterCoronaDisk.material.uniforms[`layer${e}Strength`].value=n,this.counterCoronaDisk.material.uniforms[`layer${e}Enabled`].value=a?1:0)}setEclipseType(e){if(e===this.eclipseType)return;const t=this.enabled;this.previousEclipseType=this.eclipseType,this.eclipseType=e,this.enabled=e!==wi,this.manualControl=!1;const i=Ci(this.previousEclipseType),n=Ci(e);this.startShadowCoverage=i.shadowCoverage,this.targetShadowCoverage=n.shadowCoverage,!t&&this.enabled?(this.transitionDirection="in",this.isTransitioning=!0,this.transitionProgress=0):t&&!this.enabled?(this.transitionDirection="out",this.isTransitioning=!0,this.transitionProgress=0):t&&this.enabled&&(this.isTransitioning=!0,this.transitionProgress=0,this.transitionDirection="switch")}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}setManualProgress(e){this.manualControl=!0,this.transitionProgress=Math.max(0,Math.min(1,e)),this.isTransitioning=!0,this.transitionDirection="in"}setManualShadowPosition(e){this.manualControl=!0,this.manualShadowPosition=Math.max(-2,Math.min(2,e)),this.isTransitioning=!0,this.transitionDirection="manual"}update(e,t,i,n=null){const a=e.position,s=t.position,o=t.scale.x;let r=1;if(null!==n&&n>.5){const e=2*(n-.5);r=e*(2-e)}else if(null!==n&&n<=.5){const e=2*n;r=1-e*e}const l=this.eclipseType===wi?3:1;if(this.time+=i*l,this.isTransitioning&&!this.manualControl){const e=i/this.transitionDuration;this.transitionProgress+=e,this.transitionProgress>=1&&(this.transitionProgress=1,this.isTransitioning=!1)}if(this.enabled||"out"===this.transitionDirection&&this.isTransitioning){const e="out"===this.transitionDirection&&this.isTransitioning?this.previousEclipseType:this.eclipseType,t=Ci(e),n=this.sunRadius*o,l=this.easeInOutCubic(this.transitionProgress);let h;h=void 0!==this.customShadowCoverage?this.customShadowCoverage:"switch"===this.transitionDirection&&this.isTransitioning&&void 0!==this.startShadowCoverage&&void 0!==this.targetShadowCoverage?this.startShadowCoverage+(this.targetShadowCoverage-this.startShadowCoverage)*l:t.shadowCoverage;const c=n*h/this.sunRadius;this.shadowDisk.scale.setScalar(c),this.currentShadowPosX=-2,"manual"===this.transitionDirection&&void 0!==this.manualShadowPosition?this.currentShadowPosX=this.manualShadowPosition:this.isTransitioning?"in"===this.transitionDirection?this.currentShadowPosX=2*l-2:"out"===this.transitionDirection?this.currentShadowPosX=0+1*l:"switch"===this.transitionDirection&&(this.currentShadowPosX=0):this.currentShadowPosX=0;const u=this.currentShadowPosX,d=2.5*n,m=u*d*.5,p=-u*u*d*.25;this._directionToCamera.subVectors(a,s).normalize(),this._right.crossVectors(this._directionToCamera,this._up).normalize(),this._upVector.crossVectors(this._right,this._directionToCamera).normalize();const g=0;this._tempOffset.copy(this._directionToCamera).multiplyScalar(g),this.shadowDisk.position.copy(s).add(this._tempOffset),this._tempOffset.copy(this._right).multiplyScalar(m),this.shadowDisk.position.add(this._tempOffset),this._tempOffset.copy(this._upVector).multiplyScalar(p),this.shadowDisk.position.add(this._tempOffset),this.shadowDisk.lookAt(a),this.coronaDisk.parent&&this.coronaDisk.parent!==this.scene||(this.coronaDisk.position.copy(s),this.counterCoronaDisk.position.copy(s),this.coronaDisk.scale.setScalar(o),this.counterCoronaDisk.scale.setScalar(o));const f=Math.abs(this.currentShadowPosX||0),y=2,v=Math.max(0,1-f/y);let b=0;if("switch"===this.transitionDirection&&this.isTransitioning){const e=this.previousEclipseType===Si,t=this.eclipseType===Si;t&&!e?b=l:!t&&e&&(b=1-l)}else e===Si&&(b=1);const w=1+(1+24*Math.pow(v,4)-1)*b,M=1+(1+199*Math.pow(v,5)-1)*b;this.coronaDisk.material.uniforms.rayElongation.value=w,this.counterCoronaDisk.material.uniforms.rayElongation.value=w,this.coronaDisk.material.uniforms.uberHeroElongation.value=M,this.counterCoronaDisk.material.uniforms.uberHeroElongation.value=M;const S=.5,x=.99,C=Math.max(0,Math.min(1,(v-S)/(x-S))),D=C*C*(3-2*C),P=D*b;this.coronaDisk.material.uniforms.isTotalEclipse.value=P,this.counterCoronaDisk.material.uniforms.isTotalEclipse.value=P;const B=b>0&&v>=S,k=1-.947*D*b;this.setCoronaBlendLayer(3,{mode:1,strength:k,enabled:B}),this.coronaDisk.lookAt(a),this.counterCoronaDisk.lookAt(a);let T=0;if(e===wi)T=i/1e3*.075;else if(e===Mi){const e=.075;T=i/1e3*(e-(e-.25*e)*v)}else if(e===Si){const e=.075;T=i/1e3*(e-(e-.05*e)*v)}this.coronaDisk.material.uniforms.uvRotation.value+=T,this.counterCoronaDisk.material.uniforms.uvRotation.value-=T;let E=1.2;if(e===wi)E=3.6;else if(e===Mi){const e=3.6,t=.08*e;this.transitionDirection,E=e-(e-t)*v}else if(e===Si){const e=3.6,t=.65*e;this.transitionDirection,E=e-(e-t)*v}this.coronaDisk.material.uniforms.intensity.value=E*r,this.counterCoronaDisk.material.uniforms.intensity.value=E*r,this.coronaDisk.material.uniforms.time.value=this.time,this.counterCoronaDisk.material.uniforms.time.value=this.time}else{this.shadowDisk.position.set(200,0,0),this.coronaDisk.parent&&this.coronaDisk.parent!==this.scene||(this.coronaDisk.position.copy(s),this.counterCoronaDisk.position.copy(s),this.coronaDisk.scale.setScalar(o),this.counterCoronaDisk.scale.setScalar(o)),this.coronaDisk.material.uniforms.rayElongation.value=1,this.counterCoronaDisk.material.uniforms.rayElongation.value=1,this.coronaDisk.material.uniforms.uberHeroElongation.value=1,this.counterCoronaDisk.material.uniforms.uberHeroElongation.value=1,this.coronaDisk.material.uniforms.isTotalEclipse.value=0,this.counterCoronaDisk.material.uniforms.isTotalEclipse.value=0,this.coronaDisk.material.uniforms.intensity.value=3.06*r,this.counterCoronaDisk.material.uniforms.intensity.value=3.06*r,this.setCoronaBlendLayer(3,{mode:1,strength:0,enabled:!1}),this.coronaDisk.lookAt(a),this.counterCoronaDisk.lookAt(a);const e=i/1e3*.075;this.coronaDisk.material.uniforms.uvRotation.value+=e,this.counterCoronaDisk.material.uniforms.uvRotation.value-=e,this.coronaDisk.material.uniforms.intensity.value=3.6*r,this.counterCoronaDisk.material.uniforms.intensity.value=3.6*r,this.coronaDisk.material.uniforms.time.value=this.time,this.counterCoronaDisk.material.uniforms.time.value=this.time}if(this.eclipseType===Si){let t=0,n=!1;if("manual"===this.transitionDirection){const e=Math.abs(this.currentShadowPosX),i=2;t=Math.max(0,Math.min(1,1-e/i)),t>=.9&&t<=1&&(n=!0)}else if("in"===this.transitionDirection&&this.isTransitioning){const e=.8;this.transitionProgress>=e&&(n=!0,t=.9+(this.transitionProgress-e)/(1-e)*.1)}else if("out"===this.transitionDirection&&this.isTransitioning){const e=.2;this.transitionProgress<=e&&(n=!0,t=1-this.transitionProgress/e*.1)}else this.isTransitioning||(t=1,n=!0);this.baileysBeads.setVisible(n),this.baileysBeads.update(e,s,t,i,o)}else this.baileysBeads.setVisible(!1),this.baileysBeads.update(e,s,0,i,o)}dispose(){this.shadowDisk&&(this.scene.remove(this.shadowDisk),this.shadowDisk.geometry.dispose(),this.shadowDisk.material.dispose(),this.shadowDisk=null),this.coronaDisk&&(this.coronaDisk.parent&&this.coronaDisk.parent.remove(this.coronaDisk),this.coronaDisk.geometry.dispose(),this.coronaDisk.material.dispose(),this.coronaDisk=null),this.counterCoronaDisk&&(this.counterCoronaDisk.parent&&this.counterCoronaDisk.parent.remove(this.counterCoronaDisk),this.counterCoronaDisk.material.dispose(),this.counterCoronaDisk=null),this.baileysBeads&&(this.baileysBeads.dispose(),this.baileysBeads=null),this._directionToCamera=null,this._up=null,this._right=null,this._upVector=null,this._tempOffset=null,this._tempColor=null,this.scene=null,this.sunMesh=null}}class Bi{constructor(e){this.material=e,this.eclipseType="off",this.progress=0,this.targetProgress=0,this.animating=!1,this.bloodMoonColor={r:.85,g:.18,b:.08},this.animationDuration=3e3,this.startTime=0,this.shadowX=-2,this.shadowY=0,this.shadowRadius=.7,this.targetShadowX=-2,this.shadowSpeed=1,this.material.uniforms.eclipseProgress||(this.material.uniforms.eclipseProgress={value:0},this.material.uniforms.eclipseIntensity={value:0},this.material.uniforms.bloodMoonColor={value:[this.bloodMoonColor.r,this.bloodMoonColor.g,this.bloodMoonColor.b]},this.material.uniforms.eclipseShadowPos={value:[this.shadowX,this.shadowY]},this.material.uniforms.eclipseShadowRadius={value:this.shadowRadius})}setEclipseType(e){if(this.eclipseType===e)return;const t="off"===this.eclipseType;switch(this.eclipseType=e,t&&"off"!==e&&(this.shadowX=-2,this.material.uniforms.eclipseShadowPos.value=[this.shadowX,this.shadowY]),e){case"off":this.targetProgress=0,this.targetShadowX=2;break;case"penumbral":this.targetProgress=.3,this.targetShadowX=-1;break;case"partial":this.targetProgress=.65,this.targetShadowX=-.6;break;case"total":this.targetProgress=1,this.targetShadowX=0;break;default:return void console.warn(`Unknown lunar eclipse type: ${e}`)}this.animating=!0,this.startTime=performance.now()}update(e){if(!this.animating)return;const t=performance.now()-this.startTime,i=Math.min(t/this.animationDuration,1),n=this.easeInOutCubic(i);this.progress=this.progress+(this.targetProgress-this.progress)*n,this.shadowX=this.shadowX+(this.targetShadowX-this.shadowX)*n*this.shadowSpeed,this.material.uniforms.eclipseProgress.value=this.progress,this.material.uniforms.eclipseShadowPos.value=[this.shadowX,this.shadowY];let a=0;"total"===this.eclipseType?a=this.progress:"partial"===this.eclipseType?a=.6*this.progress:"penumbral"===this.eclipseType&&(a=.25*this.progress),this.material.uniforms.eclipseIntensity.value=a,i>=1&&(this.animating=!1)}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}reset(){this.progress=0,this.targetProgress=0,this.shadowX=-2,this.targetShadowX=-2,this.animating=!1,this.eclipseType="off",this.material.uniforms.eclipseProgress&&(this.material.uniforms.eclipseProgress.value=0,this.material.uniforms.eclipseIntensity.value=0,this.material.uniforms.eclipseShadowPos.value=[this.shadowX,this.shadowY])}dispose(){}}const ki={quartz:{sssStrength:.8,sssAbsorption:[2.8,2.9,3],sssScatterDistance:[.2,.2,.25],sssThicknessBias:.6,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.12,frostiness:.15,innerGlowStrength:.2,fresnelIntensity:1.5,causticIntensity:1.2},emerald:{sssStrength:2,sssAbsorption:[.05,4,.1],sssScatterDistance:[.1,.5,.1],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.2,innerGlowStrength:.15,fresnelIntensity:1.2,emotionColorBleed:.35},ruby:{sssStrength:1.8,sssAbsorption:[4,.03,.08],sssScatterDistance:[.4,.04,.08],sssThicknessBias:.65,sssThicknessScale:1.9,sssCurvatureScale:2.5,sssAmbient:.08,frostiness:.12,innerGlowStrength:.12,fresnelIntensity:1.2,causticIntensity:1.15,emotionColorBleed:.35},sapphire:{sssStrength:2.2,sssAbsorption:[.15,.4,4],sssScatterDistance:[.1,.15,.5],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.18,innerGlowStrength:.15,fresnelIntensity:1.3,emotionColorBleed:.35},amethyst:{sssStrength:2.5,sssAbsorption:[3,.05,4.5],sssScatterDistance:[.4,.05,.5],sssThicknessBias:.7,sssThicknessScale:2,sssCurvatureScale:3,sssAmbient:.08,frostiness:.18,innerGlowStrength:.12,fresnelIntensity:1.4,emotionColorBleed:.35}},Ti=`\nuniform float time;\nuniform vec3 emotionColor;\nuniform float glowIntensity;\nuniform float opacity;\n\n// Crystal appearance controls\nuniform float frostiness; // 0 = clear glass, 1 = fully frosted (default: 0.7)\nuniform float fresnelPower; // Edge brightness falloff (default: 3.0)\nuniform float fresnelIntensity; // Edge brightness strength (default: 1.2)\nuniform float innerGlowStrength; // How much inner soul shows through (default: 0.8)\nuniform float surfaceRoughness; // Surface texture variation (default: 0.3)\n\n// Enhanced lighting controls\nuniform float shadowDarkness; // How dark shadows can get (0-1, default: 0.4)\nuniform float specularIntensity; // Edge highlight brightness (default: 0.8)\nuniform float specularPower; // Specular falloff sharpness (default: 32.0)\nuniform float transmissionContrast; // Thin/thick brightness ratio (default: 1.5)\nuniform float minBrightness; // Minimum brightness floor (default: 0.05)\n\n// Noise scale controls\nuniform float surfaceNoiseScale; // Scale of surface frost pattern (default: 1.5)\nuniform float noiseFrequency; // Frequency of hash noise pattern (default: 1.0)\n\n// Internal caustics - light pooling inside the gem\nuniform float causticIntensity; // Brightness of internal caustics (default: 0.4)\nuniform float causticScale; // Scale of caustic pattern (default: 3.0)\nuniform float causticSpeed; // Animation speed of caustics (default: 0.15)\n\n// Texture\nuniform sampler2D crystalTexture;\nuniform float textureStrength; // How much texture affects appearance (default: 0.5)\n\n// Soul refraction - samples soul rendered to texture with optical distortion\nuniform sampler2D soulTexture; // Soul mesh rendered to texture\nuniform vec2 resolution; // Screen resolution for UV calculation\nuniform vec2 soulTextureSize; // Soul render target size (may differ from screen)\nuniform vec2 soulScreenCenter; // Soul center projected to screen UV (0-1 range)\nuniform float refractionIndex; // Index of refraction (1.5 glass, 2.4 diamond)\nuniform float refractionStrength; // Distortion magnitude (0.1-0.5)\n\n// Physically-based subsurface scattering\nuniform float sssStrength; // Overall SSS intensity (0-1)\nuniform vec3 sssAbsorption; // Absorption coefficients per RGB channel\nuniform vec3 sssScatterDistance; // Mean free path / scatter radius per RGB\nuniform float sssThicknessBias; // Thickness offset (0-1)\nuniform float sssThicknessScale; // Thickness multiplier\nuniform float sssCurvatureScale; // How much curvature affects SSS\nuniform float sssAmbient; // Ambient SSS contribution\nuniform vec3 sssLightDir; // Primary light direction for SSS\nuniform vec3 sssLightColor; // Light color for SSS\n\n// Emotion color bleed - how much soul color tints the gem material\nuniform float emotionColorBleed; // 0 = gem color only, 1 = full emotion tint (default: 0.0)\n\n// Component-specific blend layers\n// Shell layers - affect the frosted crystal shell\nuniform float shellLayer1Mode;\nuniform float shellLayer1Strength;\nuniform float shellLayer1Enabled;\nuniform float shellLayer2Mode;\nuniform float shellLayer2Strength;\nuniform float shellLayer2Enabled;\n\n// Soul layers - affect the inner glowing soul color\nuniform float soulLayer1Mode;\nuniform float soulLayer1Strength;\nuniform float soulLayer1Enabled;\nuniform float soulLayer2Mode;\nuniform float soulLayer2Strength;\nuniform float soulLayer2Enabled;\n\n// Rim layers - affect the fresnel rim glow\nuniform float rimLayer1Mode;\nuniform float rimLayer1Strength;\nuniform float rimLayer1Enabled;\nuniform float rimLayer2Mode;\nuniform float rimLayer2Strength;\nuniform float rimLayer2Enabled;\n\n// SSS layers - affect subsurface scattering contribution\nuniform float sssLayer1Mode;\nuniform float sssLayer1Strength;\nuniform float sssLayer1Enabled;\nuniform float sssLayer2Mode;\nuniform float sssLayer2Strength;\nuniform float sssLayer2Enabled;\n\nvarying vec3 vPosition;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// NOISE FUNCTIONS for surface variation and frosted effect\n// ═══════════════════════════════════════════════════════════════════════════\n\n// Simple 3D noise for frosted surface\nfloat hash(vec3 p) {\n p = p * noiseFrequency; // Apply frequency control\n p = fract(p * vec3(443.8975, 397.2973, 491.1871));\n p += dot(p.zxy, p.yxz + 19.19);\n return fract(p.x * p.y * p.z);\n}\n\nfloat noise3D(vec3 p) {\n vec3 i = floor(p);\n vec3 f = fract(p);\n f = f * f * (3.0 - 2.0 * f); // Smoothstep\n\n float n = mix(\n mix(\n mix(hash(i), hash(i + vec3(1, 0, 0)), f.x),\n mix(hash(i + vec3(0, 1, 0)), hash(i + vec3(1, 1, 0)), f.x),\n f.y\n ),\n mix(\n mix(hash(i + vec3(0, 0, 1)), hash(i + vec3(1, 0, 1)), f.x),\n mix(hash(i + vec3(0, 1, 1)), hash(i + vec3(1, 1, 1)), f.x),\n f.y\n ),\n f.z\n );\n return n;\n}\n\n// Fractal Brownian Motion for natural-looking frosted texture\nfloat fbm(vec3 p) {\n float value = 0.0;\n float amplitude = 0.5;\n float frequency = 1.0;\n\n for (int i = 0; i < 3; i++) {\n value += amplitude * noise3D(p * frequency);\n frequency *= 2.0;\n amplitude *= 0.5;\n }\n return value;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// BLEND MODES (from universal library)\n// ═══════════════════════════════════════════════════════════════════════════\n${S}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ENHANCED LIGHTING FUNCTIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n// Calculate ambient occlusion from geometry\nfloat calculateAO(vec3 normal, vec3 viewDir, vec3 position) {\n // Faces pointing away from view are in shadow\n float viewAO = max(0.0, dot(normal, viewDir));\n\n // Use light direction for directional shadow instead of gravity\n // This creates shadows on the side away from light\n vec3 lightDir = normalize(vec3(0.5, 1.0, 0.8)); // Match sssLightDir default\n float lightAO = dot(normal, lightDir) * 0.5 + 0.5;\n\n // Combine AO factors - no gravity term\n return viewAO * 0.5 + lightAO * 0.5;\n}\n\n// Calculate specular highlights on facet edges\nfloat calculateFacetSpecular(vec3 normal, vec3 viewDir, vec3 lightDir, float power) {\n // Detect facet edges from normal discontinuities\n float edgeDetect = length(fwidth(normal)) * 15.0;\n edgeDetect = smoothstep(0.1, 0.5, edgeDetect);\n\n // Standard Blinn-Phong specular\n vec3 halfVec = normalize(lightDir + viewDir);\n float specular = pow(max(0.0, dot(normal, halfVec)), power);\n\n // Boost specular on edges\n specular += edgeDetect * 0.5;\n\n return specular;\n}\n\n// Calculate "fire" - intense sparkle points that real gems exhibit\n// These are concentrated, view-dependent highlights from light dispersion\nfloat calculateFire(vec3 normal, vec3 viewDir, vec3 lightDir) {\n // Primary fire highlight - VERY sharp falloff for pinpoint sparkles\n vec3 reflectDir = reflect(-lightDir, normal);\n float fire1 = pow(max(0.0, dot(reflectDir, viewDir)), 512.0);\n\n // Secondary fire from different light angle (simulates environment)\n vec3 lightDir2 = normalize(vec3(-0.3, 0.8, 0.5));\n vec3 reflectDir2 = reflect(-lightDir2, normal);\n float fire2 = pow(max(0.0, dot(reflectDir2, viewDir)), 384.0);\n\n // Third fire point for more sparkle\n vec3 lightDir3 = normalize(vec3(0.7, 0.4, -0.6));\n vec3 reflectDir3 = reflect(-lightDir3, normal);\n float fire3 = pow(max(0.0, dot(reflectDir3, viewDir)), 256.0);\n\n // Combine fire points - only keep the brightest peaks\n float fire = fire1 + fire2 * 0.7 + fire3 * 0.5;\n\n // Facet edges catch more fire\n float edgeFactor = length(fwidth(normal)) * 20.0;\n fire *= (1.0 + edgeFactor * 2.0);\n\n return fire;\n}\n\n// Calculate bright lines along facet edges where bevels catch light\nfloat calculateFacetEdgeLines(vec3 normal, vec3 viewDir, vec3 lightDir) {\n // Detect edges from normal discontinuities\n float edgeMag = length(fwidth(normal));\n\n // Sharp threshold to create distinct lines\n float edgeLine = smoothstep(0.02, 0.08, edgeMag);\n\n // Modulate by light angle - edges facing light are brighter\n float lightFacing = max(0.0, dot(normal, lightDir));\n edgeLine *= (0.3 + lightFacing * 0.7);\n\n // View-dependent - edges perpendicular to view are more visible\n float viewPerp = 1.0 - abs(dot(normal, viewDir));\n edgeLine *= (0.5 + viewPerp * 0.5);\n\n return edgeLine;\n}\n\n// Calculate light transmission based on thickness\nfloat calculateTransmission(vec3 position, vec3 normal, vec3 viewDir, float contrast) {\n // Thickness estimation - edges are thin, center is thick\n float distFromCenter = length(position);\n float thickness = smoothstep(0.0, 0.6, distFromCenter);\n\n // View angle affects perceived thickness\n float viewThickness = 1.0 - abs(dot(normal, viewDir));\n thickness = mix(thickness, viewThickness, 0.5);\n\n // Thin areas transmit more light (brighter), thick areas are darker\n float transmission = 1.0 - thickness * contrast * 0.5;\n\n return clamp(transmission, 0.3, 1.5);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// PHYSICALLY-BASED SUBSURFACE SCATTERING\n// ═══════════════════════════════════════════════════════════════════════════\n\n// ═══════════════════════════════════════════════════════════════════════════\n// PHYSICALLY-BASED SUBSURFACE SCATTERING\n// Based on Disney's Burley Normalized Diffusion (2015)\n// ═══════════════════════════════════════════════════════════════════════════\n\n// SSS Uniforms - declare these in your shader\n// uniform float sssStrength; // Overall SSS intensity (0-1)\n// uniform vec3 sssAbsorption; // Absorption coefficients per RGB channel\n// uniform vec3 sssScatterDistance; // Mean free path / scatter radius per RGB\n// uniform float sssThicknessBias; // Thickness offset (0-1)\n// uniform float sssThicknessScale; // Thickness multiplier\n// uniform float sssCurvatureScale; // How much curvature affects SSS\n// uniform float sssAmbient; // Ambient SSS contribution\n// uniform vec3 sssLightDir; // Primary light direction for SSS\n// uniform vec3 sssLightColor; // Light color for SSS\n\n/**\n * Estimate local thickness from geometry\n * Uses the relationship between view angle and surface normal\n * Combined with a simple depth approximation\n *\n * @param normal - Surface normal in view space\n * @param viewDir - View direction\n * @param position - Vertex position (for depth-based estimation)\n * @param thicknessBias - Base thickness value\n * @param thicknessScale - Thickness multiplier\n * @return Estimated thickness (0-1)\n */\nfloat estimateThickness(vec3 normal, vec3 viewDir, vec3 position, float thicknessBias, float thicknessScale) {\n // Method 1: View-dependent thickness\n // Surfaces facing away from viewer are "thicker" (light travels further)\n float viewThickness = 1.0 - abs(dot(normal, viewDir));\n\n // Method 2: Position-based depth (simple spherical assumption)\n // Objects are thinner at edges, thicker in center\n float posDepth = 1.0 - length(position) * 0.5;\n posDepth = clamp(posDepth, 0.0, 1.0);\n\n // Method 3: Curvature hint from normal variation\n // High-frequency normal changes indicate thin areas (edges, details)\n // This is approximated by the gradient of the normal\n float curvatureHint = length(fwidth(normal)) * 10.0;\n curvatureHint = 1.0 - clamp(curvatureHint, 0.0, 1.0);\n\n // Combine methods with weighting\n float thickness = viewThickness * 0.4 + posDepth * 0.4 + curvatureHint * 0.2;\n\n // Apply bias and scale\n thickness = thicknessBias + thickness * thicknessScale;\n\n return clamp(thickness, 0.01, 1.0);\n}\n\n/**\n * Beer's Law absorption - light attenuates exponentially through material\n * Different wavelengths absorb at different rates, creating color shifts\n *\n * @param thickness - Distance light travels through material\n * @param absorption - Absorption coefficients per RGB (higher = more absorbed)\n * @return Transmittance per RGB channel (0-1)\n */\nvec3 beersLawAbsorption(float thickness, vec3 absorption) {\n // Beer-Lambert Law: T = e^(-σ * d)\n // Where σ is absorption coefficient, d is distance\n return exp(-absorption * thickness * 4.0);\n}\n\n/**\n * Burley Normalized Diffusion Profile\n * Disney's approximation of the full BSSRDF, energy-conserving\n *\n * R(r) = A * s * (e^(-s*r) + e^(-s*r/3)) / (8πr)\n *\n * @param radius - Distance from entry point (normalized)\n * @param scatterDist - Mean free path / diffusion length\n * @return Diffusion weight at this radius\n */\nfloat burleyDiffusionProfile(float radius, float scatterDist) {\n // Prevent division by zero\n float r = max(radius, 0.001);\n float s = 1.0 / max(scatterDist, 0.001);\n\n // Burley's two-term approximation\n float term1 = exp(-s * r);\n float term2 = exp(-s * r / 3.0);\n\n // Normalized profile (simplified, without 8πr for real-time)\n float profile = (term1 + term2) * s * 0.25;\n\n return profile;\n}\n\n/**\n * Christensen-Burley Normalized Diffusion\n * Improved version with better energy conservation\n *\n * @param radius - Distance from entry point\n * @param A - Surface albedo\n * @param d - Diffusion length (mean free path)\n * @return RGB diffusion weights\n */\nvec3 christensenBurleyDiffusion(float radius, vec3 A, vec3 d) {\n vec3 result = vec3(0.0);\n\n // Per-channel diffusion (different scatter distances for RGB)\n for (int i = 0; i < 3; i++) {\n float s = 1.9 - A[i] + 3.5 * (A[i] - 0.8) * (A[i] - 0.8);\n s = 1.0 / (s * max(d[i], 0.001));\n\n float r = max(radius, 0.001);\n\n // Two-exponential fit\n float profile = s * (exp(-s * r) + exp(-s * r / 3.0)) / (8.0 * 3.14159 * r);\n\n result[i] = profile;\n }\n\n return result;\n}\n\n/**\n * Calculate curvature factor for SSS intensity\n * SSS is more visible on curved surfaces (fingers, ears, edges)\n *\n * @param normal - Surface normal\n * @return Curvature factor (higher = more curved)\n */\nfloat calculateCurvature(vec3 normal) {\n // Use screen-space derivatives to estimate curvature\n vec3 dx = dFdx(normal);\n vec3 dy = dFdy(normal);\n\n // Curvature magnitude\n float curvature = length(dx) + length(dy);\n\n // Normalize to useful range\n return clamp(curvature * 5.0, 0.0, 1.0);\n}\n\n/**\n * Full physically-based SSS calculation\n * Combines all components for realistic translucent materials\n *\n * @param normal - Surface normal (view space)\n * @param viewDir - View direction\n * @param position - Vertex position\n * @param lightDir - Light direction\n * @param lightColor - Light color\n * @param baseColor - Material base/albedo color\n * @param sssStrength - Overall SSS strength\n * @param absorption - Absorption coefficients RGB (inverted: higher = MORE of that color)\n * @param scatterDist - Scatter distance RGB (higher = more scatter)\n * @param thicknessBias - Base thickness\n * @param thicknessScale - Thickness multiplier\n * @param curvatureScale - Curvature influence\n * @param ambient - Ambient SSS contribution\n * @return Final SSS color contribution\n */\nvec3 calculatePhysicalSSS(\n vec3 normal,\n vec3 viewDir,\n vec3 position,\n vec3 lightDir,\n vec3 lightColor,\n vec3 baseColor,\n float sssStrength,\n vec3 absorption,\n vec3 scatterDist,\n float thicknessBias,\n float thicknessScale,\n float curvatureScale,\n float ambient\n) {\n if (sssStrength < 0.001) {\n return vec3(0.0);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // THICKNESS ESTIMATION\n // ─────────────────────────────────────────────────────────────────────\n float thickness = estimateThickness(normal, viewDir, position, thicknessBias, thicknessScale);\n\n // ─────────────────────────────────────────────────────────────────────\n // ABSORPTION COLOR (Beer's Law with artist-friendly values)\n // Creates the characteristic color of translucent materials\n // absorption values: high value = MORE of that color passes through (transmitted)\n // This is inverted from physics but intuitive: jade has high green absorption\n // ─────────────────────────────────────────────────────────────────────\n // Use absorption directly as transmittance - higher = more of that color shows\n // Normalize to prevent any channel from dominating\n float maxAbsorption = max(absorption.r, max(absorption.g, absorption.b));\n vec3 normalizedTransmit = absorption / max(maxAbsorption, 0.001);\n\n // Apply thickness-based falloff - thin areas show more color\n float thicknessFactor = 1.0 - thickness * 0.3;\n vec3 colorShift = normalizedTransmit * thicknessFactor;\n\n // Ensure minimum color presence\n colorShift = max(colorShift, vec3(0.15));\n\n // ─────────────────────────────────────────────────────────────────────\n // SCATTER INTENSITY\n // How much light scatters based on material properties\n // ─────────────────────────────────────────────────────────────────────\n // Higher scatter distance = more light gets through, but keep it subtle\n vec3 scatterIntensity = scatterDist * 0.8;\n scatterIntensity = clamp(scatterIntensity, vec3(0.1), vec3(1.0));\n\n // ─────────────────────────────────────────────────────────────────────\n // LIGHTING TERMS - Boosted for visibility\n // ─────────────────────────────────────────────────────────────────────\n\n // Back-lighting: light passing through from behind (strongest SSS cue)\n float NdotL = dot(normal, lightDir);\n float backLight = max(0.0, -NdotL);\n backLight = pow(backLight, 1.2) * 1.5; // Boosted\n\n // Wrap lighting: soft diffuse that wraps around\n float wrapLight = (NdotL + 1.0) * 0.5; // Full wrap, 0-1 range\n wrapLight = wrapLight * wrapLight;\n\n // View-dependent translucency (looking through thin parts)\n float VdotL = dot(viewDir, -lightDir);\n float translucency = pow(max(0.0, VdotL), 1.5) * 1.2; // Boosted\n\n // Edge glow (fresnel-like SSS at silhouettes)\n float edgeGlow = pow(1.0 - abs(dot(normal, viewDir)), 2.0);\n\n // ─────────────────────────────────────────────────────────────────────\n // THICKNESS-BASED TRANSMISSION\n // Thin areas let more light through\n // ─────────────────────────────────────────────────────────────────────\n float thinTransmission = 1.0 - thickness * 0.5;\n thinTransmission = max(thinTransmission, 0.3);\n\n // ─────────────────────────────────────────────────────────────────────\n // CURVATURE ENHANCEMENT\n // ─────────────────────────────────────────────────────────────────────\n float curvature = calculateCurvature(normal);\n float curvatureFactor = 1.0 + curvature * curvatureScale;\n\n // ─────────────────────────────────────────────────────────────────────\n // COMBINE ALL TERMS\n // ─────────────────────────────────────────────────────────────────────\n\n // Total light contribution (more additive for visibility)\n float totalLight = backLight + translucency * 0.8 + wrapLight * 0.4 + edgeGlow * 0.5;\n totalLight *= curvatureFactor * thinTransmission;\n\n // Base SSS color - colorShift IS the tint (e.g., green for jade)\n // Don't multiply by baseColor to avoid washing out with emotionColor\n vec3 sssColor = colorShift * scatterIntensity;\n\n // Ambient SSS (always visible, gives material its translucent look)\n vec3 ambientSSS = sssColor * ambient;\n\n // Direct SSS from lighting - subtle contribution\n vec3 directSSS = sssColor * lightColor * totalLight * 0.5;\n\n // Final combination\n vec3 finalSSS = directSSS + ambientSSS;\n\n // Apply overall strength (linear, no boost to prevent blowout)\n return finalSSS * sssStrength;\n}\n\n/**\n * Simplified SSS for performance-critical scenarios\n * Uses pre-computed approximations\n *\n * @param normal - Surface normal\n * @param viewDir - View direction\n * @param lightDir - Light direction\n * @param thickness - Pre-computed or approximated thickness\n * @param baseColor - Material color\n * @param scatterColor - Scatter tint color\n * @param strength - SSS strength\n * @return SSS color contribution\n */\nvec3 calculateSimpleSSS(\n vec3 normal,\n vec3 viewDir,\n vec3 lightDir,\n float thickness,\n vec3 baseColor,\n vec3 scatterColor,\n float strength\n) {\n if (strength < 0.001) {\n return vec3(0.0);\n }\n\n // Back-lighting\n float backLight = pow(max(0.0, dot(viewDir, -lightDir)), 2.0);\n\n // Transmittance (simplified Beer's law)\n float transmit = exp(-thickness * 2.0);\n\n // Edge enhancement\n float edge = pow(1.0 - abs(dot(normal, viewDir)), 2.0);\n\n // Combine\n float sssIntensity = (backLight * transmit + edge * 0.3) * strength;\n\n return mix(baseColor, scatterColor, 0.5) * sssIntensity;\n}\n\n\nvoid main() {\n vec3 normal = normalize(vNormal);\n vec3 viewDir = normalize(vViewPosition);\n\n // ═══════════════════════════════════════════════════════════════════════\n // FRESNEL EFFECT - Colored rim at edges (cyan-tinted)\n // ═══════════════════════════════════════════════════════════════════════\n float fresnel = pow(1.0 - abs(dot(normal, viewDir)), fresnelPower);\n fresnel *= fresnelIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════\n // AMBIENT OCCLUSION - Dark shadows for depth\n // ═══════════════════════════════════════════════════════════════════════\n float ao = calculateAO(normal, viewDir, vPosition);\n float shadowFactor = mix(1.0, ao, shadowDarkness);\n\n // ═══════════════════════════════════════════════════════════════════════\n // SPECULAR HIGHLIGHTS - Bright catches on facet edges\n // ═══════════════════════════════════════════════════════════════════════\n vec3 lightDir = normalize(sssLightDir);\n float specular = calculateFacetSpecular(normal, viewDir, lightDir, specularPower);\n specular *= specularIntensity;\n\n // ═══════════════════════════════════════════════════════════════════════\n // LIGHT TRANSMISSION - Thin areas glow, thick areas darken\n // ═══════════════════════════════════════════════════════════════════════\n float transmission = calculateTransmission(vPosition, normal, viewDir, transmissionContrast);\n\n // ═══════════════════════════════════════════════════════════════════════\n // TEXTURE SAMPLING - Crystal surface detail from UV-mapped texture\n // ═══════════════════════════════════════════════════════════════════════\n vec4 texColor = texture2D(crystalTexture, vUv);\n float texValue = (texColor.r + texColor.g + texColor.b) / 3.0; // Grayscale\n\n // ═══════════════════════════════════════════════════════════════════════\n // FROSTED SURFACE - Subtle cloudy variation (not opaque white!)\n // ═══════════════════════════════════════════════════════════════════════\n float surfaceNoise = fbm(vPosition * surfaceNoiseScale + time * 0.02);\n surfaceNoise = surfaceNoise * surfaceRoughness;\n\n // ═══════════════════════════════════════════════════════════════════════\n // INNER SOUL GLOW - The glowing core visible through the crystal\n // ═══════════════════════════════════════════════════════════════════════\n\n // Animated internal glow - subtle pulsing\n float glowPulse = sin(time * 0.5) * 0.15 + 0.85;\n\n // Core glow - strongest in center, fades toward edges with sharper falloff\n float distFromCenter = length(vPosition);\n float coreGlow = exp(-distFromCenter * 2.5) * glowPulse;\n\n // ═══════════════════════════════════════════════════════════════════════\n // INTERNAL CAUSTICS - Light refraction pools inside the gem\n // Creates bright concentrated spots that shift with viewing angle\n // Real caustics form where refracted light rays converge inside the gem\n // Now with CHROMATIC ABERRATION - different wavelengths refract differently\n // ═══════════════════════════════════════════════════════════════════════\n\n // Refract view direction through gem surface with different IOR per wavelength\n // Red refracts less (higher IOR ratio), blue refracts more (lower IOR ratio)\n // Chromatic separation is REDUCED for colored gems to avoid color contamination\n // Quartz (low sssStrength) gets full rainbow, colored gems get subtle dispersion\n float chromaticStrength = 1.0 - clamp((sssStrength - 0.5) * 0.8, 0.0, 0.8);\n float iorR = mix(0.57, 0.70, chromaticStrength); // Red - approaches green for colored gems\n float iorB = mix(0.57, 0.44, chromaticStrength); // Blue - approaches green for colored gems\n vec3 refractDirR = refract(-viewDir, normal, iorR);\n vec3 refractDirG = refract(-viewDir, normal, 0.57); // Green - always medium\n vec3 refractDirB = refract(-viewDir, normal, iorB);\n\n // Animated drift\n float causticTime = time * causticSpeed;\n vec3 drift = vec3(causticTime * 0.3, causticTime * 0.2, causticTime * 0.1);\n\n // Sample positions for each color channel\n // Offset is also reduced for colored gems to minimize chromatic contamination\n float spatialOffset = mix(1.0, 3.0, chromaticStrength);\n vec3 causticPosR = vPosition * causticScale + refractDirR * spatialOffset + drift;\n vec3 causticPosG = vPosition * causticScale + refractDirG * spatialOffset + drift;\n vec3 causticPosB = vPosition * causticScale + refractDirB * spatialOffset + drift;\n\n // Create caustic pattern for each channel\n // Red channel\n float waveR1 = sin(causticPosR.x * 2.0 + causticPosR.y * 1.5 + causticPosR.z);\n float waveR2 = sin(causticPosR.y * 2.3 - causticPosR.x * 1.2 + causticPosR.z * 1.8);\n float waveR3 = sin(causticPosR.z * 1.9 + causticPosR.x * 0.8 - causticPosR.y * 1.4);\n float interferenceR = (waveR1 + waveR2 + waveR3) / 3.0;\n float causticR = smoothstep(0.3, 0.8, interferenceR);\n\n // Green channel\n float waveG1 = sin(causticPosG.x * 2.0 + causticPosG.y * 1.5 + causticPosG.z);\n float waveG2 = sin(causticPosG.y * 2.3 - causticPosG.x * 1.2 + causticPosG.z * 1.8);\n float waveG3 = sin(causticPosG.z * 1.9 + causticPosG.x * 0.8 - causticPosG.y * 1.4);\n float interferenceG = (waveG1 + waveG2 + waveG3) / 3.0;\n float causticG = smoothstep(0.3, 0.8, interferenceG);\n\n // Blue channel\n float waveB1 = sin(causticPosB.x * 2.0 + causticPosB.y * 1.5 + causticPosB.z);\n float waveB2 = sin(causticPosB.y * 2.3 - causticPosB.x * 1.2 + causticPosB.z * 1.8);\n float waveB3 = sin(causticPosB.z * 1.9 + causticPosB.x * 0.8 - causticPosB.y * 1.4);\n float interferenceB = (waveB1 + waveB2 + waveB3) / 3.0;\n float causticB = smoothstep(0.3, 0.8, interferenceB);\n\n // Combine into RGB caustic with chromatic separation\n vec3 causticRGB = vec3(causticR, causticG, causticB);\n\n // Add noise variation to break up uniformity\n float noiseVar = noise3D(causticPosG * 0.5);\n causticRGB *= (0.7 + noiseVar * 0.6);\n\n // Clamp caustic peaks to prevent hot spot blobs\n // This keeps caustics subtle and distributed rather than concentrated\n causticRGB = min(causticRGB, vec3(0.6));\n\n // Caustics are MORE visible in thick areas (center) where light has more\n // material to refract through and pool\n float thickness = abs(dot(normal, viewDir)); // 1 at center, 0 at edges\n causticRGB *= (0.3 + thickness * 0.7);\n\n // Apply intensity control\n causticRGB *= causticIntensity;\n\n // Boost caustic visibility for colored gems to compensate for reduced chromatic spread\n // Colored gems (high sssStrength) have suppressed chromatic aberration, so boost their\n // monochromatic caustics to maintain internal "life" and sparkle\n float causticBoost = 1.0 + clamp((sssStrength - 0.5) * 0.8, 0.0, 0.6);\n causticRGB *= causticBoost;\n\n // Also keep a scalar caustic for compatibility\n float caustic = (causticRGB.r + causticRGB.g + causticRGB.b) / 3.0;\n\n // Animation pattern (0-1 range) - core glow + caustic hot spots\n float animationPattern = coreGlow * 0.7 + caustic * 0.3;\n\n // Soul intensity controls overall brightness with more dramatic falloff\n // Brighter near core, darker at edges\n float baseLevel = 0.1; // Lower base for more contrast\n float patternContrast = 0.9; // Higher contrast for more variation\n float soulIntensity = (baseLevel + animationPattern * patternContrast) * innerGlowStrength;\n\n // Apply transmission to soul - thin areas glow brighter\n soulIntensity *= transmission;\n\n // Soul color from emotion\n // NOTE: emotionColor is pre-normalized by normalizeColorLuminance() in Core3DManager\n // This ensures consistent perceived brightness across all emotions (yellow won't wash out, blue stays visible)\n // Reduced intensity to prevent blowout - soul should be visible but not white\n float glowCurve = sqrt(innerGlowStrength * glowIntensity) * 0.5;\n vec3 soulColor = emotionColor * soulIntensity * glowCurve;\n // Clamp soul color to prevent blowout\n soulColor = min(soulColor, vec3(0.8));\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFRACTED SOUL SAMPLING - True optical lensing through crystal\n // The soul is rendered to a texture, then sampled with refraction distortion\n // This creates the effect of looking at the soul through a crystal lens\n // ═══════════════════════════════════════════════════════════════════════\n\n // ═══════════════════════════════════════════════════════════════════\n // REFRACTED SOUL SAMPLING\n // Sample the soul texture with physical refraction distortion\n // Creates the "looking through glass" lensing effect\n // ═══════════════════════════════════════════════════════════════════\n vec3 refractedSoulColor = vec3(0.0);\n float refractedSoulAlpha = 0.0;\n\n if (soulTextureSize.x > 0.0 && soulScreenCenter.x >= 0.0) {\n // Fragment's screen UV position\n vec2 fragUV = gl_FragCoord.xy / soulTextureSize;\n\n // Calculate refraction offset using Snell's law\n float ior = refractionIndex;\n vec3 refractedDir = refract(-viewDir, normal, 1.0 / ior);\n\n // Apply refraction distortion toward the soul center\n // This creates the magnifying glass effect - bending light toward center\n vec2 refractionOffset = refractedDir.xy * refractionStrength * 0.1;\n\n // Sample at fragment position with refraction offset\n // The soul texture contains the soul rendered at its actual screen position\n vec2 soulUV = fragUV + refractionOffset;\n\n // Clamp to valid UV range\n soulUV = clamp(soulUV, 0.0, 1.0);\n\n // Sample the soul texture\n vec4 soulSample = texture2D(soulTexture, soulUV);\n\n // Store for later use in final composition\n refractedSoulColor = soulSample.rgb;\n refractedSoulAlpha = soulSample.a;\n\n // Also blend into soulColor for existing pipeline\n soulColor = mix(soulColor, soulSample.rgb, soulSample.a * 0.5);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // SOUL BLEND LAYERS - Apply before combining with shell\n // ═══════════════════════════════════════════════════════════════════════\n if (soulLayer1Enabled > 0.5) {\n int mode = int(soulLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(soulColor, emotionColor * soulLayer1Strength, mode);\n soulColor = mix(soulColor, blendResult, soulLayer1Strength);\n }\n if (soulLayer2Enabled > 0.5) {\n int mode = int(soulLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(soulColor, emotionColor * soulLayer2Strength, mode);\n soulColor = mix(soulColor, blendResult, soulLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FROSTED SHELL - Milky white layer with INTERNAL lighting model\n // Lit from inside: thin edges bright, thick center dark\n // ═══════════════════════════════════════════════════════════════════════\n\n // Frosted glass base - will be modulated by thickness\n // Lower base values allow for darker thick areas while maintaining bright edges\n vec3 frostBase = vec3(0.45, 0.48, 0.55) * frostiness;\n\n // THICKNESS-BASED DARKNESS (internal lighting model)\n // Face-on facets are THICK (light travels far through) = DARK\n // Edge-on facets are THIN (light escapes easily) = BRIGHT\n float edgeThinness = 1.0 - abs(dot(normal, viewDir)); // 1 at edges, 0 facing camera\n\n // Apply curve to make face-on areas darker more aggressively\n float thinness = pow(edgeThinness, 0.7); // Push more area toward dark\n\n // Thickness multiplier: thin edges=bright (1.0), thick face-on=dark (0.01 for near-black)\n float thicknessMultiplier = 0.01 + thinness * 0.99;\n frostBase *= thicknessMultiplier;\n\n // Surface variation adds subtle texture\n frostBase += vec3(surfaceNoise * 0.03);\n\n // Specular highlights on facet edges (external light catch)\n float facetHighlight = pow(max(0.0, dot(normal, normalize(vec3(0.5, 1.0, 0.8)))), 16.0);\n frostBase += vec3(facetHighlight * 0.2);\n\n // SOUL BLEED - Inner glow illuminates the shell from inside\n // Use gentler falloff so color reaches the shell surface\n float soulBleed = exp(-distFromCenter * 1.2) * innerGlowStrength;\n // Stronger color contribution - tint the frost with emotion color\n frostBase = mix(frostBase, frostBase + emotionColor * 0.4, soulBleed);\n\n // ═══════════════════════════════════════════════════════════════════════\n // SHELL BLEND LAYERS - Apply to frosted shell\n // ═══════════════════════════════════════════════════════════════════════\n if (shellLayer1Enabled > 0.5) {\n int mode = int(shellLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(frostBase, emotionColor * shellLayer1Strength, mode);\n frostBase = mix(frostBase, blendResult, shellLayer1Strength);\n }\n if (shellLayer2Enabled > 0.5) {\n int mode = int(shellLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(frostBase, emotionColor * shellLayer2Strength, mode);\n frostBase = mix(frostBase, blendResult, shellLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FRESNEL RIM - Bright emotion-colored edge glow\n // ═══════════════════════════════════════════════════════════════════════\n vec3 rimColor = mix(vec3(0.5, 0.9, 1.0), emotionColor, 0.6);\n vec3 rimGlow = rimColor * fresnel * 1.2;\n\n // ═══════════════════════════════════════════════════════════════════════\n // RIM BLEND LAYERS - Apply to fresnel rim glow\n // ═══════════════════════════════════════════════════════════════════════\n if (rimLayer1Enabled > 0.5) {\n int mode = int(rimLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(rimGlow, emotionColor * rimLayer1Strength, mode);\n rimGlow = mix(rimGlow, blendResult, rimLayer1Strength);\n }\n if (rimLayer2Enabled > 0.5) {\n int mode = int(rimLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(rimGlow, emotionColor * rimLayer2Strength, mode);\n rimGlow = mix(rimGlow, blendResult, rimLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // PHYSICALLY-BASED SUBSURFACE SCATTERING\n // Uses BSSRDF with Beer's Law absorption and Burley diffusion profile\n // ═══════════════════════════════════════════════════════════════════════\n vec3 sss = calculatePhysicalSSS(\n normal,\n viewDir,\n vPosition,\n normalize(sssLightDir),\n sssLightColor,\n emotionColor,\n sssStrength,\n sssAbsorption,\n sssScatterDistance,\n sssThicknessBias,\n sssThicknessScale,\n sssCurvatureScale,\n sssAmbient\n );\n\n // ═══════════════════════════════════════════════════════════════════════\n // SSS BLEND LAYERS - Apply to subsurface scattering contribution\n // ═══════════════════════════════════════════════════════════════════════\n if (sssLayer1Enabled > 0.5) {\n int mode = int(sssLayer1Mode + 0.5);\n vec3 blendResult = applyBlendMode(sss, emotionColor * sssLayer1Strength, mode);\n sss = mix(sss, blendResult, sssLayer1Strength);\n }\n if (sssLayer2Enabled > 0.5) {\n int mode = int(sssLayer2Mode + 0.5);\n vec3 blendResult = applyBlendMode(sss, emotionColor * sssLayer2Strength, mode);\n sss = mix(sss, blendResult, sssLayer2Strength);\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // COMBINE - Frosted shell base + soul glow (soul adds to shell, doesn't replace)\n // ═══════════════════════════════════════════════════════════════════════\n\n // Start with shell as base - preserves dark shadows\n vec3 finalColor = frostBase;\n\n // Add soul glow on top (additive, not replacement) - concentrated in center\n // Soul should illuminate dark areas but not wash out entirely\n float soulBlendFactor = soulIntensity * 0.6;\n finalColor += soulColor * soulBlendFactor;\n\n // Apply texture - blend based on texture brightness and strength\n vec3 texContribution = texColor.rgb * textureStrength;\n finalColor = mix(finalColor, finalColor + texContribution, textureStrength);\n\n // Apply SSS material color - PRESERVE BRIGHTNESS, only change HUE\n // The sssAbsorption values define the material color hue\n // But thickness-based darkness must be preserved for gemstone look\n if (sssStrength > 0.01) {\n // Get current brightness (this includes thickness darkening)\n float currentLum = dot(finalColor, vec3(0.299, 0.587, 0.114));\n\n // Normalize absorption to get hue direction (0-1 range)\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 hue = absorption / max(maxAbs, 0.001);\n\n // Create material color that PRESERVES current brightness\n // This keeps dark areas dark while tinting them with the gem color\n float hueLum = dot(hue, vec3(0.299, 0.587, 0.114));\n vec3 materialColor = hue * currentLum / max(hueLum, 0.001);\n\n // Clamp to prevent blowout on bright areas\n materialColor = min(materialColor, vec3(1.0));\n\n // Add subtle variation from SSS lighting calculation\n float sssLum = dot(sss, vec3(0.299, 0.587, 0.114));\n materialColor *= (0.9 + sssLum * 0.2);\n\n // Replace crystal color with material color\n float replaceAmount = sssStrength * 0.7;\n finalColor = mix(finalColor, materialColor, replaceAmount);\n }\n\n // Add rim glow, tinted toward material color\n if (sssStrength > 0.01) {\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 hue = absorption / max(maxAbs, 0.001);\n // Stronger tint for colored gems - use gem hue directly\n float rimTintStrength = clamp(sssStrength * 0.6, 0.0, 0.95);\n vec3 tintedRim = rimGlow * mix(vec3(1.0), hue * 1.2, rimTintStrength);\n // Cap rim to prevent bloom\n tintedRim = min(tintedRim, vec3(0.5));\n finalColor += tintedRim;\n } else {\n finalColor += rimGlow;\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // SPECULAR HIGHLIGHTS - Add bright hot spots\n // Tinted by gem color for colored gems to prevent white bloom\n // ═══════════════════════════════════════════════════════════════════════\n vec3 specularColor = vec3(1.0, 0.98, 0.95); // Warm white highlights for clear gems\n float specularIntensityMod = 1.0;\n\n if (sssStrength > 0.5) {\n // Tint specular by gem color to prevent white bloom\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 gemHue = absorption / max(maxAbs, 0.001);\n float colorStrength = clamp((sssStrength - 0.5) * 0.5, 0.0, 1.0);\n // Use gem hue for specular color\n specularColor = mix(specularColor, gemHue * 1.3, colorStrength);\n // Also reduce specular intensity for colored gems\n specularIntensityMod = mix(1.0, 0.4, colorStrength);\n }\n\n vec3 specularContrib = specularColor * specular * transmission * specularIntensityMod;\n specularContrib = min(specularContrib, vec3(0.5)); // Cap specular to prevent bloom\n finalColor += specularContrib;\n\n // ═══════════════════════════════════════════════════════════════════════\n // FACET EDGE LINES - Bright catches along beveled edges\n // ═══════════════════════════════════════════════════════════════════════\n float edgeLines = calculateFacetEdgeLines(normal, viewDir, lightDir);\n finalColor += vec3(edgeLines * 0.15) * transmission;\n\n // ═══════════════════════════════════════════════════════════════════════\n // SATURATION BOOST AT THIN EDGES\n // Real gems have MORE saturated color at thin edges where light escapes\n // ═══════════════════════════════════════════════════════════════════════\n if (sssStrength > 0.01) {\n // thinness: 1 at edges, 0 facing camera\n float satBoost = thinness * 0.4; // Up to 40% saturation boost at edges\n\n // Get current color's saturation\n float maxC = max(max(finalColor.r, finalColor.g), finalColor.b);\n float minC = min(min(finalColor.r, finalColor.g), finalColor.b);\n float currentSat = maxC > 0.001 ? (maxC - minC) / maxC : 0.0;\n\n // Boost saturation at thin areas\n if (maxC > 0.001 && currentSat > 0.01) {\n // Calculate luminance\n float lum = dot(finalColor, vec3(0.299, 0.587, 0.114));\n // Increase saturation by moving away from gray toward the color\n vec3 gray = vec3(lum);\n float newSat = min(currentSat + satBoost, 1.0);\n float satRatio = currentSat > 0.001 ? newSat / currentSat : 1.0;\n finalColor = gray + (finalColor - gray) * satRatio;\n }\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FINAL THICKNESS APPLICATION - Apply AFTER all additive terms\n // This ensures thick areas stay dark even with glow added\n // ═══════════════════════════════════════════════════════════════════════\n // thicknessMultiplier: 0.15 in thick center, 1.0 at thin edges\n finalColor *= thicknessMultiplier;\n\n // ═══════════════════════════════════════════════════════════════════════\n // INTERNAL CAUSTICS - Bright spots from light concentration inside gem\n // Now with chromatic aberration for rainbow dispersion effect\n // Applied AFTER thickness darkening so they punch through dark areas\n // ═══════════════════════════════════════════════════════════════════════\n if (causticIntensity > 0.01) {\n // Get material hue for tinting caustics\n vec3 causticTint = vec3(1.0); // Default white\n float causticTintStrength = 0.4; // Default for clear gems\n if (sssStrength > 0.5) {\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 hue = absorption / max(maxAbs, 0.001);\n // Stronger tint for colored gems to prevent white bloom\n causticTintStrength = clamp((sssStrength - 0.5) * 0.8 + 0.4, 0.4, 0.9);\n causticTint = mix(vec3(1.0), hue * 1.2, causticTintStrength);\n }\n // Add RGB caustic with chromatic aberration\n // Reduce raw RGB blend for colored gems\n float rawBlend = mix(0.3, 0.1, clamp((sssStrength - 0.5) * 0.5, 0.0, 1.0));\n vec3 causticFinal = causticRGB * causticTint + causticRGB * rawBlend;\n causticFinal = min(causticFinal, vec3(0.4)); // Cap to prevent bloom\n finalColor += causticFinal;\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // FIRE - Intense sparkle points from light dispersion in facets\n // The "fire" effect that makes gems sparkle brilliantly\n // ═══════════════════════════════════════════════════════════════════════\n float fire = calculateFire(normal, viewDir, lightDir);\n\n // Tint fire by gem color - colored gems should have tinted highlights\n // Pure white fire only for quartz/clear gems (low sssStrength)\n vec3 fireColor = vec3(1.0, 0.99, 0.97); // Base warm white\n float fireIntensity = 0.3; // Base intensity for clear gems\n float fireClamp = 1.5; // Max fire value for clear gems\n\n if (sssStrength > 0.5) {\n // Get gem hue from absorption - this IS the gem's color\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 gemHue = absorption / max(maxAbs, 0.001);\n\n // For colored gems, fire should BE the gem color, not white\n // The more colored the gem (higher sssStrength), the more the fire matches the gem\n float colorStrength = clamp((sssStrength - 0.5) * 0.5, 0.0, 1.0);\n\n // Use gem hue directly as fire color - NOT mixed with white\n // This ensures fire can never bloom to white\n fireColor = gemHue * 1.2; // Slight brightness boost but stay saturated\n\n // Reduce fire intensity AND clamp for colored gems to prevent bloom washout\n // Colored gems should have subtle, saturated fire, not bright white spots\n fireIntensity = mix(0.3, 0.08, colorStrength); // Much lower for colored gems\n fireClamp = mix(1.5, 0.5, colorStrength); // Much lower clamp for colored gems\n }\n\n // Apply fire clamp BEFORE multiplying by color\n fire = min(fire, fireClamp);\n\n // Calculate fire contribution and clamp to prevent any channel from blooming\n vec3 fireContribution = fireColor * fire * fireIntensity;\n fireContribution = min(fireContribution, vec3(0.4)); // Hard cap on fire brightness\n finalColor += fireContribution;\n\n // Ensure minimum brightness - allow near-black for gemstones\n // minBrightness of 0.01 allows true darks while preventing total black\n finalColor = max(finalColor, vec3(minBrightness));\n\n // ═══════════════════════════════════════════════════════════════════════\n // ALPHA - More opaque for visibility\n // ═══════════════════════════════════════════════════════════════════════\n\n // Higher base opacity\n float baseAlpha = 0.6 + frostiness * 0.25;\n\n // Fresnel makes edges solid\n float rimAlpha = fresnel * 0.3;\n\n // Soul glow adds opacity\n float glowAlpha = soulIntensity * 0.15;\n\n float finalAlpha = min(baseAlpha + rimAlpha + glowAlpha, 0.95) * opacity;\n\n // ═══════════════════════════════════════════════════════════════════════\n // REFRACTED SOUL - Add the soul visible through the crystal\n // This is the actual soul mesh rendered to texture and sampled with refraction\n // ═══════════════════════════════════════════════════════════════════════\n if (refractedSoulAlpha > 0.01) {\n // The soul should glow through the crystal, tinted by the crystal's color\n // Use additive blending so the soul illuminates the crystal from within\n vec3 soulGlow = refractedSoulColor * refractedSoulAlpha;\n\n // Tint the soul by the crystal's SSS color for colored gems\n // emotionColorBleed controls how much pure emotion color comes through\n // 0 = fully tinted by gem color, 1 = pure emotion color\n if (sssStrength > 0.01) {\n vec3 absorption = sssAbsorption;\n float maxAbs = max(max(absorption.r, absorption.g), absorption.b);\n vec3 gemHue = absorption / max(maxAbs, 0.001);\n float tintAmount = sssStrength * 0.5 * (1.0 - emotionColorBleed);\n soulGlow *= mix(vec3(1.0), gemHue, tintAmount);\n }\n\n // Add soul glow to final color\n finalColor += soulGlow * 0.8;\n }\n\n // ═══════════════════════════════════════════════════════════════════════\n // EMOTION COLOR BLEED - Additional inner glow from soul emotion\n // Adds pure emotion color as light shining through the gem from the soul\n // ═══════════════════════════════════════════════════════════════════════\n if (emotionColorBleed > 0.001 && sssStrength > 0.01) {\n // Inner glow based on thickness - thinner areas show more soul light\n float innerGlow = 1.0 - abs(dot(normal, viewDir)); // Edges are thin\n innerGlow = pow(innerGlow, 1.5) * emotionColorBleed;\n\n // Also add glow near the core\n float coreProximity = exp(-distFromCenter * 2.0);\n innerGlow += coreProximity * emotionColorBleed * 0.5;\n\n // Add pure emotion color as inner light\n finalColor += emotionColor * innerGlow * 0.4;\n }\n\n gl_FragColor = vec4(finalColor, finalAlpha);\n}\n`,Ei={time:0,glowIntensity:1,opacity:1,frostiness:.55,fresnelPower:2.8,fresnelIntensity:.35,innerGlowStrength:.55,surfaceRoughness:.12,shadowDarkness:.6,specularIntensity:.9,specularPower:28,transmissionContrast:1,minBrightness:.005,surfaceNoiseScale:1.5,noiseFrequency:1.33,causticIntensity:.8,causticScale:2,causticSpeed:.12,textureStrength:.55,refractionIndex:1.5,refractionStrength:.5,resolution:[1920,1080],soulTextureSize:[1920,1080],soulScreenCenter:[.5,.5],sssStrength:.65,sssAbsorption:[2.4,2.5,2.8],sssScatterDistance:[.35,.4,.45],sssThicknessBias:.18,sssThicknessScale:.6,sssCurvatureScale:1.8,sssAmbient:.3,sssLightDir:[.5,1,.8],sssLightColor:[1,.98,.95],shellLayer1Mode:0,shellLayer1Strength:0,shellLayer1Enabled:0,shellLayer2Mode:0,shellLayer2Strength:0,shellLayer2Enabled:0,soulLayer1Mode:0,soulLayer1Strength:0,soulLayer1Enabled:0,soulLayer2Mode:0,soulLayer2Strength:0,soulLayer2Enabled:0,rimLayer1Mode:0,rimLayer1Strength:0,rimLayer1Enabled:0,rimLayer2Mode:0,rimLayer2Strength:0,rimLayer2Enabled:0,sssLayer1Mode:0,sssLayer1Strength:0,sssLayer1Enabled:0,sssLayer2Mode:0,sssLayer2Strength:0,sssLayer2Enabled:0};function Ii(t,i,n={}){const{glowColor:a=[1,1,.95],glowIntensity:s=1,materialVariant:o=null,emotionData:r=null,assetBasePath:l="/assets"}=n;return"custom"===i.material?function(t,i,n,a,s,o){const r=new e.TextureLoader;switch(t){case"moon":return function(t,i,n,a=null,s="/assets"){if("multiplexer"===a)return{material:U(t,{resolution:"2k",glowColor:new e.Color(i[0],i[1],i[2]),glowIntensity:n,assetBasePath:s}),type:"moon-multiplexer"};return{material:L(t,{resolution:"2k",glowColor:new e.Color(i[0],i[1],i[2]),glowIntensity:n,moonPhase:"full",assetBasePath:s}),type:"moon"}}(r,i,n,a,o);case"crystal":return Ai(i,n,"crystal",{sssPreset:"quartz"},o);case"rough":return Ai(i,n,"rough",{frostiness:.05,innerGlowStrength:0,fresnelIntensity:1.6},o);case"heart":return Ai(i,n,"heart",{frostiness:.475,innerGlowStrength:.117,fresnelIntensity:1.206},o);case"star":return Ai(i,n,"star",{sssPreset:"citrine"},o);default:return console.warn("Unknown custom material type:",t),null}}(t,a,s,o,0,l):"emissive"===i.material?function(t,i,n,a,s,o){const r=new e.TextureLoader;return"sun"===t?function(e,t,i,n=null,a=null,s="/assets"){return{material:X(e,{glowColor:t,glowIntensity:i,resolution:"4k",materialVariant:n,assetBasePath:s}),type:"sun"}}(r,i,n,a,s,o):(console.warn("Unknown emissive material type:",t),null)}(t,a,s,o,r,l):null}function Ai(t,i,n="crystal",a={},s="/assets"){const{vertexShader:o,fragmentShader:r}={vertexShader:"\nvarying vec3 vPosition;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n vPosition = position;\n vNormal = normalize(normalMatrix * normal);\n\n vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n vViewPosition = -mvPosition.xyz;\n\n gl_Position = projectionMatrix * mvPosition;\n}\n",fragmentShader:Ti};let l=null;if(n){const t=new e.TextureLoader,i={crystal:`${s}/textures/Crystal/crystal.jpg`,rough:`${s}/textures/Crystal/rough.jpg`,heart:`${s}/textures/Crystal/heart.jpg`,star:`${s}/textures/Crystal/star.jpg`},a=i[n]||i.crystal;l=t.load(a,void 0,e=>console.warn(`💎 ${n} texture failed to load:`,e))}const h=a.sssPreset?ki[a.sssPreset]:null;return{material:new e.ShaderMaterial({uniforms:{time:{value:0},emotionColor:{value:new e.Color(t[0],t[1],t[2])},glowIntensity:{value:i},opacity:{value:1},frostiness:{value:a.frostiness??Ei.frostiness},fresnelPower:{value:a.fresnelPower??Ei.fresnelPower},fresnelIntensity:{value:a.fresnelIntensity??Ei.fresnelIntensity},innerGlowStrength:{value:a.innerGlowStrength??Ei.innerGlowStrength},surfaceRoughness:{value:Ei.surfaceRoughness},shadowDarkness:{value:a.shadowDarkness??Ei.shadowDarkness},specularIntensity:{value:a.specularIntensity??Ei.specularIntensity},specularPower:{value:a.specularPower??Ei.specularPower},transmissionContrast:{value:a.transmissionContrast??Ei.transmissionContrast},minBrightness:{value:a.minBrightness??Ei.minBrightness},surfaceNoiseScale:{value:Ei.surfaceNoiseScale},noiseFrequency:{value:Ei.noiseFrequency},causticIntensity:{value:a.causticIntensity??Ei.causticIntensity},causticScale:{value:a.causticScale??Ei.causticScale},causticSpeed:{value:a.causticSpeed??Ei.causticSpeed},crystalTexture:{value:l},textureStrength:{value:"heart"===n?.35:n?Ei.textureStrength:0},soulTexture:{value:null},resolution:{value:new e.Vector2(Ei.resolution[0],Ei.resolution[1])},soulTextureSize:{value:new e.Vector2(Ei.soulTextureSize[0],Ei.soulTextureSize[1])},soulScreenCenter:{value:new e.Vector2(Ei.soulScreenCenter[0],Ei.soulScreenCenter[1])},refractionIndex:{value:a.refractionIndex??Ei.refractionIndex},refractionStrength:{value:a.refractionStrength??Ei.refractionStrength},sssStrength:{value:a.sssStrength??h?.sssStrength??Ei.sssStrength},sssAbsorption:{value:new e.Vector3(...a.sssAbsorption??h?.sssAbsorption??Ei.sssAbsorption)},sssScatterDistance:{value:new e.Vector3(...a.sssScatterDistance??h?.sssScatterDistance??Ei.sssScatterDistance)},sssThicknessBias:{value:a.sssThicknessBias??h?.sssThicknessBias??Ei.sssThicknessBias},sssThicknessScale:{value:a.sssThicknessScale??h?.sssThicknessScale??Ei.sssThicknessScale},sssCurvatureScale:{value:a.sssCurvatureScale??h?.sssCurvatureScale??Ei.sssCurvatureScale},sssAmbient:{value:a.sssAmbient??h?.sssAmbient??Ei.sssAmbient},sssLightDir:{value:new e.Vector3(...a.sssLightDir??Ei.sssLightDir)},sssLightColor:{value:new e.Vector3(...a.sssLightColor??Ei.sssLightColor)},emotionColorBleed:{value:a.emotionColorBleed??h?.emotionColorBleed??0},shellLayer1Mode:{value:Ei.shellLayer1Mode},shellLayer1Strength:{value:Ei.shellLayer1Strength},shellLayer1Enabled:{value:Ei.shellLayer1Enabled},shellLayer2Mode:{value:Ei.shellLayer2Mode},shellLayer2Strength:{value:Ei.shellLayer2Strength},shellLayer2Enabled:{value:Ei.shellLayer2Enabled},soulLayer1Mode:{value:Ei.soulLayer1Mode},soulLayer1Strength:{value:Ei.soulLayer1Strength},soulLayer1Enabled:{value:Ei.soulLayer1Enabled},soulLayer2Mode:{value:Ei.soulLayer2Mode},soulLayer2Strength:{value:Ei.soulLayer2Strength},soulLayer2Enabled:{value:Ei.soulLayer2Enabled},rimLayer1Mode:{value:Ei.rimLayer1Mode},rimLayer1Strength:{value:Ei.rimLayer1Strength},rimLayer1Enabled:{value:Ei.rimLayer1Enabled},rimLayer2Mode:{value:Ei.rimLayer2Mode},rimLayer2Strength:{value:Ei.rimLayer2Strength},rimLayer2Enabled:{value:Ei.rimLayer2Enabled},sssLayer1Mode:{value:Ei.sssLayer1Mode},sssLayer1Strength:{value:Ei.sssLayer1Strength},sssLayer1Enabled:{value:Ei.sssLayer1Enabled},sssLayer2Mode:{value:Ei.sssLayer2Mode},sssLayer2Strength:{value:Ei.sssLayer2Strength},sssLayer2Enabled:{value:Ei.sssLayer2Enabled}},vertexShader:o,fragmentShader:r,transparent:!0,side:e.DoubleSide,depthWrite:!1,blending:e.NormalBlending}),type:"crystal"}}function Ri(e){e&&(e.map&&e.map.dispose(),e.normalMap&&e.normalMap.dispose(),e.emissiveMap&&e.emissiveMap.dispose(),e.roughnessMap&&e.roughnessMap.dispose(),e.metalnessMap&&e.metalnessMap.dispose())}const zi=new Map;async function _i(e,t={}){if(zi.has(e)){const t=zi.get(e);if(t.loaded)return t}const i=ie[e];if(!i)return console.warn(`[GeometryCache] Unknown geometry type: ${e}`),null;const n={geometry:null,material:null,materialType:null,config:i,loaded:!1};if(i.geometryLoader?n.geometry=await i.geometryLoader(t.assetBasePath):n.geometry=i.geometry,"custom"===i.material||"emissive"===i.material){const a=Ii(e,i,{glowColor:t.glowColor||[1,1,.95],glowIntensity:t.glowIntensity||1,materialVariant:t.materialVariant,emotionData:t.emotionData,assetBasePath:t.assetBasePath});a&&(n.material=a.material,n.materialType=a.type)}return n.loaded=!0,zi.set(e,n),n}async function Oi(e={}){await Promise.all(["crystal","rough","heart","moon","sun"].map(t=>_i(t,e)))}function Fi(){for(const[e,t]of zi.entries())t.material&&(Ri(t.material),t.material.dispose());zi.clear()}var Li={preload:_i,preloadAll:Oi,get:function(e){const t=zi.get(e);return t&&t.loaded?t:null},has:function(e){const t=zi.get(e);return t&&t.loaded},updateMaterialOptions:function(e,t){const i=zi.get(e);if(!i||!i.material)return;const{uniforms:n}=i.material;n&&(t.glowColor&&n.glowColor&&n.glowColor.value.set(...t.glowColor),void 0!==t.glowIntensity&&n.glowIntensity&&(n.glowIntensity.value=t.glowIntensity))},dispose:Fi,getStatus:function(){const e={};for(const[t,i]of zi.entries())e[t]={loaded:i.loaded,hasGeometry:!!i.geometry,hasMaterial:!!i.material,materialType:i.materialType};return e}};class Gi{constructor(t,i={}){this._instanceId=Math.random().toString(36).substr(2,6),this.canvas=t,this.options=i,this._destroyed=!1,this._ready=!1,this._readyPromise=null,this.assetBasePath=i.assetBasePath||"/assets",this.geometryType=i.geometry||"sphere";const n="moon"===this.geometryType;this.renderer=new M(t,{enablePostProcessing:!1!==i.enablePostProcessing,enableShadows:i.enableShadows||!1,enableControls:!1!==i.enableControls,autoRotate:!n&&!1!==i.autoRotate,autoRotateSpeed:i.autoRotateSpeed,cameraDistance:i.cameraDistance,fov:i.fov,minZoom:i.minZoom,maxZoom:i.maxZoom,assetBasePath:this.assetBasePath});const a=ie[this.geometryType];a?this.geometryConfig=a:(console.warn(`Unknown geometry: ${this.geometryType}, falling back to sphere`),this.geometryConfig=ie.sphere),this.geometry=this.geometryConfig.geometry,this.geometry&&!this.geometry.isGroup&&(this.geometry.userData.geometryType=this.geometryType),this.materialVariant=i.materialVariant||null,this.onMaterialSwap=null;let s=null;const o=me(this.emotion),r=Ii(this.geometryType,this.geometryConfig,{glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:o,assetBasePath:this.assetBasePath});if(r&&(s=r.material,this.customMaterial=s,this.customMaterialType=r.type),this.geometryConfig.geometryLoader?this._readyPromise=this._loadAsyncGeometry():(this._ready=!0,this._readyPromise=Promise.resolve()),null===this.geometry&&this.geometryConfig.geometryLoader?this._deferredMeshCreation=!0:(this.coreMesh=this.renderer.createCoreMesh(this.geometry,s),"crystal"===this.customMaterialType&&this.createCrystalInnerCore()),this.calibrationRotation=[0,0,0],this.cameraRoll=0,"moon"===this.geometryType){const e=Math.PI/180;this.calibrationRotation=[B*e,k*e,T*e],this.cameraRoll=0}if("crystal"===this.geometryType||"rough"===this.geometryType||"heart"===this.geometryType||"star"===this.geometryType){const e=Math.PI/180;this.calibrationRotation=[0*e,30*e,0*e]}if(this.animator=new ne,this.breathingAnimator=new ae,this.breathingEnabled=!1!==i.enableBreathing,this._breathPhase=null,this._breathPhaseStartTime=0,this._breathPhaseDuration=0,this._breathPhaseStartScale=1,this._breathPhaseTargetScale=1,this._breathPhaseScale=1,this.gestureBlender=new se,this.geometryMorpher=new Me,this.blinkAnimator=new ye(this.geometryConfig),this.blinkAnimator.setEmotion(this.emotion),this.blinkingManuallyDisabled=!1,!1===i.enableBlinking&&(this.blinkAnimator.pause(),this.blinkingManuallyDisabled=!0),this.rotationBehavior=null,this.rotationDisabled=!1===i.autoRotate,this.wobbleEnabled=!0,this.rightingBehavior=new xe({strength:5,damping:.85,centerOfMass:[0,-.3,0],axes:{pitch:!0,roll:!0,yaw:!1}}),this.facingBehavior=null,n&&E.enabled){const e=Math.PI/180;this.facingBehavior=new Ce({strength:E.strength,lockedFace:E.lockedFace,lerpSpeed:E.lerpSpeed,calibrationRotation:[B*e,k*e,T*e]},this.renderer.camera)}this.emotion=i.emotion||"neutral",this.undertone=i.undertone||null,this.glowColor=[1,1,1],this.glowColorHex="#FFFFFF",this.glowIntensity=1,this.coreGlowEnabled=!0,this.glowIntensityOverride=null,this.intensityCalibrationOffset=0,this.baseEuler=[0,0,0],this.baseQuaternion=new e.Quaternion,this.gestureQuaternion=new e.Quaternion,this.tempEuler=new e.Euler,this.rotation=[0,0,0],this.baseScale=.16,this.scale=.16,this.position=[0,0,0],this.rhythmEngine=i.rhythmEngine||null,this.rhythm3DAdapter=we,this.rhythmEnabled=!1!==i.enableRhythm,this.rhythmEnabled&&this.rhythm3DAdapter.initialize(),this.particlesEnabled=!1!==i.enableParticles,this.particleVisibility=this.particlesEnabled;const l=new hi(50);l.canvasWidth=t.width,l.canvasHeight=t.height;const h=new ci({worldScale:2,baseRadius:1.5,depthScale:.75,verticalScale:1,coreRadius3D:2}),c=new gi(150,{renderer:this.renderer.renderer}),u=c.getPoints();if(u.layers.set(1),this.renderer.scene.add(u),this.particleOrchestrator=new bi(l,h,c),this.particleOrchestrator.setGeometryType(this.geometryType),this.particlesEnabled||c.geometry.setDrawRange(0,0),"sun"===this.geometryType){const e=this.geometry.parameters?.radius||.5;this.solarEclipse=new Pi(this.renderer.scene,e,this.coreMesh)}"moon"===this.geometryType&&this.customMaterial&&(this.lunarEclipse=new Bi(this.customMaterial)),this.virtualParticlePool=this.createVirtualParticlePool(5),this.nextPoolIndex=0,this.geometryConfig.defaultGlassMode&&!this.customMaterial&&this.setGlassMaterialEnabled(!0),this.setEmotion(this.emotion)}createVirtualParticlePool(e){const t=[];for(let i=0;i<e;i++)t.push({x:0,y:0,vx:0,vy:0,size:1,baseSize:1,opacity:1,scaleFactor:1,gestureData:null});return t}getVirtualParticleFromPool(){const e=this.virtualParticlePool[this.nextPoolIndex];return this.nextPoolIndex=(this.nextPoolIndex+1)%this.virtualParticlePool.length,e.x=0,e.y=0,e.vx=0,e.vy=0,e.size=1,e.baseSize=1,e.opacity=1,e.scaleFactor=1,e.gestureData=null,e}setEmotion(t,i=null){this.emotion=t,this.undertone=i;const n=me(t);if(n&&n.visual){if(n.visual.glowColor){let e=(a=(a=n.visual.glowColor).replace("#",""),[parseInt(a.substring(0,2),16)/255,parseInt(a.substring(2,4),16)/255,parseInt(a.substring(4,6),16)/255]);e=function(e,t){if(!t||"clear"===t||"none"===t)return e;const i={intense:{saturation:2.5,lightness:1.3},confident:{saturation:1.8,lightness:1.15},nervous:{saturation:1.6,lightness:1.1},tired:{saturation:.4,lightness:.65},subdued:{saturation:.25,lightness:.55}}[t];if(!i)return e;const n=function(e,t,i){const n=Math.max(e,t,i),a=Math.min(e,t,i),s=n-a,o=n+a;let r=0,l=0;const h=o/2;if(0!==s)switch(l=h>.5?s/(2-o):s/o,n){case e:r=((t-i)/s+(t<i?6:0))/6;break;case t:r=((i-e)/s+2)/6;break;case i:r=((e-t)/s+4)/6}return[360*r,100*l,100*h]}(e[0],e[1],e[2]);return n[1]=Math.min(100,n[1]*i.saturation),n[2]=Math.min(100,Math.max(0,n[2]*i.lightness)),function(e,t,i){let n,a,s;if(e/=360,i/=100,0==(t/=100))n=a=s=i;else{const o=(e,t,i)=>(i<0&&(i+=1),i>1&&(i-=1),i<1/6?e+6*(t-e)*i:i<.5?t:i<2/3?e+(t-e)*(2/3-i)*6:e),r=i<.5?i*(1+t):i+t-i*t,l=2*i-r;n=o(l,r,e+1/3),a=o(l,r,e),s=o(l,r,e-1/3)}return[n,a,s]}(n[0],n[1],n[2])}(e,i),this.glowColor=e,this.glowColorHex=n.visual.glowColor;const t=this.renderer.materialMode||"glass";this.glowIntensity=b(n.visual.glowColor,this.intensityCalibrationOffset,t)}if(this.renderer.updateLighting(t,n),this.customMaterial&&"moon"===this.customMaterialType){const t=new e.Color(this.glowColor[0],this.glowColor[1],this.glowColor[2]);N(this.customMaterial,t,this.glowIntensity)}else this.customMaterial&&"sun"===this.customMaterialType&&$(this.coreMesh,this.glowColor,this.glowIntensity,0)}var a;const s="sun"===this.geometryType?W:null;this.rotationDisabled||"moon"===this.geometryType?this.rotationBehavior=null:n&&n["3d"]&&n["3d"].rotation?this.rotationBehavior?this.rotationBehavior.updateConfig(n["3d"].rotation):(this.rotationBehavior=new Se(n["3d"].rotation,this.rhythmEngine,s),this.rotationBehavior.setWobbleEnabled(this.wobbleEnabled)):this.rotationBehavior||this.rotationDisabled||(this.rotationBehavior=new Se({type:"gentle",speed:1,axes:[0,.01,0]},this.rhythmEngine,s),this.rotationBehavior.setWobbleEnabled(this.wobbleEnabled)),this.rightingBehavior&&this.rightingBehavior.reset(),this.baseEuler[0]=0,this.baseEuler[2]=0;const o=vt(i);if(o&&o["3d"]){const e=o["3d"];e.rotation&&this.rotationBehavior&&this.rotationBehavior.applyUndertoneMultipliers(e.rotation),e.righting&&this.rightingBehavior&&this.rightingBehavior.applyUndertoneMultipliers(e.righting)}this.animator.stopAll();const r=n?.visual?.glowColor||"#00BCD4",l=this.renderer.materialMode||"glass";if(this.baseGlowIntensity=b(r,this.intensityCalibrationOffset,l),o&&o["3d"]&&o["3d"].glow&&(this.baseGlowIntensity,this.baseGlowIntensity*=o["3d"].glow.intensityMultiplier),this.breathingAnimator.setEmotion(t,o),this.blinkAnimator.setEmotion(t),this.renderer.updateBloom(this.baseGlowIntensity,1,this.geometryType),this.animator.playEmotion(t),this.particlesEnabled&&this.particleOrchestrator&&this.particleOrchestrator.setEmotion(t,i),n&&n.soulAnimation){const e=n.soulAnimation;this.setCrystalSoulEffects({driftEnabled:!0,driftSpeed:e.driftSpeed||.5,shimmerEnabled:!0,shimmerSpeed:e.shimmerSpeed||.5})}}setCoreGlowEnabled(e){this.coreGlowEnabled=e,this.crystalSoul&&this.crystalSoul.setVisible(e)}setGlassMaterialEnabled(e){const t=e?"glass":"glow";this.renderer.setMaterialMode(t)}setGlowIntensity(e){this.glowIntensityOverride=e,null!==e&&(this.glowIntensity=e,this.baseGlowIntensity=e)}sliderToIntensity(e){const t=e/100;return.3*Math.pow(10/.3,t)}setIntensityCalibration(e){this.intensityCalibrationOffset=e,this.setEmotion(this.emotion,this.undertone)}getGlowIntensity(){return this.glowIntensity}playGesture(e){const t=ft(e);if(!t)return void console.warn(`Unknown gesture: ${e}`);const i=this.getVirtualParticleFromPool(),n=t.config||{},a=n.musicalDuration?.musical?500*(n.musicalDuration.beats||2):n.duration||800,s=this.animator.time;if(this.position,this.rotation,this.scale,this.animator.animations.length>=10){const e=this.animator.animations.shift();console.warn(`⚠️ Animation limit reached (10), removed oldest: ${e.gestureName||"unknown"}`)}const o={initialized:!1};this.animator.animations.push({gestureName:e,duration:a,startTime:s,config:n,evaluate:e=>{i.x=0,i.y=0,i.vx=0,i.vy=0,i.size=1,i.opacity=1,t.apply&&t.apply(i,o,n,e,1,0,0);const a={...n,particle:i,config:n,strength:n.strength||1};return t["3d"]&&t["3d"].evaluate?t["3d"].evaluate.call(t,e,a):{position:[0,0,0],rotation:[0,0,0],scale:1}},callbacks:{onUpdate:(e,t)=>{e.position&&(this.position=e.position),e.rotation&&(this.tempEuler.set(e.rotation[0],e.rotation[1],e.rotation[2],"XYZ"),this.gestureQuaternion.setFromEuler(this.tempEuler)),void 0!==e.scale&&(this.scale=this.baseScale*e.scale),void 0!==e.glowIntensity&&(this.glowIntensity=this.baseGlowIntensity*e.glowIntensity)},onComplete:()=>{t.cleanup&&t.cleanup(i),this.position=[0,0,0],this.scale=this.baseScale}}})}setSunShadow(e="off"){"sun"===this.geometryType&&this.solarEclipse?this.solarEclipse.setEclipseType(e):console.warn("⚠️ Eclipse only available for sun geometry")}startSolarEclipse(e={}){const t=e.type||"total";"sun"===this.geometryType&&this.solarEclipse?this.solarEclipse.setEclipseType(t):(this.morphToShape("sun"),setTimeout(()=>{this.solarEclipse&&this.solarEclipse.setEclipseType(t)},600))}startLunarEclipse(e={}){const t=e.type||"total";"moon"===this.geometryType&&this.lunarEclipse?this.lunarEclipse.setEclipseType(t):(this.morphToShape("moon"),setTimeout(()=>{this.lunarEclipse&&this.lunarEclipse.setEclipseType(t)},600))}stopEclipse(){this.solarEclipse&&this.solarEclipse.setEclipseType("off"),this.lunarEclipse&&this.lunarEclipse.setEclipseType("off")}setMoonEclipse(e="off"){"moon"===this.geometryType&&this.lunarEclipse?this.lunarEclipse.setEclipseType(e):console.warn("⚠️ Lunar eclipse only available for moon geometry")}setBloodMoonBlend(e={}){"moon"===this.geometryType&&this.customMaterial?(void 0!==e.blendMode&&(this.customMaterial.uniforms.blendMode.value=e.blendMode),void 0!==e.blendStrength&&(this.customMaterial.uniforms.blendStrength.value=e.blendStrength),void 0!==e.emissiveStrength&&(this.customMaterial.uniforms.emissiveStrength.value=e.emissiveStrength),void 0!==e.eclipseIntensity&&(this.customMaterial.uniforms.eclipseIntensity.value=e.eclipseIntensity)):console.warn("⚠️ Blood moon blend only available for moon geometry")}setBlendLayer(e,t={}){if("moon"!==this.geometryType&&"sun"!==this.geometryType||!this.customMaterial)return void console.warn("⚠️ Blend layers only available for moon and sun geometry");const i=`layer${e}`;void 0!==t.mode&&this.customMaterial.uniforms[`${i}Mode`]&&(this.customMaterial.uniforms[`${i}Mode`].value=t.mode),void 0!==t.strength&&this.customMaterial.uniforms[`${i}Strength`]&&(this.customMaterial.uniforms[`${i}Strength`].value=t.strength),void 0!==t.enabled&&this.customMaterial.uniforms[`${i}Enabled`]&&(this.customMaterial.uniforms[`${i}Enabled`].value=t.enabled?1:0)}setAllBlendLayers(e){"moon"!==this.geometryType&&"sun"!==this.geometryType||!this.customMaterial?console.warn("⚠️ Blend layers only available for moon and sun geometry"):e.forEach((e,t)=>{this.setBlendLayer(t+1,e)})}setCrystalBlendLayer(e,t,i={}){if("crystal"!==this.geometryType&&"rough"!==this.geometryType||!this.customMaterial||"crystal"!==this.customMaterialType)return;const n=`${e}Blend${t}`;void 0!==i.mode&&this.customMaterial.uniforms[`${n}Mode`]&&(this.customMaterial.uniforms[`${n}Mode`].value=i.mode),void 0!==i.strength&&this.customMaterial.uniforms[`${n}Strength`]&&(this.customMaterial.uniforms[`${n}Strength`].value=i.strength),void 0!==i.enabled&&this.customMaterial.uniforms[`${n}Enabled`]&&(this.customMaterial.uniforms[`${n}Enabled`].value=i.enabled?1:0)}setCrystalUniforms(e={}){if("crystal"!==this.geometryType&&"rough"!==this.geometryType||!this.customMaterial||"crystal"!==this.customMaterialType)return void console.warn("⚠️ Crystal uniforms only available with crystal blend-layers material");const{uniforms:t}=this.customMaterial,i=(e,t,i=0,n=10)=>{e&&"number"==typeof t&&!isNaN(t)&&isFinite(t)&&(e.value=Math.max(i,Math.min(n,t)))};i(t.coreGlowStrength,e.coreGlowStrength,0,2),void 0===e.coreGlowFalloff||isNaN(e.coreGlowFalloff)||(i(t.coreGlowFalloff,e.coreGlowFalloff,.1,3),this.setCrystalCoreSize(e.coreGlowFalloff)),i(t.fresnelStrength,e.fresnelStrength,0,2),i(t.fresnelPower,e.fresnelPower,.5,10),i(t.transmissionStrength,e.transmissionStrength,0,1),i(t.facetStrength,e.facetStrength,0,2),i(t.iridescenceStrength,e.iridescenceStrength,0,1),i(t.chromaticAberration,e.chromaticAberration,0,1),i(t.causticStrength,e.causticStrength,0,1),i(t.emissiveIntensity,e.emissiveIntensity,0,5),i(t.sparkleEnabled,e.sparkleEnabled,0,1),i(t.sparkleSpeed,e.sparkleSpeed,.1,5),i(t.causticEnabled,e.causticEnabled,0,1),i(t.causticSpeed,e.causticSpeed,.1,10),i(t.causticScale,e.causticScale,.5,10),i(t.causticCoverage,e.causticCoverage,0,1),i(t.energyPulseEnabled,e.energyPulseEnabled,0,1),i(t.energyPulseSpeed,e.energyPulseSpeed,.1,5)}createCrystalInnerCore(){if(this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null),!this.coreMesh)return;const e=this._targetGeometryType||this.geometryType;this.crystalSoul=new pi({radius:.35,detail:1,geometryType:e,renderer:this.renderer,assetBasePath:this.assetBasePath}),this.crystalSoul.attachTo(this.coreMesh,this.renderer?.scene);let t=1;"heart"===e?(this.crystalShellBaseScale=2.4,t=1):"rough"===e?(this.crystalShellBaseScale=1.6,t=1):"star"===e?(this.crystalShellBaseScale=2,t=1.4):"crystal"===e&&(this.crystalShellBaseScale=2,t=1),this.crystalSoul.baseScale=t,this.crystalSoul.mesh.scale.setScalar(t),this.crystalSoul.setVisible(this.coreGlowEnabled),this.crystalInnerCore=this.crystalSoul.mesh,this.crystalInnerCoreMaterial=this.crystalSoul.material,this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale}updateCrystalInnerCore(e,t=0){if(!this.crystalSoul)return;const i=this.breathingAnimator&&this.breathingEnabled?this.breathingAnimator.getBreathingScale():1;this.crystalSoul.update(t,e,i),this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale}setCrystalSoulEffects(e={}){this.crystalSoul&&this.crystalSoul.setEffects(e)}setCrystalCoreSize(e){this.crystalSoul&&(this.crystalSoul.setSize(e),this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale)}setCrystalShellSize(e){!this.coreMesh||"crystal"!==this.geometryType&&"rough"!==this.geometryType&&"heart"!==this.geometryType||(this.crystalShellBaseScale=e)}setWobbleEnabled(e){this.wobbleEnabled=e,this.rotationBehavior&&this.rotationBehavior.setWobbleEnabled(e),e||(this.rightingBehavior&&this.rightingBehavior.reset(),this.baseEuler[0]=0,this.baseEuler[2]=0)}setMaterialVariant(e){this.materialVariant=e}setRhythmEnabled(e){this.rhythmEnabled=e,e&&this.rhythm3DAdapter&&!this.rhythm3DAdapter.enabled&&this.rhythm3DAdapter.initialize()}setGrooveEnabled(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setGrooveEnabled(e)}setBeatSyncStrength(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setBeatSyncStrength(e)}setGrooveConfig(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setGrooveConfig(e)}isRhythmPlaying(){return this.rhythm3DAdapter?.isPlaying()||!1}getRhythmBPM(){return this.rhythm3DAdapter?.getBPM()||120}startRhythm(e=120,t="straight"){this.rhythm3DAdapter&&this.rhythm3DAdapter.start(e,t)}stopRhythm(){this.rhythm3DAdapter&&this.rhythm3DAdapter.stop()}setRhythmBPM(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setBPM(e)}setRhythmPattern(e){this.rhythm3DAdapter&&this.rhythm3DAdapter.setPattern(e)}breathePhase(e,t){const i=Math.max(.5,Math.min(30,t));switch(this._breathPhaseStartScale=this._breathPhaseScale,this._breathPhaseStartTime=performance.now(),this._breathPhaseDuration=1e3*i,this._breathPhase=e,e){case"inhale":this._breathPhaseTargetScale=1.3;break;case"exhale":this._breathPhaseTargetScale=.85;break;default:this._breathPhaseTargetScale=this._breathPhaseStartScale}console.log(`[Core3D] breathePhase: ${e} for ${i}s (${this._breathPhaseStartScale.toFixed(2)} → ${this._breathPhaseTargetScale.toFixed(2)})`)}stopBreathingPhase(){this._breathPhase=null,this._breathPhaseScale=1,this._breathPhaseStartScale=1,this._breathPhaseTargetScale=1,console.log("[Core3D] breathePhase stopped, scale reset to 1.0")}_updateBreathingPhase(e){if(!this._breathPhase)return this._breathPhaseScale;const t=performance.now()-this._breathPhaseStartTime,i=this._breathPhaseDuration,n=Math.min(1,t/i),a=Math.sin(n*Math.PI/2);return this._breathPhaseScale=this._breathPhaseStartScale+(this._breathPhaseTargetScale-this._breathPhaseStartScale)*a,n>=1&&(this._breathPhaseScale=this._breathPhaseTargetScale,this._breathPhase=null),this._breathPhaseScale}morphToShape(e,t=800){const i=ie[e];i?this.geometryMorpher.startMorph(this.geometryType,e,t)&&(this.geometryMorpher.getInterruptedTarget(),this.blinkAnimator.pause(),this._targetGeometryConfig=i,this._targetGeometryType=e,i.geometryLoader&&!i.geometry?(this._targetGeometry=null,this._pendingGeometryLoad=i.geometryLoader(this.assetBasePath).then(e=>{this._targetGeometry=e,i.geometry=e,this._pendingGeometryLoad=null})):(this._targetGeometry=i.geometry,this._pendingGeometryLoad=null)):console.warn(`Unknown shape: ${e}`)}isMorphing(){return this.geometryMorpher.isTransitioning}getMorphState(){return this.geometryMorpher.getState()}growIn(e=500){this.geometryMorpher.growIn(this.geometryType,e)}easeInOutCubic(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}render(e){if(this._destroyed)return;if(!this._ready)return;this.animator.update(e);const t=this.geometryMorpher.update(e);if(t.shouldSwapGeometry&&this._pendingGeometryLoad&&this.geometryMorpher.pauseAtSwap(),t.waitingForGeometry&&this._targetGeometry&&!this._pendingGeometryLoad&&(this.geometryMorpher.resumeFromSwap(),this.geometryMorpher.hasSwappedGeometry=!1),t.shouldSwapGeometry&&this._targetGeometry){const e=this.geometryType;this.customMaterial&&function(e,t){switch(e){case"moon":!function(e){if(!e||!e.uniforms)return;const t=e.uniforms;t.shadowOffset&&t.shadowOffset.value.set(I.full.x,I.full.y),t.shadowCoverage&&(t.shadowCoverage.value=.5),t.shadowSoftness&&(t.shadowSoftness.value=.05),t.eclipseProgress&&(t.eclipseProgress.value=0),t.eclipseIntensity&&(t.eclipseIntensity.value=0),t.bloodMoonColor&&(t.bloodMoonColor.value=[.85,.18,.08]),t.emissiveStrength&&(t.emissiveStrength.value=.39),t.eclipseShadowPos&&(t.eclipseShadowPos.value=[-2,0]),t.eclipseShadowRadius&&(t.eclipseShadowRadius.value=1.2),t.shadowDarkness&&(t.shadowDarkness.value=.53),t.eclipseShadowColor&&(t.eclipseShadowColor.value=[1,.58,0]),t.eclipseMidtoneColor&&(t.eclipseMidtoneColor.value=[.71,.43,.03]),t.eclipseHighlightColor&&(t.eclipseHighlightColor.value=[1,.28,.1]),t.eclipseGlowColor&&(t.eclipseGlowColor.value=[.09,.09,.09]),t.eclipseBrightnessModel&&(t.eclipseBrightnessModel.value=0),t.layer1Mode&&(t.layer1Mode.value=9),t.layer1Strength&&(t.layer1Strength.value=.322),t.layer1Enabled&&(t.layer1Enabled.value=1),t.layer2Mode&&(t.layer2Mode.value=0),t.layer2Strength&&(t.layer2Strength.value=2.785),t.layer2Enabled&&(t.layer2Enabled.value=1),t.layer3Mode&&(t.layer3Mode.value=7),t.layer3Strength&&(t.layer3Strength.value=.199),t.layer3Enabled&&(t.layer3Enabled.value=1),t.layer4Mode&&(t.layer4Mode.value=0),t.layer4Strength&&(t.layer4Strength.value=0),t.layer4Enabled&&(t.layer4Enabled.value=0),t.opacity&&(t.opacity.value=1)}(t);break;case"sun":!function(e){if(!e||!e.uniforms)return;const t=e.uniforms;t.eclipseProgress&&(t.eclipseProgress.value=0),t.eclipseShadowPos&&(t.eclipseShadowPos.value=[-2,0]),t.eclipseShadowRadius&&(t.eclipseShadowRadius.value=.882),t.shadowDarkness&&(t.shadowDarkness.value=1),t.shadowOffset&&t.shadowOffset.value.set(200,0),t.shadowCoverage&&(t.shadowCoverage.value=.5),t.shadowSoftness&&(t.shadowSoftness.value=.1),t.layer1Mode&&(t.layer1Mode.value=0),t.layer1Strength&&(t.layer1Strength.value=.23),t.layer1Enabled&&(t.layer1Enabled.value=1),t.layer2Mode&&(t.layer2Mode.value=0),t.layer2Strength&&(t.layer2Strength.value=0),t.layer2Enabled&&(t.layer2Enabled.value=0),t.layer3Mode&&(t.layer3Mode.value=0),t.layer3Strength&&(t.layer3Strength.value=0),t.layer3Enabled&&(t.layer3Enabled.value=0),t.layer4Mode&&(t.layer4Mode.value=0),t.layer4Strength&&(t.layer4Strength.value=0),t.layer4Enabled&&(t.layer4Enabled.value=0),t.emissiveIntensity&&(t.emissiveIntensity.value=4),t.opacity&&(t.opacity.value=1),t.time&&(t.time.value=0)}(t);break;case"crystal":case"diamond":!function(e){if(!e||!e.uniforms)return;const t=e.uniforms,i=Ei;t.frostiness&&(t.frostiness.value=i.frostiness),t.fresnelPower&&(t.fresnelPower.value=i.fresnelPower),t.fresnelIntensity&&(t.fresnelIntensity.value=i.fresnelIntensity),t.innerGlowStrength&&(t.innerGlowStrength.value=i.innerGlowStrength),t.surfaceRoughness&&(t.surfaceRoughness.value=i.surfaceRoughness),t.surfaceNoiseScale&&(t.surfaceNoiseScale.value=i.surfaceNoiseScale),t.noiseFrequency&&(t.noiseFrequency.value=i.noiseFrequency),t.causticIntensity&&(t.causticIntensity.value=i.causticIntensity),t.causticScale&&(t.causticScale.value=i.causticScale),t.causticSpeed&&(t.causticSpeed.value=i.causticSpeed),t.textureStrength&&(t.textureStrength.value=i.textureStrength),t.layer1Mode&&(t.layer1Mode.value=i.layer1Mode),t.layer1Strength&&(t.layer1Strength.value=i.layer1Strength),t.layer1Enabled&&(t.layer1Enabled.value=i.layer1Enabled),t.layer2Mode&&(t.layer2Mode.value=i.layer2Mode),t.layer2Strength&&(t.layer2Strength.value=i.layer2Strength),t.layer2Enabled&&(t.layer2Enabled.value=i.layer2Enabled),t.layer3Mode&&(t.layer3Mode.value=i.layer3Mode),t.layer3Strength&&(t.layer3Strength.value=i.layer3Strength),t.layer3Enabled&&(t.layer3Enabled.value=i.layer3Enabled),t.layer4Mode&&(t.layer4Mode.value=i.layer4Mode),t.layer4Strength&&(t.layer4Strength.value=i.layer4Strength),t.layer4Enabled&&(t.layer4Enabled.value=i.layer4Enabled),t.glowIntensity&&(t.glowIntensity.value=i.glowIntensity),t.opacity&&(t.opacity.value=i.opacity),t.time&&(t.time.value=i.time)}(t)}}(e,this.customMaterial),this.geometry=this._targetGeometry,this.geometryType=this._targetGeometryType,this.geometryConfig=this._targetGeometryConfig,this.customMaterial&&(Ri(this.customMaterial),this.renderer.disposeMaterial(this.customMaterial),this.customMaterial=null,this.customMaterialType=null);let t=null;const i=me(this.emotion),n=Ii(this._targetGeometryType,this._targetGeometryConfig,{glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:i,assetBasePath:this.assetBasePath});if(n&&(t=n.material,this.customMaterial=t,this.customMaterialType=n.type),t)this.renderer.swapGeometry(this.geometry,t);else{this.renderer.swapGeometry(this.geometry);const e=!0===this._targetGeometryConfig.defaultGlassMode;this.setGlassMaterialEnabled(e)}if(this.onMaterialSwap&&this.onMaterialSwap({geometryType:this._targetGeometryType,material:this.customMaterial,materialType:this.customMaterialType}),this.blinkAnimator.setGeometry(this._targetGeometryConfig),this.rightingBehavior&&this.rightingBehavior.reset(),this.rotation=[0,0,0],"sun"===this._targetGeometryType){if(!this.solarEclipse){const e=this.geometry.parameters?.radius||.5;this.solarEclipse=new Pi(this.renderer.scene,e,this.renderer.coreMesh)}}else this.solarEclipse&&(this.solarEclipse.dispose(),this.solarEclipse=null);if("moon"===this._targetGeometryType?!this.lunarEclipse&&this.customMaterial&&(this.lunarEclipse=new Bi(this.customMaterial)):this.lunarEclipse&&(this.lunarEclipse.dispose(),this.lunarEclipse=null),"crystal"===this._targetGeometryType||"rough"===this._targetGeometryType||"heart"===this._targetGeometryType||"star"===this._targetGeometryType?"crystal"===this.customMaterialType&&this.createCrystalInnerCore():this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null,this.crystalInnerCore=null,this.crystalInnerCoreMaterial=null),"moon"===this._targetGeometryType){this.rotationBehavior=null,this.renderer?.controls&&(this.renderer.controls.autoRotate=!1),this.renderer?.setCameraPreset&&this.renderer.setCameraPreset("front",0,!0);const e=Math.PI/180;this.calibrationRotation[0]=B*e,this.calibrationRotation[1]=k*e,this.calibrationRotation[2]=T*e,!this.facingBehavior&&E.enabled&&(this.facingBehavior=new Ce({strength:E.strength,lockedFace:E.lockedFace,lerpSpeed:E.lerpSpeed,calibrationRotation:[B*e,k*e,T*e]},this.renderer.camera))}else{if(this.facingBehavior&&(this.facingBehavior.dispose(),this.facingBehavior=null),this.renderer?.controls&&!1!==this.options.autoRotate&&(this.renderer.controls.autoRotate=!0),"crystal"===this._targetGeometryType||"rough"===this._targetGeometryType||"heart"===this._targetGeometryType){const e=Math.PI/180;this.calibrationRotation[0]=0*e,this.calibrationRotation[1]=30*e,this.calibrationRotation[2]=0*e}else this.calibrationRotation[0]=0,this.calibrationRotation[1]=0,this.calibrationRotation[2]=0;if(this.rotationDisabled)this.rotationBehavior=null;else{const e=me(this.emotion);e&&e["3d"]&&e["3d"].rotation&&(this.rotationBehavior?this.rotationBehavior.updateConfig(e["3d"].rotation):(this.rotationBehavior=new Se(e["3d"].rotation,this.rhythmEngine),this.rotationBehavior.setWobbleEnabled(this.wobbleEnabled)))}}}t.completed&&(this._targetGeometry=null,this._targetGeometryType=null,this._targetGeometryConfig=null,this.blinkingManuallyDisabled||this.blinkAnimator.resume()),this.breathingAnimator.update(e,this.emotion,vt(this.undertone));const i=this._updateBreathingPhase(e),n=1!==i?i:this.breathingEnabled?this.breathingAnimator.getBreathingScale():1,a=t.scaleMultiplier,s=this.blinkAnimator.update(e);this.rotationBehavior?this.rotationBehavior.update(e,this.baseEuler):"moon"===this.geometryType||this.rotationDisabled||(this.baseEuler[1]+=3e-4*e),this.rightingBehavior&&this.rightingBehavior.update(e,this.baseEuler),this.facingBehavior&&(this.baseEuler[0]=0,this.baseEuler[1]=0,this.baseEuler[2]=0);this.baseEuler[0]=Math.max(-.35,Math.min(.35,this.baseEuler[0])),this.baseEuler[2]=Math.max(-.35,Math.min(.35,this.baseEuler[2])),this.tempEuler.set(this.baseEuler[0],this.baseEuler[1],this.baseEuler[2],"XYZ"),this.baseQuaternion.setFromEuler(this.tempEuler),this.rhythm3DAdapter&&this.rhythm3DAdapter.update(e);const o=this.gestureBlender.blend(this.animator.animations,this.animator.time,this.baseQuaternion,this.baseScale,this.baseGlowIntensity),r=this.rhythm3DAdapter?.isPlaying()?this.rhythm3DAdapter.getModulation():null,l=this.animator.animations.length>0;this.position=r&&!l?[o.position[0]+r.grooveOffset[0],o.position[1]+r.grooveOffset[1],o.position[2]+r.grooveOffset[2]]:r&&l?[o.position[0]*r.positionMultiplier,o.position[1]*r.positionMultiplier,o.position[2]*r.positionMultiplier]:o.position,this.rotation=r&&!l?[o.rotation[0]+r.grooveRotation[0],o.rotation[1]+r.grooveRotation[1],o.rotation[2]+r.grooveRotation[2]]:o.rotation,this.scale=r&&!l?o.scale*r.grooveScale:r&&l?o.scale*r.scaleMultiplier:o.scale,null===this.glowIntensityOverride&&(this.glowIntensity=r&&l?o.glowIntensity*r.glowMultiplier:o.glowIntensity),this.gestureQuaternion=o.gestureQuaternion,this.glowBoost=o.glowBoost||0,s.isBlinking&&s.rotation&&(this.rotation[0]+=s.rotation[0],this.rotation[1]+=s.rotation[1],this.rotation[2]+=s.rotation[2]);const h="crystal"!==this.geometryType&&"rough"!==this.geometryType,c=s.isBlinking&&h?s.scale[1]:1,u=this.crystalShellBaseScale||2,d=this.scale*a*n*c*u;if(this.particleVisibility&&this.particleOrchestrator){const t=this.geometryConfig?.particleRadiusMultiplier||1,i=(this.crystalShellBaseScale||2)*this.scale*n*t;this.particleOrchestrator.update(e,this.emotion,this.undertone,this.animator.animations,this.animator.time,{x:this.position[0],y:this.position[1],z:this.position[2]},{width:this.canvas.width,height:this.canvas.height},{euler:this.baseEuler,quaternion:this.baseQuaternion,angularVelocity:this.rotationBehavior?this.rotationBehavior.axes:[0,0,0]},this.baseScale,i)}const m=s.isBlinking&&s.glowBoost?1+s.glowBoost:1,p=this.coreGlowEnabled?this.glowIntensity*m:0,g=this.emotiveEngine?.getVirtualParticle(),f=p*(g?.opacity??1),y=t.isTransitioning?.3:.1;if(this.renderer.updateBloom(f,y,this.geometryType),this.glowBoost>0||this.renderer.glowLayer&&this.renderer.glowLayer.isActive()){const t=this.coreMesh?.position;this.renderer.updateGlowLayer(this.glowBoost,this.glowColor,t,e)}if("sun"===this.customMaterialType&&$(this.coreMesh,this.glowColor,f,e),"moon"!==this.customMaterialType&&"moon-multiplexer"!==this.customMaterialType||!this.customMaterial||this.customMaterial.uniforms&&this.customMaterial.uniforms.glowIntensity&&(this.customMaterial.uniforms.glowIntensity.value=f),"crystal"===this.customMaterialType&&this.customMaterial){if(this.customMaterial.uniforms){this.customMaterial.uniforms.time.value+=e/1e3,this.customMaterial.uniforms.glowIntensity&&(this.customMaterial.uniforms.glowIntensity.value=f);const t=v(this.glowColor,.3),i=[t.r,t.g,t.b];if(this.customMaterial.uniforms.emotionColor.value.setRGB(i[0],i[1],i[2]),this.customMaterial.uniforms.blinkIntensity){const e=s.isBlinking?Math.sin(s.progress*Math.PI):0;this.customMaterial.uniforms.blinkIntensity.value=e}}if(this.coreGlowEnabled){const t=v(this.glowColor,.3),i=[t.r,t.g,t.b];this.updateCrystalInnerCore(i,e)}}this.renderer.render({position:this.position,rotation:this.rotation,scale:d,glowColor:this.glowColor,glowColorHex:this.glowColorHex,glowIntensity:f,hasActiveGesture:this.animator.animations.length>0,calibrationRotation:this.calibrationRotation,solarEclipse:this.solarEclipse,deltaTime:e,morphProgress:t.isTransitioning?t.visualProgress:null}),this.lunarEclipse&&this.lunarEclipse.update(e)}async _loadAsyncGeometry(){try{const e=await _i(this.geometryType,{glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:me(this.emotion),assetBasePath:this.assetBasePath});if(this._destroyed)return;if(!e||!e.geometry)return console.warn(`[Core3D:${this._instanceId}] Async geometry load returned null!`),void(this._ready=!0);const t=e.geometry.clone();if(t.userData.geometryType=this.geometryType,this.geometry=t,this._deferredMeshCreation){if(this.coreMesh=this.renderer.createCoreMesh(t,this.customMaterial),this._destroyed)return;if("crystal"===this.customMaterialType&&(await this._createCrystalInnerCoreAsync(),this._destroyed))return;this._deferredMeshCreation=!1}else if(this.coreMesh){const e=this.coreMesh.geometry;if(this.coreMesh.geometry=t,e&&e!==t&&e.dispose(),this._destroyed)return;if("crystal"===this.customMaterialType&&(await this._createCrystalInnerCoreAsync(),this._destroyed))return}if(this._destroyed)return;this._logSceneHierarchy(),this._ready=!0}catch(e){console.warn(`[Core3D:${this._instanceId}] Async geometry load FAILED:`,e),this._destroyed||(this._ready=!0)}}_logSceneHierarchy(){const e=this.renderer?.scene;e&&e.children.forEach((e,t)=>{const i=null===e?"NULL!":void 0===e?"UNDEFINED!":null===e.visible?"visible=NULL!":void 0===e.visible?"visible=UNDEF!":"OK";console.log(` [${t}] ${e?.name||e?.type||"UNKNOWN"} status=${i} uuid=${e?.uuid?.slice(0,8)||"N/A"}`)})}async _createCrystalInnerCoreAsync(){if(this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null),!this.coreMesh)return;if(await pi._loadInclusionGeometry(this.assetBasePath),this._destroyed||!this.coreMesh)return;this.crystalSoul=new pi({radius:.35,detail:1,geometryType:this.geometryType,renderer:this.renderer,assetBasePath:this.assetBasePath}),this.crystalSoul.attachTo(this.coreMesh,this.renderer?.scene);let e=1;"heart"===this.geometryType?(this.crystalShellBaseScale=2.4,e=1):"rough"===this.geometryType?(this.crystalShellBaseScale=1.6,e=1):"crystal"===this.geometryType&&(e=1),this.crystalSoul.baseScale=e,this.crystalSoul.mesh.scale.setScalar(e),this.crystalSoul.setVisible(this.coreGlowEnabled),this.crystalInnerCore=this.crystalSoul.mesh,this.crystalInnerCoreMaterial=this.crystalSoul.material,this.crystalInnerCoreBaseScale=this.crystalSoul.baseScale}isReady(){return this._ready}async waitUntilReady(){this._ready||this._readyPromise&&await this._readyPromise}destroy(){if(this._instanceId,this._ready,this._destroyed,this.crystalSoul,this.renderer,this._destroyed=!0,this.crystalSoul&&(this.crystalSoul.dispose(),this.crystalSoul=null,this.crystalInnerCore=null,this.crystalInnerCoreMaterial=null),this.particleOrchestrator){const e=this.particleOrchestrator.renderer;if(e){const t=e.getPoints();t&&this.renderer?.scene&&this.renderer.scene.remove(t)}this.particleOrchestrator.destroy(),this.particleOrchestrator=null}this.solarEclipse&&(this.solarEclipse.dispose(),this.solarEclipse=null),this.lunarEclipse&&(this.lunarEclipse.dispose(),this.lunarEclipse=null),this.customMaterial&&(this.renderer.disposeMaterial(this.customMaterial),this.customMaterial=null,this.customMaterialType=null),this.facingBehavior&&(this.facingBehavior.dispose(),this.facingBehavior=null),this.animator.stopAll(),this.renderer.destroy(),this.virtualParticlePool&&(this.virtualParticlePool.length=0,this.virtualParticlePool=null),this.animator.destroy?.(),this.breathingAnimator.destroy?.(),this.gestureBlender.destroy?.(),this.geometryMorpher.destroy?.(),this.blinkAnimator.destroy?.(),this.rotationBehavior&&(this.rotationBehavior.destroy?.(),this.rotationBehavior=null),this.rightingBehavior&&(this.rightingBehavior.destroy?.(),this.rightingBehavior=null),this.tempEuler=null,this.baseQuaternion=null,this.gestureQuaternion=null,this.geometry=null,this.geometryConfig=null,this._targetGeometry=null,this._targetGeometryConfig=null,this._targetGeometryType=null,this.canvas=null,this.options=null,this.coreMesh=null,this.rhythmEngine=null,this.rhythm3DAdapter=null,this.emotiveEngine=null,Fi()}async preloadGeometries(){const e={glowColor:this.glowColor||[1,1,.95],glowIntensity:this.glowIntensity||1,materialVariant:this.materialVariant,emotionData:me(this.emotion)};await Oi(e)}}class Vi{constructor(){this.listeners=new Map,this.groups=new Map,this.stats={registered:0,removed:0,active:0}}addEventListener(e,t,i,n={},a="default"){const s=this.generateId(),o={id:s,target:e,eventType:t,handler:i,options:n,group:a,active:!0};return this.listeners.set(s,o),this.groups.has(a)||this.groups.set(a,new Set),this.groups.get(a).add(s),e.addEventListener(t,i,n),this.stats.registered++,this.stats.active++,s}removeEventListener(e){const t=this.listeners.get(e);if(!t||!t.active)return!1;t.target.removeEventListener(t.eventType,t.handler,t.options),t.active=!1;const i=this.groups.get(t.group);return i&&(i.delete(e),0===i.size&&this.groups.delete(t.group)),this.listeners.delete(e),this.stats.removed++,this.stats.active--,!0}removeGroup(e){const t=this.groups.get(e);if(!t)return 0;let i=0;for(const e of t)this.removeEventListener(e)&&i++;return i}removeAllForTarget(e){let t=0;for(const[i,n]of this.listeners.entries())n.target===e&&n.active&&this.removeEventListener(i)&&t++;return t}removeAllOfType(e){let t=0;for(const[i,n]of this.listeners.entries())n.eventType===e&&n.active&&this.removeEventListener(i)&&t++;return t}removeAll(){let e=0;for(const[t,i]of this.listeners.entries())i.active&&this.removeEventListener(t)&&e++;return e}createAutoRemove(e,t,i,n={}){const a=this.addEventListener(e,t,i,n);return{id:a,remove:()=>this.removeEventListener(a)}}once(e,t,i,n={}){const a=this.addEventListener(e,t,e=>{i(e),this.removeEventListener(a)},n);return a}debounced(e,t,i,n=250,a={}){let s;return this.addEventListener(e,t,e=>{clearTimeout(s),s=setTimeout(()=>i(e),n)},a)}throttled(e,t,i,n=100,a={}){let s=!1;return this.addEventListener(e,t,e=>{s||(i(e),s=!0,setTimeout(()=>{s=!1},n))},a)}generateId(){return`listener_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}getStats(){return{...this.stats,groups:this.groups.size,listeners:this.listeners.size}}getActiveListeners(){const e=[];for(const[t,i]of this.listeners.entries())i.active&&e.push({id:t,eventType:i.eventType,group:i.group,target:i.target.constructor.name});return e}analyzeLeaks(){const e={totalListeners:this.listeners.size,activeListeners:this.stats.active,inactiveButNotRemoved:0,byTarget:new Map,byType:new Map,potentialLeaks:[]};for(const[t,i]of this.listeners.entries()){const n=i.target.constructor.name;e.byTarget.set(n,(e.byTarget.get(n)||0)+1),e.byType.set(i.eventType,(e.byType.get(i.eventType)||0)+1),i.active||(e.inactiveButNotRemoved++,e.potentialLeaks.push({id:t,eventType:i.eventType,target:n}))}return e.byTarget=Object.fromEntries(e.byTarget),e.byType=Object.fromEntries(e.byType),e}cleanup(){let e=0;for(const[t,i]of this.listeners.entries())i.active||(this.listeners.delete(t),e++);return e}destroy(){const e=this.removeAll();return this.listeners.clear(),this.groups.clear(),this.stats={registered:0,removed:0,active:0},e}}class qi{constructor(){this.errors=[],this.maxErrors=10,this.errorCounts=new Map,this.defaults={emotion:"neutral",gesture:null,audioLevel:0,particleCount:0,glowIntensity:.7,coreSize:1,breathRate:1,color:"#B0B0B0"}}wrap(e,t,i=null){return(...n)=>{try{return e(...n)}catch(e){return this.logError(e,t),null!==i?i:this.getDefault(t)}}}logError(e,t){const i={timestamp:(new Date).toISOString(),context:t,message:e.message,stack:e.stack};this.errors.push(i);const n=this.errorCounts.get(t)||0;this.errorCounts.set(t,n+1),this.errors.length>this.maxErrors&&this.errors.shift()}getDefault(e){const t={"emotion-transition":this.defaults.emotion,"gesture-execution":this.defaults.gesture,"audio-processing":this.defaults.audioLevel,"particle-system":this.defaults.particleCount,rendering:{glowIntensity:this.defaults.glowIntensity,coreSize:this.defaults.coreSize,color:this.defaults.color},"canvas-operations":null,"state-management":this.defaults.emotion};return Object.prototype.hasOwnProperty.call(t,e)?t[e]:null}validateInput(e,t,i){try{switch(t){case"emotion":return["neutral","joy","sadness","anger","fear","surprise","disgust","love","euphoria"].includes(e)?e:i;case"undertone":return null===e||["nervous","confident","tired","intense","subdued"].includes(e)?e:null;case"gesture":return["bounce","pulse","shake","spin","nod","tilt","expand","contract","flash","drift"].includes(e)?e:i;case"number":return"number"!=typeof e||isNaN(e)?i:e;case"string":return"string"==typeof e?e:i;case"boolean":return"boolean"==typeof e?e:i;default:return null!=e?e:i}}catch(e){return this.logError(e,"input-validation"),i}}hasExceededThreshold(e,t=5){return(this.errorCounts.get(e)||0)>=t}getErrorStats(){return{totalErrors:this.errors.length,errorsByContext:Object.fromEntries(this.errorCounts),recentErrors:this.errors.slice(-5)}}clearErrors(){this.errors=[],this.errorCounts.clear()}async attemptRecovery(e,t,i=3){let n=0;for(;n<i;)try{return await t()}catch(t){if(n++,this.logError(t,`recovery-${e}-attempt-${n}`),n>=i)throw new Error(`Recovery failed for ${e} after ${i} attempts`);await new Promise(e=>setTimeout(e,100*Math.pow(2,n)))}}}const Ni={quartz:{sssStrength:.8,sssAbsorption:[2.8,2.9,3],sssScatterDistance:[.2,.2,.25],sssThicknessBias:.6,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.12,frostiness:.15,innerGlowStrength:.2,fresnelIntensity:1.5,causticIntensity:1.2,emotionColorBleed:0},emerald:{sssStrength:2,sssAbsorption:[.05,4,.1],sssScatterDistance:[.1,.5,.1],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.2,innerGlowStrength:.15,fresnelIntensity:1.2,causticIntensity:1,emotionColorBleed:.35},ruby:{sssStrength:1.8,sssAbsorption:[4,.03,.08],sssScatterDistance:[.4,.04,.08],sssThicknessBias:.65,sssThicknessScale:1.9,sssCurvatureScale:2.5,sssAmbient:.08,frostiness:.12,innerGlowStrength:.12,fresnelIntensity:1.2,causticIntensity:1.15,emotionColorBleed:.35},sapphire:{sssStrength:2.2,sssAbsorption:[.15,.4,4],sssScatterDistance:[.1,.15,.5],sssThicknessBias:.65,sssThicknessScale:1.8,sssCurvatureScale:3,sssAmbient:.1,frostiness:.18,innerGlowStrength:.15,fresnelIntensity:1.3,causticIntensity:1,emotionColorBleed:.35},amethyst:{sssStrength:2.5,sssAbsorption:[3,.05,4.5],sssScatterDistance:[.4,.05,.5],sssThicknessBias:.7,sssThicknessScale:2,sssCurvatureScale:3,sssAmbient:.08,frostiness:.18,innerGlowStrength:.12,fresnelIntensity:1.4,causticIntensity:1,emotionColorBleed:.35},topaz:{sssStrength:1.5,sssAbsorption:[3.5,2,.1],sssScatterDistance:[.3,.2,.05],sssThicknessBias:.6,sssThicknessScale:1.7,sssCurvatureScale:2.8,sssAmbient:.12,frostiness:.14,innerGlowStrength:.18,fresnelIntensity:1.4,causticIntensity:1.1,emotionColorBleed:.25},citrine:{sssStrength:1.6,sssAbsorption:[3.8,2.5,.05],sssScatterDistance:[.35,.25,.05],sssThicknessBias:.58,sssThicknessScale:1.6,sssCurvatureScale:2.6,sssAmbient:.14,frostiness:.12,innerGlowStrength:.22,fresnelIntensity:1.3,causticIntensity:1.2,emotionColorBleed:.2},diamond:{sssStrength:.5,sssAbsorption:[2.5,2.5,2.5],sssScatterDistance:[.15,.15,.15],sssThicknessBias:.55,sssThicknessScale:1.5,sssCurvatureScale:4,sssAmbient:.15,frostiness:.08,innerGlowStrength:.25,fresnelIntensity:2,causticIntensity:1.5,emotionColorBleed:0}};function ji(e,t){if(!t||!e?.core3D?.customMaterial?.uniforms)return!1;const i=Ni[t];if(!i)return!1;const n=e.core3D.customMaterial.uniforms;return n.sssStrength&&(n.sssStrength.value=i.sssStrength),n.sssAbsorption&&n.sssAbsorption.value.set(...i.sssAbsorption),n.sssScatterDistance&&n.sssScatterDistance.value.set(...i.sssScatterDistance),n.sssThicknessBias&&(n.sssThicknessBias.value=i.sssThicknessBias),n.sssThicknessScale&&(n.sssThicknessScale.value=i.sssThicknessScale),n.sssCurvatureScale&&(n.sssCurvatureScale.value=i.sssCurvatureScale),n.sssAmbient&&(n.sssAmbient.value=i.sssAmbient),n.frostiness&&(n.frostiness.value=i.frostiness),n.innerGlowStrength&&(n.innerGlowStrength.value=i.innerGlowStrength),n.fresnelIntensity&&(n.fresnelIntensity.value=i.fresnelIntensity),void 0!==i.causticIntensity&&n.causticIntensity&&(n.causticIntensity.value=i.causticIntensity),n.emotionColorBleed&&(n.emotionColorBleed.value=i.emotionColorBleed??0),!0}function Ui(){return Object.keys(Ni)}function Hi(e){return Ni[e]||null}const Wi=["bouncing up and down","hopping around","rocking back and forth","side to side","light on feet","spring in step","leaning forward","leaning in","leaning closer","leaning toward","reaching out","reaching toward","pointing at","pointing to","waving hello","waving goodbye","nodding head","shaking head","head shake","head nod","head bob","head tilt","deep breath","taking a breath","breathing deeply","settling down","calming down","winding down","getting bigger","getting smaller","puffing up","spinning around","twirling around","at peace","in love","on cloud nine","over the moon","on top of the world","in awe","grossed out","freaked out","low key","low-key","high key","on edge","keyed up","wound up","low energy","no energy","running low","just a bit","just a little","a little bit","kind of","sort of","a bit","a little","a lot","over the top","off the charts","through the roof","split second","one time","few times","many times","again and again","over and over","on repeat","blood moon","full moon","new moon","half moon","solar eclipse","lunar eclipse","total eclipse","ring of fire","diamond ring","killing it","crushing it","nailed it","sussy baka","side eye"],Xi=/[,;|\/]+/,Yi=new Set(["a","an","the","is","are","am","be","being","been","i","me","my","it","its","to","of","for","with","as","this","that","these","those","just","only","also","too","please","pls","plz"]),$i=new Set(["but","and","or","yet","while","although","not","no","never","very","really","so","quite","rather","slightly","barely","extremely","completely","feeling","feel","feels","become","becoming","morph","morphing"]);function Qi(e){return e.toLowerCase().trim().replace(/['']/g,"'").replace(/[""]/g,'"').replace(/\s+/g," ")}function Zi(e){return["but","and","or","yet","while","although","with"].includes(e)}function Ji(e){return["not","no","never","don't","dont","doesn't","doesnt","isn't","isnt"].includes(e)}const Ki={nervous:{candidates:[{category:"emotion",target:"fear",priority:1},{category:"undertone",target:"nervous",priority:2}],rule:"standalone_is_emotion",examples:[{input:"nervous",resolved:{emotion:"fear"}},{input:"happy but nervous",resolved:{emotion:"joy",undertone:"nervous"}}]},anxious:{candidates:[{category:"emotion",target:"fear",priority:1},{category:"undertone",target:"nervous",priority:2}],rule:"standalone_is_emotion"},confident:{candidates:[{category:"emotion",target:"trust",priority:2},{category:"undertone",target:"confident",priority:1}],rule:"prefer_undertone",examples:[{input:"confident",resolved:{undertone:"confident"}},{input:"feeling confident",resolved:{emotion:"trust"}}]},tired:{candidates:[{category:"emotion",target:"sadness",priority:2},{category:"undertone",target:"tired",priority:1}],rule:"prefer_undertone",examples:[{input:"tired",resolved:{undertone:"tired"}},{input:"feeling tired",resolved:{emotion:"sadness",undertone:"tired"}}]},intense:{candidates:[{category:"undertone",target:"intense",priority:1},{category:"modifier",target:"intensity.very",priority:2}],rule:"prefer_undertone"},curious:{candidates:[{category:"emotion",target:"focused",priority:1},{category:"gesture",target:"lean",priority:2}],rule:"standalone_is_emotion",examples:[{input:"curious",resolved:{emotion:"focused"}},{input:"curious, leaning in",resolved:{emotion:"focused",gesture:"lean"}}]},interested:{candidates:[{category:"emotion",target:"focused",priority:1},{category:"gesture",target:"lean",priority:2}],rule:"standalone_is_emotion"},excited:{candidates:[{category:"emotion",target:"joy",priority:1},{category:"gesture",target:"bounce",priority:3}],rule:"standalone_is_emotion"},shaking:{candidates:[{category:"gesture",target:"shake",priority:1},{category:"emotion",target:"fear",priority:2}],rule:"standalone_is_gesture"},nodding:{candidates:[{category:"gesture",target:"nod",priority:1}],rule:"always_gesture"},glowing:{candidates:[{category:"gesture",target:"glow",priority:1},{category:"shape",target:"sun",priority:3}],rule:"standalone_is_gesture"},spinning:{candidates:[{category:"gesture",target:"spin",priority:1}],rule:"always_gesture"},love:{candidates:[{category:"emotion",target:"love",priority:1},{category:"shape",target:"heart",priority:2}],rule:"standalone_is_emotion",examples:[{input:"love",resolved:{emotion:"love"}},{input:"love heart",resolved:{emotion:"love",shape:"heart"}},{input:"become love",resolved:{shape:"heart"}}]},suspicious:{candidates:[{category:"emotion",target:"suspicion",priority:1},{category:"shape",target:"suspicion",priority:2}],rule:"standalone_is_emotion"},bright:{candidates:[{category:"emotion",target:"joy",priority:2},{category:"shape",target:"sun",priority:3},{category:"modifier",target:"intensity.very",priority:4}],rule:"context_dependent"},yes:{candidates:[{category:"gesture",target:"nod",priority:1}],rule:"always_gesture"},no:{candidates:[{category:"gesture",target:"shake",priority:1}],rule:"always_gesture"},agree:{candidates:[{category:"gesture",target:"nod",priority:1},{category:"emotion",target:"trust",priority:2}],rule:"standalone_is_gesture"},disagree:{candidates:[{category:"gesture",target:"shake",priority:1}],rule:"always_gesture"}},en={emotionContext:["feeling","feel","feels","felt","emotion","emotional","emotionally","mood","moody","state","am","is","are","being","becoming","become","grew","growing"],gestureContext:["do","doing","does","did","perform","performing","action","move","moving","movement","start","starting","begin","beginning","physically","motion"],shapeContext:["morph","morphing","morphed","transform","transforming","transformed","become","becoming","turn into","shape","form","look like","change to","change into"],undertoneContext:["but","yet","while","although","with","and also","mixed with","underneath","underlying","beneath","a bit","slightly","somewhat"],modifierContext:["very","really","so","extremely","slightly","barely","completely","quickly","slowly","briefly"]};function tn(e,t,i){const n=en[`${i}Context`];if(!n)return!1;const a=Math.max(0,t-3),s=Math.min(e.length,t+4);for(let i=a;i<s;i++)if(i!==t&&n.includes(e[i]))return!0;return!1}function nn(e,t){switch(t){case"emotion":return null!==e.emotion;case"gesture":return e.gestures&&e.gestures.length>0;case"shape":return null!==e.shape;case"undertone":return null!==e.undertone;default:return!1}}function an(e,t,i,n){const a=Ki[e];if(!a)return null;const{candidates:s,rule:o}=a;if(1===s.length)return s[0];switch(o){case"standalone_is_emotion":if(nn(n,"emotion")){const e=s.find(e=>"emotion"!==e.category);if(e)return e}return tn(t,i,"emotion"),s.find(e=>"emotion"===e.category)||s[0];case"standalone_is_gesture":if(nn(n,"gesture")){const e=s.find(e=>"gesture"!==e.category);if(e)return e}return tn(t,i,"gesture"),s.find(e=>"gesture"===e.category)||s[0];case"prefer_undertone":return tn(t,i,"emotion")?s.find(e=>"emotion"===e.category)||s[0]:s.find(e=>"undertone"===e.category)||s[0];case"always_gesture":return s.find(e=>"gesture"===e.category)||s[0];case"always_emotion":return s.find(e=>"emotion"===e.category)||s[0];case"context_dependent":for(const e of["emotion","gesture","shape","undertone"])if(tn(t,i,e)){const t=s.find(t=>t.category===e);if(t)return t}return s.sort((e,t)=>e.priority-t.priority)[0];default:return s.sort((e,t)=>e.priority-t.priority)[0]}}function sn(e){return e in Ki}const on={neutral:["neutral","default","normal","baseline","standard","nothing special","nothing particular","no strong feeling","not much","meh","whatever","indifferent","balanced","even","steady","stable","centered","level","middle ground","in between","ready","waiting","standing by","at attention","present","here","available","attentive","reset","clear","blank","empty","clean slate"],joy:["happy","joy","joyful","joyous","pleased","glad","content","satisfied","gratified","comfortable","good","cheerful","cheery","merry","jovial","jolly","upbeat","sunny","bright","lighthearted","buoyant","delighted","thrilled","overjoyed","elated","jubilant","exultant","gleeful","glowing","beaming","radiant","pumped","stoked","psyched","amped","hyped","vibing","living","slaying","winning","lit","fire","sick","dope","chuffed","pleased as punch","over the moon","made up","tickled","tickled pink","felicitous","beatific","blissful","smiling","grinning","laughing","giggling"],calm:["calm","peaceful","serene","tranquil","relaxed","at ease","comfortable","loose","unwound","decompressed","chilled","still","quiet","hushed","silent","soft","gentle","mild","placid","smooth","composed","collected","centered","grounded","untroubled","unworried","unbothered","unfazed","meditative","zen","mindful","contemplative","reflective","introspective","soothed","eased","mellowed","softened","chill","coasting","floating","drifting","laid back","easy going","low key","sorted","easy peasy"],excited:["excited","exciting","excitable","enthusiastic","eager","keen","avid","passionate","fervent","ardent","zealous","energetic","energized","animated","lively","spirited","vivacious","vibrant","dynamic","bouncy","peppy","perky","sprightly","anticipating","expectant","looking forward","itching","raring","chomping at the bit","fired up","charged","electric","electrified","buzzing","tingling","crackling","sparking","jazzed","juiced","geeked","hype","turnt","going off","well excited","buzzing","restless","fidgety","antsy","jumpy","twitchy","keyed up","wound up"],sadness:["sad","sadness","saddened","unhappy","down","low","blue","glum","bummed","disappointed","let down","discouraged","disheartened","dispirited","deflated","melancholy","melancholic","somber","gloomy","mournful","sorrowful","doleful","woeful","heavy-hearted","downcast","crestfallen","heartbroken","devastated","crushed","shattered","despairing","despondent","desolate","inconsolable","grief","grieving","mourning","bereft","empty","hollow","numb","void","wistful","longing","yearning","pining","nostalgic","bummed out","down in the dumps","in a funk","in the dumps","feeling low","gutted","choked","crying","tearful","weeping","sobbing","sighing","drooping","wilting","slumping"],anger:["angry","anger","angered","mad","annoyed","irritated","bothered","irked","peeved","miffed","vexed","displeased","put out","ticked off","ticked","frustrated","aggravated","exasperated","fed up","sick of","had enough","cross","upset","worked up","furious","enraged","livid","irate","incensed","infuriated","outraged","seething","fuming","boiling","burning","smoldering","raging","ballistic","apoplectic","berserk","seeing red","losing it","pissed","pissed off","salty","pressed","triggered","tilted","heated","steaming","narked","cheesed off","brassed off","shirty","stroppy","mardy","ropeable","filthy","spewing","clenching","tensing","grinding"],fear:["afraid","scared","fear","fearful","uneasy","unsettled","apprehensive","wary","concerned","worried","jittery","shaky","trembling","quivering","tense","tight","clenched","knotted","frightened","alarmed","startled","spooked","freaked","freaked out","creeped out","on edge","rattled","unnerved","terrified","petrified","horrified","panicked","panic","panicking","terror","dread","paranoid","distrustful","looking over shoulder","sketched","sketched out","wigged out","shook","bricking it","having kittens","in a flap","frozen","paralyzed","deer in headlights","heart racing","heart pounding","sweating"],surprise:["surprised","surprise","surprising","oh","huh","hmm","interesting","unexpected","caught off guard","astonished","amazed","astounded","startled","taken aback","struck","shocked","stunned","staggered","floored","dumbfounded","flabbergasted","gobsmacked","blown away","mind blown","speechless","wow","whoa","omg","no way","incredible","unbelievable","amazing","alarmed","dismayed","appalled","bewildered","baffled","perplexed","puzzled","confused","disoriented","thrown","shooketh","gagged","dead","wait what","blimey","crikey","bloody hell","jaw dropped","eyes wide","double take","gasp","gasping"],disgust:["disgusted","disgust","disgusting","distaste","dislike","aversion","put off","turned off","off-putting","repulsed","revolted","repelled","grossed out","creeped out","icked out","sickened","nauseated","nauseous","appalled","horrified","scandalized","offended","outraged","indignant","contempt","contemptuous","disdain","scorn","gagging","retching","cringing","wincing","recoiling","shrinking back","gross","ew","eww","yuck","yucky","ick","nasty","foul","vile","rank","minging","manky","grotty"],love:["love","loving","loved","affection","affectionate","fond","fondness","tender","tenderness","gentle","caring","care","nurturing","supportive","protective","devoted","dedicated","warm","warmth","warm-hearted","kind","kind-hearted","compassionate","sympathetic","adoring","adore","cherish","cherishing","treasure","treasuring","doting","romantic","amorous","passionate","smitten","infatuated","enamored","besotted","head over heels","falling for","connected","bonded","attached","close","intimate","deep","profound","heart eyes","crushing","swooning","melting","hugging","embracing","holding","cuddling","snuggling","nuzzling"],euphoria:["euphoric","euphoria","bliss","blissful","transcendent","otherworldly","sublime","heavenly","divine","ethereal","celestial","ecstatic","ecstasy","rapture","rapturous","exultant","exalted","elevated","peak","pinnacle","height","climax","breakthrough","revelation","epiphany","overwhelming joy","pure joy","absolute joy","complete happiness","total bliss","floating","soaring","flying","weightless","radiating","shining","on cloud nine","in heaven","on top of the world","walking on air","living my best life","ascended"],focused:["focused","focus","focusing","concentrating","concentration","concentrated","attentive","attention","attending","thinking","thought","thoughtful","pondering","considering","contemplating","reflecting","musing","mulling","engaged","absorbed","immersed","engrossed","rapt","riveted","captivated","enthralled","intent","determined","resolute","single-minded","laser focused","zeroed in","working","processing","analyzing","examining","studying","learning","figuring out","locked in","dialed in","in the zone","flow state","deep work","grinding","staring","gazing","peering","squinting","furrowed brow"],suspicion:["suspicious","suspicion","suspect","doubtful","doubt","doubting","skeptical","skepticism","questioning","uncertain","unsure","unconvinced","wary","cautious","guarded","careful","leery","circumspect","vigilant","distrustful","mistrust","mistrustful","disbelieving","incredulous","unbelieving","scrutinizing","examining","assessing","evaluating","judging","sizing up","sus","sussy","suss","side eye","giving side eye","side-eyeing","eyeing","not buying it","narrowed eyes","squinting","raised eyebrow","cocked head","tilted head","looking askance"],resting:["resting","rest","restful","tired","weary","fatigued","exhausted","drained","spent","depleted","worn out","sleepy","drowsy","dozy","groggy","yawning","nodding off","drifting off","sluggish","lethargic","listless","languid","lazy","idle","inactive","recovering","recuperating","recharging","winding down","powering down","shutting down","sleeping","asleep","slumbering","dozing","napping","snoozing","zonked","wiped","beat","dead tired","running on empty","out of gas","crashed","knackered","shattered","cream crackered"],glitch:["glitch","glitchy","glitching","malfunction","malfunctioning","broken","bugged","buggy","error","erroring","corrupted","corruption","scrambled","garbled","distorted","warped","static","noise","interference","pixelated","artifacting","tearing","haywire","fritzing","shorting out","going crazy","spazzing","unstable","erratic","unpredictable","flickering","stuttering","lagging","does not compute","syntax error","crash"]},rn={nervous:["nervous","nervously","anxious","anxiously","worried","worriedly","uneasy","uneasily","apprehensive","jittery","shaky","trembling","quivering","fidgety","restless","twitchy","tense","tensely","on edge","edgy","keyed up","wound up","uptight","self-conscious","awkward","awkwardly","hesitant","hesitantly","uncertain","uncertainly","sketchy","stressed","stressing","low-key panicking","kinda freaking out"],confident:["confident","confidently","confidence","assured","assuredly","certain","certainly","sure","surely","positive","positively","bold","boldly","brave","bravely","daring","daringly","fearless","fearlessly","strong","strongly","powerful","powerfully","firm","firmly","solid","solidly","authoritative","commanding","assertive","decisive","decisively","resolute","resolutely","poised","self-assured","unflappable","unfazed","owning it","killing it","crushing it","boss","like a boss"],tired:["tired","tiredly","tiredness","exhausted","weary","wearily","fatigued","drained","spent","depleted","sluggish","sluggishly","slow","slowly","lethargic","listless","languid","low energy","no energy","out of energy","running low","running on fumes","droopy","drooping","sagging","slumping","heavy","weighted","dragging","wiped","beat","dead","zonked","burned out","fried","cooked","toast"],intense:["intense","intensely","intensity","heightened","elevated","amplified","magnified","increased","enhanced","forceful","forcefully","powerful","powerfully","fierce","fiercely","strong","strongly","passionate","passionately","fervent","fervently","ardent","ardently","vehement","vehemently","sharp","sharply","acute","acutely","keen","keenly","piercing","piercingly","extreme","extremely","deeply","profoundly","tremendously","immensely","incredibly","super","mega","ultra","hella","mad","crazy"],subdued:["subdued","subduedly","soft","softly","gentle","gently","mild","mildly","light","lightly","restrained","held back","contained","tempered","moderated","toned down","quiet","quietly","hushed","muted","understated","subtle","subtly","modest","modestly","humble","humbly","reserved","demure","unassuming","faint","faintly","dim","dimly","pale","faded","washed out","low key","lowkey","easy","easy going"],clear:["clear","clearly","pure","purely","clean","cleanly","simple","simply","plain","plainly","direct","directly","straightforward","honest","honestly","frank","frankly","transparent","transparently","open","openly","obvious","obviously","evident","evidently","unmodified","unaltered","unchanged","normal","normally","regular","regularly","standard","basic","baseline"]},ln={bounce:["bounce","bouncing","bouncy","hop","hopping","hoppy","spring","springing","springy","boing","boinging","bouncing up and down","hopping around","spring in step","light on feet"],pulse:["pulse","pulsing","pulsate","pulsating","throb","throbbing","beat","beating","pulsing gently","steady pulse","heartbeat","heart beat"],shake:["shake","shaking","shaky","shudder","shuddering","tremble","trembling","quake","quaking","shiver","shivering","no","nope","nah","disagree","disagreeing","refuse","refusing","deny","denying","shaking head","shake head","head shake","saying no","shaking no"],nod:["nod","nodding","yes","yeah","yep","yup","agree","agreeing","acknowledge","acknowledging","confirm","confirming","accept","accepting","approve","approving","understand","understanding","got it","gotcha","i see","makes sense","understood","nodding head","nod head","head nod","nodding along","nodding yes"],vibrate:["vibrate","vibrating","vibration","buzz","buzzing","hum","humming","quiver","quivering","vibrating slightly","gentle buzz","low hum","subtle vibration"],orbit:["orbit","orbiting","circle","circling","revolve","revolving","rotate","rotating","circling around","going around","rotating slowly","orbital motion"],sway:["sway","swaying","rock","rocking","swing","swinging","oscillate","oscillating","swaying gently","rocking back and forth","gentle sway","side to side"],float:["float","floating","drift","drifting","hover","hovering","glide","gliding","levitate","levitating","weightless","weightlessness","buoyant","airy","floating gently","drifting along","hovering in place","light as air"],lean:["lean","leaning","incline","inclining","tilt","tilting","leaning in","lean in","leaning forward","lean forward","leaning toward","lean toward","leaning closer","lean closer","moving closer","coming closer","drawing near","approaching","interested","intrigued","curious","engaged","attentive","listening closely","paying attention"],reach:["reach","reaching","extend","extending","stretch","stretching","reaching out","reach out","reaching toward","reach toward","extending toward","stretching toward","offer","offering","present","presenting","give","giving","help","helping"],point:["point","pointing","indicate","indicating","gesture","gesturing","direct","directing","pointing at","pointing to","pointing toward","gesturing toward","showing","directing attention"],wave:["wave","waving","greet","greeting","hello","hi","hey","goodbye","bye","farewell","welcome","welcoming","waving hello","waving goodbye","friendly wave","waving hand"],headBob:["headbob","head bob","headbobbing","head bobbing","bobbing","bob","nodding to beat","nodding to music","bobbing along","bobbing to rhythm","vibing","grooving","jamming","bobbing head","bob head","feeling the beat","moving to music"],wiggle:["wiggle","wiggling","wiggly","jiggle","jiggling","jiggly","squirm","squirming","wriggle","wriggling","wiggling around","little wiggle","happy wiggle","excited wiggle"],groove:["groove","grooving","groovy","dance","dancing","boogie","boogying","funk","funky","rhythmic","moving to music","feeling the music","in the groove","getting down","busting a move","doing a little dance"],twitch:["twitch","twitching","twitchy","spasm","spasming","jerk","jerking","jerky","flinch","flinching","quick twitch","nervous twitch","sudden movement"],jitter:["jitter","jittering","jittery","stutter","stuttering","jittering around","slight jitter","nervous jitter"],spin:["spin","spinning","twirl","twirling","whirl","whirling","rotate","rotating","turn","turning","spinning around","quick spin","full rotation","twirling around"],jump:["jump","jumping","jumpy","leap","leaping","spring","springing","bound","bounding","jumping up","leap up","spring up","jumping for joy"],stretch:["stretch","stretching","stretchy","elongate","elongating","extend","extending","lengthen","lengthening","stretching out","big stretch","reaching up","stretching tall"],expand:["expand","expanding","grow","growing","enlarge","enlarging","swell","swelling","inflate","inflating","bloat","bloating","getting bigger","growing larger","puffing up","expanding outward"],contract:["contract","contracting","shrink","shrinking","compress","compressing","deflate","deflating","reduce","reducing","getting smaller","shrinking down","pulling in","contracting inward"],twist:["twist","twisting","twisty","contort","contorting","warp","warping","distort","distorting","twisting around","getting twisted","warping shape"],tilt:["tilt","tilting","tilted","angle","angling","angled","cock","cocking","cocked","tilting head","tilt head","cocking head","curious tilt","angling sideways","head tilt"],hula:["hula","hula-ing","hip sway","swaying hips","circular sway","round motion","hula motion","hula dance"],sparkle:["sparkle","sparkling","sparkly","twinkle","twinkling","twinkly","glitter","glittering","glittery","shine","shining","shiny","celebrate","celebrating","celebration","celebratory","festive","party","partying","victory","triumphant","triumph","winning","success","successful","achievement","accomplished","nailed it","slay","slaying","killing it","yasss","yay","woo","woohoo"],shimmer:["shimmer","shimmering","shimmery","glisten","glistening","gleam","gleaming","lustrous","luminous","soft shimmer","gentle gleam","shimmering light","pearlescent"],glow:["glow","glowing","glowy","radiate","radiating","emanate","emanating","luminous","luminescent","bright","brighten","brightening","soft glow","warm glow","inner glow","glowing warmly","lighting up","lit up"],flash:["flash","flashing","flashy","blink","blinking","strobe","strobing","flare","flaring","quick flash","bright flash","flashing light","strobing light"],flicker:["flicker","flickering","flickery","flutter","fluttering","waver","wavering","guttering","flickering light","unsteady light","wavering glow","candle-like"],burst:["burst","bursting","explode","exploding","explosion","erupt","erupting","eruption","pop","popping","boom","booming","bursting out","burst of energy","explosive","big burst"],settle:["settle","settling","settled","calm","calming","ground","grounding","grounded","center","centering","centered","anchor","anchoring","anchored","root","rooting","rooted","relax","relaxing","unwind","unwinding","decompress","decompressing","settling down","calming down","winding down","cooling down","coming to rest","finding peace","sinking into","melting into"],breathe:["breathe","breathing","breath","inhale","inhaling","exhale","exhaling","sigh","sighing","respire","respiring","deep breath","deep breathing","slow breath","slow breathing","long breath","full breath","breathing deeply","breathing slowly","taking a breath","take a breath","catching breath","breath work","breathwork","inhale exhale","in and out","meditative breathing","calming breath","cleansing breath","relaxing breath","centering breath","mindful breathing"],peek:["peek","peeking","peer","peering","peep","peeping","glance","glancing","peeking out","peek out","looking shyly","shy glance","quick peek","sneaking a look"],fade:["fade","fading","dim","dimming","disappear","disappearing","vanish","vanishing","fading out","fading away","growing dim","becoming transparent","dissolving","melting away"],hold:["hold","holding","pause","pausing","paused","freeze","freezing","frozen","still","stillness","stop","stopping","stopped","holding still","staying still","frozen in place","completely still","motionless","stationary"],rain:["rain","raining","shower","showering","drip","dripping","pour","pouring","fall","falling","raining down","particles falling","gentle rain","shower of particles"]},hn={circle:["circle","circular","round","rounded","orb","ball","sphere","spherical","ring","disc","disk","whole","complete","unity","unified","endless","infinite","continuous","full circle","perfect round","come full circle"],sphere:["sphere","spherical","globe","globular","ball","3d circle","three dimensional","round ball","floating sphere"],square:["square","squared","boxy","box","rectangle","rectangular","quadrilateral","cube","cubic","block","blocky","stable","solid","grounded","sturdy","rigid","firm","structured","four sided","four corners","box shape"],triangle:["triangle","triangular","tri","pyramid","pyramidal","delta","wedge","arrow","arrowhead","pointed","sharp","dynamic","directional","ascending","three sided","three pointed","pointing up"],heart:["heart","hearted","hearts","love","loving","lovely","valentine","romantic","affection","affectionate","caring","care","tender","warmth","warm-hearted","heartfelt","compassion","compassionate","devotion","devoted","luv","wuv","<3","❤️","💕","💗","full of love","with love","heart shape","heart shaped","from the heart"],suspicion:["suspicion","suspicious","suspect","sly","slyly","sneaky","sneakily","mischievous","mischief","smirk","smirking","smirky","grin","grinning","sly grin","side eye","sideeye","side-eye","skeptical","skepticism","doubtful","doubt","doubting","wary","distrustful","distrust","sus","sussy","sussy baka","hmm","hmmm","hmmmm","shady","fishy","sketchy","not buying it","something fishy","seems off","up to something"],star:["star","starred","starry","stars","stellar","astral","twinkle","twinkling","achievement","achieved","excellence","excellent","gold star","five star","superstar","rockstar","rock star","wonder","wonderful","wondrous","magical","magic","miraculous","amazing","spectacular","reach for stars","seeing stars","star shape","shining star"],sun:["sun","sunny","sunshine","sunlight","solar","sol","daylight","daytime","day","radiant","radiance","radiating","bright","brightness","brilliant","glowing","glow","blazing","blaze","warm","warmth","cheerful","cheery","optimistic","optimism","hopeful","hope","positive","positivity","full of light","ray of sunshine","like the sun","sunny disposition"],moon:["moon","moony","moonlight","moonlit","lunar","crescent","nighttime","night","nocturnal","waxing","waning","gibbous","new moon","full moon","half moon","quarter moon","crescent moon","dreamy","dreamlike","dream","mysterious","mystery","mystical","ethereal","otherworldly","serene","serenity","tranquil","contemplative","reflective","moonlit night","by moonlight","moon shape","under the moon"],lunar:["lunar eclipse","blood moon","blood-moon","red moon","copper moon","rust moon","eclipsing","eclipsed","shadow crossing","earth shadow","ominous","foreboding","portentous","dramatic","intense","transforming","transformation","moon in shadow","moon turning red","eclipse phase","lunar event"],solar:["solar eclipse","total eclipse","corona","diamond ring","totality","umbra","penumbra","ring of fire","dark sun","blocked sun","occluded","awe","awesome","awe-inspiring","rare","momentous","historic","breathtaking","magnificent","sun blocked","sun covered","total darkness","corona visible"],eclipse:["eclipse","eclipsing","eclipsed","celestial event","astronomical event","overshadow","overshadowed","blocked","blocking","obscured","hidden","hiding","concealed","passing","crossing","alignment","in eclipse","going dark","being eclipsed","eclipsed by"]},cn={intensity:{barely:["barely","hardly","scarcely","faintly","slightly","marginally","just a bit","just a little","just barely","hint of","touch of","trace of"],slightly:["slightly","somewhat","a little","a bit","mildly","lightly","kind of","kinda","sort of","sorta","a tad","a touch","a smidge"],moderately:["moderately","reasonably","fairly","pretty","rather","quite"],normal:["normal","normally","regular","regularly","standard","typical","typically","average","ordinary"],notably:["notably","noticeably","clearly","definitely","certainly","decidedly","genuinely","truly","really"],very:["very","really","so","such","quite","highly","deeply","seriously","majorly","hella","super","extra","mad"],extremely:["extremely","incredibly","immensely","tremendously","enormously","hugely","intensely","fiercely","wildly","insanely","crazy","ridiculously","mega","ultra","hyper"],absolutely:["absolutely","completely","totally","utterly","entirely","wholly","fully","maximum","max","over the top","off the charts","through the roof","to the max"]},duration:{flash:["flash","instant","instantaneous","split second","split-second","momentary","fleeting","brief flash"],quick:["quick","quickly","fast","rapid","swift","swiftly","brief","briefly","short","shortly","snap"],normal:["normal","regular","standard","typical","usual"],slow:["slow","slowly","gradual","gradually","gentle","gently","easy","easily","leisurely","unhurried"],long:["long","prolonged","extended","sustained","lasting","lingering","drawn out","drawn-out"],persistent:["persistent","constant","continuous","ongoing","steady","maintained","held","holding","stay","staying","keep","keeping","remain","remaining"]},transition:{instant:["instant","instantly","immediate","immediately","sudden","suddenly","abrupt","abruptly","snap","cut","jump"],snappy:["snappy","crisp","sharp","sharply","brisk","briskly","punchy"],smooth:["smooth","smoothly","natural","naturally","fluid","fluidly","flowing"],gentle:["gentle","gently","soft","softly","gradual","gradually","easing","gliding","drifting"],dreamy:["dreamy","dreamlike","floaty","ethereal","languid","lazy","flowing","melting"]},repetition:{once:["once","one time","single","just once","only once","one shot"],few:["few","few times","couple","couple times","twice","two times","thrice","three times"],several:["several","several times","multiple","multiple times","repeatedly","again and again"],many:["many","many times","lots","lots of times","over and over","nonstop"],loop:["loop","looping","looped","continuous","continuously","forever","infinitely","endlessly","always","keep going","on repeat"]}},un={barely:{min:.1,max:.2,default:.15},slightly:{min:.2,max:.4,default:.3},moderately:{min:.4,max:.5,default:.45},normal:{min:.5,max:.6,default:.55},notably:{min:.6,max:.7,default:.65},very:{min:.7,max:.85,default:.8},extremely:{min:.85,max:.95,default:.9},absolutely:{min:.95,max:1,default:1}},dn={flash:{min:100,max:500,default:250},quick:{min:500,max:1e3,default:750},normal:{min:1e3,max:2e3,default:1500},slow:{min:2e3,max:4e3,default:3e3},long:{min:4e3,max:8e3,default:6e3},persistent:{min:8e3,max:1/0,default:1e4}};function mn(e){const t=new Map;for(const[i,n]of Object.entries(e)){for(const e of n){const n=e.toLowerCase().trim();t.set(n,i)}t.set(i.toLowerCase(),i)}return t}class pn{constructor(){this.emotionLookup=mn(on),this.undertoneLookup=mn(rn),this.gestureLookup=mn(ln),this.shapeLookup=mn(hn),this.modifierLookup=function(e){const t=new Map;for(const[i,n]of Object.entries(e))for(const[e,a]of Object.entries(n))for(const n of a){const a=n.toLowerCase().trim();t.set(a,{type:i,level:e})}return t}(cn)}parse(e){const t={emotion:null,undertone:"clear",gestures:[],shape:null,intensity:un.normal.default,duration:dn.normal.default,transition:"smooth",repetition:"once",unrecognized:[],raw:e};if(!e||"string"!=typeof e)return t;const{tokens:i}=function(e){if(!e||"string"!=typeof e)return{tokens:[],segments:[],phrases:new Map};const t=Qi(e),{processed:i,phrases:n}=function(e){const t=new Map;let i=e,n=0;for(const e of Wi){const a=Qi(e);if(i.includes(a)){const e=`__PHRASE_${n}__`;i=i.replace(new RegExp(a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),e),t.set(e,a),n++}}return{processed:i,phrases:t}}(t),a=i.split(Xi).map(e=>e.trim()).filter(e=>e.length>0),s=[],o=[];for(const e of a){let t=e;for(const[e,i]of n)t=t.replace(e,i);o.push(t.trim());const i=e.split(/\s+/);for(const e of i){if(n.has(e)){s.push(n.get(e));continue}if(!e)continue;if(Yi.has(e)&&!$i.has(e))continue;const t=e.replace(/^[^\w]+|[^\w]+$/g,"");t&&s.push(t)}}return{tokens:s,segments:o,phrases:n}}(e);if(0===i.length)return t;let n=!1;for(let e=0;e<i.length;e++){const a=i[e];if(!Zi(a))if(Ji(a))n=!0;else if(n)n=!1;else{if(sn(a)){const n=an(a,i,e,t);if(n){this._applyResolution(t,n);continue}}this._tryEmotion(a,t)||this._tryGesture(a,t)||this._tryShape(a,t)||this._tryUndertone(a,t)||this._tryModifier(a,t)||t.unrecognized.push(a)}}return t}_applyResolution(e,t){const{category:i,target:n}=t;switch(i){case"emotion":e.emotion||(e.emotion=n);break;case"undertone":"clear"===e.undertone&&(e.undertone=n);break;case"gesture":e.gestures.includes(n)||e.gestures.push(n);break;case"shape":e.shape||(e.shape=n)}}_tryEmotion(e,t){const i=this.emotionLookup.get(e);return!(!i||t.emotion||(t.emotion=i,0))}_tryGesture(e,t){const i=this.gestureLookup.get(e);return!(!i||t.gestures.includes(i)||(t.gestures.push(i),0))}_tryShape(e,t){const i=this.shapeLookup.get(e);return!(!i||t.shape||(t.shape=i,0))}_tryUndertone(e,t){const i=this.undertoneLookup.get(e);return!(!i||"clear"!==t.undertone||(t.undertone=i,0))}_tryModifier(e,t){const i=this.modifierLookup.get(e);if(i){const{type:e,level:n}=i;switch(e){case"intensity":t.intensity=un[n]?.default||t.intensity;break;case"duration":t.duration=dn[n]?.default||t.duration;break;case"transition":t.transition=n;break;case"repetition":t.repetition=n}return!0}return!1}validate(e){const t=[];return e.emotion||0!==e.gestures.length||e.shape||t.push("No actionable intent found (need emotion, gesture, or shape)"),(e.intensity<0||e.intensity>1)&&t.push(`Intensity ${e.intensity} out of range [0, 1]`),e.duration<=0&&t.push(`Duration ${e.duration} must be positive`),{valid:0===t.length,errors:t}}static getAvailableEmotions(){return Object.keys(on)}static getAvailableUndertones(){return Object.keys(rn)}static getAvailableGestures(){return Object.keys(ln)}static getAvailableShapes(){return Object.keys(hn)}}function gn(e=32,t=32){const i=[],n=[],a=[];for(let a=0;a<=t;a++){const s=a/t*Math.PI;for(let t=0;t<=e;t++){const a=t/e*Math.PI*2,o=Math.cos(a)*Math.sin(s),r=Math.cos(s),l=Math.sin(a)*Math.sin(s);i.push(o,r,l),n.push(o,r,l)}}for(let i=0;i<t;i++)for(let t=0;t<e;t++){const n=i*(e+1)+t,s=n+e+1,o=n+1,r=s+1;a.push(n,s,o),a.push(o,s,r)}return{vertices:new Float32Array(i),normals:new Float32Array(n),indices:new Uint16Array(a)}}function fn(e=6){const t=[],i=[],n=[],a=new Map;let s=0;function o(e,n,o,r,l,h){const c=`${e},${n},${o}`;return a.has(c)||(t.push(e,n,o),i.push(r,l,h),a.set(c,s++)),a.get(c)}const r=o(0,1.5,0,0,1,0),l=[];for(let t=0;t<e;t++){const i=t/e*Math.PI*2,n=o(.7*Math.cos(i),0,.7*Math.sin(i),Math.cos(i),0,Math.sin(i));l.push(n)}const h=o(0,-1.5,0,0,-1,0);for(let t=0;t<e;t++){const i=(t+1)%e;n.push(r,l[t],l[i])}for(let t=0;t<e;t++){const i=(t+1)%e;n.push(l[t],h,l[i])}return{vertices:new Float32Array(t),normals:new Float32Array(i),indices:new Uint16Array(n)}}function yn(){const e=[],t=[],i=[],n=[0,1.2,0],a=[0,-.8,0],s=[];for(let e=0;e<8;e++){const t=e/8*Math.PI*2;s.push([.8*Math.cos(t),0,.8*Math.sin(t)])}function o(n,a,s){const o=[a[0]-n[0],a[1]-n[1],a[2]-n[2]],r=[s[0]-n[0],s[1]-n[1],s[2]-n[2]],l=o[1]*r[2]-o[2]*r[1],h=o[2]*r[0]-o[0]*r[2],c=o[0]*r[1]-o[1]*r[0],u=Math.sqrt(l*l+h*h+c*c),d=[l/u,h/u,c/u],m=e.length/3;e.push(...n),t.push(...d),e.push(...a),t.push(...d),e.push(...s),t.push(...d),i.push(m,m+1,m+2)}for(let e=0;e<8;e++){const t=(e+1)%8;o(n,s[e],s[t])}for(let e=0;e<8;e++){const t=(e+1)%8;o(s[e],a,s[t])}return{vertices:new Float32Array(e),normals:new Float32Array(t),indices:new Uint16Array(i)}}const vn={sphere:gn(32,32),crystal:fn(6),diamond:yn()};function bn(){Object.values(vn).forEach(e=>{e&&e.vertices&&(e.vertices=null,e.normals=null,e.indices=null)})}class wn{constructor(e={}){this.config={canvasId:e.canvasId||"emotive-canvas",coreGeometry:e.coreGeometry||"sphere",targetFPS:e.targetFPS||60,enableParticles:!1!==e.enableParticles,defaultEmotion:e.defaultEmotion||"neutral",...e},this.container=null,this.webglCanvas=null,this.canvas2D=null,this.core3D=null,this.particleSystem=null,this.isRunning=!1,this._destroyed=!1,this.animationFrameId=null,this.lastFrameTime=0,this.gestureTimeouts=[],this.eventManager=new Vi,this.eventManager.emit||(this.eventManager._listeners={},this.eventManager.emit=(e,t)=>{const i=this.eventManager._listeners[e];i&&i.forEach(e=>e(t))},this.eventManager.on=(e,t)=>{this.eventManager._listeners[e]||(this.eventManager._listeners[e]=[]),this.eventManager._listeners[e].push(t)},this.eventManager.off=(e,t)=>{const i=this.eventManager._listeners[e];if(i){const e=i.indexOf(t);e>-1&&i.splice(e,1)}}),this.errorBoundary=new qi,this.emotion="neutral",this.undertone=null,this._intentParser=new pn,this._feelRateLimiter={calls:[],windowMs:1e3,maxCallsPerSecond:10}}init(e){try{if(this.setupCanvasLayers(e),this.core3D=new Gi(this.webglCanvas,{geometry:this.config.coreGeometry,emotion:this.config.defaultEmotion,enableParticles:this.config.enableParticles,enablePostProcessing:this.config.enablePostProcessing,enableShadows:this.config.enableShadows,enableControls:this.config.enableControls,autoRotate:this.config.autoRotate,enableBlinking:this.config.enableBlinking,enableBreathing:this.config.enableBreathing,cameraDistance:this.config.cameraDistance,fov:this.config.fov,minZoom:this.config.minZoom,maxZoom:this.config.maxZoom,materialVariant:this.config.materialVariant,assetBasePath:this.config.assetBasePath}),this.ctx2D=this.canvas2D.getContext("2d"),this.config.enableParticles&&!this.core3D?.particleOrchestrator){const e=this.config.maxParticles||300;this.particleSystem=new hi(e,this.errorBoundary),this.particleSystem.canvasWidth=this.canvas2D.width,this.particleSystem.canvasHeight=this.canvas2D.height}return this}catch(e){throw console.error("Failed to initialize 3D engine:",e),e}}setupCanvasLayers(e){if("CANVAS"===e.tagName){const t=e.parentElement;this.container=document.createElement("div"),this.container.style.position="relative",this.container.style.width="100%",this.container.style.height="100%",t.replaceChild(this.container,e)}else this.container=e,this.container.style.position&&"static"!==this.container.style.position||(this.container.style.position="relative");this.canvas2D=document.createElement("canvas"),this.canvas2D.id=`${this.config.canvasId}-particles`,this.canvas2D.width=this.container.offsetWidth||400,this.canvas2D.height=this.container.offsetHeight||400,this.canvas2D.style.position="absolute",this.canvas2D.style.top="0",this.canvas2D.style.left="0",this.canvas2D.style.width="100%",this.canvas2D.style.height="100%",this.canvas2D.style.background="transparent",this.canvas2D.style.zIndex="1",this.canvas2D.style.pointerEvents="none",this.container.appendChild(this.canvas2D),this.webglCanvas=document.createElement("canvas"),this.webglCanvas.id=`${this.config.canvasId}-3d`,this.webglCanvas.width=this.canvas2D.width,this.webglCanvas.height=this.canvas2D.height,this.webglCanvas.style.position="absolute",this.webglCanvas.style.top="0",this.webglCanvas.style.left="0",this.webglCanvas.style.width="100%",this.webglCanvas.style.height="100%",this.webglCanvas.style.background="transparent",this.webglCanvas.style.zIndex="2",this.config.enableControls?(this.webglCanvas.style.pointerEvents="auto",this.webglCanvas.style.touchAction="none"):(this.webglCanvas.style.pointerEvents="none",this.webglCanvas.style.touchAction="auto"),this.container.appendChild(this.webglCanvas)}async start(){this.isRunning||(this.core3D&&await this.core3D.waitUntilReady(),this.isRunning=!0,this.lastFrameTime=null,this.animationFrameId=requestAnimationFrame(this.animate.bind(this)))}stop(){this.isRunning=!1,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}animate(e){if(!this.isRunning||this._destroyed)return;if(null===this.lastFrameTime)return this.lastFrameTime=e,void(this.animationFrameId=requestAnimationFrame(this.animate.bind(this)));const t=e-this.lastFrameTime,i=Math.min(t,100);if(this.lastFrameTime=e,this.core3D&&!this._destroyed&&this.core3D.render(i),this.canvas2D&&this.ctx2D&&(this.ctx2D.clearRect(0,0,this.canvas2D.width,this.canvas2D.height),this.ctx2D.fillStyle="rgba(0,0,0,0)",this.ctx2D.fillRect(0,0,this.canvas2D.width,this.canvas2D.height),this.particleSystem)){const t=this.canvas2D.width/2,n=this.canvas2D.height/2,a=this.core3D?this.core3D.emotion:"neutral",s=me(a),o=this.core3D?this.rgbToHex(this.core3D.glowColor):"#FFFFFF",r=s?.visual?.particleBehavior||"ambient",l=s?.visual?.particleRate||15,h=s?.visual?.minParticles||5,c=s?.visual?.maxParticles||30,u=s?.visual?.particleColors||null;this.particleSystem.spawn(r,a,l,t,n,i,null,h,c,1,1,u,this.undertone);let d=null,m=0;if(this.currentGesture){const t=e-this.currentGesture.startTime;m=Math.min(t/this.currentGesture.duration,1),d={...this.currentGesture.config,type:this.currentGesture.name}}this.particleSystem.update(i,t,n,d,m,this.undertone),this.particleSystem.render(this.ctx2D,o,null)}this.animationFrameId=requestAnimationFrame(e=>this.animate(e))}setEmotion(e,t){this.eventManager&&this.eventManager._listeners&&(this.emotion=e,void 0!==t&&("string"==typeof t?this.undertone=t:t&&"object"==typeof t?this.undertone=t.undertone||null:null===t&&(this.undertone=null)),this.core3D&&this.core3D.setEmotion(e,this.undertone),this.particleSystem&&(this.particleSystem.particles=[]),this.eventManager.emit("emotion:change",{emotion:e,undertone:this.undertone}))}updateUndertone(e){this.undertone=e,this.core3D&&this.emotion&&this.core3D.setEmotion(this.emotion,e),this.eventManager.emit("undertone:change",{undertone:e})}setUndertone(e){this.updateUndertone(e)}express(e){if(!this.eventManager||!this.eventManager._listeners)return;this.core3D&&this.core3D.playGesture(e);const t=ft(e);if(t){const i=t.config||{},n=i.musicalDuration?.musical?500*(i.musicalDuration.beats||2):i.duration||800;this.currentGesture={name:e,gesture:t,config:i,startTime:performance.now(),duration:n};const a=setTimeout(()=>{this.currentGesture&&this.currentGesture.name===e&&(this.currentGesture=null)},n);this.gestureTimeouts.push(a)}this.eventManager.emit("gesture:trigger",{gesture:e})}chain(e){const t=("string"==typeof e?{rise:"breathe > sway+lean+tilt",flow:"sway > lean+tilt > spin > bounce",burst:"jump > nod > shake > flash",drift:"sway+breathe+float+drift",chaos:"shake+shake > spin+flash > bounce+pulse > twist+sparkle",morph:"expand > contract > morph+glow > expand+flash",rhythm:"pulse > pulse+sparkle > pulse+flicker",spiral:"spin > orbital > twist > orbital+sparkle",routine:"nod > bounce > spin+sparkle > sway+pulse > nod+flash",radiance:"sparkle > pulse+flicker > shimmer",twinkle:"sparkle > flash > pulse+sparkle > shimmer+flicker",stream:"wave > nod+pulse > sparkle > flash"}[e]||e:e.join(">")).split(">").map(e=>e.trim().split("+").map(e=>e.trim()).filter(e=>e.length>0));this.executeChainSequence(t)}executeChainSequence(e){if(!e||0===e.length)return;let t=0;const i=()=>{if(!(t>=e.length)&&(e[t].forEach(e=>{this.express(e)}),t++,t<e.length)){const e=setTimeout(i,800);this.gestureTimeouts.push(e)}};i()}morphTo(e,t={}){if(this.core3D){if(void 0!==t.materialVariant&&this.core3D.setMaterialVariant(t.materialVariant),t.onMaterialSwap){const e=this.core3D.onMaterialSwap;this.core3D.onMaterialSwap=i=>{e&&e(i),t.onMaterialSwap(i),this.core3D.onMaterialSwap=e}}const i=t.duration||800;this.core3D.morphToShape(e,i)}this.eventManager.emit("shape:morph",{shape:e})}feel(e){if(!this.eventManager||!this.eventManager._listeners)return{success:!1,error:"Engine destroyed",parsed:null};const t=Date.now(),i=this._feelRateLimiter;if(i.calls=i.calls.filter(e=>t-e<i.windowMs),i.calls.length>=i.maxCallsPerSecond)return console.warn("[feel] Rate limit exceeded. Max 10 calls per second."),{success:!1,error:"Rate limit exceeded",parsed:null};i.calls.push(t);const n=this._intentParser.parse(e),a=this._intentParser.validate(n);if(!a.valid)return console.warn("[feel] Invalid intent:",a.errors),{success:!1,error:a.errors.join("; "),parsed:n};try{if(n.emotion){const e={};n.undertone&&"clear"!==n.undertone&&(e.undertone=n.undertone),this.setEmotion(n.emotion,e)}for(const e of n.gestures)this.express(e);return n.shape&&this.morphTo(n.shape),{success:!0,error:null,parsed:n}}catch(e){return console.error("[feel] Execution error:",e),{success:!1,error:e.message,parsed:n}}}isMorphing(){return!!this.core3D&&this.core3D.isMorphing()}getMorphState(){return this.core3D?this.core3D.getMorphState():null}growIn(e=500){this.core3D&&this.core3D.growIn(e),this.eventManager.emit("animation:growIn",{duration:e})}setCoreGlowEnabled(e){this.core3D&&this.core3D.setCoreGlowEnabled(e),this.eventManager.emit("coreGlow:toggle",{enabled:e})}isCoreGlowEnabled(){return!this.core3D||this.core3D.coreGlowEnabled}enableAutoRotate(){this.core3D&&"moon"!==this.core3D.geometryType&&(this.core3D.renderer?.controls&&(this.core3D.renderer.controls.autoRotate=!0,this.core3D.renderer.controls.autoRotateSpeed=this.core3D.options?.autoRotateSpeed??.5),this.core3D.rotationDisabled=!1,this.setEmotion(this.core3D.emotion,this.undertone))}disableAutoRotate(){this.core3D?.renderer?.controls&&(this.core3D.renderer.controls.autoRotate=!1,this.core3D.renderer.controls.autoRotateSpeed=0),this.core3D&&(this.core3D.rotationDisabled=!0,this.core3D.rotationBehavior=null,this.core3D.baseEuler&&(this.core3D.baseEuler[0]=0,this.core3D.baseEuler[1]=0,this.core3D.baseEuler[2]=0))}setCameraPreset(e,t=1e3){this.core3D?.renderer?.setCameraPreset&&this.core3D.renderer.setCameraPreset(e,t)}get autoRotateEnabled(){return!1===this.core3D?.rotationDisabled}enableParticles(){if(this.core3D?.particleOrchestrator?.renderer&&(this.core3D.particleVisibility=!0,this.core3D.particleOrchestrator.renderer.setVisible(!0),this.core3D.particleOrchestrator.setEmotion(this.core3D.emotion,this.core3D.undertone)),!this.core3D?.particleOrchestrator&&!this.particleSystem&&this.canvas2D){const e=this.config.maxParticles||300;this.particleSystem=new hi(e,this.errorBoundary),this.particleSystem.canvasWidth=this.canvas2D.width,this.particleSystem.canvasHeight=this.canvas2D.height}}disableParticles(){this.core3D?.particleOrchestrator?.renderer&&(this.core3D.particleVisibility=!1,this.core3D.particleOrchestrator.renderer.setVisible(!1),this.core3D.particleOrchestrator.clear()),this.core3D?.particleOrchestrator||this.particleSystem&&(this.particleSystem.destroy(),this.particleSystem=null)}get particlesEnabled(){return this.core3D?.particleOrchestrator?!0===this.core3D.particleVisibility:null!==this.particleSystem}enableBlinking(){this.core3D&&(this.core3D.blinkingManuallyDisabled=!1,this.core3D.blinkAnimator&&this.core3D.blinkAnimator.resume())}disableBlinking(){this.core3D&&(this.core3D.blinkingManuallyDisabled=!0,this.core3D.blinkAnimator&&this.core3D.blinkAnimator.pause())}get blinkingEnabled(){return!(!this.core3D||!this.core3D.blinkAnimator)&&this.core3D.blinkAnimator.enabled}enableBreathing(){this.core3D&&(this.core3D.breathingEnabled=!0)}disableBreathing(){this.core3D&&(this.core3D.breathingEnabled=!1)}get breathingEnabled(){return!this.core3D||!1!==this.core3D.breathingEnabled}breathePhase(e,t){this.core3D&&this.core3D.breathePhase(e,t)}stopBreathingPhase(){this.core3D&&this.core3D.stopBreathingPhase()}enableWobble(){this.core3D&&this.core3D.setWobbleEnabled(!0)}disableWobble(){this.core3D&&this.core3D.setWobbleEnabled(!1)}get wobbleEnabled(){return!this.core3D||!1!==this.core3D.wobbleEnabled}enableRhythmSync(){this.core3D&&this.core3D.setRhythmEnabled(!0)}disableRhythmSync(){this.core3D&&this.core3D.setRhythmEnabled(!1)}get rhythmSyncEnabled(){return!!this.core3D&&this.core3D.rhythmEnabled}enableGroove(){this.core3D&&this.core3D.setGrooveEnabled(!0)}disableGroove(){this.core3D&&this.core3D.setGrooveEnabled(!1)}setBeatSyncStrength(e){this.core3D&&this.core3D.setBeatSyncStrength(e)}setGrooveConfig(e){this.core3D&&this.core3D.setGrooveConfig(e)}isRhythmPlaying(){return this.core3D?.isRhythmPlaying()||!1}getRhythmBPM(){return this.core3D?.getRhythmBPM()||120}startRhythm(e=120,t="straight"){this.core3D&&this.core3D.startRhythm(e,t)}stopRhythm(){this.core3D&&this.core3D.stopRhythm()}setRhythmBPM(e){this.core3D&&this.core3D.setRhythmBPM(e)}setRhythmPattern(e){this.core3D&&this.core3D.setRhythmPattern(e)}async connectAudio(e){if(!e)return;this._audioElement=e,this._audioContext||(this._audioContext=new(window.AudioContext||window.webkitAudioContext)),"suspended"===this._audioContext.state&&await this._audioContext.resume(),this._analyzerNode||(this._analyzerNode=this._audioContext.createAnalyser(),this._analyzerNode.fftSize=256,this._analyzerNode.smoothingTimeConstant=.8),this._audioSourceNode||(this._audioSourceNode=this._audioContext.createMediaElementSource(e),this._audioSourceNode.connect(this._analyzerNode),this._analyzerNode.connect(this._audioContext.destination));const t=()=>{const e=this._detectedBPM||120;this.startRhythm(e,"straight")},i=()=>{this.stopRhythm()},n=()=>{this.stopRhythm()};this._audioHandlers={onPlay:t,onPause:i,onEnded:n},e.addEventListener("play",t),e.addEventListener("pause",i),e.addEventListener("ended",n),e.paused||t(),this._startBPMDetection()}disconnectAudio(){this.stopRhythm(),this._audioElement&&this._audioHandlers&&(this._audioElement.removeEventListener("play",this._audioHandlers.onPlay),this._audioElement.removeEventListener("pause",this._audioHandlers.onPause),this._audioElement.removeEventListener("ended",this._audioHandlers.onEnded)),this._stopBPMDetection(),this._audioElement=null,this._audioHandlers=null}_startBPMDetection(){if(this._bpmDetectionInterval)return;const e=this._analyzerNode?.frequencyBinCount||128,t=new Uint8Array(e);let i=0;const n=[];this._bpmDetectionInterval=setInterval(()=>{if(!this._analyzerNode||!this._audioElement||this._audioElement.paused)return;this._analyzerNode.getByteFrequencyData(t);let e=0;for(let i=0;i<8;i++)e+=t[i];e/=8;const a=performance.now();if(e>180&&a-i>200){if(i>0){const e=a-i;if(n.push(e),n.length>8&&n.shift(),n.length>=4){const e=n.reduce((e,t)=>e+t,0)/n.length,t=Math.round(6e4/e);t>=60&&t<=180&&(this._detectedBPM=t,this.isRhythmPlaying()&&this.setRhythmBPM(t))}}i=a}},50)}_stopBPMDetection(){this._bpmDetectionInterval&&(clearInterval(this._bpmDetectionInterval),this._bpmDetectionInterval=null)}rgbToHex(e){return`#${[Math.round(255*e[0]),Math.round(255*e[1]),Math.round(255*e[2])].map(e=>{const t=e.toString(16);return 1===t.length?`0${t}`:t}).join("")}`}setPosition(e,t,i=0){if(!this.container)return;this.position={x:e,y:t,z:i};const n=window.innerWidth<768;this.container.style.transform=n?`translate(calc(-50% + ${e}px), calc(-50% + ${t}px))`:`translate(${e}px, calc(-50% + ${t}px))`}getPosition(){return this.position||{x:0,y:0,z:0}}animateToPosition(e,t,i=0,n=1e3,a="easeOutCubic"){if(!this.container)return;const s=this.getPosition(),o=performance.now(),r=a=>{const l=a-o,h=Math.min(l/n,1),c=(u=h,1-Math.pow(1-u,3));var u;const d=s.x+(e-s.x)*c,m=s.y+(t-s.y)*c,p=s.z+(i-s.z)*c;this.setPosition(d,m,p),h<1&&requestAnimationFrame(r)};requestAnimationFrame(r)}setContainment(e,t=1){if(this._containmentBounds=e,this._containmentScale=t,this.particleSystem&&1!==t){const e=this.config.particleSpawnRadius||150;this.particleSystem.setSpawnRadius(e*t)}return this}attachToElement(e,t={}){const i="string"==typeof e?document.querySelector(e):e;if(!i)return console.error(`[EmotiveMascot3D] Element not found: ${e}`),this;this._attachedElement=i,this._attachOptions={offsetX:t.offsetX||0,offsetY:t.offsetY||0,animate:!1!==t.animate,duration:t.duration||1e3,scale:t.scale||1,containParticles:!1!==t.containParticles},this._hasAttachedBefore=this._hasAttachedBefore||!1;const n=i.getBoundingClientRect();return this._attachOptions.containParticles?this.setContainment({width:n.width,height:n.height},this._attachOptions.scale):1!==this._attachOptions.scale&&this.setContainment(null,this._attachOptions.scale),this._updateAttachedPosition(),this._setupElementTracking(),this}_updateAttachedPosition(){if(!this._attachedElement||!this.container)return;const e=this._attachedElement.getBoundingClientRect(),t=window.innerWidth<768,i=e.left+e.width/2,n=e.top+e.height/2;let a,s;if(t)a=window.innerWidth/2,s=.18*window.innerHeight;else{const e=750;a=Math.max(20,(window.innerWidth/2-500)/2-375)+e/2,s=window.innerHeight/2}const o=i-a+this._attachOptions.offsetX,r=n-s+this._attachOptions.offsetY,l=!this._hasAttachedBefore;this._hasAttachedBefore=!0,l&&this._attachOptions.animate?this.animateToPosition(o,r,0,this._attachOptions.duration):this.setPosition(o,r,0)}_setupElementTracking(){this._elementTrackingHandlers||(this._elementTrackingHandlers={scroll:()=>this._updateAttachedPosition(),resize:()=>this._updateAttachedPosition()},window.addEventListener("scroll",this._elementTrackingHandlers.scroll,{passive:!0}),window.addEventListener("resize",this._elementTrackingHandlers.resize))}isAttachedToElement(){return!!this._attachedElement}detachFromElement(){return this._attachedElement=null,this._hasAttachedBefore=!1,this._elementTrackingHandlers&&(window.removeEventListener("scroll",this._elementTrackingHandlers.scroll),window.removeEventListener("resize",this._elementTrackingHandlers.resize),this._elementTrackingHandlers=null),this.setContainment(null,1),this.setEmotion("neutral"),this}setSSSPreset(e){this._currentSSSPreset=e,this.core3D&&!this._materialSwapCallbackSet&&(this._materialSwapCallbackSet=!0,this.core3D.onMaterialSwap=e=>{this._currentSSSPreset&&setTimeout(()=>{ji(this,this._currentSSSPreset)},50)});const t=ji(this,e);return t&&this.eventManager.emit("sss:presetChanged",{preset:e}),t}setGeometry(e,t={}){this.morphTo(e,t)}startSolarEclipse(e={}){this.core3D&&"function"==typeof this.core3D.startSolarEclipse?this.core3D.startSolarEclipse(e):(this.morphTo("sun"),this.eventManager.emit("eclipse:solar:start",{type:e.type||"total"}))}startLunarEclipse(e={}){this.core3D&&"function"==typeof this.core3D.startLunarEclipse?this.core3D.startLunarEclipse(e):(this.morphTo("moon"),this.eventManager.emit("eclipse:lunar:start",{type:e.type||"total"}))}stopEclipse(){this.core3D&&"function"==typeof this.core3D.stopEclipse&&this.core3D.stopEclipse(),this.eventManager&&this.eventManager.emit("eclipse:stop")}destroy(){this._destroyed=!0,this.stop(),this.disconnectAudio(),this._audioContext&&(this._audioContext.close(),this._audioContext=null),this._analyzerNode=null,this._audioSourceNode=null,this._elementTrackingHandlers&&(window.removeEventListener("scroll",this._elementTrackingHandlers.scroll),window.removeEventListener("resize",this._elementTrackingHandlers.resize),this._elementTrackingHandlers=null),this._attachedElement=null,this.gestureTimeouts.forEach(e=>clearTimeout(e)),this.gestureTimeouts=[],this.eventManager&&this.eventManager._listeners&&(Object.keys(this.eventManager._listeners).forEach(e=>{this.eventManager._listeners[e]=[]}),this.eventManager._listeners=null),this.core3D&&this.core3D.destroy(),this.particleSystem&&this.particleSystem.destroy(),this.webglCanvas&&this.webglCanvas.parentNode&&this.webglCanvas.parentNode.removeChild(this.webglCanvas),this.canvas2D&&this.canvas2D.parentNode&&this.canvas2D.parentNode.removeChild(this.canvas2D),this.container=null,this.webglCanvas=null,this.canvas2D=null,this.ctx2D=null,this.config=null,this.errorBoundary=null,this.currentGesture=null}}export{vn as CORE_GEOMETRIES,Gi as Core3DManager,wn as EmotiveMascot3D,Li as GeometryCache,I as MOON_PHASES,be as Rhythm3DAdapter,Ni as SSSPresets,q as animateMoonPhase,ji as applySSSPreset,x as blendModeNames,fn as createCrystal,yn as createDiamond,z as createMoon,G as createMoonCrescentMaterial,F as createMoonFallbackMaterial,O as createMoonMaterial,gn as createSphere,Y as createSunGeometry,X as createSunMaterial,wn as default,bn as disposeCoreGeometries,_ as disposeMoon,Q as disposeSun,D as getBlendModeIndex,C as getBlendModeName,A as getMoonPhaseNames,R as getPhaseFromProgress,Hi as getSSSPreset,Ui as getSSSPresetNames,we as rhythm3DAdapter,V as setMoonPhase,j as updateCrescentShadow,N as updateMoonGlow,$ as updateSunMaterial};
2
2
  //# sourceMappingURL=emotive-mascot-3d.js.map