hz-particles 1.0.15 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class ${constructor(t={}){this.config=t,this._posOut=[0,0,0],this._rotMatrix=null,this._invRotMatrix=null,this._cachedRotX=void 0,this._cachedRotY=void 0,this._cachedRotZ=void 0}_updateRotationMatrix(){const t=this.config.emissionRotationX||0,e=this.config.emissionRotationY||0,i=this.config.emissionRotationZ||0;if(t===this._cachedRotX&&e===this._cachedRotY&&i===this._cachedRotZ)return;this._cachedRotX=t,this._cachedRotY=e,this._cachedRotZ=i;const s=t*Math.PI/180,a=e*Math.PI/180,n=i*Math.PI/180,o=Math.cos(s),r=Math.sin(s),l=Math.cos(a),d=Math.sin(a),u=Math.cos(n),f=Math.sin(n);this._rotMatrix=[l*u,r*d*u-o*f,o*d*u+r*f,l*f,r*d*f+o*u,o*d*f-r*u,-d,r*l,o*l],this._invRotMatrix=[this._rotMatrix[0],this._rotMatrix[3],this._rotMatrix[6],this._rotMatrix[1],this._rotMatrix[4],this._rotMatrix[7],this._rotMatrix[2],this._rotMatrix[5],this._rotMatrix[8]]}emitParticle(t,e,i){const s=this._posOut;if(this.config.emissionShape==="cube"?this._emitFromCube(s):this.config.emissionShape==="sphere"?this._emitFromSphere(s):this.config.emissionShape==="square"?this._emitFromSquare(s):this.config.emissionShape==="circle"?this._emitFromCircle(s):this.config.emissionShape==="cylinder"?this._emitFromCylinder(s):this.config.emissionShape==="plain"?this._emitFromPlain(s):this.config.emissionShape==="cone"?this._emitFromCone(s):this.config.emissionShape==="torus"?this._emitFromTorus(s):this.config.emissionShape==="line"?this._emitFromLine(s):this.config.emissionShape==="hemisphere"?this._emitFromHemisphere(s):this.config.emissionShape==="disc"?this._emitFromDisc(s):this.config.emissionShape==="annulus"?this._emitFromAnnulus(s):this.config.emissionShape==="capsule"?this._emitFromCapsule(s):this.config.emissionShape==="arc"?this._emitFromArc(s):this.config.emissionShape==="spiral"?this._emitFromSpiral(s):this.config.emissionShape==="frustum"?this._emitFromFrustum(s):this.config.emissionShape==="cubeSurface"?this._emitFromCubeSurface(s):this.config.emissionShape==="sphereSurface"?this._emitFromSphereSurface(s):this.config.emissionShape==="boxFrame"?this._emitFromBoxFrame(s):this.config.emissionShape==="polygon"?this._emitFromPolygon(s):this.config.emissionShape==="rectangle"?this._emitFromRectangle(s):(s[0]=0,s[1]=0,s[2]=0),this.config.emissionRotationX||this.config.emissionRotationY||this.config.emissionRotationZ){this._updateRotationMatrix();const o=this._rotMatrix,r=s[0],l=s[1],d=s[2];s[0]=o[0]*r+o[1]*l+o[2]*d,s[1]=o[3]*r+o[4]*l+o[5]*d,s[2]=o[6]*r+o[7]*l+o[8]*d}(this.config.emissionTranslationX||this.config.emissionTranslationY||this.config.emissionTranslationZ)&&(s[0]+=this.config.emissionTranslationX||0,s[1]+=this.config.emissionTranslationY||0,s[2]+=this.config.emissionTranslationZ||0);const a=e*8;t[a]=s[0],t[a+1]=s[1],t[a+2]=s[2];const n=e*4;this.calculateVelocity(s[0],s[1],s[2],i,n),this.setParticleColor(t,a),this.setParticleLifetime(t,a)}applyRotation(t,e,i){this._updateRotationMatrix();const s=this._rotMatrix;return[s[0]*t+s[1]*e+s[2]*i,s[3]*t+s[4]*e+s[5]*i,s[6]*t+s[7]*e+s[8]*i]}inverseRotation(t,e,i){this._updateRotationMatrix();const s=this._invRotMatrix;return[s[0]*t+s[1]*e+s[2]*i,s[3]*t+s[4]*e+s[5]*i,s[6]*t+s[7]*e+s[8]*i]}_emitFromCube(t){let e=this.config.innerLength||0,i=this.config.outerLength||this.config.cubeLength;if(e>0){const s=Math.floor(Math.random()*6),a=Math.random()-.5,n=Math.random()-.5;let o,r,l;switch(s){case 0:o=a,r=n,l=.5;break;case 1:o=a,r=n,l=-.5;break;case 2:o=.5,r=a,l=n;break;case 3:o=-.5,r=a,l=n;break;case 4:o=a,r=.5,l=n;break;case 5:o=a,r=-.5,l=n;break}const d=Math.random(),u=e+d*(i-e);t[0]=o*u,t[1]=r*u,t[2]=l*u}else t[0]=(Math.random()-.5)*i,t[1]=(Math.random()-.5)*i,t[2]=(Math.random()-.5)*i}_emitFromSphere(t){const e=Math.random()*2*Math.PI,i=Math.acos(2*Math.random()-1),s=Math.sin(i)*Math.cos(e),a=Math.sin(i)*Math.sin(e),n=Math.cos(i);let o;this.config.innerRadius===0?o=this.config.outerRadius*Math.cbrt(Math.random()):o=this.config.innerRadius+(this.config.outerRadius-this.config.innerRadius)*Math.random(),t[0]=s*o,t[1]=a*o,t[2]=n*o}_emitFromSquare(t){const e=this.config.squareInnerSize||0,i=this.config.squareSize||2;if(e>0){const s=Math.floor(Math.random()*4);let a=e+(i-e)*Math.random();switch(s){case 0:t[0]=(Math.random()*2-1)*a,t[1]=a;break;case 1:t[0]=a,t[1]=(Math.random()*2-1)*a;break;case 2:t[0]=(Math.random()*2-1)*a,t[1]=-a;break;case 3:t[0]=-a,t[1]=(Math.random()*2-1)*a;break}}else t[0]=(Math.random()*2-1)*i,t[1]=(Math.random()*2-1)*i;t[2]=0}_emitFromCircle(t){const e=this.config.circleInnerRadius||0,i=this.config.circleOuterRadius||2,s=Math.random()*Math.PI*2;let a;e>0?a=e+(i-e)*Math.random():a=i*Math.sqrt(Math.random()),t[0]=Math.cos(s)*a,t[1]=Math.sin(s)*a,t[2]=0}_emitFromPlain(t){const e=this.config.planeWidth||2,i=this.config.planeDepth||2;t[0]=(Math.random()-.5)*e,t[1]=0,t[2]=(Math.random()-.5)*i}_emitFromCone(t){const e=this.config.coneInnerRadius||0,i=this.config.coneOuterRadius||2,s=this.config.coneHeight||4,a=Math.random()*Math.PI*2,n=Math.random(),o=n*s,r=i*(1-n);let l;if(e>0){const d=e*(1-n);l=d+(r-d)*Math.random()}else l=r*Math.sqrt(Math.random());t[0]=Math.cos(a)*l,t[1]=o,t[2]=Math.sin(a)*l}_emitFromTorus(t){const e=this.config.torusMajorRadius||2,i=this.config.torusMinorRadius||.5,s=Math.random()*Math.PI*2,a=Math.random()*Math.PI*2,n=i*Math.sqrt(Math.random());t[0]=(e+n*Math.cos(a))*Math.cos(s),t[1]=n*Math.sin(a),t[2]=(e+n*Math.cos(a))*Math.sin(s)}_emitFromLine(t){const e=this.config.lineLength||4,i=Math.random();t[0]=0,t[1]=(i-.5)*e,t[2]=0}_emitFromHemisphere(t){const e=this.config.hemisphereInnerRadius||0,i=this.config.hemisphereOuterRadius||2,s=Math.random()*Math.PI*2,a=Math.acos(Math.random()),n=Math.sin(a)*Math.cos(s),o=Math.cos(a),r=Math.sin(a)*Math.sin(s);let l;e>0?l=e+(i-e)*Math.random():l=i*Math.cbrt(Math.random()),t[0]=n*l,t[1]=o*l,t[2]=r*l}_emitFromDisc(t){const e=this.config.discRadius||2,i=Math.random()*Math.PI*2,s=e*Math.sqrt(Math.random());t[0]=Math.cos(i)*s,t[1]=0,t[2]=Math.sin(i)*s}_emitFromAnnulus(t){const e=this.config.annulusInnerRadius||1,i=this.config.annulusOuterRadius||2,s=Math.random()*Math.PI*2,a=e+(i-e)*Math.random();t[0]=Math.cos(s)*a,t[1]=0,t[2]=Math.sin(s)*a}_emitFromCapsule(t){const e=this.config.capsuleRadius||.5,i=this.config.capsuleHeight||4,s=i*.5,a=Math.PI*e*e*i,n=4/3*Math.PI*e*e*e,o=a/(a+n);if(Math.random()<o){const r=Math.random()*Math.PI*2,l=e*Math.sqrt(Math.random());t[0]=Math.cos(r)*l,t[1]=(Math.random()-.5)*i,t[2]=Math.sin(r)*l}else{const r=Math.random()*Math.PI*2,l=Math.acos(2*Math.random()-1),d=e*Math.cbrt(Math.random());t[0]=d*Math.sin(l)*Math.cos(r),t[1]=d*Math.cos(l),t[2]=d*Math.sin(l)*Math.sin(r),t[1]+=t[1]>=0?s:-s}}_emitFromArc(t){const e=this.config.arcStartAngle||0,i=this.config.arcEndAngle||180,s=this.config.arcInnerRadius||0,a=this.config.arcOuterRadius||2,n=e*Math.PI/180,o=i*Math.PI/180,r=n+Math.random()*(o-n);let l;s>0?l=s+(a-s)*Math.random():l=a*Math.sqrt(Math.random()),t[0]=Math.cos(r)*l,t[1]=Math.sin(r)*l,t[2]=0}_emitFromSpiral(t){const e=this.config.spiralTurns||3,i=this.config.spiralRadiusStart||.5,s=this.config.spiralRadiusEnd||2,a=this.config.spiralHeight||4,n=Math.random(),o=n*e*Math.PI*2,r=i+(s-i)*n;t[0]=Math.cos(o)*r,t[1]=(n-.5)*a,t[2]=Math.sin(o)*r}_emitFromFrustum(t){const e=this.config.frustumRadiusNear||.5,i=this.config.frustumRadiusFar||2,s=this.config.frustumHeight||4,a=Math.random()*Math.PI*2,n=Math.random(),o=n*s,l=(e+(i-e)*n)*Math.sqrt(Math.random());t[0]=Math.cos(a)*l,t[1]=o,t[2]=Math.sin(a)*l}_emitFromCubeSurface(t){const e=this.config.cubeSurfaceSize||2,i=e*.5,s=Math.floor(Math.random()*6),a=(Math.random()-.5)*e,n=(Math.random()-.5)*e;switch(s){case 0:t[0]=a,t[1]=n,t[2]=i;break;case 1:t[0]=a,t[1]=n,t[2]=-i;break;case 2:t[0]=i,t[1]=a,t[2]=n;break;case 3:t[0]=-i,t[1]=a,t[2]=n;break;case 4:t[0]=a,t[1]=i,t[2]=n;break;case 5:t[0]=a,t[1]=-i,t[2]=n;break}}_emitFromSphereSurface(t){const e=this.config.sphereSurfaceRadius||2,i=Math.random()*Math.PI*2,s=Math.acos(2*Math.random()-1);t[0]=e*Math.sin(s)*Math.cos(i),t[1]=e*Math.sin(s)*Math.sin(i),t[2]=e*Math.cos(s)}_emitFromBoxFrame(t){const e=this.config.boxFrameSize||2,i=e*.5,s=Math.floor(Math.random()*12),n=(Math.random()-.5)*e,o=[[-1,-1],[-1,1],[1,-1],[1,1]];if(s<4){const[r,l]=o[s];t[0]=n,t[1]=r*i,t[2]=l*i}else if(s<8){const[r,l]=o[s-4];t[0]=r*i,t[1]=n,t[2]=l*i}else{const[r,l]=o[s-8];t[0]=r*i,t[1]=l*i,t[2]=n}}_emitFromPolygon(t){const e=Math.max(3,Math.floor(this.config.polygonSides||6)),i=this.config.polygonRadius||2,s=Math.floor(Math.random()*e),a=s/e*Math.PI*2,n=(s+1)/e*Math.PI*2;let o=Math.random(),r=Math.random();o+r>1&&(o=1-o,r=1-r);const l=o*Math.cos(a)+r*Math.cos(n),d=o*Math.sin(a)+r*Math.sin(n);t[0]=l*i,t[1]=d*i,t[2]=0}_emitFromRectangle(t){const e=this.config.rectangleWidth||2,i=this.config.rectangleHeight||2;t[0]=(Math.random()-.5)*e,t[1]=(Math.random()-.5)*i,t[2]=0}_emitFromCylinder(t){const e=this.config.cylinderInnerRadius||0,i=this.config.cylinderOuterRadius||2,s=this.config.cylinderHeight||4,a=Math.random()*Math.PI*2;let n;e>0?n=e+(i-e)*Math.random():n=i*Math.sqrt(Math.random()),t[0]=Math.cos(a)*n,t[1]=(Math.random()-.5)*s,t[2]=Math.sin(a)*n}calculateVelocity(t,e,i,s,a){const n=this.config.emissionTranslationX||0,o=this.config.emissionTranslationY||0,r=this.config.emissionTranslationZ||0,l=t-n,d=e-o,u=i-r,f=Math.sqrt(l*l+d*d+u*u);let h,p,m;if(f>1e-4){let S=!1;if(this.config.emissionShape==="circle"&&this.config.circleVelocityDirection==="tangential"){const y=this.inverseRotation(l,d,u),_=Math.sqrt(y[0]*y[0]+y[1]*y[1]);if(_>1e-4){const g=-y[1]/_,x=y[0]/_,P=this.applyRotation(g,x,0);h=P[0],p=P[1],m=P[2],S=!0}}else if(this.config.emissionShape==="cylinder"&&this.config.cylinderVelocityDirection==="tangential"){const y=this.inverseRotation(l,d,u),_=Math.sqrt(y[0]*y[0]+y[2]*y[2]);if(_>1e-4){const g=-y[2]/_,x=y[0]/_,P=this.applyRotation(g,0,x);h=P[0],p=P[1],m=P[2],S=!0}else{const g=Math.random()*Math.PI*2,x=this.applyRotation(Math.cos(g),0,Math.sin(g));h=x[0],p=x[1],m=x[2],S=!0}}S||(h=l/f,p=d/f,m=u/f)}else{const S=Math.random()*Math.PI*2,y=Math.acos(2*Math.random()-1);h=Math.sin(y)*Math.cos(S),p=Math.sin(y)*Math.sin(S),m=Math.cos(y)}let b;this.config.randomSpeed?b=(this.config.minSpeed||0)+Math.random()*((this.config.maxSpeed||1)-(this.config.minSpeed||0)):b=this.config.particleSpeed,s[a]=this.config.overrideXVelocity?this.config.xVelocity:h*b,s[a+1]=this.config.overrideYVelocity?this.config.yVelocity:p*b,s[a+2]=this.config.overrideZVelocity?this.config.zVelocity:m*b,s[a+3]=0}setParticleColor(t,e){if(this.config.randomColorEnabled&&this.config.randomColors.length>0){const i=this.config.randomColors,s=i[Math.floor(Math.random()*i.length)];t[e+3]=s[0],t[e+4]=s[1],t[e+5]=s[2]}else this.config.colorTransitionEnabled?(t[e+3]=this.config.startColor[0],t[e+4]=this.config.startColor[1],t[e+5]=this.config.startColor[2]):(t[e+3]=this.config.particleColor[0],t[e+4]=this.config.particleColor[1],t[e+5]=this.config.particleColor[2])}setParticleLifetime(t,e){const i=this.config.lifetime||5;t[e+6]=0,t[e+7]=i+(Math.random()*.4-.2)*i}}class H{constructor(t,e=1e4){this.device=t,this.physicsSettings={deltaTime:.016,gravity:0,turbulence:0,attractorStrength:0,attractorPosition:[0,0,0],damping:0,confinementEnabled:!1,confinementShape:"box",confinementMode:"bounce",confinementSpace:"world",confinementBoxHalfSize:[2,2,2],confinementSphereRadius:3,confinementRestitution:.8,confinementFriction:.1,confinementCenter:[0,0,0],softBoundaryEnabled:!1,softBoundaryStrength:5,softBoundaryFalloff:.5},this.fixedDeltaTime=1/60,this.physicsClock=0,this.physicsAccumulator=0,this.minUpdatesPerSecond=30,this.lastUpdateTime=0,this.computeReady=!1,this.computePipeline=null,this.computeBindGroupLayout=null,this._physicsData=new Float32Array(32),this._physicsDataU32View=new Uint32Array(this._physicsData.buffer),this.physicsUniformBuffer=t.createBuffer({size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,label:"physicsUniformBuffer"}),this._maxParticles=e,this._particleDataStagingBuffer=t.createBuffer({size:e*8*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"ParticleDataReadbackBuffer_Pooled"}),this._velocityStagingBuffer=t.createBuffer({size:e*4*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"VelocityReadbackBuffer_Pooled"}),this._stagingInUse=!1,this._renderStagingParticleBuffer=t.createBuffer({size:e*8*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"RenderReadback_ParticleData"}),this._renderStagingVelocityBuffer=t.createBuffer({size:e*4*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"RenderReadback_Velocity"}),this._renderStagingInUse=!1,this._scriptStagingParticleBuffer=t.createBuffer({size:e*8*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"ScriptReadback_ParticleData"}),this._scriptStagingVelocityBuffer=t.createBuffer({size:e*4*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"ScriptReadback_Velocity"}),this._scriptStagingInUse=!1}async initComputePipeline(t,e,i){try{return await this.createComputePipeline(t,e,i),this.computeReady=!0,!0}catch(s){return console.error("Error initializing compute pipeline:",s),!1}}async createComputePipeline(t,e,i){const{particlePhysicsShader:s}=await Promise.resolve().then(()=>te);this.computeBindGroupLayout=this.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),this.computePipeline=this.device.createComputePipeline({layout:this.device.createPipelineLayout({bindGroupLayouts:[this.computeBindGroupLayout]}),compute:{module:this.device.createShaderModule({code:s}),entryPoint:"main"}}),this.computeBindGroup=this.device.createBindGroup({layout:this.computeBindGroupLayout,entries:[{binding:0,resource:{buffer:this.physicsUniformBuffer}},{binding:1,resource:{buffer:t}},{binding:2,resource:{buffer:e}},{binding:3,resource:{buffer:i}}]})}updatePhysics(t,e,i,s,a,n){if(e<=0||!this.computeReady)return;const o=this._physicsData,r=this.physicsSettings;o[0]=t,o[1]=i.particleSpeed,o[2]=r.gravity,o[3]=r.turbulence,o[4]=r.attractorStrength,o[5]=r.damping,o[6]=r.attractorPosition[0],o[7]=r.attractorPosition[1],o[8]=r.attractorPosition[2],this._physicsDataU32View[9]=e,o[10]=r.confinementEnabled?1:0,o[11]=r.confinementShape==="sphere"?1:0,o[12]=r.confinementMode==="kill"?1:0,o[13]=r.confinementSpace==="local"?1:0,o[14]=r.confinementBoxHalfSize[0],o[15]=r.confinementBoxHalfSize[1],o[16]=r.confinementBoxHalfSize[2],o[17]=r.confinementSphereRadius,o[18]=r.confinementRestitution,o[19]=r.confinementFriction,o[20]=r.confinementCenter[0],o[21]=r.confinementCenter[1],o[22]=r.confinementCenter[2],o[23]=r.softBoundaryEnabled?1:0,o[24]=r.softBoundaryStrength,o[25]=r.softBoundaryFalloff,o[26]=i.velocityStretchEnabled?1:0,o[27]=i.velocityStretchFactor??1,o[28]=0,o[29]=0,o[30]=0,o[31]=0,this.device.queue.writeBuffer(this.physicsUniformBuffer,0,o);const l=n||this.device.createCommandEncoder({label:"ParticlePhysicsEncoder"}),d=l.beginComputePass({label:"ParticlePhysicsPass"});d.setPipeline(this.computePipeline),d.setBindGroup(0,this.computeBindGroup);const u=Math.max(1,Math.ceil(e/64));d.dispatchWorkgroups(u,1,1),d.end(),n||this.device.queue.submit([l.finish()]),this.lastUpdateTime=performance.now()/1e3}async readbackAndProcessParticles(t,e,i,s,a){if(t<=0)return{activeCount:0,shouldUpdate:!1};if(this._stagingInUse)return{activeCount:t,shouldUpdate:!1};try{this._stagingInUse=!0;const n=this.device.createCommandEncoder({label:"ParticleReadbackEncoder"}),o=t*8*4;n.copyBufferToBuffer(s,0,this._particleDataStagingBuffer,0,o);const r=t*4*4;return n.copyBufferToBuffer(a,0,this._velocityStagingBuffer,0,r),this.device.queue.submit([n.finish()]),await Promise.all([(async()=>{await this._particleDataStagingBuffer.mapAsync(GPUMapMode.READ,0,o);const l=new Float32Array(this._particleDataStagingBuffer.getMappedRange(0,o));e.set(l),this._particleDataStagingBuffer.unmap()})(),(async()=>{await this._velocityStagingBuffer.mapAsync(GPUMapMode.READ,0,r);const l=new Float32Array(this._velocityStagingBuffer.getMappedRange(0,r));i.set(l),this._velocityStagingBuffer.unmap()})()]),this._stagingInUse=!1,{particleData:e,particleVelocities:i,shouldUpdate:!0}}catch(n){return this._stagingInUse=!1,console.error("Error reading back particle data:",n),{activeCount:t,shouldUpdate:!1}}}setDamping(t){this.physicsSettings.damping=t}setGravity(t){this.physicsSettings.gravity=t}setAttractor(t,e){this.physicsSettings.attractorStrength=t,this.physicsSettings.attractorPosition=e}setConfinement(t){const e=this.physicsSettings;t.enabled!==void 0&&(e.confinementEnabled=t.enabled),t.shape!==void 0&&(e.confinementShape=t.shape),t.mode!==void 0&&(e.confinementMode=t.mode),t.space!==void 0&&(e.confinementSpace=t.space),t.boxSize!==void 0&&(e.confinementBoxHalfSize=t.boxSize),t.sphereRadius!==void 0&&(e.confinementSphereRadius=t.sphereRadius),t.restitution!==void 0&&(e.confinementRestitution=t.restitution),t.friction!==void 0&&(e.confinementFriction=t.friction),t.center!==void 0&&(e.confinementCenter=t.center)}async readbackForRendering(t,e,i,s,a){if(t<=0)return{shouldUpdate:!1};if(this._renderStagingInUse)return{shouldUpdate:!1};try{this._renderStagingInUse=!0;const n=t*8*4,o=t*4*4,r=this.device.createCommandEncoder({label:"RenderReadbackEncoder"});return r.copyBufferToBuffer(s,0,this._renderStagingParticleBuffer,0,n),r.copyBufferToBuffer(a,0,this._renderStagingVelocityBuffer,0,o),this.device.queue.submit([r.finish()]),await Promise.all([(async()=>{await this._renderStagingParticleBuffer.mapAsync(GPUMapMode.READ,0,n);const l=new Float32Array(this._renderStagingParticleBuffer.getMappedRange(0,n));e.set(l),this._renderStagingParticleBuffer.unmap()})(),(async()=>{await this._renderStagingVelocityBuffer.mapAsync(GPUMapMode.READ,0,o);const l=new Float32Array(this._renderStagingVelocityBuffer.getMappedRange(0,o));i.set(l),this._renderStagingVelocityBuffer.unmap()})()]),this._renderStagingInUse=!1,{particleData:e,particleVelocities:i,shouldUpdate:!0}}catch(n){return this._renderStagingInUse=!1,console.error("Error in rendering readback:",n),{shouldUpdate:!1}}}async readbackForScript(t,e,i,s,a){if(t<=0)return{shouldUpdate:!1};if(this._scriptStagingInUse)return{shouldUpdate:!1};try{this._scriptStagingInUse=!0;const n=t*8*4,o=t*4*4,r=this.device.createCommandEncoder({label:"ScriptReadbackEncoder"});return r.copyBufferToBuffer(s,0,this._scriptStagingParticleBuffer,0,n),r.copyBufferToBuffer(a,0,this._scriptStagingVelocityBuffer,0,o),this.device.queue.submit([r.finish()]),await Promise.all([(async()=>{await this._scriptStagingParticleBuffer.mapAsync(GPUMapMode.READ,0,n);const l=new Float32Array(this._scriptStagingParticleBuffer.getMappedRange(0,n));e.set(l),this._scriptStagingParticleBuffer.unmap()})(),(async()=>{await this._scriptStagingVelocityBuffer.mapAsync(GPUMapMode.READ,0,o);const l=new Float32Array(this._scriptStagingVelocityBuffer.getMappedRange(0,o));i.set(l),this._scriptStagingVelocityBuffer.unmap()})()]),this._scriptStagingInUse=!1,{shouldUpdate:!0}}catch(n){return this._scriptStagingInUse=!1,console.error("Error in script readback:",n),{shouldUpdate:!1}}}destroy(){this.physicsUniformBuffer.destroy(),this._particleDataStagingBuffer.destroy(),this._velocityStagingBuffer.destroy(),this._renderStagingParticleBuffer.destroy(),this._renderStagingVelocityBuffer.destroy(),this._scriptStagingParticleBuffer.destroy(),this._scriptStagingVelocityBuffer.destroy()}setSoftBoundary(t){const e=this.physicsSettings;t.enabled!==void 0&&(e.softBoundaryEnabled=t.enabled),t.strength!==void 0&&(e.softBoundaryStrength=t.strength),t.falloff!==void 0&&(e.softBoundaryFalloff=t.falloff)}}class W{constructor(t){this.device=t,this.defaultTexture=null,this.createDefaultTexture()}createDefaultTexture(){const t=new Uint8Array([255,255,255,255]);this.defaultTexture=this.device.createTexture({size:[1,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST,label:"defaultParticleTexture"}),this.device.queue.writeTexture({texture:this.defaultTexture},t,{bytesPerRow:4},[1,1])}async loadTexture(t){const e=this.device.createTexture({size:[t.width,t.height],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT,label:"particleTexture"});return this.device.queue.copyExternalImageToTexture({source:t},{texture:e},[t.width,t.height]),e}getDefaultTexture(){return this.defaultTexture}destroyTexture(t){t&&t.label!=="defaultParticleTexture"&&t.destroy()}}const J=Object.freeze({sin:Math.sin,cos:Math.cos,abs:Math.abs,floor:Math.floor,ceil:Math.ceil,round:Math.round,min:Math.min,max:Math.max,sqrt:Math.sqrt,pow:Math.pow,random:Math.random,PI:Math.PI,TAU:Math.PI*2,clamp(c,t,e){return c<t?t:c>e?e:c},lerp(c,t,e){return c+(t-c)*e},smoothstep(c,t,e){const i=J.clamp((e-c)/(t-c),0,1);return i*i*(3-2*i)}}),C=new Set(["particleSize","particleSpeed","particleColor","startColor","endColor","opacity","emissionRate","gravityStrength","dampingStrength","attractorStrength","attractorPosition","pulseAmplitude","pulseFrequency","bloomIntensity"]);class ne{constructor(t){this._collection=t,this._pd=null,this._vd=null,this._pi=0,this._vi=0}_bind(t,e,i){return this._pd=t,this._vd=e,this._pi=i*8,this._vi=i*4,this}get x(){return this._pd[this._pi]}set x(t){this._pd[this._pi]=t,this._collection._dirty=!0}get y(){return this._pd[this._pi+1]}set y(t){this._pd[this._pi+1]=t,this._collection._dirty=!0}get z(){return this._pd[this._pi+2]}set z(t){this._pd[this._pi+2]=t,this._collection._dirty=!0}get r(){return this._pd[this._pi+3]}set r(t){this._pd[this._pi+3]=t,this._collection._dirty=!0}get g(){return this._pd[this._pi+4]}set g(t){this._pd[this._pi+4]=t,this._collection._dirty=!0}get b(){return this._pd[this._pi+5]}set b(t){this._pd[this._pi+5]=t,this._collection._dirty=!0}get age(){return this._pd[this._pi+6]}set age(t){this._pd[this._pi+6]=t,this._collection._dirty=!0}get lifetime(){return this._pd[this._pi+7]}set lifetime(t){this._pd[this._pi+7]=t,this._collection._dirty=!0}get vx(){return this._vd[this._vi]}set vx(t){this._vd[this._vi]=t,this._collection._dirty=!0}get vy(){return this._vd[this._vi+1]}set vy(t){this._vd[this._vi+1]=t,this._collection._dirty=!0}get vz(){return this._vd[this._vi+2]}set vz(t){this._vd[this._vi+2]=t,this._collection._dirty=!0}}class oe{constructor(){this._proxy=new ne(this),this._pd=null,this._vd=null,this.count=0,this._dirty=!1}_bind(t,e,i){this._pd=t,this._vd=e,this.count=i,this._dirty=!1}get(t){return t<0||t>=this.count?null:this._proxy._bind(this._pd,this._vd,t)}}const le=1e6;function ce(c){let t=0;return c.replace(/\b(for|while)\s*\([^)]*\)\s*\{/g,e=>{const i=`__lc${t++}`;return`${e} if(++${i}>${le})throw new Error("Loop limit exceeded");`}).replace(/\b(for|while)\s*\([^)]*\)\s*\{/g,e=>e).replace(/^/,()=>{let e="";for(let i=0;i<t;i++)e+=`let __lc${i}=0;`;return e})}const U=new Map;for(const c of C)U.set(c.toLowerCase(),c);function de(c){const t={value:!1},e=new Set;return new Proxy(c,{get(s,a){if(a==="__dirty")return t.value;if(a==="__resetDirty")return()=>{t.value=!1};if(typeof a!="string")return;if(C.has(a))return s[a];const n=U.get(a.toLowerCase());if(n)return e.has(a)||(e.add(a),console.warn(`[ParticleScript] config.${a} → did you mean config.${n}?`)),s[n]},set(s,a,n){if(typeof a!="string")return!0;let o=a;if(!C.has(o)){const r=U.get(o.toLowerCase());if(r)e.has(a)||(e.add(a),console.warn(`[ParticleScript] config.${a} → did you mean config.${r}?`)),o=r;else return!0}return s[o]=n,t.value=!0,!0}})}class z{constructor(t,e,i){this._particles=new oe,this._configProxy=de(e),this._configSnapshot=null,this._fn=null,this._error=!1,this.compile(t)}compile(t){if(this._fn=null,this._error=!1,!(!t||typeof t!="string"))try{const i=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class _i{constructor(t={}){this.config=t,this._posOut=[0,0,0],this._rotMatrix=null,this._invRotMatrix=null,this._cachedRotX=void 0,this._cachedRotY=void 0,this._cachedRotZ=void 0}_updateRotationMatrix(){const t=this.config.emissionRotationX||0,e=this.config.emissionRotationY||0,i=this.config.emissionRotationZ||0;if(t===this._cachedRotX&&e===this._cachedRotY&&i===this._cachedRotZ)return;this._cachedRotX=t,this._cachedRotY=e,this._cachedRotZ=i;const s=t*Math.PI/180,n=e*Math.PI/180,o=i*Math.PI/180,a=Math.cos(s),c=Math.sin(s),l=Math.cos(n),u=Math.sin(n),f=Math.cos(o),h=Math.sin(o);this._rotMatrix=[l*f,c*u*f-a*h,a*u*f+c*h,l*h,c*u*h+a*f,a*u*h-c*f,-u,c*l,a*l],this._invRotMatrix=[this._rotMatrix[0],this._rotMatrix[3],this._rotMatrix[6],this._rotMatrix[1],this._rotMatrix[4],this._rotMatrix[7],this._rotMatrix[2],this._rotMatrix[5],this._rotMatrix[8]]}emitParticle(t,e,i){const s=this._posOut;if(this.config.emissionShape==="cube"||this.config.emissionShape==="box"?this._emitFromCube(s):this.config.emissionShape==="sphere"?this._emitFromSphere(s):this.config.emissionShape==="square"?this._emitFromSquare(s):this.config.emissionShape==="circle"?this._emitFromCircle(s):this.config.emissionShape==="cylinder"?this._emitFromCylinder(s):this.config.emissionShape==="plain"?this._emitFromPlain(s):this.config.emissionShape==="cone"?this._emitFromCone(s):this.config.emissionShape==="torus"?this._emitFromTorus(s):this.config.emissionShape==="line"?this._emitFromLine(s):this.config.emissionShape==="hemisphere"?this._emitFromHemisphere(s):this.config.emissionShape==="disc"?this._emitFromDisc(s):this.config.emissionShape==="annulus"?this._emitFromAnnulus(s):this.config.emissionShape==="capsule"?this._emitFromCapsule(s):this.config.emissionShape==="arc"?this._emitFromArc(s):this.config.emissionShape==="spiral"?this._emitFromSpiral(s):this.config.emissionShape==="frustum"?this._emitFromFrustum(s):this.config.emissionShape==="cubeSurface"?this._emitFromCubeSurface(s):this.config.emissionShape==="sphereSurface"?this._emitFromSphereSurface(s):this.config.emissionShape==="boxFrame"?this._emitFromBoxFrame(s):this.config.emissionShape==="polygon"?this._emitFromPolygon(s):this.config.emissionShape==="rectangle"?this._emitFromRectangle(s):(s[0]=0,s[1]=0,s[2]=0),this.config.emissionRotationX||this.config.emissionRotationY||this.config.emissionRotationZ){this._updateRotationMatrix();const a=this._rotMatrix,c=s[0],l=s[1],u=s[2];s[0]=a[0]*c+a[1]*l+a[2]*u,s[1]=a[3]*c+a[4]*l+a[5]*u,s[2]=a[6]*c+a[7]*l+a[8]*u}(this.config.emissionPositionX||this.config.emissionPositionY||this.config.emissionPositionZ)&&(s[0]+=this.config.emissionPositionX||0,s[1]+=this.config.emissionPositionY||0,s[2]+=this.config.emissionPositionZ||0);const n=e*8;t[n]=s[0],t[n+1]=s[1],t[n+2]=s[2];const o=e*4;this.calculateVelocity(s[0],s[1],s[2],i,o),this.setParticleColor(t,n),this.setParticleLifetime(t,n)}applyRotation(t,e,i){this._updateRotationMatrix();const s=this._rotMatrix;return[s[0]*t+s[1]*e+s[2]*i,s[3]*t+s[4]*e+s[5]*i,s[6]*t+s[7]*e+s[8]*i]}inverseRotation(t,e,i){this._updateRotationMatrix();const s=this._invRotMatrix;return[s[0]*t+s[1]*e+s[2]*i,s[3]*t+s[4]*e+s[5]*i,s[6]*t+s[7]*e+s[8]*i]}_emitFromCube(t){let e=this.config.innerLength||0,i=this.config.outerLength||this.config.cubeLength;if(e>0){const s=Math.floor(Math.random()*6),n=Math.random()-.5,o=Math.random()-.5;let a,c,l;switch(s){case 0:a=n,c=o,l=.5;break;case 1:a=n,c=o,l=-.5;break;case 2:a=.5,c=n,l=o;break;case 3:a=-.5,c=n,l=o;break;case 4:a=n,c=.5,l=o;break;case 5:a=n,c=-.5,l=o;break}const u=Math.random(),f=e+u*(i-e);t[0]=a*f,t[1]=c*f,t[2]=l*f}else t[0]=(Math.random()-.5)*i,t[1]=(Math.random()-.5)*i,t[2]=(Math.random()-.5)*i}_emitFromSphere(t){const e=Math.random()*2*Math.PI,i=Math.acos(2*Math.random()-1),s=Math.sin(i)*Math.cos(e),n=Math.sin(i)*Math.sin(e),o=Math.cos(i);let a;this.config.innerRadius===0?a=this.config.outerRadius*Math.cbrt(Math.random()):a=this.config.innerRadius+(this.config.outerRadius-this.config.innerRadius)*Math.random(),t[0]=s*a,t[1]=n*a,t[2]=o*a}_emitFromSquare(t){const e=this.config.squareInnerSize||0,i=this.config.squareSize||2;if(e>0){const s=Math.floor(Math.random()*4);let n=e+(i-e)*Math.random();switch(s){case 0:t[0]=(Math.random()*2-1)*n,t[1]=n;break;case 1:t[0]=n,t[1]=(Math.random()*2-1)*n;break;case 2:t[0]=(Math.random()*2-1)*n,t[1]=-n;break;case 3:t[0]=-n,t[1]=(Math.random()*2-1)*n;break}}else t[0]=(Math.random()*2-1)*i,t[1]=(Math.random()*2-1)*i;t[2]=0}_emitFromCircle(t){const e=this.config.circleInnerRadius||0,i=this.config.circleOuterRadius||2,s=Math.random()*Math.PI*2;let n;e>0?n=e+(i-e)*Math.random():n=i*Math.sqrt(Math.random()),t[0]=Math.cos(s)*n,t[1]=Math.sin(s)*n,t[2]=0}_emitFromPlain(t){const e=this.config.planeWidth||2,i=this.config.planeDepth||2;t[0]=(Math.random()-.5)*e,t[1]=0,t[2]=(Math.random()-.5)*i}_emitFromCone(t){const e=this.config.coneInnerRadius||0,i=this.config.coneOuterRadius||2,s=this.config.coneHeight||4,n=Math.random()*Math.PI*2,o=Math.random(),a=o*s,c=i*(1-o);let l;if(e>0){const u=e*(1-o);l=u+(c-u)*Math.random()}else l=c*Math.sqrt(Math.random());t[0]=Math.cos(n)*l,t[1]=a,t[2]=Math.sin(n)*l}_emitFromTorus(t){const e=this.config.torusMajorRadius||2,i=this.config.torusMinorRadius||.5,s=Math.random()*Math.PI*2,n=Math.random()*Math.PI*2,o=i*Math.sqrt(Math.random());t[0]=(e+o*Math.cos(n))*Math.cos(s),t[1]=o*Math.sin(n),t[2]=(e+o*Math.cos(n))*Math.sin(s)}_emitFromLine(t){const e=this.config.lineLength||4,i=Math.random();t[0]=0,t[1]=(i-.5)*e,t[2]=0}_emitFromHemisphere(t){const e=this.config.hemisphereInnerRadius||0,i=this.config.hemisphereOuterRadius||2,s=Math.random()*Math.PI*2,n=Math.acos(Math.random()),o=Math.sin(n)*Math.cos(s),a=Math.cos(n),c=Math.sin(n)*Math.sin(s);let l;e>0?l=e+(i-e)*Math.random():l=i*Math.cbrt(Math.random()),t[0]=o*l,t[1]=a*l,t[2]=c*l}_emitFromDisc(t){const e=this.config.discRadius||2,i=Math.random()*Math.PI*2,s=e*Math.sqrt(Math.random());t[0]=Math.cos(i)*s,t[1]=0,t[2]=Math.sin(i)*s}_emitFromAnnulus(t){const e=this.config.annulusInnerRadius||1,i=this.config.annulusOuterRadius||2,s=Math.random()*Math.PI*2,n=e+(i-e)*Math.random();t[0]=Math.cos(s)*n,t[1]=0,t[2]=Math.sin(s)*n}_emitFromCapsule(t){const e=this.config.capsuleRadius||.5,i=this.config.capsuleHeight||4,s=i*.5,n=Math.PI*e*e*i,o=4/3*Math.PI*e*e*e,a=n/(n+o);if(Math.random()<a){const c=Math.random()*Math.PI*2,l=e*Math.sqrt(Math.random());t[0]=Math.cos(c)*l,t[1]=(Math.random()-.5)*i,t[2]=Math.sin(c)*l}else{const c=Math.random()*Math.PI*2,l=Math.acos(2*Math.random()-1),u=e*Math.cbrt(Math.random());t[0]=u*Math.sin(l)*Math.cos(c),t[1]=u*Math.cos(l),t[2]=u*Math.sin(l)*Math.sin(c),t[1]+=t[1]>=0?s:-s}}_emitFromArc(t){const e=this.config.arcStartAngle||0,i=this.config.arcEndAngle||180,s=this.config.arcInnerRadius||0,n=this.config.arcOuterRadius||2,o=e*Math.PI/180,a=i*Math.PI/180,c=o+Math.random()*(a-o);let l;s>0?l=s+(n-s)*Math.random():l=n*Math.sqrt(Math.random()),t[0]=Math.cos(c)*l,t[1]=Math.sin(c)*l,t[2]=0}_emitFromSpiral(t){const e=this.config.spiralTurns||3,i=this.config.spiralRadiusStart||.5,s=this.config.spiralRadiusEnd||2,n=this.config.spiralHeight||4,o=Math.random(),a=o*e*Math.PI*2,c=i+(s-i)*o;t[0]=Math.cos(a)*c,t[1]=(o-.5)*n,t[2]=Math.sin(a)*c}_emitFromFrustum(t){const e=this.config.frustumRadiusNear||.5,i=this.config.frustumRadiusFar||2,s=this.config.frustumHeight||4,n=Math.random()*Math.PI*2,o=Math.random(),a=o*s,l=(e+(i-e)*o)*Math.sqrt(Math.random());t[0]=Math.cos(n)*l,t[1]=a,t[2]=Math.sin(n)*l}_emitFromCubeSurface(t){const e=this.config.cubeSurfaceSize||2,i=e*.5,s=Math.floor(Math.random()*6),n=(Math.random()-.5)*e,o=(Math.random()-.5)*e;switch(s){case 0:t[0]=n,t[1]=o,t[2]=i;break;case 1:t[0]=n,t[1]=o,t[2]=-i;break;case 2:t[0]=i,t[1]=n,t[2]=o;break;case 3:t[0]=-i,t[1]=n,t[2]=o;break;case 4:t[0]=n,t[1]=i,t[2]=o;break;case 5:t[0]=n,t[1]=-i,t[2]=o;break}}_emitFromSphereSurface(t){const e=this.config.sphereSurfaceRadius||2,i=Math.random()*Math.PI*2,s=Math.acos(2*Math.random()-1);t[0]=e*Math.sin(s)*Math.cos(i),t[1]=e*Math.sin(s)*Math.sin(i),t[2]=e*Math.cos(s)}_emitFromBoxFrame(t){const e=this.config.boxFrameSize||2,i=e*.5,s=Math.floor(Math.random()*12),o=(Math.random()-.5)*e,a=[[-1,-1],[-1,1],[1,-1],[1,1]];if(s<4){const[c,l]=a[s];t[0]=o,t[1]=c*i,t[2]=l*i}else if(s<8){const[c,l]=a[s-4];t[0]=c*i,t[1]=o,t[2]=l*i}else{const[c,l]=a[s-8];t[0]=c*i,t[1]=l*i,t[2]=o}}_emitFromPolygon(t){const e=Math.max(3,Math.floor(this.config.polygonSides||6)),i=this.config.polygonRadius||2,s=Math.floor(Math.random()*e),n=s/e*Math.PI*2,o=(s+1)/e*Math.PI*2;let a=Math.random(),c=Math.random();a+c>1&&(a=1-a,c=1-c);const l=a*Math.cos(n)+c*Math.cos(o),u=a*Math.sin(n)+c*Math.sin(o);t[0]=l*i,t[1]=u*i,t[2]=0}_emitFromRectangle(t){const e=this.config.rectangleWidth||2,i=this.config.rectangleHeight||2;t[0]=(Math.random()-.5)*e,t[1]=(Math.random()-.5)*i,t[2]=0}_emitFromCylinder(t){const e=this.config.cylinderInnerRadius||0,i=this.config.cylinderOuterRadius||2,s=this.config.cylinderHeight||4,n=Math.random()*Math.PI*2;let o;e>0?o=e+(i-e)*Math.random():o=i*Math.sqrt(Math.random()),t[0]=Math.cos(n)*o,t[1]=(Math.random()-.5)*s,t[2]=Math.sin(n)*o}calculateVelocity(t,e,i,s,n){const o=this.config.emissionPositionX||0,a=this.config.emissionPositionY||0,c=this.config.emissionPositionZ||0,l=t-o,u=e-a,f=i-c,h=Math.sqrt(l*l+u*u+f*f);let m,S,R;if(h>1e-4){let C=!1;if(this.config.emissionShape==="circle"&&this.config.circleVelocityDirection==="tangential"){const B=this.inverseRotation(l,u,f),A=Math.sqrt(B[0]*B[0]+B[1]*B[1]);if(A>1e-4){const P=-B[1]/A,_=B[0]/A,T=this.applyRotation(P,_,0);m=T[0],S=T[1],R=T[2],C=!0}}else if(this.config.emissionShape==="cylinder"&&this.config.cylinderVelocityDirection==="tangential"){const B=this.inverseRotation(l,u,f),A=Math.sqrt(B[0]*B[0]+B[2]*B[2]);if(A>1e-4){const P=-B[2]/A,_=B[0]/A,T=this.applyRotation(P,0,_);m=T[0],S=T[1],R=T[2],C=!0}else{const P=Math.random()*Math.PI*2,_=this.applyRotation(Math.cos(P),0,Math.sin(P));m=_[0],S=_[1],R=_[2],C=!0}}C||(m=l/h,S=u/h,R=f/h)}else{const C=Math.random()*Math.PI*2,B=Math.acos(2*Math.random()-1);m=Math.sin(B)*Math.cos(C),S=Math.sin(B)*Math.sin(C),R=Math.cos(B)}let D;this.config.randomSpeed?D=(this.config.minSpeed||0)+Math.random()*((this.config.maxSpeed||1)-(this.config.minSpeed||0)):D=this.config.particleSpeed,s[n]=this.config.overrideXVelocity?this.config.xVelocity:m*D,s[n+1]=this.config.overrideYVelocity?this.config.yVelocity:S*D,s[n+2]=this.config.overrideZVelocity?this.config.zVelocity:R*D,s[n+3]=0}setParticleColor(t,e){if(this.config.randomColorEnabled&&this.config.randomColors.length>0){const i=this.config.randomColors,s=i[Math.floor(Math.random()*i.length)];t[e+3]=s[0],t[e+4]=s[1],t[e+5]=s[2]}else this.config.colorTransitionEnabled?(t[e+3]=this.config.startColor[0],t[e+4]=this.config.startColor[1],t[e+5]=this.config.startColor[2]):(t[e+3]=this.config.particleColor[0],t[e+4]=this.config.particleColor[1],t[e+5]=this.config.particleColor[2])}setParticleLifetime(t,e){const i=this.config.lifetime||5;t[e+6]=0,t[e+7]=i+(Math.random()*.4-.2)*i}}class wi{constructor(t,e=1e4){this.device=t,this.physicsSettings={deltaTime:.016,gravity:0,turbulence:0,attractorStrength:0,attractorPosition:[0,0,0],damping:0,confinementEnabled:!1,confinementShape:"box",confinementMode:"bounce",confinementSpace:"world",confinementBoxHalfSize:[2,2,2],confinementSphereRadius:3,confinementRestitution:.8,confinementFriction:.1,confinementCenter:[0,0,0],softBoundaryEnabled:!1,softBoundaryStrength:5,softBoundaryFalloff:.5},this.fixedDeltaTime=1/60,this.physicsClock=0,this.physicsAccumulator=0,this.minUpdatesPerSecond=30,this.lastUpdateTime=0,this.computeReady=!1,this.computePipeline=null,this.computeBindGroupLayout=null,this._physicsData=new Float32Array(32),this._physicsDataU32View=new Uint32Array(this._physicsData.buffer),this.physicsUniformBuffer=t.createBuffer({size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,label:"physicsUniformBuffer"}),this._maxParticles=e,this._particleDataStagingBuffer=t.createBuffer({size:e*8*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"ParticleDataReadbackBuffer_Pooled"}),this._velocityStagingBuffer=t.createBuffer({size:e*4*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"VelocityReadbackBuffer_Pooled"}),this._stagingInUse=!1,this._renderStagingParticleBuffer=t.createBuffer({size:e*8*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"RenderReadback_ParticleData"}),this._renderStagingVelocityBuffer=t.createBuffer({size:e*4*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"RenderReadback_Velocity"}),this._renderStagingInUse=!1,this._scriptStagingParticleBuffer=t.createBuffer({size:e*8*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"ScriptReadback_ParticleData"}),this._scriptStagingVelocityBuffer=t.createBuffer({size:e*4*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ,label:"ScriptReadback_Velocity"}),this._scriptStagingInUse=!1}async initComputePipeline(t,e,i){try{return await this.createComputePipeline(t,e,i),this.computeReady=!0,!0}catch(s){return console.error("Error initializing compute pipeline:",s),!1}}async createComputePipeline(t,e,i){const{particlePhysicsShader:s}=await Promise.resolve().then(()=>Ii);this.computeBindGroupLayout=this.device.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),this.computePipeline=this.device.createComputePipeline({layout:this.device.createPipelineLayout({bindGroupLayouts:[this.computeBindGroupLayout]}),compute:{module:this.device.createShaderModule({code:s}),entryPoint:"main"}}),this.computeBindGroup=this.device.createBindGroup({layout:this.computeBindGroupLayout,entries:[{binding:0,resource:{buffer:this.physicsUniformBuffer}},{binding:1,resource:{buffer:t}},{binding:2,resource:{buffer:e}},{binding:3,resource:{buffer:i}}]})}updatePhysics(t,e,i,s,n,o){if(e<=0||!this.computeReady)return;const a=this._physicsData,c=this.physicsSettings;a[0]=t,a[1]=i.particleSpeed,a[2]=c.gravity,a[3]=c.turbulence,a[4]=c.attractorStrength,a[5]=c.damping,a[6]=c.attractorPosition[0],a[7]=c.attractorPosition[1],a[8]=c.attractorPosition[2],this._physicsDataU32View[9]=e,a[10]=c.confinementEnabled?1:0,a[11]=c.confinementShape==="sphere"?1:0,a[12]=c.confinementMode==="kill"?1:0,a[13]=c.confinementSpace==="local"?1:0,a[14]=c.confinementBoxHalfSize[0],a[15]=c.confinementBoxHalfSize[1],a[16]=c.confinementBoxHalfSize[2],a[17]=c.confinementSphereRadius,a[18]=c.confinementRestitution,a[19]=c.confinementFriction,a[20]=c.confinementCenter[0],a[21]=c.confinementCenter[1],a[22]=c.confinementCenter[2],a[23]=c.softBoundaryEnabled?1:0,a[24]=c.softBoundaryStrength,a[25]=c.softBoundaryFalloff,a[26]=i.velocityStretchEnabled?1:0,a[27]=i.velocityStretchFactor??1,a[28]=0,a[29]=0,a[30]=0,a[31]=0,this.device.queue.writeBuffer(this.physicsUniformBuffer,0,a);const l=o||this.device.createCommandEncoder({label:"ParticlePhysicsEncoder"}),u=l.beginComputePass({label:"ParticlePhysicsPass"});u.setPipeline(this.computePipeline),u.setBindGroup(0,this.computeBindGroup);const f=Math.max(1,Math.ceil(e/64));u.dispatchWorkgroups(f,1,1),u.end(),o||this.device.queue.submit([l.finish()]),this.lastUpdateTime=performance.now()/1e3}async readbackAndProcessParticles(t,e,i,s,n){if(t<=0)return{activeCount:0,shouldUpdate:!1};if(this._stagingInUse)return{activeCount:t,shouldUpdate:!1};try{this._stagingInUse=!0;const o=this.device.createCommandEncoder({label:"ParticleReadbackEncoder"}),a=t*8*4;o.copyBufferToBuffer(s,0,this._particleDataStagingBuffer,0,a);const c=t*4*4;return o.copyBufferToBuffer(n,0,this._velocityStagingBuffer,0,c),this.device.queue.submit([o.finish()]),await Promise.all([(async()=>{await this._particleDataStagingBuffer.mapAsync(GPUMapMode.READ,0,a);const l=new Float32Array(this._particleDataStagingBuffer.getMappedRange(0,a));e.set(l),this._particleDataStagingBuffer.unmap()})(),(async()=>{await this._velocityStagingBuffer.mapAsync(GPUMapMode.READ,0,c);const l=new Float32Array(this._velocityStagingBuffer.getMappedRange(0,c));i.set(l),this._velocityStagingBuffer.unmap()})()]),this._stagingInUse=!1,{particleData:e,particleVelocities:i,shouldUpdate:!0}}catch(o){return this._stagingInUse=!1,o&&o.name==="AbortError"||console.error("Error reading back particle data:",o),{activeCount:t,shouldUpdate:!1}}}setDamping(t){this.physicsSettings.damping=t}setGravity(t){this.physicsSettings.gravity=t}setAttractor(t,e){this.physicsSettings.attractorStrength=t,this.physicsSettings.attractorPosition=e}setConfinement(t){const e=this.physicsSettings;t.enabled!==void 0&&(e.confinementEnabled=t.enabled),t.shape!==void 0&&(e.confinementShape=t.shape),t.mode!==void 0&&(e.confinementMode=t.mode),t.space!==void 0&&(e.confinementSpace=t.space),t.boxSize!==void 0&&(e.confinementBoxHalfSize=t.boxSize),t.sphereRadius!==void 0&&(e.confinementSphereRadius=t.sphereRadius),t.restitution!==void 0&&(e.confinementRestitution=t.restitution),t.friction!==void 0&&(e.confinementFriction=t.friction),t.center!==void 0&&(e.confinementCenter=t.center)}async readbackForRendering(t,e,i,s,n){if(t<=0)return{shouldUpdate:!1};if(this._renderStagingInUse)return{shouldUpdate:!1};try{this._renderStagingInUse=!0;const o=t*8*4,a=t*4*4,c=this.device.createCommandEncoder({label:"RenderReadbackEncoder"});return c.copyBufferToBuffer(s,0,this._renderStagingParticleBuffer,0,o),c.copyBufferToBuffer(n,0,this._renderStagingVelocityBuffer,0,a),this.device.queue.submit([c.finish()]),await Promise.all([(async()=>{await this._renderStagingParticleBuffer.mapAsync(GPUMapMode.READ,0,o);const l=new Float32Array(this._renderStagingParticleBuffer.getMappedRange(0,o));e.set(l),this._renderStagingParticleBuffer.unmap()})(),(async()=>{await this._renderStagingVelocityBuffer.mapAsync(GPUMapMode.READ,0,a);const l=new Float32Array(this._renderStagingVelocityBuffer.getMappedRange(0,a));i.set(l),this._renderStagingVelocityBuffer.unmap()})()]),this._renderStagingInUse=!1,{particleData:e,particleVelocities:i,shouldUpdate:!0}}catch(o){return this._renderStagingInUse=!1,console.error("Error in rendering readback:",o),{shouldUpdate:!1}}}async readbackForScript(t,e,i,s,n){if(t<=0)return{shouldUpdate:!1};if(this._scriptStagingInUse)return{shouldUpdate:!1};try{this._scriptStagingInUse=!0;const o=t*8*4,a=t*4*4,c=this.device.createCommandEncoder({label:"ScriptReadbackEncoder"});return c.copyBufferToBuffer(s,0,this._scriptStagingParticleBuffer,0,o),c.copyBufferToBuffer(n,0,this._scriptStagingVelocityBuffer,0,a),this.device.queue.submit([c.finish()]),await Promise.all([(async()=>{await this._scriptStagingParticleBuffer.mapAsync(GPUMapMode.READ,0,o);const l=new Float32Array(this._scriptStagingParticleBuffer.getMappedRange(0,o));e.set(l),this._scriptStagingParticleBuffer.unmap()})(),(async()=>{await this._scriptStagingVelocityBuffer.mapAsync(GPUMapMode.READ,0,a);const l=new Float32Array(this._scriptStagingVelocityBuffer.getMappedRange(0,a));i.set(l),this._scriptStagingVelocityBuffer.unmap()})()]),this._scriptStagingInUse=!1,{shouldUpdate:!0}}catch(o){return this._scriptStagingInUse=!1,console.error("Error in script readback:",o),{shouldUpdate:!1}}}destroy(){this.physicsUniformBuffer.destroy(),this._particleDataStagingBuffer.destroy(),this._velocityStagingBuffer.destroy(),this._renderStagingParticleBuffer.destroy(),this._renderStagingVelocityBuffer.destroy(),this._scriptStagingParticleBuffer.destroy(),this._scriptStagingVelocityBuffer.destroy()}setSoftBoundary(t){const e=this.physicsSettings;t.enabled!==void 0&&(e.softBoundaryEnabled=t.enabled),t.strength!==void 0&&(e.softBoundaryStrength=t.strength),t.falloff!==void 0&&(e.softBoundaryFalloff=t.falloff)}}class Bi{constructor(t){this.device=t,this.defaultTexture=null,this.createDefaultTexture()}createDefaultTexture(){const t=new Uint8Array([255,255,255,255]);this.defaultTexture=this.device.createTexture({size:[1,1],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST,label:"defaultParticleTexture"}),this.device.queue.writeTexture({texture:this.defaultTexture},t,{bytesPerRow:4},[1,1])}async loadTexture(t){const e=this.device.createTexture({size:[t.width,t.height],format:"rgba8unorm",usage:GPUTextureUsage.TEXTURE_BINDING|GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT,label:"particleTexture"});return this.device.queue.copyExternalImageToTexture({source:t},{texture:e},[t.width,t.height]),e}getDefaultTexture(){return this.defaultTexture}destroyTexture(t){t&&t.label!=="defaultParticleTexture"&&t.destroy()}}const Ri=Object.freeze({sin:Math.sin,cos:Math.cos,abs:Math.abs,floor:Math.floor,ceil:Math.ceil,round:Math.round,min:Math.min,max:Math.max,sqrt:Math.sqrt,pow:Math.pow,random:Math.random,PI:Math.PI,TAU:Math.PI*2,clamp(r,t,e){return r<t?t:r>e?e:r},lerp(r,t,e){return r+(t-r)*e},smoothstep(r,t,e){const i=Ri.clamp((e-r)/(t-r),0,1);return i*i*(3-2*i)}}),Ze=new Set(["particleSize","particleSpeed","particleColor","startColor","endColor","opacity","emissionRate","gravityStrength","dampingStrength","attractorStrength","attractorPosition","pulseAmplitude","pulseFrequency","bloomIntensity"]);class Ms{constructor(t){this._collection=t,this._pd=null,this._vd=null,this._pi=0,this._vi=0}_bind(t,e,i){return this._pd=t,this._vd=e,this._pi=i*8,this._vi=i*4,this}get x(){return this._pd[this._pi]}set x(t){this._pd[this._pi]=t,this._collection._dirty=!0}get y(){return this._pd[this._pi+1]}set y(t){this._pd[this._pi+1]=t,this._collection._dirty=!0}get z(){return this._pd[this._pi+2]}set z(t){this._pd[this._pi+2]=t,this._collection._dirty=!0}get r(){return this._pd[this._pi+3]}set r(t){this._pd[this._pi+3]=t,this._collection._dirty=!0}get g(){return this._pd[this._pi+4]}set g(t){this._pd[this._pi+4]=t,this._collection._dirty=!0}get b(){return this._pd[this._pi+5]}set b(t){this._pd[this._pi+5]=t,this._collection._dirty=!0}get age(){return this._pd[this._pi+6]}set age(t){this._pd[this._pi+6]=t,this._collection._dirty=!0}get lifetime(){return this._pd[this._pi+7]}set lifetime(t){this._pd[this._pi+7]=t,this._collection._dirty=!0}get vx(){return this._vd[this._vi]}set vx(t){this._vd[this._vi]=t,this._collection._dirty=!0}get vy(){return this._vd[this._vi+1]}set vy(t){this._vd[this._vi+1]=t,this._collection._dirty=!0}get vz(){return this._vd[this._vi+2]}set vz(t){this._vd[this._vi+2]=t,this._collection._dirty=!0}}class Ts{constructor(){this._proxy=new Ms(this),this._pd=null,this._vd=null,this.count=0,this._dirty=!1}_bind(t,e,i){this._pd=t,this._vd=e,this.count=i,this._dirty=!1}get(t){return t<0||t>=this.count?null:this._proxy._bind(this._pd,this._vd,t)}}const Es=1e6;function Cs(r){let t=0;return r.replace(/\b(for|while)\s*\([^)]*\)\s*\{/g,e=>{const i=`__lc${t++}`;return`${e} if(++${i}>${Es})throw new Error("Loop limit exceeded");`}).replace(/\b(for|while)\s*\([^)]*\)\s*\{/g,e=>e).replace(/^/,()=>{let e="";for(let i=0;i<t;i++)e+=`let __lc${i}=0;`;return e})}const vt=new Map;for(const r of Ze)vt.set(r.toLowerCase(),r);function As(r){const t={value:!1},e=new Set;return new Proxy(r,{get(s,n){if(n==="__dirty")return t.value;if(n==="__resetDirty")return()=>{t.value=!1};if(typeof n!="string")return;if(Ze.has(n))return s[n];const o=vt.get(n.toLowerCase());if(o)return e.has(n)||(e.add(n),console.warn(`[ParticleScript] config.${n} → did you mean config.${o}?`)),s[o]},set(s,n,o){if(typeof n!="string")return!0;let a=n;if(!Ze.has(a)){const c=vt.get(a.toLowerCase());if(c)e.has(n)||(e.add(n),console.warn(`[ParticleScript] config.${n} → did you mean config.${c}?`)),a=c;else return!0}return s[a]=o,t.value=!0,!0}})}class Pt{constructor(t,e,i){this._particles=new Ts,this._configProxy=As(e),this._configSnapshot=null,this._fn=null,this._error=!1,this.compile(t)}compile(t){if(this._fn=null,this._error=!1,!(!t||typeof t!="string"))try{const i=`
2
2
  return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles, __config, __math) {
3
3
  var window = void 0, document = void 0, globalThis = void 0;
4
4
  var Function = void 0, eval = void 0, fetch = void 0;
@@ -6,8 +6,8 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
6
6
  var deltaTime = __deltaTime, time = __time;
7
7
  var currentFrame = __currentFrame, totalFrames = __totalFrames;
8
8
  var particles = __particles, config = __config, math = __math;
9
- ${ce(t)}
10
- };`,s=new Function(i);this._fn=s()}catch(e){console.warn("[ParticleScript] Compilation error:",e.message),this._fn=null,this._error=!0}}execute(t,e,i,s,a,n,o){if(!this._fn||this._error)return{configDirty:!1,particlesDirty:!1};this._particles._bind(a,n,o),this._configProxy.__resetDirty();try{this._fn(t,e,i,s,this._particles,this._configProxy,J)}catch(r){console.warn("[ParticleScript] Runtime error:",r.message)}return{configDirty:this._configProxy.__dirty,particlesDirty:this._particles._dirty}}snapshotConfig(t){const e={};for(const i of C){const s=t[i];s!==void 0&&(e[i]=Array.isArray(s)?[...s]:s)}this._configSnapshot=e}restoreConfig(t){if(this._configSnapshot){for(const e of C)if(e in this._configSnapshot){const i=this._configSnapshot[e];t[e]=Array.isArray(i)?[...i]:i}}}destroy(){this._fn=null,this._particles=null,this._configProxy=null,this._configSnapshot=null}}async function F(c){const t=new DataView(c);if(t.getUint32(0,!0)!==1179937895)throw new Error("Invalid GLB file: incorrect magic number");const i=t.getUint32(4,!0);if(i!==2)throw new Error(`Unsupported GLB version: ${i} (only version 2 is supported)`);const s=t.getUint32(8,!0);let a=12,n=null,o=null;for(;a<s;){const g=t.getUint32(a,!0),x=t.getUint32(a+4,!0),P=c.slice(a+8,a+8+g);if(x===1313821514){const w=new TextDecoder("utf-8").decode(P);n=JSON.parse(w)}else x===5130562&&(o=P);a+=8+g}if(!n)throw new Error("GLB file missing JSON chunk");if(!n.meshes||n.meshes.length===0)throw new Error("GLB file contains no meshes");const l=n.meshes[0].primitives[0];if(!l)throw new Error("First mesh has no primitives");const d=l.attributes.POSITION;if(d===void 0)throw new Error("Mesh primitive missing POSITION attribute");const u=A(n,o,d,3,5126);let f;if(l.attributes.NORMAL!==void 0)f=A(n,o,l.attributes.NORMAL,3,5126);else{const g=l.indices;if(g===void 0)throw new Error("Cannot generate normals without indices");const x=O(n,o,g);f=ue(u,x)}const h=l.indices;if(h===void 0)throw new Error("Mesh primitive missing indices");const p=O(n,o,h),m=u.length/3,b=p.length;let S=null;l.attributes.TEXCOORD_0!==void 0&&(S=A(n,o,l.attributes.TEXCOORD_0,2,5126));let y=!1;if(n.materials&&n.materials.length>0){const g=n.materials[0];g.pbrMetallicRoughness&&g.pbrMetallicRoughness.baseColorTexture!==void 0&&(y=!0)}let _=null;if(n.skins&&n.skins.length>0)try{_=ge(n,o,l),console.log("Animation data extracted:",_)}catch(g){console.warn("Failed to extract animation data:",g)}return{positions:u,normals:f,indices:p,texCoords:S,vertexCount:m,indexCount:b,animationData:_,hasBaseColorTexture:y}}function A(c,t,e,i,s){const a=c.accessors[e],o={SCALAR:1,VEC2:2,VEC3:3,VEC4:4}[a.type];if(o!==i)throw new Error(`Attribute accessor type mismatch: expected ${i} components, got ${o}`);if(a.componentType!==s)throw new Error(`Attribute component type mismatch: expected ${s}, got ${a.componentType}`);const l=(c.bufferViews[a.bufferView].byteOffset||0)+(a.byteOffset||0),d=a.count,u=new DataView(t,l,d*i*4),f=new Float32Array(d*i);for(let h=0;h<d*i;h++)f[h]=u.getFloat32(h*4,!0);return f}function O(c,t,e){const i=c.accessors[e];if(i.type!=="SCALAR")throw new Error(`Indices accessor must be SCALAR, got ${i.type}`);const a=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5123){const o=new DataView(t,a,n*2),r=new Uint16Array(n);for(let l=0;l<n;l++)r[l]=o.getUint16(l*2,!0);return r}else if(i.componentType===5125){const o=new DataView(t,a,n*4),r=new Uint32Array(n);for(let l=0;l<n;l++)r[l]=o.getUint32(l*4,!0);return r}else throw new Error(`Unsupported index component type: ${i.componentType}`)}function ue(c,t){const e=new Float32Array(c.length);for(let i=0;i<t.length;i+=3){const s=t[i]*3,a=t[i+1]*3,n=t[i+2]*3,o=[c[s],c[s+1],c[s+2]],r=[c[a],c[a+1],c[a+2]],l=[c[n],c[n+1],c[n+2]],d=[r[0]-o[0],r[1]-o[1],r[2]-o[2]],u=[l[0]-o[0],l[1]-o[1],l[2]-o[2]],f=[d[1]*u[2]-d[2]*u[1],d[2]*u[0]-d[0]*u[2],d[0]*u[1]-d[1]*u[0]],h=Math.sqrt(f[0]*f[0]+f[1]*f[1]+f[2]*f[2]);h>0&&(f[0]/=h,f[1]/=h,f[2]/=h),e[s]=e[a]=e[n]=f[0],e[s+1]=e[a+1]=e[n+1]=f[1],e[s+2]=e[a+2]=e[n+2]=f[2]}return e}function fe(c,t,e){const i=c.accessors[e];if(i.type!=="VEC4")throw new Error(`JOINTS_0 must be VEC4, got ${i.type}`);const a=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5121){const o=new DataView(t,a,n*4),r=new Uint8Array(n*4);for(let l=0;l<n*4;l++)r[l]=o.getUint8(l);return r}else if(i.componentType===5123){const o=new DataView(t,a,n*8),r=new Uint8Array(n*4);for(let l=0;l<n*4;l++)r[l]=o.getUint16(l*2,!0);return r}else throw new Error(`Unsupported JOINTS_0 component type: ${i.componentType}`)}function he(c,t,e){const i=c.accessors[e];if(i.type!=="VEC4")throw new Error(`WEIGHTS_0 must be VEC4, got ${i.type}`);const a=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5126){const o=new DataView(t,a,n*16),r=new Float32Array(n*4);for(let l=0;l<n*4;l++)r[l]=o.getFloat32(l*4,!0);return r}else if(i.componentType===5121){const o=new DataView(t,a,n*4),r=new Float32Array(n*4);for(let l=0;l<n*4;l++)r[l]=o.getUint8(l)/255;return r}else throw new Error(`Unsupported WEIGHTS_0 component type: ${i.componentType}`)}function pe(c,t,e){const i=c.accessors[e];if(i.type!=="MAT4")throw new Error(`Expected MAT4, got ${i.type}`);if(i.componentType!==5126)throw new Error(`Expected FLOAT component type for MAT4, got ${i.componentType}`);const a=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count,o=new DataView(t,a,n*64),r=new Float32Array(n*16);for(let l=0;l<n*16;l++)r[l]=o.getFloat32(l*4,!0);return r}function me(c,t,e){const i=c.accessors[e];if(i.type!=="SCALAR")throw new Error(`Expected SCALAR, got ${i.type}`);if(i.componentType!==5126)throw new Error(`Expected FLOAT component type for SCALAR, got ${i.componentType}`);const a=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count,o=new DataView(t,a,n*4),r=new Float32Array(n);for(let l=0;l<n;l++)r[l]=o.getFloat32(l*4,!0);return r}function ye(c,t,e){const i=c.accessors[e],a={VEC3:3,VEC4:4}[i.type];if(!a)throw new Error(`Expected VEC3 or VEC4, got ${i.type}`);if(i.componentType!==5126)throw new Error(`Expected FLOAT component type, got ${i.componentType}`);const o=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),r=i.count,l=new DataView(t,o,r*a*4),d=new Float32Array(r*a);for(let u=0;u<r*a;u++)d[u]=l.getFloat32(u*4,!0);return d}function ge(c,t,e){const i=c.skins[0],s=i.joints,a=pe(c,t,i.inverseBindMatrices),n=e.attributes.JOINTS_0!==void 0?fe(c,t,e.attributes.JOINTS_0):null,o=e.attributes.WEIGHTS_0!==void 0?he(c,t,e.attributes.WEIGHTS_0):null;if(!n||!o)throw new Error("Mesh missing JOINTS_0 or WEIGHTS_0 attributes");const r=c.nodes.map(d=>({translation:d.translation||[0,0,0],rotation:d.rotation||[0,0,0,1],scale:d.scale||[1,1,1],children:d.children||[],name:d.name||""})),l=[];if(c.animations&&c.animations.length>0)for(const d of c.animations){const u=[];let f=0;for(const h of d.channels){const p=d.samplers[h.sampler],m=me(c,t,p.input),b=ye(c,t,p.output),S=m[m.length-1];S>f&&(f=S),u.push({targetNode:h.target.node,targetPath:h.target.path,interpolation:p.interpolation||"LINEAR",timestamps:m,values:b})}l.push({name:d.name||`Animation ${l.length}`,duration:f,channels:u})}return{joints:s,inverseBindMatrices:a,jointIndices:n,jointWeights:o,nodes:r,animations:l}}async function K(c){const t=new DataView(c);if(t.getUint32(0,!0)!==1179937895)throw new Error("Invalid GLB file: incorrect magic number");const i=t.getUint32(4,!0);if(i!==2)throw new Error(`Unsupported GLB version: ${i}`);const s=t.getUint32(8,!0);let a=12,n=null,o=null;for(;a<s;){const _=t.getUint32(a,!0),g=t.getUint32(a+4,!0),x=c.slice(a+8,a+8+_);if(g===1313821514){const M=new TextDecoder("utf-8").decode(x);n=JSON.parse(M)}else g===5130562&&(o=x);a+=8+_}if(!n)throw new Error("GLB file missing JSON chunk");if(!n.materials||n.materials.length===0)return null;const r=n.materials[0];if(!r.pbrMetallicRoughness||r.pbrMetallicRoughness.baseColorTexture===void 0)return null;const l=r.pbrMetallicRoughness.baseColorTexture.index;if(!n.textures||!n.textures[l])return null;const u=n.textures[l].source;if(u===void 0||!n.images||!n.images[u])return null;const f=n.images[u],h=f.mimeType||"image/png";if(f.bufferView===void 0)return null;if(!o)throw new Error("GLB file missing BIN chunk (required for embedded textures)");const p=n.bufferViews[f.bufferView],m=p.byteOffset||0,b=p.byteLength,S=o.slice(m,m+b);return{imageBlob:new Blob([S],{type:h}),mimeType:h}}const j=Object.freeze(Object.defineProperty({__proto__:null,extractGLBTexture:K,parseGLB:F},Symbol.toStringTag,{value:"Module"}));function k(c,t,e){return[c[0]+(t[0]-c[0])*e,c[1]+(t[1]-c[1])*e,c[2]+(t[2]-c[2])*e]}function N(c,t,e){let i=c[0]*t[0]+c[1]*t[1]+c[2]*t[2]+c[3]*t[3],s=t;if(i<0&&(i=-i,s=[-t[0],-t[1],-t[2],-t[3]]),i>.9995){const l=[c[0]+(s[0]-c[0])*e,c[1]+(s[1]-c[1])*e,c[2]+(s[2]-c[2])*e,c[3]+(s[3]-c[3])*e];return be(l)}const a=Math.acos(i),n=Math.sin(a),o=Math.sin((1-e)*a)/n,r=Math.sin(e*a)/n;return[c[0]*o+s[0]*r,c[1]*o+s[1]*r,c[2]*o+s[2]*r,c[3]*o+s[3]*r]}function be(c){const t=Math.sqrt(c[0]*c[0]+c[1]*c[1]+c[2]*c[2]+c[3]*c[3]);return t>1e-4?[c[0]/t,c[1]/t,c[2]/t,c[3]/t]:[0,0,0,1]}function Se(c){const t=c[0],e=c[1],i=c[2],s=c[3],a=t+t,n=e+e,o=i+i,r=t*a,l=t*n,d=t*o,u=e*n,f=e*o,h=i*o,p=s*a,m=s*n,b=s*o;return new Float32Array([1-(u+h),l+b,d-m,0,l-b,1-(r+h),f+p,0,d+m,f-p,1-(r+u),0,0,0,0,1])}function xe(c,t,e){const i=Se(t);return new Float32Array([i[0]*e[0],i[1]*e[0],i[2]*e[0],0,i[4]*e[1],i[5]*e[1],i[6]*e[1],0,i[8]*e[2],i[9]*e[2],i[10]*e[2],0,c[0],c[1],c[2],1])}function X(c,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let s=0;s<4;s++)e[i*4+s]=c[0+s]*t[i*4+0]+c[4+s]*t[i*4+1]+c[8+s]*t[i*4+2]+c[12+s]*t[i*4+3];return e}class Q{constructor(t){this.joints=t.joints,this.inverseBindMatrices=t.inverseBindMatrices,this.jointWeights=t.jointWeights,this.jointIndices=t.jointIndices,this.nodes=t.nodes,this.animations=t.animations,this.restPositions=null,this.restNormals=null,this.currentAnimIndex=0,this.currentTime=0,this.playing=!0,this.speed=1,this.loop=!0,this.jointLocalTransforms=new Array(this.nodes.length),this.jointGlobalTransforms=new Array(this.nodes.length),this.jointFinalMatrices=new Array(this.joints.length);for(let e=0;e<this.nodes.length;e++)this.jointLocalTransforms[e]=new Float32Array(16),this.jointGlobalTransforms[e]=new Float32Array(16);for(let e=0;e<this.joints.length;e++)this.jointFinalMatrices[e]=new Float32Array(16);this.skinnedPositions=null,this.skinnedNormals=null,this._gpuSkinningReady=!1,this._buildTopologicalOrder(),console.log(`GLBAnimator initialized: ${this.joints.length} joints, ${this.animations.length} animations`)}setRestPose(t,e){this.restPositions=new Float32Array(t),this.restNormals=new Float32Array(e),this.skinnedPositions=new Float32Array(t.length),this.skinnedNormals=new Float32Array(e.length)}async initGPUSkinning(t,e,i){try{this._gpuDevice=t,this._gpuOutputBuffer=e;const s=this.restPositions.length/3,a=new Float32Array(s*8);for(let l=0;l<s;l++){const d=l*8,u=l*3,f=l*2;a[d]=this.restPositions[u],a[d+1]=this.restPositions[u+1],a[d+2]=this.restPositions[u+2],a[d+3]=this.restNormals[u],a[d+4]=this.restNormals[u+1],a[d+5]=this.restNormals[u+2],a[d+6]=i?i[f]:0,a[d+7]=i?i[f+1]:0}this._gpuRestDataBuffer=t.createBuffer({size:a.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_restData"}),t.queue.writeBuffer(this._gpuRestDataBuffer,0,a),this._gpuJointWeightsBuffer=t.createBuffer({size:this.jointWeights.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_jointWeights"}),t.queue.writeBuffer(this._gpuJointWeightsBuffer,0,this.jointWeights);const n=new Uint32Array(this.jointIndices.length);for(let l=0;l<this.jointIndices.length;l++)n[l]=this.jointIndices[l];this._gpuJointIndicesBuffer=t.createBuffer({size:n.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_jointIndices"}),t.queue.writeBuffer(this._gpuJointIndicesBuffer,0,n),this._gpuJointMatricesBuffer=t.createBuffer({size:this.joints.length*16*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_jointMatrices"}),this._gpuJointMatricesData=new Float32Array(this.joints.length*16);const{skinningComputeShader:o}=await Promise.resolve().then(()=>te),r=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:4,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]});this._gpuSkinningPipeline=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[r]}),compute:{module:t.createShaderModule({code:o}),entryPoint:"main"}}),this._gpuSkinningBindGroup=t.createBindGroup({layout:r,entries:[{binding:0,resource:{buffer:this._gpuRestDataBuffer}},{binding:1,resource:{buffer:this._gpuJointWeightsBuffer}},{binding:2,resource:{buffer:this._gpuJointIndicesBuffer}},{binding:3,resource:{buffer:this._gpuJointMatricesBuffer}},{binding:4,resource:{buffer:this._gpuOutputBuffer}}]}),this._gpuVertexCount=s,this._gpuSkinningReady=!0,console.log(`GPU skinning initialized: ${s} vertices, ${this.joints.length} joints`)}catch(s){console.warn("GPU skinning init failed, using CPU fallback:",s),this._gpuSkinningReady=!1}}_applySkinningGPU(){for(let i=0;i<this.joints.length;i++)this._gpuJointMatricesData.set(this.jointFinalMatrices[i],i*16);this._gpuDevice.queue.writeBuffer(this._gpuJointMatricesBuffer,0,this._gpuJointMatricesData);const t=this._gpuDevice.createCommandEncoder({label:"SkinningComputeEncoder"}),e=t.beginComputePass({label:"SkinningComputePass"});e.setPipeline(this._gpuSkinningPipeline),e.setBindGroup(0,this._gpuSkinningBindGroup),e.dispatchWorkgroups(Math.ceil(this._gpuVertexCount/64),1,1),e.end(),this._gpuDevice.queue.submit([t.finish()])}update(t){if(!this.playing||this.animations.length===0)return{positions:this.skinnedPositions,normals:this.skinnedNormals,changed:!1};this.currentTime+=t*this.speed;const e=this.animations[this.currentAnimIndex];return this.loop?this.currentTime=this.currentTime%e.duration:this.currentTime>e.duration&&(this.currentTime=e.duration,this.playing=!1),this._computeLocalTransforms(this.currentTime),this._computeGlobalTransforms(),this._computeFinalMatrices(),this._gpuSkinningReady?(this._applySkinningGPU(),{gpuSkinned:!0,changed:!0}):(this._applySkinning(),{positions:this.skinnedPositions,normals:this.skinnedNormals,changed:!0})}getCurrentAnimation(){return this.animations[this.currentAnimIndex]}setAnimation(t){t>=0&&t<this.animations.length&&(this.currentAnimIndex=t,this.currentTime=0)}getAnimationNames(){return this.animations.map(t=>t.name)}_buildTopologicalOrder(){const t=new Set,e=[],i=a=>{if(t.has(a))return;t.add(a);const n=this.nodes[a];for(const o of n.children)i(o);e.push(a)},s=new Set;for(const a of this.nodes)for(const n of a.children)s.add(n);for(let a=0;a<this.nodes.length;a++)s.has(a)||i(a);this.topologicalOrder=e.reverse()}_sampleChannel(t,e){const{timestamps:i,values:s,interpolation:a,targetPath:n}=t;if(e<=i[0])return this._extractValue(s,0,n);if(e>=i[i.length-1])return this._extractValue(s,i.length-1,n);let o=0,r=i.length-1;for(;r-o>1;){const p=Math.floor((o+r)/2);i[p]<=e?o=p:r=p}const l=i[o],d=i[r],u=(e-l)/(d-l),f=this._extractValue(s,o,n),h=this._extractValue(s,r,n);return a==="STEP"?f:n==="rotation"?N(f,h,u):k(f,h,u)}_extractValue(t,e,i){if(i==="rotation"){const s=e*4;return[t[s],t[s+1],t[s+2],t[s+3]]}else{const s=e*3;return[t[s],t[s+1],t[s+2]]}}_computeLocalTransforms(t){const e=this.animations[this.currentAnimIndex];for(let i=0;i<this.nodes.length;i++){const s=this.nodes[i];let a=s.translation,n=s.rotation,o=s.scale;for(const r of e.channels)if(r.targetNode===i){const l=this._sampleChannel(r,t);r.targetPath==="translation"?a=l:r.targetPath==="rotation"?n=l:r.targetPath==="scale"&&(o=l)}this.jointLocalTransforms[i]=xe(a,n,o)}}_computeGlobalTransforms(){const t=new Array(this.nodes.length).fill(-1);for(let e=0;e<this.nodes.length;e++){const i=this.nodes[e];for(const s of i.children)t[s]=e}for(const e of this.topologicalOrder){const i=t[e];i===-1?this.jointGlobalTransforms[e]=this.jointLocalTransforms[e]:this.jointGlobalTransforms[e]=X(this.jointGlobalTransforms[i],this.jointLocalTransforms[e])}}_computeFinalMatrices(){for(let t=0;t<this.joints.length;t++){const e=this.joints[t],i=this.jointGlobalTransforms[e],s=t*16,a=this.inverseBindMatrices.slice(s,s+16);this.jointFinalMatrices[t]=X(i,a)}}_applySkinning(){const t=this.restPositions.length/3,e=this.restPositions,i=this.restNormals,s=this.skinnedPositions,a=this.skinnedNormals,n=this.jointWeights,o=this.jointIndices,r=this.jointFinalMatrices;for(let l=0;l<t;l++){const d=l*3,u=l*4,f=e[d],h=e[d+1],p=e[d+2],m=i[d],b=i[d+1],S=i[d+2];let y=0,_=0,g=0,x=0,P=0,M=0;for(let B=0;B<4;B++){const R=n[u+B];if(R===0)continue;const v=r[o[u+B]];y+=(v[0]*f+v[4]*h+v[8]*p+v[12])*R,_+=(v[1]*f+v[5]*h+v[9]*p+v[13])*R,g+=(v[2]*f+v[6]*h+v[10]*p+v[14])*R,x+=(v[0]*m+v[4]*b+v[8]*S)*R,P+=(v[1]*m+v[5]*b+v[9]*S)*R,M+=(v[2]*m+v[6]*b+v[10]*S)*R}const w=Math.sqrt(x*x+P*P+M*M);w>1e-4&&(a[d]=x/w,a[d+1]=P/w,a[d+2]=M/w),s[d]=y,s[d+1]=_,s[d+2]=g}}}function Y(c){const t=atob(c),e=new Uint8Array(t.length);for(let i=0;i<t.length;i++)e[i]=t.charCodeAt(i);return e.buffer}class E{constructor(t,e){this.device=t,this.config=e,this.MAX_PARTICLES=e.maxParticles||1e4,this.particleCount=e.particleCount||100,this.activeParticles=0,this.emitting=!1,this.currentEmissionTime=0,this.particleData=new Float32Array(this.MAX_PARTICLES*8),this.particleVelocities=new Float32Array(this.MAX_PARTICLES*4),this.instanceBuffer=t.createBuffer({size:this.MAX_PARTICLES*8*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST|GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC,label:"particleInstanceBuffer"}),this.velocityBuffer=t.createBuffer({size:this.MAX_PARTICLES*4*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,label:"particleVelocityBuffer"}),this.trailBuffer=t.createBuffer({size:this.MAX_PARTICLES*4*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,label:"particleTrailBuffer"}),this._trailResetData=new Float32Array(this.MAX_PARTICLES*4),this.appearanceUniformBuffer=t.createBuffer({size:176,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,label:"appearanceUniformBuffer"}),this.bloomIntensityBuffer=t.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,label:"systemBloomIntensityBuffer"}),e.overrideXVelocity===void 0&&(e.overrideXVelocity=!1),e.overrideYVelocity===void 0&&(e.overrideYVelocity=!1),e.overrideZVelocity===void 0&&(e.overrideZVelocity=!1),e.xVelocity===void 0&&(e.xVelocity=0),e.yVelocity===void 0&&(e.yVelocity=0),e.zVelocity===void 0&&(e.zVelocity=0),e.textureEnabled===void 0&&(e.textureEnabled=!1),e.glbModelEnabled===void 0&&(e.glbModelEnabled=!1),e.textureType===void 0&&(e.textureType="image"),e.glbFileName===void 0&&(e.glbFileName=null),e.animationIndex===void 0&&(e.animationIndex=0),e.animationSpeed===void 0&&(e.animationSpeed=1),e.animationLoop===void 0&&(e.animationLoop=!0),e.useGlbTexture===void 0&&(e.useGlbTexture=!1),e.glbHasTexture===void 0&&(e.glbHasTexture=!1),e.particleShape===void 0&&(e.particleShape="square"),e.particleShapeRotation===void 0&&(e.particleShapeRotation=0),e.particleShapeRotationX===void 0&&(e.particleShapeRotationX=0),e.particleShapeRotationY===void 0&&(e.particleShapeRotationY=0),e.particleShapeRotationZ===void 0&&(e.particleShapeRotationZ=0),e.particleColor===void 0&&(e.particleColor=[1,1,1]),e.startColor===void 0&&(e.startColor=[1,0,0]),e.endColor===void 0&&(e.endColor=[0,0,1]),e.fadeEnabled===void 0&&(e.fadeEnabled=!0),e.colorTransitionEnabled===void 0&&(e.colorTransitionEnabled=!1),e.randomColorEnabled===void 0&&(e.randomColorEnabled=!1),e.randomColors===void 0&&(e.randomColors=[]),e.particleSize===void 0&&(e.particleSize=.5),e.particleSpeed===void 0&&(e.particleSpeed=1),e.opacity===void 0&&(e.opacity=1),e.aspectRatio===void 0&&(e.aspectRatio=1),e.rotation===void 0&&(e.rotation=0),e.rotationMode===void 0&&(e.rotationMode="fixed"),e.minRotation===void 0&&(e.minRotation=0),e.maxRotation===void 0&&(e.maxRotation=90),e.randomSize===void 0&&(e.randomSize=!1),e.minSize===void 0&&(e.minSize=.1),e.maxSize===void 0&&(e.maxSize=.5),e.randomSpeed===void 0&&(e.randomSpeed=!1),e.minSpeed===void 0&&(e.minSpeed=.1),e.maxSpeed===void 0&&(e.maxSpeed=1),e.fadeSizeEnabled===void 0&&(e.fadeSizeEnabled=!1),e.increaseSizeEnabled===void 0&&(e.increaseSizeEnabled=!1),e.sizeLifetimeSpeed===void 0&&(e.sizeLifetimeSpeed=1),e.bloomEnabled===void 0&&(e.bloomEnabled=!0),e.bloomIntensity===void 0&&(e.bloomIntensity=1),e.bloomColor===void 0&&(e.bloomColor=[1,1,1]),e.gravityEnabled===void 0&&(e.gravityEnabled=!1),e.gravityStrength===void 0&&(e.gravityStrength=2),e.dampingEnabled===void 0&&(e.dampingEnabled=!1),e.dampingStrength===void 0&&(e.dampingStrength=1),e.attractorEnabled===void 0&&(e.attractorEnabled=!1),e.attractorStrength===void 0&&(e.attractorStrength=1),e.attractorPosition===void 0&&(e.attractorPosition=[0,0,0]),e.burstMode===void 0&&(e.burstMode=!1),e.emissionShape===void 0&&(e.emissionShape="cube"),e.lifetime===void 0&&(e.lifetime=5),e.emissionRate===void 0&&(e.emissionRate=10),e.emissionDuration===void 0&&(e.emissionDuration=10),e.cubeLength===void 0&&(e.cubeLength=2),e.outerLength===void 0&&(e.outerLength=2),e.innerLength===void 0&&(e.innerLength=0),e.outerRadius===void 0&&(e.outerRadius=2),e.innerRadius===void 0&&(e.innerRadius=0),e.squareSize===void 0&&(e.squareSize=2),e.squareInnerSize===void 0&&(e.squareInnerSize=0),e.circleInnerRadius===void 0&&(e.circleInnerRadius=0),e.circleOuterRadius===void 0&&(e.circleOuterRadius=2),e.circleVelocityDirection===void 0&&(e.circleVelocityDirection="outward"),e.cylinderInnerRadius===void 0&&(e.cylinderInnerRadius=0),e.cylinderOuterRadius===void 0&&(e.cylinderOuterRadius=2),e.cylinderHeight===void 0&&(e.cylinderHeight=4),e.cylinderVelocityDirection===void 0&&(e.cylinderVelocityDirection="outward"),e.planeWidth===void 0&&(e.planeWidth=2),e.planeDepth===void 0&&(e.planeDepth=2),e.coneOuterRadius===void 0&&(e.coneOuterRadius=2),e.coneInnerRadius===void 0&&(e.coneInnerRadius=0),e.coneHeight===void 0&&(e.coneHeight=4),e.torusMajorRadius===void 0&&(e.torusMajorRadius=2),e.torusMinorRadius===void 0&&(e.torusMinorRadius=.5),e.lineLength===void 0&&(e.lineLength=4),e.hemisphereOuterRadius===void 0&&(e.hemisphereOuterRadius=2),e.hemisphereInnerRadius===void 0&&(e.hemisphereInnerRadius=0),e.discRadius===void 0&&(e.discRadius=2),e.annulusInnerRadius===void 0&&(e.annulusInnerRadius=1),e.annulusOuterRadius===void 0&&(e.annulusOuterRadius=2),e.capsuleRadius===void 0&&(e.capsuleRadius=.5),e.capsuleHeight===void 0&&(e.capsuleHeight=4),e.arcStartAngle===void 0&&(e.arcStartAngle=0),e.arcEndAngle===void 0&&(e.arcEndAngle=180),e.arcInnerRadius===void 0&&(e.arcInnerRadius=0),e.arcOuterRadius===void 0&&(e.arcOuterRadius=2),e.spiralTurns===void 0&&(e.spiralTurns=3),e.spiralRadiusStart===void 0&&(e.spiralRadiusStart=.5),e.spiralRadiusEnd===void 0&&(e.spiralRadiusEnd=2),e.spiralHeight===void 0&&(e.spiralHeight=4),e.frustumRadiusNear===void 0&&(e.frustumRadiusNear=.5),e.frustumRadiusFar===void 0&&(e.frustumRadiusFar=2),e.frustumHeight===void 0&&(e.frustumHeight=4),e.cubeSurfaceSize===void 0&&(e.cubeSurfaceSize=2),e.sphereSurfaceRadius===void 0&&(e.sphereSurfaceRadius=2),e.boxFrameSize===void 0&&(e.boxFrameSize=2),e.polygonSides===void 0&&(e.polygonSides=6),e.polygonRadius===void 0&&(e.polygonRadius=2),e.emissionRotationX===void 0&&(e.emissionRotationX=0),e.emissionRotationY===void 0&&(e.emissionRotationY=0),e.emissionRotationZ===void 0&&(e.emissionRotationZ=0),e.emissionTranslationX===void 0&&(e.emissionTranslationX=0),e.emissionTranslationY===void 0&&(e.emissionTranslationY=0),e.emissionTranslationZ===void 0&&(e.emissionTranslationZ=0),e.pulseEnabled===void 0&&(e.pulseEnabled=!1),e.pulseAmplitude===void 0&&(e.pulseAmplitude=.5),e.pulseFrequency===void 0&&(e.pulseFrequency=1),e.pulsePhaseRandom===void 0&&(e.pulsePhaseRandom=0),e.pulseOpacity===void 0&&(e.pulseOpacity=!1),e.confinementEnabled===void 0&&(e.confinementEnabled=!1),e.confinementShape===void 0&&(e.confinementShape="box"),e.confinementMode===void 0&&(e.confinementMode="bounce"),e.confinementSpace===void 0&&(e.confinementSpace="world"),e.confinementBoxHalfSize===void 0&&(e.confinementBoxHalfSize=[2,2,2]),e.confinementSphereRadius===void 0&&(e.confinementSphereRadius=3),e.confinementRestitution===void 0&&(e.confinementRestitution=.8),e.confinementFriction===void 0&&(e.confinementFriction=.1),e.softBoundaryEnabled===void 0&&(e.softBoundaryEnabled=!1),e.softBoundaryStrength===void 0&&(e.softBoundaryStrength=5),e.softBoundaryFalloff===void 0&&(e.softBoundaryFalloff=.5),e.depthWriteEnabled===void 0&&(e.depthWriteEnabled=!1),e.velocityStretchEnabled===void 0&&(e.velocityStretchEnabled=!1),e.velocityStretchFactor===void 0&&(e.velocityStretchFactor=1),e.emissionTrailEnabled===void 0&&(e.emissionTrailEnabled=!1),e.emissionTrailDuration===void 0&&(e.emissionTrailDuration=1),e.emissionTrailWidth===void 0&&(e.emissionTrailWidth=.3),e.emissionTrailMinDistance===void 0&&(e.emissionTrailMinDistance=.05),e.emissionTrailMaxPoints===void 0&&(e.emissionTrailMaxPoints=256),e.emissionTrailSegments===void 0&&(e.emissionTrailSegments=8),e.emissionTrailShape===void 0&&(e.emissionTrailShape="straight"),e.emissionTrailShapeAmplitude===void 0&&(e.emissionTrailShapeAmplitude=.1),e.emissionTrailShapeFrequency===void 0&&(e.emissionTrailShapeFrequency=4),e.emissionTrailShapeSpeed===void 0&&(e.emissionTrailShapeSpeed=0),e.shapeDisplay===void 0&&(e.shapeDisplay=!0),e.followSystemTranslation===void 0&&(e.followSystemTranslation=!0),e.followSystemId===void 0&&(e.followSystemId=null),this._newEmissions=[],this._emptyEmissions=[],this._pendingFollowEmissions=this._emptyEmissions,this.glbVertexBuffer=null,this.glbIndexBuffer=null,this.glbIndexCount=0,this.glbIndexFormat="uint16",this.glbMeshData=null,this.glbRawArrayBuffer=null,this.glbAnimator=null,this.glbAnimated=!1,this._glbInterleavedData=null,this._appearanceData=new Float32Array(44),this._bloomIntensityData=new Float32Array(16),this._simPosition=[0,0,0],this._simVelocity=[0,0,0],this._simRotMatrix=null,this._simRotX=0,this._simRotZ=0,this.emitter=new $(e),this.physics=new H(t,this.MAX_PARTICLES),this.textureManager=new W(t),e.gravityEnabled&&this.setGravity(e.gravityStrength||0),e.dampingEnabled&&this.physics.setDamping(e.dampingStrength||0),e.attractorEnabled&&e.attractorPosition&&this.setAttractor(e.attractorStrength||0,e.attractorPosition),e.confinementEnabled&&this.setConfinement({enabled:!0,shape:e.confinementShape,mode:e.confinementMode,space:e.confinementSpace,boxSize:e.confinementBoxHalfSize,sphereRadius:e.confinementSphereRadius,restitution:e.confinementRestitution,friction:e.confinementFriction}),e.softBoundaryEnabled&&this.setSoftBoundary({enabled:!0,strength:e.softBoundaryStrength,falloff:e.softBoundaryFalloff}),this.particleTexture=this.textureManager.getDefaultTexture(),this.updateBloomIntensity(),this.updateAppearanceUniform(),this.frameCount=0,this.shouldReset=!1,this._scriptParticleData=new Float32Array(this.MAX_PARTICLES*8),this._scriptVelocityData=new Float32Array(this.MAX_PARTICLES*4),this._scriptReadbackPending=!1,this._scriptReadbackReady=!1,this._scriptFrame=0,this._scriptTime=0,this._scriptConfigRestored=!1,this._particleScript=null,e.script&&(this._particleScript=new z(e.script,e,this.MAX_PARTICLES)),this.initComputePipeline(t)}async initComputePipeline(t){this.computeReady=await this.physics.initComputePipeline(this.instanceBuffer,this.velocityBuffer,this.trailBuffer)}setScript(t){this._particleScript&&(this._particleScript.destroy(),this._particleScript=null),this._scriptReadbackPending=!1,this._scriptReadbackReady=!1,this._scriptFrame=0,this._scriptTime=0,this._scriptConfigRestored=!1,t?(this.config.script=t,this._particleScript=new z(t,this.config,this.MAX_PARTICLES),this._particleScript.snapshotConfig(this.config)):delete this.config.script}async setTexture(t){this.textureManager.destroyTexture(this.particleTexture),this.particleTexture=await this.textureManager.loadTexture(t),this.config.textureEnabled=!0,this.updateAppearanceUniform(),this.updateBuffers()}resetTexture(){this.textureManager.destroyTexture(this.particleTexture),this.particleTexture=this.textureManager.getDefaultTexture(),this.config.textureEnabled=!1,this.updateAppearanceUniform(),this.updateBuffers()}async setGLBModel(t){try{this.glbRawArrayBuffer=t;const e=await F(t);this.glbMeshData=e,this.config.glbHasTexture=e.hasBaseColorTexture||!1;const i=new Float32Array(e.vertexCount*8);for(let s=0;s<e.vertexCount;s++){const a=s*8,n=s*3,o=s*2;i[a+0]=e.positions[n+0],i[a+1]=e.positions[n+1],i[a+2]=e.positions[n+2],i[a+3]=e.normals[n+0],i[a+4]=e.normals[n+1],i[a+5]=e.normals[n+2],e.texCoords?(i[a+6]=e.texCoords[o+0],i[a+7]=e.texCoords[o+1]):(i[a+6]=0,i[a+7]=0)}if(this.glbVertexBuffer&&this.glbVertexBuffer.destroy(),this.glbIndexBuffer&&this.glbIndexBuffer.destroy(),this.glbVertexBuffer=this.device.createBuffer({size:i.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST|GPUBufferUsage.STORAGE,label:"glbVertexBuffer"}),this.device.queue.writeBuffer(this.glbVertexBuffer,0,i),this.glbIndexBuffer=this.device.createBuffer({size:e.indices.byteLength,usage:GPUBufferUsage.INDEX|GPUBufferUsage.COPY_DST,label:"glbIndexBuffer"}),this.device.queue.writeBuffer(this.glbIndexBuffer,0,e.indices),this.glbIndexCount=e.indexCount,this.glbIndexFormat=e.indices instanceof Uint32Array?"uint32":"uint16",this.config.glbModelEnabled=!0,this.config.textureType="glb",e.animationData){this.glbAnimator=new Q(e.animationData),this.glbAnimator.setRestPose(e.positions,e.normals),this.glbAnimated=!0,this.config.glbAnimated=!0,this.glbAnimator.loop=this.config.animationLoop,this._glbInterleavedData=new Float32Array(e.vertexCount*8);try{await this.glbAnimator.initGPUSkinning(this.device,this.glbVertexBuffer,e.texCoords)}catch(s){console.warn("GPU skinning init failed, using CPU fallback:",s)}console.log(`GLB animated model loaded: ${e.animationData.animations.length} animations`)}else this.glbAnimator=null,this.glbAnimated=!1,this.config.glbAnimated=!1,this._glbInterleavedData=null;console.log(`GLB model loaded: ${e.vertexCount} vertices, ${e.indexCount} indices`)}catch(e){throw console.error("Failed to load GLB model:",e),e}}resetGLBModel(){this.glbVertexBuffer&&(this.glbVertexBuffer.destroy(),this.glbVertexBuffer=null),this.glbIndexBuffer&&(this.glbIndexBuffer.destroy(),this.glbIndexBuffer=null),this.glbIndexCount=0,this.glbIndexFormat="uint16",this.glbMeshData=null,this.glbRawArrayBuffer=null,this.glbAnimator=null,this.glbAnimated=!1,this.config.glbAnimated=!1,this._glbInterleavedData=null,this.config.glbFileName=null,this.config.glbHasTexture=!1,this.config.useGlbTexture=!1,this.config.glbModelEnabled=!1,this.config.textureType="image"}setSimulationTransform(t){if(t.position&&(this._simPosition[0]=t.position[0],this._simPosition[1]=t.position[1],this._simPosition[2]=t.position[2]),t.rotation){this._simRotX=t.rotation[0],this._simRotZ=t.rotation[1];const e=Math.cos(this._simRotX),i=Math.sin(this._simRotX),s=Math.cos(this._simRotZ),a=Math.sin(this._simRotZ);this._simRotMatrix=[s,-a*e,a*i,a,s*e,-s*i,0,i,e]}else this._simRotMatrix=null,this._simRotX=0,this._simRotZ=0;t.velocity&&(this._simVelocity[0]=t.velocity[0],this._simVelocity[1]=t.velocity[1],this._simVelocity[2]=t.velocity[2])}clearSimulationTransform(){this._simPosition[0]=this._simPosition[1]=this._simPosition[2]=0,this._simVelocity[0]=this._simVelocity[1]=this._simVelocity[2]=0,this._simRotMatrix=null,this._simRotX=0,this._simRotZ=0}updateAnimatedGLBBuffer(){if(!this.glbAnimator||!this.glbAnimator.playing)return!1;if(this.glbAnimator._gpuSkinningReady)return!0;const t=this.glbAnimator.skinnedPositions,e=this.glbAnimator.skinnedNormals,i=this.glbMeshData.texCoords;for(let s=0;s<this.glbMeshData.vertexCount;s++){const a=s*8,n=s*3,o=s*2;this._glbInterleavedData[a]=t[n],this._glbInterleavedData[a+1]=t[n+1],this._glbInterleavedData[a+2]=t[n+2],this._glbInterleavedData[a+3]=e[n],this._glbInterleavedData[a+4]=e[n+1],this._glbInterleavedData[a+5]=e[n+2],i?(this._glbInterleavedData[a+6]=i[o],this._glbInterleavedData[a+7]=i[o+1]):(this._glbInterleavedData[a+6]=0,this._glbInterleavedData[a+7]=0)}return this.device.queue.writeBuffer(this.glbVertexBuffer,0,this._glbInterleavedData),!0}updateAppearanceUniform(){let t=0;this.config.rotationMode==="random"?t=1:this.config.rotationMode==="velocity"&&(t=2);const i={square:0,circle:1,triangle:2,diamond:3,star:4,hexagon:5,ring:6,heart:7,cross:8,spark:9,leaf:10,capsule:11,crescent:12,line:13,"curved-line":14}[this.config.particleShape]??0,s=this._appearanceData;s[0]=this.config.fadeEnabled?1:0,s[1]=this.config.randomColorEnabled?2:this.config.colorTransitionEnabled?1:0,s[2]=this.config.particleSize,s[3]=this.config.textureEnabled?1:0,s[4]=this.config.particleColor[0],s[5]=this.config.particleColor[1],s[6]=this.config.particleColor[2],s[7]=this.config.rotation||0,s[8]=this.config.startColor[0],s[9]=this.config.startColor[1],s[10]=this.config.startColor[2],s[11]=t,s[12]=this.config.endColor[0],s[13]=this.config.endColor[1],s[14]=this.config.endColor[2],s[15]=this.config.minRotation||0,s[16]=this.config.maxRotation||90,s[17]=this.config.aspectRatio||1,s[18]=this.config.randomSize?1:0,s[19]=this.config.minSize||.1,s[20]=this.config.maxSize||.5,s[21]=this.config.fadeSizeEnabled?1:0,s[22]=this.config.opacity!==void 0?this.config.opacity:1,s[23]=this.config.increaseSizeEnabled?1:0,s[24]=this.config.sizeLifetimeSpeed??1,s[25]=i,s[26]=this.config.particleShapeRotation||0,s[27]=this.config.pulseEnabled?1:0,s[28]=this.config.pulseAmplitude??.5,s[29]=this.config.pulseFrequency??1,s[30]=this.config.pulsePhaseRandom??0,s[31]=this.config.pulseOpacity?1:0,s[32]=this.config.particleShapeRotationX||0,s[33]=this.config.particleShapeRotationY||0,s[34]=this.config.particleShapeRotationZ||0,s[35]=0,(s[32]!==0||s[33]!==0||s[34]!==0)&&console.log(`[updateAppearanceUniform] ${this.config.name}: d[32-34] = ${s[32]}, ${s[33]}, ${s[34]}`);const a=this.config.followSystemTranslation??!0;s[36]=a?this._simPosition[0]:0,s[37]=a?this._simPosition[1]:0,s[38]=a?this._simPosition[2]:0,s[39]=0,s[40]=this._simRotX,s[41]=this._simRotZ,s[42]=this.config.velocityStretchEnabled?1:0,s[43]=this.config.velocityStretchFactor??1,this.device.queue.writeBuffer(this.appearanceUniformBuffer,0,s)}updateBloomIntensity(){const t=this._bloomIntensityData;t[0]=this.config.bloomIntensity||1;const e=this.config.bloomColor||[1,1,1];t[4]=e[0],t[5]=e[1],t[6]=e[2],this.device.queue.writeBuffer(this.bloomIntensityBuffer,0,t)}spawnParticles(){if(this.activeParticles=0,this.currentEmissionTime=0,this._newEmissions.length=0,this._pendingFollowEmissions=this._emptyEmissions,this._scriptFrame=0,this._scriptTime=0,this._scriptReadbackPending=!1,this._scriptReadbackReady=!1,this._scriptConfigRestored=!1,this._particleScript&&(this._particleScript._configSnapshot?(this._particleScript.restoreConfig(this.config),this.config.gravityEnabled&&this.setGravity(this.config.gravityStrength),this.config.dampingEnabled&&this.physics.setDamping(this.config.dampingStrength),this.config.attractorEnabled&&this.setAttractor(this.config.attractorStrength,this.config.attractorPosition),this.updateAppearanceUniform(),this.updateBloomIntensity()):this._particleScript.snapshotConfig(this.config)),this.device.queue.writeBuffer(this.trailBuffer,0,this._trailResetData,0,this.MAX_PARTICLES*4),this.glbAnimator&&(this.glbAnimator.currentTime=0,this.glbAnimator.playing=!0),this.config.followSystemId){this.emitting=!0,this.particleCount=this.MAX_PARTICLES;return}if(this.config.burstMode){const t=this.config.particleCount;this.particleCount=t;let e=0;const i=500;for(let s=0;s<t;s++)if(this.emitParticle(),e++,e>=i||s===t-1){const a=s-e+1,n=a*8,o=a*4;this.device.queue.writeBuffer(this.instanceBuffer,n*4,this.particleData,n,e*8),this.device.queue.writeBuffer(this.velocityBuffer,o*4,this.particleVelocities,o,e*4),e=0}this.emitting=!1}else{this.emitting=!0;const t=this.config.lifetime||5,e=Math.max(this.config.emissionDuration||10,t);this.particleCount=Math.min(Math.ceil((this.config.emissionRate||10)*e),this.MAX_PARTICLES)}}emitParticle(){if(this.activeParticles>=this.particleCount)return!1;this.emitter.emitParticle(this.particleData,this.activeParticles,this.particleVelocities);const t=this.activeParticles*8,e=this.activeParticles*4;if(this._simRotMatrix){let i=this.particleData[t],s=this.particleData[t+1],a=this.particleData[t+2],n=this.particleVelocities[e],o=this.particleVelocities[e+1],r=this.particleVelocities[e+2];const l=this._simRotMatrix;this.particleData[t]=l[0]*i+l[1]*s+l[2]*a,this.particleData[t+1]=l[3]*i+l[4]*s+l[5]*a,this.particleData[t+2]=l[6]*i+l[7]*s+l[8]*a,this.particleVelocities[e]=l[0]*n+l[1]*o+l[2]*r,this.particleVelocities[e+1]=l[3]*n+l[4]*o+l[5]*r,this.particleVelocities[e+2]=l[6]*n+l[7]*o+l[8]*r}return(this.config.followSystemTranslation??!0)||(this.particleData[t]+=this._simPosition[0],this.particleData[t+1]+=this._simPosition[1],this.particleData[t+2]+=this._simPosition[2]),this._newEmissions.push(this.particleData[t],this.particleData[t+1],this.particleData[t+2],this.particleVelocities[e],this.particleVelocities[e+1],this.particleVelocities[e+2]),this.activeParticles++,!0}emitFollowerParticle(t,e,i){if(this.activeParticles>=this.particleCount)return!1;const s=this.activeParticles*8,a=t+(this.config.emissionTranslationX||0),n=e+(this.config.emissionTranslationY||0),o=i+(this.config.emissionTranslationZ||0);this.particleData[s]=a,this.particleData[s+1]=n,this.particleData[s+2]=o;const r=this.activeParticles*4;return this.emitter.calculateVelocity(a,n,o,this.particleVelocities,r),this.emitter.setParticleColor(this.particleData,s),this.emitter.setParticleLifetime(this.particleData,s),this.activeParticles++,!0}updateParticles(t,e){if(this._particleScript&&this._scriptReadbackReady){this._scriptReadbackReady=!1,this._scriptTime+=t,this._scriptFrame++;const o=(this.config.emissionDuration||0)+(this.config.lifetime||0);if(o>0&&this._scriptTime>=o&&!this._scriptConfigRestored)this._scriptConfigRestored=!0,this._particleScript._configSnapshot&&(this._particleScript.restoreConfig(this.config),this.updateAppearanceUniform(),this.updateBloomIntensity(),this.config.gravityEnabled&&this.setGravity(this.config.gravityStrength),this.config.dampingEnabled&&this.physics.setDamping(this.config.dampingStrength),this.config.attractorEnabled&&this.setAttractor(this.config.attractorStrength,this.config.attractorPosition));else if(!this._scriptConfigRestored){const r=o>0?Math.ceil(o/.016666666666666666):0,{configDirty:l,particlesDirty:d}=this._particleScript.execute(t,this._scriptTime,this._scriptFrame,r,this._scriptParticleData,this._scriptVelocityData,this.activeParticles);d&&this.activeParticles>0&&(this.device.queue.writeBuffer(this.instanceBuffer,0,this._scriptParticleData,0,this.activeParticles*8),this.device.queue.writeBuffer(this.velocityBuffer,0,this._scriptVelocityData,0,this.activeParticles*4)),l&&(this.updateAppearanceUniform(),this.updateBloomIntensity(),this.config.gravityEnabled&&this.setGravity(this.config.gravityStrength),this.config.dampingEnabled&&this.physics.setDamping(this.config.dampingStrength),this.config.attractorEnabled&&this.setAttractor(this.config.attractorStrength,this.config.attractorPosition))}}this.physics.physicsAccumulator+=t;const i=performance.now()/1e3,a=i-this.physics.lastUpdateTime>1/this.physics.minUpdatesPerSecond,n=this.activeParticles;if(this.emitting)if(this.currentEmissionTime+=t,this.currentEmissionTime<this.config.emissionDuration){const o=this.activeParticles;let r=!1;if(this.config.followSystemId){if(this._pendingFollowEmissions.length>0){const l=this._pendingFollowEmissions.length/6;for(let d=0;d<l;d++){const u=d*6;if(this.emitFollowerParticle(this._pendingFollowEmissions[u],this._pendingFollowEmissions[u+1],this._pendingFollowEmissions[u+2]))r=!0;else break}}}else{let l=0;if(this.config.emissionRate>=1){l=Math.floor(this.config.emissionRate*t);const d=this.config.emissionRate*t-l;Math.random()<d&&(l+=1)}else{const d=this.config.emissionRate*t;Math.random()<d&&(l=1)}l===0&&a&&this.config.emissionRate>0&&this.activeParticles<this.particleCount&&(l=1);for(let d=0;d<l&&this.emitParticle();d++)r=!0}if(r){const l=this.activeParticles-o,d=o*8,u=o*4;this.device.queue.writeBuffer(this.instanceBuffer,d*4,this.particleData,d,l*8),this.device.queue.writeBuffer(this.velocityBuffer,u*4,this.particleVelocities,u,l*4)}}else this.emitting=!1,this.currentEmissionTime=this.config.emissionDuration;for(;this.physics.physicsAccumulator>=this.physics.fixedDeltaTime;)this.physics.updatePhysics(this.physics.fixedDeltaTime,n,this.config,this.instanceBuffer,this.velocityBuffer,e),this.physics.physicsAccumulator-=this.physics.fixedDeltaTime,this.physics.physicsClock+=this.physics.fixedDeltaTime;a&&n>0&&(this.physics.updatePhysics(this.physics.fixedDeltaTime,n,this.config,this.instanceBuffer,this.velocityBuffer,e),this.physics.lastUpdateTime=i),this.frameCount++%300===0&&this.readbackAndProcessParticles(),this._particleScript&&this.activeParticles>0&&!this._scriptReadbackPending&&(this._scriptReadbackPending=!0,this.physics.readbackForScript(this.activeParticles,this._scriptParticleData,this._scriptVelocityData,this.instanceBuffer,this.velocityBuffer).then(o=>{this._scriptReadbackPending=!1,o.shouldUpdate&&(this._scriptReadbackReady=!0)}).catch(()=>{this._scriptReadbackPending=!1}))}async readbackAndProcessParticles(){if(!(this.activeParticles<=0))try{if(!(await this.physics.readbackAndProcessParticles(this.activeParticles,this.particleData,this.particleVelocities,this.instanceBuffer,this.velocityBuffer)).shouldUpdate)return;let e=0;for(let i=0;i<this.activeParticles;i++){const s=this.particleData[i*8+6],a=this.particleData[i*8+7];if(s>=a){if(this.emitting&&this.currentEmissionTime<this.config.emissionDuration&&e<this.particleCount){this.respawnParticle(i,e),e++;continue}continue}if(e!==i){const n=i*8,o=e*8;this.particleData.copyWithin(o,n,n+8);const r=i*4,l=e*4;this.particleVelocities.copyWithin(l,r,r+4)}e++}e!==this.activeParticles&&(this.activeParticles=e,this.device.queue.writeBuffer(this.instanceBuffer,0,this.particleData,0,this.activeParticles*8),this.device.queue.writeBuffer(this.velocityBuffer,0,this.particleVelocities,0,this.activeParticles*4))}catch(t){console.error("Error reading back particle data:",t)}}respawnParticle(t,e){!this.emitting||this.currentEmissionTime>=this.config.emissionDuration||this.config.followSystemId||this.emitter.emitParticle(this.particleData,e,this.particleVelocities)}updateBuffers(){this.activeParticles>0&&this.device.queue.writeBuffer(this.instanceBuffer,0,this.particleData,0,this.activeParticles*8)}updateParticleColors(){for(let t=0;t<this.activeParticles;t++){const e=t*8;if(this.config.randomColorEnabled&&this.config.randomColors.length>0){const i=this.config.randomColors,s=i[Math.floor(Math.random()*i.length)];this.particleData[e+3]=s[0],this.particleData[e+4]=s[1],this.particleData[e+5]=s[2]}else this.config.colorTransitionEnabled?(this.particleData[e+3]=this.config.startColor[0],this.particleData[e+4]=this.config.startColor[1],this.particleData[e+5]=this.config.startColor[2]):(this.particleData[e+3]=this.config.particleColor[0],this.particleData[e+4]=this.config.particleColor[1],this.particleData[e+5]=this.config.particleColor[2])}this.activeParticles>0&&this.device.queue.writeBuffer(this.instanceBuffer,0,this.particleData,0,this.activeParticles*8)}updateParticleVelocities(){for(let t=0;t<this.activeParticles;t++){const e=t*8,i=t*4,s=this.particleData[e],a=this.particleData[e+1],n=this.particleData[e+2],o=this.particleVelocities[i],r=this.particleVelocities[i+1],l=this.particleVelocities[i+2],d=Math.sqrt(o*o+r*r+l*l);if(d>.001){const u=this.config.particleSpeed*2;this.particleVelocities[i]=o/d*u,this.particleVelocities[i+1]=r/d*u,this.particleVelocities[i+2]=l/d*u}else{const u=Math.sqrt(s*s+a*a+n*n);if(u>.001){const f=this.config.particleSpeed*2;this.particleVelocities[i]=s/u*f,this.particleVelocities[i+1]=a/u*f,this.particleVelocities[i+2]=n/u*f}else this.particleVelocities[i]=0,this.particleVelocities[i+1]=this.config.particleSpeed*2,this.particleVelocities[i+2]=0}}this.activeParticles>0&&this.device.queue.writeBuffer(this.velocityBuffer,0,this.particleVelocities,0,this.activeParticles*4)}async readbackForRendering(t,e){return this.physics.readbackForRendering(this.activeParticles,t,e,this.instanceBuffer,this.velocityBuffer)}destroy(){this.instanceBuffer.destroy(),this.velocityBuffer.destroy(),this.trailBuffer.destroy(),this.appearanceUniformBuffer.destroy(),this.bloomIntensityBuffer.destroy(),this.physics.destroy(),this.glbVertexBuffer&&(this.glbVertexBuffer.destroy(),this.glbVertexBuffer=null),this.glbIndexBuffer&&(this.glbIndexBuffer.destroy(),this.glbIndexBuffer=null),this.textureManager.destroyTexture(this.particleTexture),this._particleScript&&(this._particleScript.destroy(),this._particleScript=null),this.glbAnimator=null,this.glbMeshData=null,this.glbRawArrayBuffer=null,this.particleData=null,this.particleVelocities=null,this._scriptParticleData=null,this._scriptVelocityData=null}setGravity(t){this.physics.setGravity(t)}setAttractor(t,e){this.physics.setAttractor(t,e)}setConfinement(t){const e=t.space==="local"?[this.config.emissionTranslationX||0,this.config.emissionTranslationY||0,this.config.emissionTranslationZ||0]:[0,0,0];this.physics.setConfinement({...t,center:e})}setSoftBoundary(t){this.physics.setSoftBoundary(t)}}class ve{constructor(t){this.device=t,this.particleSystems=[],this.activeSystemIndex=0,this.systemCounter=1,this.onSystemCreated=null}createParticleSystem(t={}){const e=this.systemCounter++,i=t.name||`System ${e+1}`,s={...t,name:i,id:e},a=new E(this.device,s);return this.particleSystems.push({system:a,config:s}),this.particleSystems.length===1&&(this.activeSystemIndex=0),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(e,s),e}getActiveSystem(){return this.particleSystems.length===0?null:this.particleSystems[this.activeSystemIndex].system}getActiveConfig(){return this.particleSystems.length===0?null:this.particleSystems[this.activeSystemIndex].config}setActiveSystem(t){return t>=0&&t<this.particleSystems.length?(this.activeSystemIndex=t,!0):!1}getSystemById(t){return this.particleSystems.find(({config:e})=>e.id===t)||null}destroy(){for(const{system:t}of this.particleSystems)t.destroy();this.particleSystems=[],this.activeSystemIndex=0}removeSystem(t){if(t>=0&&t<this.particleSystems.length){const e=this.particleSystems[t].config;this.particleSystems[t].system.destroy(),this.particleSystems.splice(t,1);const i=e.id;for(const{config:s}of this.particleSystems)s.followSystemId===i&&(s.followSystemId=null);return this.particleSystems.length===0?this.activeSystemIndex=0:t<=this.activeSystemIndex&&(this.activeSystemIndex=Math.max(0,this.activeSystemIndex-1)),!0}return!1}respawnAllSystems(){for(const{system:t}of this.particleSystems)t.spawnParticles()}updateAllSystems(t){const e=this.device.createCommandEncoder({label:"BatchedPhysicsEncoder"});let i=!1;for(const{system:s,config:a}of this.particleSystems){if(a.hidden||a.followSystemId)continue;const n=s.activeParticles>0;s.updateParticles(t,e),(n||s.activeParticles>0)&&(i=!0)}for(const{system:s,config:a}of this.particleSystems){if(a.hidden||!a.followSystemId)continue;const n=this.getSystemById(a.followSystemId);n&&(s._pendingFollowEmissions=n.system._newEmissions);const o=s.activeParticles>0;s.updateParticles(t,e),(o||s.activeParticles>0)&&(i=!0)}i&&this.device.queue.submit([e.finish()]);for(const{system:s}of this.particleSystems)s._newEmissions.length=0,s._pendingFollowEmissions=s._emptyEmissions}getSystemsList(){return this.particleSystems.map(({config:t},e)=>({name:t.name,id:t.id,index:e,isActive:e===this.activeSystemIndex,hidden:t.hidden||!1}))}duplicateActiveSystem(){if(this.particleSystems.length===0)return-1;const t=this.getActiveConfig(),e=JSON.parse(JSON.stringify(t));return e.name=`${t.name} (Copy)`,e.onAppearanceChange=null,e.onColorChange=null,e.onSizeChange=null,e.onSpeedChange=null,e.onPhysicsChange=null,e.onBloomIntensityChange=null,e.onRespawn=null,e.getActiveSystem=null,delete e.id,this.createParticleSystem(e)}async replaceSystems(t){var e;if(!t||!t.systems||!Array.isArray(t.systems))return console.error("Invalid scene data provided"),!1;try{this.particleSystems=[],this.systemCounter=1;for(const s of t.systems){const a=this.systemCounter++,n={...s,id:a},o=new E(this.device,n);this.particleSystems.push({system:o,config:n})}const i={};t.systems.forEach((s,a)=>{i[s.id]=this.particleSystems[a].config.id});for(const{config:s}of this.particleSystems)s.followSystemId&&i[s.followSystemId]!==void 0&&(s.followSystemId=i[s.followSystemId]);t.activeSystemIndex!==void 0&&t.activeSystemIndex>=0&&t.activeSystemIndex<this.particleSystems.length?this.activeSystemIndex=t.activeSystemIndex:this.activeSystemIndex=0;for(const{system:s,config:a}of this.particleSystems)if(a.glbModelEnabled)try{let n=null;if(a.glbModelData)n=Y(a.glbModelData);else if(a.glbFileName){const o=await fetch(`/${a.glbFileName}`);o.ok?n=await o.arrayBuffer():console.warn(`GLB file not found: ${a.glbFileName}`)}if(n){if(await s.setGLBModel(n),a.animationIndex!==void 0&&s.glbAnimator&&s.glbAnimator.setAnimation(a.animationIndex),a.animationSpeed!==void 0&&s.glbAnimator&&(s.glbAnimator.speed=a.animationSpeed),a.animationLoop!==void 0&&s.glbAnimator&&(s.glbAnimator.loop=a.animationLoop),a.useGlbTexture&&(a.textureEnabled=!0),a.useGlbTexture&&((e=s.glbMeshData)!=null&&e.hasBaseColorTexture))try{const{extractGLBTexture:o}=await Promise.resolve().then(()=>j),r=await o(n);if(r){const l=await createImageBitmap(r.imageBlob);await s.setTexture(l),console.log(`GLB embedded texture restored for ${a.name}`)}}catch(o){console.warn(`Failed to restore GLB texture for ${a.name}:`,o),a.useGlbTexture=!1}}else a.glbModelEnabled=!1}catch(n){console.warn(`Failed to load GLB for ${a.name}:`,n),a.glbModelEnabled=!1}for(const{system:s,config:a}of this.particleSystems)if(a.textureEnabled&&!a.glbModelEnabled&&a.textureImageData)try{const n=new Image;await new Promise((r,l)=>{n.onload=r,n.onerror=l,n.src=a.textureImageData});const o=await createImageBitmap(n);await s.setTexture(o)}catch(n){console.warn(`Failed to restore texture for ${a.name}:`,n),a.textureEnabled=!1}for(const{system:s,config:a}of this.particleSystems)s.updateAppearanceUniform(),(a.particleShapeRotationX||a.particleShapeRotationY||a.particleShapeRotationZ)&&console.log(`[replaceSystems] ${a.name}: glbRotation XYZ = ${a.particleShapeRotationX}, ${a.particleShapeRotationY}, ${a.particleShapeRotationZ} | glbModelEnabled=${a.glbModelEnabled} | glbMeshData=${!!s.glbMeshData}`);return this.respawnAllSystems(),!0}catch(i){return console.error("Error replacing systems:",i),!1}}async addSystems(t,e=[0,0,0]){var i;if(!t||!t.systems||!Array.isArray(t.systems))return console.error("Invalid scene data provided"),!1;try{for(const n of t.systems){const o=this.systemCounter++,r={...n,id:o,emissionTranslationX:(n.emissionTranslationX||0)+e[0],emissionTranslationY:(n.emissionTranslationY||0)+e[1],emissionTranslationZ:(n.emissionTranslationZ||0)+e[2]};n.attractorEnabled&&n.attractorPosition&&(r.attractorPosition=[n.attractorPosition[0]+e[0],n.attractorPosition[1]+e[1],n.attractorPosition[2]+e[2]]);const l=new E(this.device,r);this.particleSystems.push({system:l,config:r}),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(o,r)}const s=this.particleSystems.length-t.systems.length,a={};t.systems.forEach((n,o)=>{a[n.id]=this.particleSystems[s+o].config.id});for(let n=s;n<this.particleSystems.length;n++){const{config:o}=this.particleSystems[n];o.followSystemId&&a[o.followSystemId]!==void 0&&(o.followSystemId=a[o.followSystemId])}for(const{system:n,config:o}of this.particleSystems)if(o.glbModelEnabled&&!n.glbMeshData)try{let r=null;if(o.glbModelData)r=Y(o.glbModelData);else if(o.glbFileName){const l=await fetch(`/${o.glbFileName}`);l.ok?r=await l.arrayBuffer():console.warn(`GLB file not found: ${o.glbFileName}`)}if(r){if(await n.setGLBModel(r),o.animationIndex!==void 0&&n.glbAnimator&&n.glbAnimator.setAnimation(o.animationIndex),o.animationSpeed!==void 0&&n.glbAnimator&&(n.glbAnimator.speed=o.animationSpeed),o.animationLoop!==void 0&&n.glbAnimator&&(n.glbAnimator.loop=o.animationLoop),o.useGlbTexture&&(o.textureEnabled=!0),o.useGlbTexture&&((i=n.glbMeshData)!=null&&i.hasBaseColorTexture))try{const{extractGLBTexture:l}=await Promise.resolve().then(()=>j),d=await l(r);if(d){const u=await createImageBitmap(d.imageBlob);await n.setTexture(u),console.log(`GLB embedded texture restored for ${o.name}`)}}catch(l){console.warn(`Failed to restore GLB texture for ${o.name}:`,l),o.useGlbTexture=!1}}else o.glbModelEnabled=!1}catch(r){console.warn(`Failed to load GLB for ${o.name}:`,r),o.glbModelEnabled=!1}for(const{system:n,config:o}of this.particleSystems)if(o.textureEnabled&&!o.glbModelEnabled&&o.textureImageData&&!n._textureRestored)try{const r=new Image;await new Promise((d,u)=>{r.onload=d,r.onerror=u,r.src=o.textureImageData});const l=await createImageBitmap(r);await n.setTexture(l),n._textureRestored=!0}catch(r){console.warn(`Failed to restore texture for ${o.name}:`,r),o.textureEnabled=!1}return!0}catch(s){return console.error("Error adding systems:",s),!1}}}async function _e(c){if(!c)throw new Error("canvas is required for initWebGPU()");if(!navigator.gpu)throw new Error("WebGPU not supported on this browser.");const t=c.getContext("webgpu"),i=await(await navigator.gpu.requestAdapter()).requestDevice(),s=navigator.gpu.getPreferredCanvasFormat();return t.configure({device:i,format:s,alphaMode:"premultiplied"}),{device:i,context:t,format:s,canvas:c}}function Pe(c,t,e,i){const s=c.createTexture({size:[e,i],format:t,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1}),a=c.createTexture({size:[e,i],format:t,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1}),n=c.createTexture({size:[e,i],format:t,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1});return{sceneTexture:s,bloomTexA:a,bloomTexB:n}}function Me(c,t,e){return c.createTexture({size:[t,e],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT})}function T(c,t,e){const i=c.createBuffer({size:t.byteLength,usage:e,mappedAtCreation:!0});return new t.constructor(i.getMappedRange()).set(t),i.unmap(),i}const D=`
9
+ ${Cs(t)}
10
+ };`,s=new Function(i);this._fn=s()}catch(e){console.warn("[ParticleScript] Compilation error:",e.message),this._fn=null,this._error=!0}}execute(t,e,i,s,n,o,a){if(!this._fn||this._error)return{configDirty:!1,particlesDirty:!1};this._particles._bind(n,o,a),this._configProxy.__resetDirty();try{this._fn(t,e,i,s,this._particles,this._configProxy,Ri)}catch(c){console.warn("[ParticleScript] Runtime error:",c.message)}return{configDirty:this._configProxy.__dirty,particlesDirty:this._particles._dirty}}snapshotConfig(t){const e={};for(const i of Ze){const s=t[i];s!==void 0&&(e[i]=Array.isArray(s)?[...s]:s)}this._configSnapshot=e}restoreConfig(t){if(this._configSnapshot){for(const e of Ze)if(e in this._configSnapshot){const i=this._configSnapshot[e];t[e]=Array.isArray(i)?[...i]:i}}}destroy(){this._fn=null,this._particles=null,this._configProxy=null,this._configSnapshot=null}}async function Bt(r){const t=new DataView(r);if(t.getUint32(0,!0)!==1179937895)throw new Error("Invalid GLB file: incorrect magic number");const i=t.getUint32(4,!0);if(i!==2)throw new Error(`Unsupported GLB version: ${i} (only version 2 is supported)`);const s=t.getUint32(8,!0);let n=12,o=null,a=null;for(;n<s;){const P=t.getUint32(n,!0),_=t.getUint32(n+4,!0),T=r.slice(n+8,n+8+P);if(_===1313821514){const N=new TextDecoder("utf-8").decode(T);o=JSON.parse(N)}else _===5130562&&(a=T);n+=8+P}if(!o)throw new Error("GLB file missing JSON chunk");if(!o.meshes||o.meshes.length===0)throw new Error("GLB file contains no meshes");const l=o.meshes[0].primitives[0];if(!l)throw new Error("First mesh has no primitives");const u=l.attributes.POSITION;if(u===void 0)throw new Error("Mesh primitive missing POSITION attribute");const f=St(o,a,u,3,5126);let h;if(l.attributes.NORMAL!==void 0)h=St(o,a,l.attributes.NORMAL,3,5126);else{const P=l.indices;if(P===void 0)throw new Error("Cannot generate normals without indices");const _=pi(o,a,P);h=Us(f,_)}const m=l.indices;if(m===void 0)throw new Error("Mesh primitive missing indices");const S=pi(o,a,m),R=f.length/3,D=S.length;let C=null;l.attributes.TEXCOORD_0!==void 0&&(C=St(o,a,l.attributes.TEXCOORD_0,2,5126));let B=!1;if(o.materials&&o.materials.length>0){const P=o.materials[0];P.pbrMetallicRoughness&&P.pbrMetallicRoughness.baseColorTexture!==void 0&&(B=!0)}let A=null;if(o.skins&&o.skins.length>0)try{A=Fs(o,a,l),console.log("Animation data extracted:",A)}catch(P){console.warn("Failed to extract animation data:",P)}return{positions:f,normals:h,indices:S,texCoords:C,vertexCount:R,indexCount:D,animationData:A,hasBaseColorTexture:B}}function St(r,t,e,i,s){const n=r.accessors[e],a={SCALAR:1,VEC2:2,VEC3:3,VEC4:4}[n.type];if(a!==i)throw new Error(`Attribute accessor type mismatch: expected ${i} components, got ${a}`);if(n.componentType!==s)throw new Error(`Attribute component type mismatch: expected ${s}, got ${n.componentType}`);const l=(r.bufferViews[n.bufferView].byteOffset||0)+(n.byteOffset||0),u=n.count,f=new DataView(t,l,u*i*4),h=new Float32Array(u*i);for(let m=0;m<u*i;m++)h[m]=f.getFloat32(m*4,!0);return h}function pi(r,t,e){const i=r.accessors[e];if(i.type!=="SCALAR")throw new Error(`Indices accessor must be SCALAR, got ${i.type}`);const n=(r.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),o=i.count;if(i.componentType===5123){const a=new DataView(t,n,o*2),c=new Uint16Array(o);for(let l=0;l<o;l++)c[l]=a.getUint16(l*2,!0);return c}else if(i.componentType===5125){const a=new DataView(t,n,o*4),c=new Uint32Array(o);for(let l=0;l<o;l++)c[l]=a.getUint32(l*4,!0);return c}else throw new Error(`Unsupported index component type: ${i.componentType}`)}function Us(r,t){const e=new Float32Array(r.length);for(let i=0;i<t.length;i+=3){const s=t[i]*3,n=t[i+1]*3,o=t[i+2]*3,a=[r[s],r[s+1],r[s+2]],c=[r[n],r[n+1],r[n+2]],l=[r[o],r[o+1],r[o+2]],u=[c[0]-a[0],c[1]-a[1],c[2]-a[2]],f=[l[0]-a[0],l[1]-a[1],l[2]-a[2]],h=[u[1]*f[2]-u[2]*f[1],u[2]*f[0]-u[0]*f[2],u[0]*f[1]-u[1]*f[0]],m=Math.sqrt(h[0]*h[0]+h[1]*h[1]+h[2]*h[2]);m>0&&(h[0]/=m,h[1]/=m,h[2]/=m),e[s]=e[n]=e[o]=h[0],e[s+1]=e[n+1]=e[o+1]=h[1],e[s+2]=e[n+2]=e[o+2]=h[2]}return e}function Is(r,t,e){const i=r.accessors[e];if(i.type!=="VEC4")throw new Error(`JOINTS_0 must be VEC4, got ${i.type}`);const n=(r.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),o=i.count;if(i.componentType===5121){const a=new DataView(t,n,o*4),c=new Uint8Array(o*4);for(let l=0;l<o*4;l++)c[l]=a.getUint8(l);return c}else if(i.componentType===5123){const a=new DataView(t,n,o*8),c=new Uint8Array(o*4);for(let l=0;l<o*4;l++)c[l]=a.getUint16(l*2,!0);return c}else throw new Error(`Unsupported JOINTS_0 component type: ${i.componentType}`)}function Gs(r,t,e){const i=r.accessors[e];if(i.type!=="VEC4")throw new Error(`WEIGHTS_0 must be VEC4, got ${i.type}`);const n=(r.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),o=i.count;if(i.componentType===5126){const a=new DataView(t,n,o*16),c=new Float32Array(o*4);for(let l=0;l<o*4;l++)c[l]=a.getFloat32(l*4,!0);return c}else if(i.componentType===5121){const a=new DataView(t,n,o*4),c=new Float32Array(o*4);for(let l=0;l<o*4;l++)c[l]=a.getUint8(l)/255;return c}else throw new Error(`Unsupported WEIGHTS_0 component type: ${i.componentType}`)}function Ds(r,t,e){const i=r.accessors[e];if(i.type!=="MAT4")throw new Error(`Expected MAT4, got ${i.type}`);if(i.componentType!==5126)throw new Error(`Expected FLOAT component type for MAT4, got ${i.componentType}`);const n=(r.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),o=i.count,a=new DataView(t,n,o*64),c=new Float32Array(o*16);for(let l=0;l<o*16;l++)c[l]=a.getFloat32(l*4,!0);return c}function zs(r,t,e){const i=r.accessors[e];if(i.type!=="SCALAR")throw new Error(`Expected SCALAR, got ${i.type}`);if(i.componentType!==5126)throw new Error(`Expected FLOAT component type for SCALAR, got ${i.componentType}`);const n=(r.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),o=i.count,a=new DataView(t,n,o*4),c=new Float32Array(o);for(let l=0;l<o;l++)c[l]=a.getFloat32(l*4,!0);return c}function Vs(r,t,e){const i=r.accessors[e],n={VEC3:3,VEC4:4}[i.type];if(!n)throw new Error(`Expected VEC3 or VEC4, got ${i.type}`);if(i.componentType!==5126)throw new Error(`Expected FLOAT component type, got ${i.componentType}`);const a=(r.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),c=i.count,l=new DataView(t,a,c*n*4),u=new Float32Array(c*n);for(let f=0;f<c*n;f++)u[f]=l.getFloat32(f*4,!0);return u}function Fs(r,t,e){const i=r.skins[0],s=i.joints,n=Ds(r,t,i.inverseBindMatrices),o=e.attributes.JOINTS_0!==void 0?Is(r,t,e.attributes.JOINTS_0):null,a=e.attributes.WEIGHTS_0!==void 0?Gs(r,t,e.attributes.WEIGHTS_0):null;if(!o||!a)throw new Error("Mesh missing JOINTS_0 or WEIGHTS_0 attributes");const c=r.nodes.map(u=>({translation:u.translation||[0,0,0],rotation:u.rotation||[0,0,0,1],scale:u.scale||[1,1,1],children:u.children||[],name:u.name||""})),l=[];if(r.animations&&r.animations.length>0)for(const u of r.animations){const f=[];let h=0;for(const m of u.channels){const S=u.samplers[m.sampler],R=zs(r,t,S.input),D=Vs(r,t,S.output),C=R[R.length-1];C>h&&(h=C),f.push({targetNode:m.target.node,targetPath:m.target.path,interpolation:S.interpolation||"LINEAR",timestamps:R,values:D})}l.push({name:u.name||`Animation ${l.length}`,duration:h,channels:f})}return{joints:s,inverseBindMatrices:n,jointIndices:o,jointWeights:a,nodes:c,animations:l}}async function Mi(r){const t=new DataView(r);if(t.getUint32(0,!0)!==1179937895)throw new Error("Invalid GLB file: incorrect magic number");const i=t.getUint32(4,!0);if(i!==2)throw new Error(`Unsupported GLB version: ${i}`);const s=t.getUint32(8,!0);let n=12,o=null,a=null;for(;n<s;){const A=t.getUint32(n,!0),P=t.getUint32(n+4,!0),_=r.slice(n+8,n+8+A);if(P===1313821514){const L=new TextDecoder("utf-8").decode(_);o=JSON.parse(L)}else P===5130562&&(a=_);n+=8+A}if(!o)throw new Error("GLB file missing JSON chunk");if(!o.materials||o.materials.length===0)return null;const c=o.materials[0];if(!c.pbrMetallicRoughness||c.pbrMetallicRoughness.baseColorTexture===void 0)return null;const l=c.pbrMetallicRoughness.baseColorTexture.index;if(!o.textures||!o.textures[l])return null;const f=o.textures[l].source;if(f===void 0||!o.images||!o.images[f])return null;const h=o.images[f],m=h.mimeType||"image/png";if(h.bufferView===void 0)return null;if(!a)throw new Error("GLB file missing BIN chunk (required for embedded textures)");const S=o.bufferViews[h.bufferView],R=S.byteOffset||0,D=S.byteLength,C=a.slice(R,R+D);return{imageBlob:new Blob([C],{type:m}),mimeType:m}}const hi=Object.freeze(Object.defineProperty({__proto__:null,extractGLBTexture:Mi,parseGLB:Bt},Symbol.toStringTag,{value:"Module"}));function mi(r,t,e){return[r[0]+(t[0]-r[0])*e,r[1]+(t[1]-r[1])*e,r[2]+(t[2]-r[2])*e]}function yi(r,t,e){let i=r[0]*t[0]+r[1]*t[1]+r[2]*t[2]+r[3]*t[3],s=t;if(i<0&&(i=-i,s=[-t[0],-t[1],-t[2],-t[3]]),i>.9995){const l=[r[0]+(s[0]-r[0])*e,r[1]+(s[1]-r[1])*e,r[2]+(s[2]-r[2])*e,r[3]+(s[3]-r[3])*e];return Os(l)}const n=Math.acos(i),o=Math.sin(n),a=Math.sin((1-e)*n)/o,c=Math.sin(e*n)/o;return[r[0]*a+s[0]*c,r[1]*a+s[1]*c,r[2]*a+s[2]*c,r[3]*a+s[3]*c]}function Os(r){const t=Math.sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]+r[3]*r[3]);return t>1e-4?[r[0]/t,r[1]/t,r[2]/t,r[3]/t]:[0,0,0,1]}function Ls(r){const t=r[0],e=r[1],i=r[2],s=r[3],n=t+t,o=e+e,a=i+i,c=t*n,l=t*o,u=t*a,f=e*o,h=e*a,m=i*a,S=s*n,R=s*o,D=s*a;return new Float32Array([1-(f+m),l+D,u-R,0,l-D,1-(c+m),h+S,0,u+R,h-S,1-(c+f),0,0,0,0,1])}function Ns(r,t,e){const i=Ls(t);return new Float32Array([i[0]*e[0],i[1]*e[0],i[2]*e[0],0,i[4]*e[1],i[5]*e[1],i[6]*e[1],0,i[8]*e[2],i[9]*e[2],i[10]*e[2],0,r[0],r[1],r[2],1])}function gi(r,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let s=0;s<4;s++)e[i*4+s]=r[0+s]*t[i*4+0]+r[4+s]*t[i*4+1]+r[8+s]*t[i*4+2]+r[12+s]*t[i*4+3];return e}class Ti{constructor(t){this.joints=t.joints,this.inverseBindMatrices=t.inverseBindMatrices,this.jointWeights=t.jointWeights,this.jointIndices=t.jointIndices,this.nodes=t.nodes,this.animations=t.animations,this.restPositions=null,this.restNormals=null,this.currentAnimIndex=0,this.currentTime=0,this.playing=!0,this.speed=1,this.loop=!0,this.jointLocalTransforms=new Array(this.nodes.length),this.jointGlobalTransforms=new Array(this.nodes.length),this.jointFinalMatrices=new Array(this.joints.length);for(let e=0;e<this.nodes.length;e++)this.jointLocalTransforms[e]=new Float32Array(16),this.jointGlobalTransforms[e]=new Float32Array(16);for(let e=0;e<this.joints.length;e++)this.jointFinalMatrices[e]=new Float32Array(16);this.skinnedPositions=null,this.skinnedNormals=null,this._gpuSkinningReady=!1,this._buildTopologicalOrder(),console.log(`GLBAnimator initialized: ${this.joints.length} joints, ${this.animations.length} animations`)}setRestPose(t,e){this.restPositions=new Float32Array(t),this.restNormals=new Float32Array(e),this.skinnedPositions=new Float32Array(t.length),this.skinnedNormals=new Float32Array(e.length)}async initGPUSkinning(t,e,i){try{this._gpuDevice=t,this._gpuOutputBuffer=e;const s=this.restPositions.length/3,n=new Float32Array(s*8);for(let l=0;l<s;l++){const u=l*8,f=l*3,h=l*2;n[u]=this.restPositions[f],n[u+1]=this.restPositions[f+1],n[u+2]=this.restPositions[f+2],n[u+3]=this.restNormals[f],n[u+4]=this.restNormals[f+1],n[u+5]=this.restNormals[f+2],n[u+6]=i?i[h]:0,n[u+7]=i?i[h+1]:0}this._gpuRestDataBuffer=t.createBuffer({size:n.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_restData"}),t.queue.writeBuffer(this._gpuRestDataBuffer,0,n),this._gpuJointWeightsBuffer=t.createBuffer({size:this.jointWeights.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_jointWeights"}),t.queue.writeBuffer(this._gpuJointWeightsBuffer,0,this.jointWeights);const o=new Uint32Array(this.jointIndices.length);for(let l=0;l<this.jointIndices.length;l++)o[l]=this.jointIndices[l];this._gpuJointIndicesBuffer=t.createBuffer({size:o.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_jointIndices"}),t.queue.writeBuffer(this._gpuJointIndicesBuffer,0,o),this._gpuJointMatricesBuffer=t.createBuffer({size:this.joints.length*16*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_jointMatrices"}),this._gpuJointMatricesData=new Float32Array(this.joints.length*16);const{skinningComputeShader:a}=await Promise.resolve().then(()=>Ii),c=t.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:3,visibility:GPUShaderStage.COMPUTE,buffer:{type:"read-only-storage"}},{binding:4,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]});this._gpuSkinningPipeline=t.createComputePipeline({layout:t.createPipelineLayout({bindGroupLayouts:[c]}),compute:{module:t.createShaderModule({code:a}),entryPoint:"main"}}),this._gpuSkinningBindGroup=t.createBindGroup({layout:c,entries:[{binding:0,resource:{buffer:this._gpuRestDataBuffer}},{binding:1,resource:{buffer:this._gpuJointWeightsBuffer}},{binding:2,resource:{buffer:this._gpuJointIndicesBuffer}},{binding:3,resource:{buffer:this._gpuJointMatricesBuffer}},{binding:4,resource:{buffer:this._gpuOutputBuffer}}]}),this._gpuVertexCount=s,this._gpuSkinningReady=!0,console.log(`GPU skinning initialized: ${s} vertices, ${this.joints.length} joints`)}catch(s){console.warn("GPU skinning init failed, using CPU fallback:",s),this._gpuSkinningReady=!1}}_applySkinningGPU(){for(let i=0;i<this.joints.length;i++)this._gpuJointMatricesData.set(this.jointFinalMatrices[i],i*16);this._gpuDevice.queue.writeBuffer(this._gpuJointMatricesBuffer,0,this._gpuJointMatricesData);const t=this._gpuDevice.createCommandEncoder({label:"SkinningComputeEncoder"}),e=t.beginComputePass({label:"SkinningComputePass"});e.setPipeline(this._gpuSkinningPipeline),e.setBindGroup(0,this._gpuSkinningBindGroup),e.dispatchWorkgroups(Math.ceil(this._gpuVertexCount/64),1,1),e.end(),this._gpuDevice.queue.submit([t.finish()])}update(t){if(!this.playing||this.animations.length===0)return{positions:this.skinnedPositions,normals:this.skinnedNormals,changed:!1};this.currentTime+=t*this.speed;const e=this.animations[this.currentAnimIndex];return this.loop?this.currentTime=this.currentTime%e.duration:this.currentTime>e.duration&&(this.currentTime=e.duration,this.playing=!1),this._computeLocalTransforms(this.currentTime),this._computeGlobalTransforms(),this._computeFinalMatrices(),this._gpuSkinningReady?(this._applySkinningGPU(),{gpuSkinned:!0,changed:!0}):(this._applySkinning(),{positions:this.skinnedPositions,normals:this.skinnedNormals,changed:!0})}getCurrentAnimation(){return this.animations[this.currentAnimIndex]}setAnimation(t){t>=0&&t<this.animations.length&&(this.currentAnimIndex=t,this.currentTime=0)}getAnimationNames(){return this.animations.map(t=>t.name)}_buildTopologicalOrder(){const t=new Set,e=[],i=n=>{if(t.has(n))return;t.add(n);const o=this.nodes[n];for(const a of o.children)i(a);e.push(n)},s=new Set;for(const n of this.nodes)for(const o of n.children)s.add(o);for(let n=0;n<this.nodes.length;n++)s.has(n)||i(n);this.topologicalOrder=e.reverse()}_sampleChannel(t,e){const{timestamps:i,values:s,interpolation:n,targetPath:o}=t;if(e<=i[0])return this._extractValue(s,0,o);if(e>=i[i.length-1])return this._extractValue(s,i.length-1,o);let a=0,c=i.length-1;for(;c-a>1;){const S=Math.floor((a+c)/2);i[S]<=e?a=S:c=S}const l=i[a],u=i[c],f=(e-l)/(u-l),h=this._extractValue(s,a,o),m=this._extractValue(s,c,o);return n==="STEP"?h:o==="rotation"?yi(h,m,f):mi(h,m,f)}_extractValue(t,e,i){if(i==="rotation"){const s=e*4;return[t[s],t[s+1],t[s+2],t[s+3]]}else{const s=e*3;return[t[s],t[s+1],t[s+2]]}}_computeLocalTransforms(t){const e=this.animations[this.currentAnimIndex];for(let i=0;i<this.nodes.length;i++){const s=this.nodes[i];let n=s.translation,o=s.rotation,a=s.scale;for(const c of e.channels)if(c.targetNode===i){const l=this._sampleChannel(c,t);c.targetPath==="translation"?n=l:c.targetPath==="rotation"?o=l:c.targetPath==="scale"&&(a=l)}this.jointLocalTransforms[i]=Ns(n,o,a)}}_computeGlobalTransforms(){const t=new Array(this.nodes.length).fill(-1);for(let e=0;e<this.nodes.length;e++){const i=this.nodes[e];for(const s of i.children)t[s]=e}for(const e of this.topologicalOrder){const i=t[e];i===-1?this.jointGlobalTransforms[e]=this.jointLocalTransforms[e]:this.jointGlobalTransforms[e]=gi(this.jointGlobalTransforms[i],this.jointLocalTransforms[e])}}_computeFinalMatrices(){for(let t=0;t<this.joints.length;t++){const e=this.joints[t],i=this.jointGlobalTransforms[e],s=t*16,n=this.inverseBindMatrices.slice(s,s+16);this.jointFinalMatrices[t]=gi(i,n)}}_applySkinning(){const t=this.restPositions.length/3,e=this.restPositions,i=this.restNormals,s=this.skinnedPositions,n=this.skinnedNormals,o=this.jointWeights,a=this.jointIndices,c=this.jointFinalMatrices;for(let l=0;l<t;l++){const u=l*3,f=l*4,h=e[u],m=e[u+1],S=e[u+2],R=i[u],D=i[u+1],C=i[u+2];let B=0,A=0,P=0,_=0,T=0,L=0;for(let k=0;k<4;k++){const X=o[f+k];if(X===0)continue;const z=c[a[f+k]];B+=(z[0]*h+z[4]*m+z[8]*S+z[12])*X,A+=(z[1]*h+z[5]*m+z[9]*S+z[13])*X,P+=(z[2]*h+z[6]*m+z[10]*S+z[14])*X,_+=(z[0]*R+z[4]*D+z[8]*C)*X,T+=(z[1]*R+z[5]*D+z[9]*C)*X,L+=(z[2]*R+z[6]*D+z[10]*C)*X}const N=Math.sqrt(_*_+T*T+L*L);N>1e-4&&(n[u]=_/N,n[u+1]=T/N,n[u+2]=L/N),s[u]=B,s[u+1]=A,s[u+2]=P}}}function bi(r){const t=atob(r),e=new Uint8Array(t.length);for(let i=0;i<t.length;i++)e[i]=t.charCodeAt(i);return e.buffer}class at{constructor(t,e){this.device=t,this.config=e,this.MAX_PARTICLES=e.maxParticles||1e4,this.particleCount=e.particleCount||100,this.activeParticles=0,this.emitting=!1,this.currentEmissionTime=0,this.destroyed=!1,this.particleData=new Float32Array(this.MAX_PARTICLES*8),this.particleVelocities=new Float32Array(this.MAX_PARTICLES*4),this.instanceBuffer=t.createBuffer({size:this.MAX_PARTICLES*8*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST|GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC,label:"particleInstanceBuffer"}),this.velocityBuffer=t.createBuffer({size:this.MAX_PARTICLES*4*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,label:"particleVelocityBuffer"}),this.trailBuffer=t.createBuffer({size:this.MAX_PARTICLES*4*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,label:"particleTrailBuffer"}),this._trailResetData=new Float32Array(this.MAX_PARTICLES*4),this.appearanceUniformBuffer=t.createBuffer({size:208,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,label:"appearanceUniformBuffer"}),this.bloomIntensityBuffer=t.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,label:"systemBloomIntensityBuffer"}),e.overrideXVelocity===void 0&&(e.overrideXVelocity=!1),e.overrideYVelocity===void 0&&(e.overrideYVelocity=!1),e.overrideZVelocity===void 0&&(e.overrideZVelocity=!1),e.xVelocity===void 0&&(e.xVelocity=0),e.yVelocity===void 0&&(e.yVelocity=0),e.zVelocity===void 0&&(e.zVelocity=0),e.textureEnabled===void 0&&(e.textureEnabled=!1),e.glbModelEnabled===void 0&&(e.glbModelEnabled=!1),e.textureType===void 0&&(e.textureType="image"),e.glbFileName===void 0&&(e.glbFileName=null),e.animationIndex===void 0&&(e.animationIndex=0),e.animationSpeed===void 0&&(e.animationSpeed=1),e.animationLoop===void 0&&(e.animationLoop=!0),e.useGlbTexture===void 0&&(e.useGlbTexture=!1),e.glbHasTexture===void 0&&(e.glbHasTexture=!1),e.particleShape===void 0&&(e.particleShape="square"),e.particleShapeRotation!==void 0&&(e.rotation=(e.rotation||0)+e.particleShapeRotation,delete e.particleShapeRotation),e.particleShapeRotationX===void 0&&(e.particleShapeRotationX=0),e.particleShapeRotationY===void 0&&(e.particleShapeRotationY=0),e.particleShapeRotationZ===void 0&&(e.particleShapeRotationZ=0),e.particleColor===void 0&&(e.particleColor=[1,1,1]),e.startColor===void 0&&(e.startColor=[1,0,0]),e.endColor===void 0&&(e.endColor=[0,0,1]),e.fadeEnabled===void 0&&(e.fadeEnabled=!0),e.colorTransitionEnabled===void 0&&(e.colorTransitionEnabled=!1),e.randomColorEnabled===void 0&&(e.randomColorEnabled=!1),e.randomColors===void 0&&(e.randomColors=[]),e.particleSize===void 0&&(e.particleSize=.1),e.particleSpeed===void 0&&(e.particleSpeed=1),e.opacity===void 0&&(e.opacity=1),e.aspectRatio===void 0&&(e.aspectRatio=1),e.rotation===void 0&&(e.rotation=0),e.rotationMode===void 0&&(e.rotationMode="fixed"),e.minRotation===void 0&&(e.minRotation=0),e.maxRotation===void 0&&(e.maxRotation=90),e.randomSize===void 0&&(e.randomSize=!1),e.minSize===void 0&&(e.minSize=.05),e.maxSize===void 0&&(e.maxSize=.15),e.randomSpeed===void 0&&(e.randomSpeed=!1),e.minSpeed===void 0&&(e.minSpeed=.1),e.maxSpeed===void 0&&(e.maxSpeed=1),e.fadeSizeEnabled===void 0&&(e.fadeSizeEnabled=!1),e.increaseSizeEnabled===void 0&&(e.increaseSizeEnabled=!1),e.sizeLifetimeSpeed===void 0&&(e.sizeLifetimeSpeed=1),e.bloomEnabled===void 0&&(e.bloomEnabled=!0),e.bloomIntensity===void 0&&(e.bloomIntensity=1),e.bloomColor===void 0&&(e.bloomColor=[1,1,1]),e.gravityEnabled===void 0&&(e.gravityEnabled=!1),e.gravityStrength===void 0&&(e.gravityStrength=2),e.dampingEnabled===void 0&&(e.dampingEnabled=!1),e.dampingStrength===void 0&&(e.dampingStrength=1),e.attractorEnabled===void 0&&(e.attractorEnabled=!1),e.attractorStrength===void 0&&(e.attractorStrength=1),e.attractorPosition===void 0&&(e.attractorPosition=[0,0,0]),e.burstMode===void 0&&(e.burstMode=!1),e.emissionShape===void 0&&(e.emissionShape="cube"),e.lifetime===void 0&&(e.lifetime=5),e.emissionRate===void 0&&(e.emissionRate=10),e.emissionDuration===void 0&&(e.emissionDuration=10),e.emissionDurationInfinite===void 0&&(e.emissionDurationInfinite=!1),e.emissionDuration>300&&(e.emissionDurationInfinite=!0,e.emissionDuration=10),e.outerLength===void 0&&(e.outerLength=e.cubeLength??2),e.innerLength===void 0&&(e.innerLength=0),e.outerRadius===void 0&&(e.outerRadius=2),e.innerRadius===void 0&&(e.innerRadius=0),e.squareSize===void 0&&(e.squareSize=2),e.squareInnerSize===void 0&&(e.squareInnerSize=0),e.circleInnerRadius===void 0&&(e.circleInnerRadius=0),e.circleOuterRadius===void 0&&(e.circleOuterRadius=2),e.circleVelocityDirection===void 0&&(e.circleVelocityDirection="outward"),e.cylinderInnerRadius===void 0&&(e.cylinderInnerRadius=0),e.cylinderOuterRadius===void 0&&(e.cylinderOuterRadius=2),e.cylinderHeight===void 0&&(e.cylinderHeight=4),e.cylinderVelocityDirection===void 0&&(e.cylinderVelocityDirection="outward"),e.planeWidth===void 0&&(e.planeWidth=2),e.planeDepth===void 0&&(e.planeDepth=2),e.coneOuterRadius===void 0&&(e.coneOuterRadius=2),e.coneInnerRadius===void 0&&(e.coneInnerRadius=0),e.coneHeight===void 0&&(e.coneHeight=4),e.torusMajorRadius===void 0&&(e.torusMajorRadius=2),e.torusMinorRadius===void 0&&(e.torusMinorRadius=.5),e.lineLength===void 0&&(e.lineLength=4),e.hemisphereOuterRadius===void 0&&(e.hemisphereOuterRadius=2),e.hemisphereInnerRadius===void 0&&(e.hemisphereInnerRadius=0),e.discRadius===void 0&&(e.discRadius=2),e.annulusInnerRadius===void 0&&(e.annulusInnerRadius=1),e.annulusOuterRadius===void 0&&(e.annulusOuterRadius=2),e.capsuleRadius===void 0&&(e.capsuleRadius=.5),e.capsuleHeight===void 0&&(e.capsuleHeight=4),e.arcStartAngle===void 0&&(e.arcStartAngle=0),e.arcEndAngle===void 0&&(e.arcEndAngle=180),e.arcInnerRadius===void 0&&(e.arcInnerRadius=0),e.arcOuterRadius===void 0&&(e.arcOuterRadius=2),e.spiralTurns===void 0&&(e.spiralTurns=3),e.spiralRadiusStart===void 0&&(e.spiralRadiusStart=.5),e.spiralRadiusEnd===void 0&&(e.spiralRadiusEnd=2),e.spiralHeight===void 0&&(e.spiralHeight=4),e.frustumRadiusNear===void 0&&(e.frustumRadiusNear=.5),e.frustumRadiusFar===void 0&&(e.frustumRadiusFar=2),e.frustumHeight===void 0&&(e.frustumHeight=4),e.cubeSurfaceSize===void 0&&(e.cubeSurfaceSize=2),e.sphereSurfaceRadius===void 0&&(e.sphereSurfaceRadius=2),e.boxFrameSize===void 0&&(e.boxFrameSize=2),e.polygonSides===void 0&&(e.polygonSides=6),e.polygonRadius===void 0&&(e.polygonRadius=2),e.emissionRotationX===void 0&&(e.emissionRotationX=0),e.emissionRotationY===void 0&&(e.emissionRotationY=0),e.emissionRotationZ===void 0&&(e.emissionRotationZ=0),e.emissionPositionX===void 0&&(e.emissionPositionX=e.emissionTranslationX??0),e.emissionPositionY===void 0&&(e.emissionPositionY=e.emissionTranslationY??0),e.emissionPositionZ===void 0&&(e.emissionPositionZ=e.emissionTranslationZ??0),e.pulseEnabled===void 0&&(e.pulseEnabled=!1),e.pulseAmplitude===void 0&&(e.pulseAmplitude=.5),e.pulseFrequency===void 0&&(e.pulseFrequency=1),e.pulsePhaseRandom===void 0&&(e.pulsePhaseRandom=0),e.pulseOpacity===void 0&&(e.pulseOpacity=!1),e.confinementEnabled===void 0&&(e.confinementEnabled=!1),e.confinementShape===void 0&&(e.confinementShape="box"),e.confinementMode===void 0&&(e.confinementMode="bounce"),e.confinementSpace===void 0&&(e.confinementSpace="world"),e.confinementBoxHalfSize===void 0&&(e.confinementBoxHalfSize=[2,2,2]),e.confinementSphereRadius===void 0&&(e.confinementSphereRadius=3),e.confinementRestitution===void 0&&(e.confinementRestitution=.8),e.confinementFriction===void 0&&(e.confinementFriction=.1),e.softBoundaryEnabled===void 0&&(e.softBoundaryEnabled=!1),e.softBoundaryStrength===void 0&&(e.softBoundaryStrength=5),e.softBoundaryFalloff===void 0&&(e.softBoundaryFalloff=.5),e.depthWriteEnabled===void 0&&(e.depthWriteEnabled=!1),e.velocityStretchEnabled===void 0&&(e.velocityStretchEnabled=!1),e.velocityStretchFactor===void 0&&(e.velocityStretchFactor=1),e.blendMode===void 0&&(e.blendMode="normal"),e.noiseDistortEnabled===void 0&&(e.noiseDistortEnabled=!1),e.noiseTilingX===void 0&&(e.noiseTilingX=3),e.noiseTilingY===void 0&&(e.noiseTilingY=3),e.noiseSpeed===void 0&&(e.noiseSpeed=-1.5),e.noiseAmplitude===void 0&&(e.noiseAmplitude=.08),e.emissionTrailEnabled===void 0&&(e.emissionTrailEnabled=!1),e.emissionTrailDuration===void 0&&(e.emissionTrailDuration=1),e.emissionTrailWidth===void 0&&(e.emissionTrailWidth=.3),e.emissionTrailMinDistance===void 0&&(e.emissionTrailMinDistance=.05),e.emissionTrailMaxPoints===void 0&&(e.emissionTrailMaxPoints=256),e.emissionTrailSegments===void 0&&(e.emissionTrailSegments=8),e.emissionTrailMode===void 0&&(e.emissionTrailMode="ribbon"),e.emissionTrailShape===void 0&&(e.emissionTrailShape="straight"),e.emissionTrailShapeAmplitude===void 0&&(e.emissionTrailShapeAmplitude=.1),e.emissionTrailShapeFrequency===void 0&&(e.emissionTrailShapeFrequency=4),e.emissionTrailShapeSpeed===void 0&&(e.emissionTrailShapeSpeed=0),e.shapeDisplay===void 0&&(e.shapeDisplay=!0),e.followSystemTranslation===void 0&&(e.followSystemTranslation=!0),e.followSystemId===void 0&&(e.followSystemId=null),this._newEmissions=[],this._emptyEmissions=[],this._pendingFollowEmissions=this._emptyEmissions,this.glbVertexBuffer=null,this.glbIndexBuffer=null,this.glbIndexCount=0,this.glbIndexFormat="uint16",this.glbMeshData=null,this.glbRawArrayBuffer=null,this.glbAnimator=null,this.glbAnimated=!1,this._glbInterleavedData=null,this._appearanceData=new Float32Array(52),this._bloomIntensityData=new Float32Array(16),this._simPosition=[0,0,0],this._simVelocity=[0,0,0],this._simRotMatrix=null,this._simRotX=0,this._simRotZ=0,this._emitSimRotY=0,this.emitter=new _i(e),this.physics=new wi(t,this.MAX_PARTICLES),this.textureManager=new Bi(t),e.gravityEnabled&&this.setGravity(e.gravityStrength||0),e.dampingEnabled&&this.physics.setDamping(e.dampingStrength||0),e.attractorEnabled&&e.attractorPosition&&this.setAttractor(e.attractorStrength||0,e.attractorPosition),e.confinementEnabled&&this.setConfinement({enabled:!0,shape:e.confinementShape,mode:e.confinementMode,space:e.confinementSpace,boxSize:e.confinementBoxHalfSize,sphereRadius:e.confinementSphereRadius,restitution:e.confinementRestitution,friction:e.confinementFriction}),e.softBoundaryEnabled&&this.setSoftBoundary({enabled:!0,strength:e.softBoundaryStrength,falloff:e.softBoundaryFalloff}),this.particleTexture=this.textureManager.getDefaultTexture(),this.updateBloomIntensity(),this.updateAppearanceUniform(),this.frameCount=0,this.shouldReset=!1,this._scriptParticleData=new Float32Array(this.MAX_PARTICLES*8),this._scriptVelocityData=new Float32Array(this.MAX_PARTICLES*4),this._scriptReadbackPending=!1,this._scriptReadbackReady=!1,this._scriptFrame=0,this._scriptTime=0,this._scriptConfigRestored=!1,this._particleScript=null,e.script&&(this._particleScript=new Pt(e.script,e,this.MAX_PARTICLES)),this.initComputePipeline(t)}async initComputePipeline(t){this.computeReady=await this.physics.initComputePipeline(this.instanceBuffer,this.velocityBuffer,this.trailBuffer)}setScript(t){this._particleScript&&(this._particleScript.destroy(),this._particleScript=null),this._scriptReadbackPending=!1,this._scriptReadbackReady=!1,this._scriptFrame=0,this._scriptTime=0,this._scriptConfigRestored=!1,t?(this.config.script=t,this._particleScript=new Pt(t,this.config,this.MAX_PARTICLES),this._particleScript.snapshotConfig(this.config)):delete this.config.script}async setTexture(t){this.destroyed||(this.textureManager.destroyTexture(this.particleTexture),this.particleTexture=await this.textureManager.loadTexture(t),this.config.textureEnabled=!0,this.updateAppearanceUniform(),this.updateBuffers())}resetTexture(){this.destroyed||(this.textureManager.destroyTexture(this.particleTexture),this.particleTexture=this.textureManager.getDefaultTexture(),this.config.textureEnabled=!1,this.updateAppearanceUniform(),this.updateBuffers())}async setGLBModel(t){try{this.glbRawArrayBuffer=t;const e=await Bt(t);this.glbMeshData=e,this.config.glbHasTexture=e.hasBaseColorTexture||!1;const i=new Float32Array(e.vertexCount*8);for(let s=0;s<e.vertexCount;s++){const n=s*8,o=s*3,a=s*2;i[n+0]=e.positions[o+0],i[n+1]=e.positions[o+1],i[n+2]=e.positions[o+2],i[n+3]=e.normals[o+0],i[n+4]=e.normals[o+1],i[n+5]=e.normals[o+2],e.texCoords?(i[n+6]=e.texCoords[a+0],i[n+7]=e.texCoords[a+1]):(i[n+6]=0,i[n+7]=0)}if(this.glbVertexBuffer&&this.glbVertexBuffer.destroy(),this.glbIndexBuffer&&this.glbIndexBuffer.destroy(),this.glbVertexBuffer=this.device.createBuffer({size:i.byteLength,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST|GPUBufferUsage.STORAGE,label:"glbVertexBuffer"}),this.device.queue.writeBuffer(this.glbVertexBuffer,0,i),this.glbIndexBuffer=this.device.createBuffer({size:e.indices.byteLength,usage:GPUBufferUsage.INDEX|GPUBufferUsage.COPY_DST,label:"glbIndexBuffer"}),this.device.queue.writeBuffer(this.glbIndexBuffer,0,e.indices),this.glbIndexCount=e.indexCount,this.glbIndexFormat=e.indices instanceof Uint32Array?"uint32":"uint16",this.config.glbModelEnabled=!0,this.config.textureType="glb",e.animationData){this.glbAnimator=new Ti(e.animationData),this.glbAnimator.setRestPose(e.positions,e.normals),this.glbAnimated=!0,this.config.glbAnimated=!0,this.glbAnimator.loop=this.config.animationLoop,this._glbInterleavedData=new Float32Array(e.vertexCount*8);try{await this.glbAnimator.initGPUSkinning(this.device,this.glbVertexBuffer,e.texCoords)}catch(s){console.warn("GPU skinning init failed, using CPU fallback:",s)}console.log(`GLB animated model loaded: ${e.animationData.animations.length} animations`)}else this.glbAnimator=null,this.glbAnimated=!1,this.config.glbAnimated=!1,this._glbInterleavedData=null;console.log(`GLB model loaded: ${e.vertexCount} vertices, ${e.indexCount} indices`)}catch(e){throw console.error("Failed to load GLB model:",e),e}}resetGLBModel(){this.glbVertexBuffer&&(this.glbVertexBuffer.destroy(),this.glbVertexBuffer=null),this.glbIndexBuffer&&(this.glbIndexBuffer.destroy(),this.glbIndexBuffer=null),this.glbIndexCount=0,this.glbIndexFormat="uint16",this.glbMeshData=null,this.glbRawArrayBuffer=null,this.glbAnimator=null,this.glbAnimated=!1,this.config.glbAnimated=!1,this._glbInterleavedData=null,this.config.glbFileName=null,this.config.glbHasTexture=!1,this.config.useGlbTexture=!1,this.config.glbModelEnabled=!1,this.config.textureType="image"}setSimulationTransform(t){if(t.position&&(this._simPosition[0]=t.position[0],this._simPosition[1]=t.position[1],this._simPosition[2]=t.position[2]),t.rotation){this._simRotX=t.rotation[0]||0,this._simRotZ=t.rotation[1]||0,this._simRotY=t.rotation[2]||0;const e=Math.cos(this._simRotX),i=Math.sin(this._simRotX),s=Math.cos(this._simRotZ),n=Math.sin(this._simRotZ),o=Math.cos(this._simRotY),a=Math.sin(this._simRotY);this._simRotMatrix=[o*s,-o*n*e+a*i,o*n*i+a*e,n,s*e,-s*i,-a*s,a*n*e+o*i,-a*n*i+o*e]}else this._simRotMatrix=null,this._simRotX=0,this._simRotZ=0,this._simRotY=0;t.velocity&&(this._simVelocity[0]=t.velocity[0],this._simVelocity[1]=t.velocity[1],this._simVelocity[2]=t.velocity[2])}clearSimulationTransform(){this._simPosition[0]=this._simPosition[1]=this._simPosition[2]=0,this._simVelocity[0]=this._simVelocity[1]=this._simVelocity[2]=0,this._simRotMatrix=null,this._simRotX=0,this._simRotZ=0}updateAnimatedGLBBuffer(){if(!this.glbAnimator||!this.glbAnimator.playing)return!1;if(this.glbAnimator._gpuSkinningReady)return!0;const t=this.glbAnimator.skinnedPositions,e=this.glbAnimator.skinnedNormals,i=this.glbMeshData.texCoords;for(let s=0;s<this.glbMeshData.vertexCount;s++){const n=s*8,o=s*3,a=s*2;this._glbInterleavedData[n]=t[o],this._glbInterleavedData[n+1]=t[o+1],this._glbInterleavedData[n+2]=t[o+2],this._glbInterleavedData[n+3]=e[o],this._glbInterleavedData[n+4]=e[o+1],this._glbInterleavedData[n+5]=e[o+2],i?(this._glbInterleavedData[n+6]=i[a],this._glbInterleavedData[n+7]=i[a+1]):(this._glbInterleavedData[n+6]=0,this._glbInterleavedData[n+7]=0)}return this.device.queue.writeBuffer(this.glbVertexBuffer,0,this._glbInterleavedData),!0}updateAppearanceUniform(){if(this.destroyed)return;let t=0;this.config.rotationMode==="random"?t=1:this.config.rotationMode==="velocity"&&(t=2);const i={square:0,circle:1,triangle:2,diamond:3,star:4,hexagon:5,ring:6,heart:7,cross:8,spark:9,leaf:10,capsule:11,crescent:12,line:13,"curved-line":14}[this.config.particleShape]??0,s=this._appearanceData;s[0]=this.config.fadeEnabled?1:0,s[1]=this.config.randomColorEnabled?2:this.config.colorTransitionEnabled?1:0,s[2]=this.config.particleSize,s[3]=this.config.textureEnabled?1:0,s[4]=this.config.particleColor[0],s[5]=this.config.particleColor[1],s[6]=this.config.particleColor[2],s[7]=this.config.rotation||0,s[8]=this.config.startColor[0],s[9]=this.config.startColor[1],s[10]=this.config.startColor[2],s[11]=t,s[12]=this.config.endColor[0],s[13]=this.config.endColor[1],s[14]=this.config.endColor[2],s[15]=this.config.minRotation||0,s[16]=this.config.maxRotation||90,s[17]=this.config.aspectRatio||1,s[18]=this.config.randomSize?1:0,s[19]=this.config.minSize||.1,s[20]=this.config.maxSize||.5,s[21]=this.config.fadeSizeEnabled?1:0,s[22]=this.config.opacity!==void 0?this.config.opacity:1,s[23]=this.config.increaseSizeEnabled?1:0,s[24]=this.config.sizeLifetimeSpeed??1,s[25]=i,s[26]=0,s[27]=this.config.pulseEnabled?1:0,s[28]=this.config.pulseAmplitude??.5,s[29]=this.config.pulseFrequency??1,s[30]=this.config.pulsePhaseRandom??0,s[31]=this.config.pulseOpacity?1:0,s[32]=this.config.particleShapeRotationX||0,s[33]=this.config.particleShapeRotationY||0,s[34]=this.config.particleShapeRotationZ||0,s[35]=0,(s[32]!==0||s[33]!==0||s[34]!==0)&&console.log(`[updateAppearanceUniform] ${this.config.name}: d[32-34] = ${s[32]}, ${s[33]}, ${s[34]}`);const n=this.config.followSystemTranslation??!0;s[36]=n?this._simPosition[0]:0,s[37]=n?this._simPosition[1]:0,s[38]=n?this._simPosition[2]:0,s[39]=0,s[40]=this._simRotX,s[41]=this._simRotZ,s[42]=this.config.velocityStretchEnabled?1:0,s[43]=this.config.velocityStretchFactor??1,s[44]=this.config.noiseDistortEnabled?1:0,s[45]=this.config.noiseTilingX??3,s[46]=this.config.noiseTilingY??3,s[47]=this.config.noiseSpeed??-1.5,s[48]=this.config.noiseAmplitude??.08,s[49]=n?this._simVelocity[0]:0,s[50]=n?this._simVelocity[1]:0,s[51]=n?this._simVelocity[2]:0,this.device.queue.writeBuffer(this.appearanceUniformBuffer,0,s)}updateBloomIntensity(){const t=this._bloomIntensityData;t[0]=this.config.bloomIntensity||1;const e=this.config.bloomColor||[1,1,1];t[4]=e[0],t[5]=e[1],t[6]=e[2],this.device.queue.writeBuffer(this.bloomIntensityBuffer,0,t)}spawnParticles(){if(this.activeParticles=0,this.currentEmissionTime=0,this._newEmissions.length=0,this._pendingFollowEmissions=this._emptyEmissions,this._scriptFrame=0,this._scriptTime=0,this._scriptReadbackPending=!1,this._scriptReadbackReady=!1,this._scriptConfigRestored=!1,this._particleScript&&(this._particleScript._configSnapshot?(this._particleScript.restoreConfig(this.config),this.config.gravityEnabled&&this.setGravity(this.config.gravityStrength),this.config.dampingEnabled&&this.physics.setDamping(this.config.dampingStrength),this.config.attractorEnabled&&this.setAttractor(this.config.attractorStrength,this.config.attractorPosition),this.updateAppearanceUniform(),this.updateBloomIntensity()):this._particleScript.snapshotConfig(this.config)),this.device.queue.writeBuffer(this.trailBuffer,0,this._trailResetData,0,this.MAX_PARTICLES*4),this.glbAnimator&&(this.glbAnimator.currentTime=0,this.glbAnimator.playing=!0),this.config.followSystemId){this.emitting=!0,this.particleCount=this.MAX_PARTICLES;return}if(this.config.burstMode){const t=this.config.particleCount;this.particleCount=t;let e=0;const i=500;for(let s=0;s<t;s++)if(this.emitParticle(),e++,e>=i||s===t-1){const n=s-e+1,o=n*8,a=n*4;this.device.queue.writeBuffer(this.instanceBuffer,o*4,this.particleData,o,e*8),this.device.queue.writeBuffer(this.velocityBuffer,a*4,this.particleVelocities,a,e*4),e=0}this.emitting=!1}else{this.emitting=!0;const t=this.config.lifetime||5,e=this.config.emissionDurationInfinite?t:Math.min(this.config.emissionDuration||10,t);this.particleCount=Math.min(Math.ceil((this.config.emissionRate||10)*e),this.MAX_PARTICLES)}}get effectiveEmissionDuration(){return this.config.emissionDurationInfinite?1/0:this.config.emissionDuration??10}_applySimTransformToParticle(t){this._emitSimRotY=this._simRotY||0;const e=t*8,i=t*4;if(this._simRotMatrix){const s=this._simRotMatrix,n=this.particleData[e],o=this.particleData[e+1],a=this.particleData[e+2],c=this.particleVelocities[i],l=this.particleVelocities[i+1],u=this.particleVelocities[i+2];this.particleData[e]=s[0]*n+s[1]*o+s[2]*a,this.particleData[e+1]=s[3]*n+s[4]*o+s[5]*a,this.particleData[e+2]=s[6]*n+s[7]*o+s[8]*a,this.particleVelocities[i]=s[0]*c+s[1]*l+s[2]*u,this.particleVelocities[i+1]=s[3]*c+s[4]*l+s[5]*u,this.particleVelocities[i+2]=s[6]*c+s[7]*l+s[8]*u}(this.config.followSystemTranslation??!0)||(this.particleData[e]+=this._simPosition[0],this.particleData[e+1]+=this._simPosition[1],this.particleData[e+2]+=this._simPosition[2])}emitParticle(){if(this.activeParticles>=this.particleCount)return!1;this.emitter.emitParticle(this.particleData,this.activeParticles,this.particleVelocities);const t=this.activeParticles*8,e=this.activeParticles*4;return this._applySimTransformToParticle(this.activeParticles),this._newEmissions.push(this.particleData[t],this.particleData[t+1],this.particleData[t+2],this.particleVelocities[e],this.particleVelocities[e+1],this.particleVelocities[e+2]),this.activeParticles++,!0}emitFollowerParticle(t,e,i){if(this.activeParticles>=this.particleCount)return!1;const s=this.activeParticles*8,n=t+(this.config.emissionPositionX||0),o=e+(this.config.emissionPositionY||0),a=i+(this.config.emissionPositionZ||0);this.particleData[s]=n,this.particleData[s+1]=o,this.particleData[s+2]=a;const c=this.activeParticles*4;return this.emitter.calculateVelocity(n,o,a,this.particleVelocities,c),this.emitter.setParticleColor(this.particleData,s),this.emitter.setParticleLifetime(this.particleData,s),this.activeParticles++,!0}updateParticles(t,e){if(this._particleScript&&this._scriptReadbackReady){this._scriptReadbackReady=!1,this._scriptTime+=t,this._scriptFrame++;const a=this.config.emissionDurationInfinite?1/0:(this.config.emissionDuration||0)+(this.config.lifetime||0);if(a>0&&this._scriptTime>=a&&!this._scriptConfigRestored)this._scriptConfigRestored=!0,this._particleScript._configSnapshot&&(this._particleScript.restoreConfig(this.config),this.updateAppearanceUniform(),this.updateBloomIntensity(),this.config.gravityEnabled&&this.setGravity(this.config.gravityStrength),this.config.dampingEnabled&&this.physics.setDamping(this.config.dampingStrength),this.config.attractorEnabled&&this.setAttractor(this.config.attractorStrength,this.config.attractorPosition));else if(!this._scriptConfigRestored){const c=a>0?Math.ceil(a/.016666666666666666):0,{configDirty:l,particlesDirty:u}=this._particleScript.execute(t,this._scriptTime,this._scriptFrame,c,this._scriptParticleData,this._scriptVelocityData,this.activeParticles);u&&this.activeParticles>0&&(this.device.queue.writeBuffer(this.instanceBuffer,0,this._scriptParticleData,0,this.activeParticles*8),this.device.queue.writeBuffer(this.velocityBuffer,0,this._scriptVelocityData,0,this.activeParticles*4)),l&&(this.updateAppearanceUniform(),this.updateBloomIntensity(),this.config.gravityEnabled&&this.setGravity(this.config.gravityStrength),this.config.dampingEnabled&&this.physics.setDamping(this.config.dampingStrength),this.config.attractorEnabled&&this.setAttractor(this.config.attractorStrength,this.config.attractorPosition))}}this.physics.physicsAccumulator+=t;const i=performance.now()/1e3,n=i-this.physics.lastUpdateTime>1/this.physics.minUpdatesPerSecond,o=this.activeParticles;if(!this.emitting&&!this.config.burstMode&&!this.config.followSystemId&&this.currentEmissionTime<this.effectiveEmissionDuration&&(this.emitting=!0),this.emitting)if(this.currentEmissionTime+=t,this.currentEmissionTime<this.effectiveEmissionDuration){const a=this.activeParticles;let c=!1;if(this.config.followSystemId){if(this._pendingFollowEmissions.length>0){const l=this._pendingFollowEmissions.length/6;for(let u=0;u<l;u++){const f=u*6;if(this.emitFollowerParticle(this._pendingFollowEmissions[f],this._pendingFollowEmissions[f+1],this._pendingFollowEmissions[f+2]))c=!0;else break}}}else{let l=0;if(this.config.emissionRate>=1){l=Math.floor(this.config.emissionRate*t);const u=this.config.emissionRate*t-l;Math.random()<u&&(l+=1)}else{const u=this.config.emissionRate*t;Math.random()<u&&(l=1)}l===0&&n&&this.config.emissionRate>0&&this.activeParticles<this.particleCount&&(l=1);for(let u=0;u<l&&this.emitParticle();u++)c=!0}if(c){const l=this.activeParticles-a,u=a*8,f=a*4;this.device.queue.writeBuffer(this.instanceBuffer,u*4,this.particleData,u,l*8),this.device.queue.writeBuffer(this.velocityBuffer,f*4,this.particleVelocities,f,l*4)}}else this.emitting=!1,this.currentEmissionTime=this.config.emissionDuration;for(;this.physics.physicsAccumulator>=this.physics.fixedDeltaTime;)this.physics.updatePhysics(this.physics.fixedDeltaTime,o,this.config,this.instanceBuffer,this.velocityBuffer,e),this.physics.physicsAccumulator-=this.physics.fixedDeltaTime,this.physics.physicsClock+=this.physics.fixedDeltaTime;n&&o>0&&(this.physics.updatePhysics(this.physics.fixedDeltaTime,o,this.config,this.instanceBuffer,this.velocityBuffer,e),this.physics.lastUpdateTime=i),this.frameCount++,(this.activeParticles>=this.particleCount||this.frameCount%300===0)&&this.readbackAndProcessParticles(),this._particleScript&&this.activeParticles>0&&!this._scriptReadbackPending&&(this._scriptReadbackPending=!0,this.physics.readbackForScript(this.activeParticles,this._scriptParticleData,this._scriptVelocityData,this.instanceBuffer,this.velocityBuffer).then(a=>{this._scriptReadbackPending=!1,a.shouldUpdate&&(this._scriptReadbackReady=!0)}).catch(()=>{this._scriptReadbackPending=!1}))}async readbackAndProcessParticles(){if(!(this.activeParticles<=0))try{if(!(await this.physics.readbackAndProcessParticles(this.activeParticles,this.particleData,this.particleVelocities,this.instanceBuffer,this.velocityBuffer)).shouldUpdate)return;let e=0,i=!1;for(let s=0;s<this.activeParticles;s++){const n=this.particleData[s*8+6],o=this.particleData[s*8+7];if(n>=o){if(this.emitting&&this.currentEmissionTime<this.effectiveEmissionDuration&&e<this.particleCount){this.respawnParticle(s,e),e++,i=!0;continue}continue}if(e!==s){const a=s*8,c=e*8;this.particleData.copyWithin(c,a,a+8);const l=s*4,u=e*4;this.particleVelocities.copyWithin(u,l,l+4),i=!0}e++}(e!==this.activeParticles||i)&&(this.activeParticles=e,this.device.queue.writeBuffer(this.instanceBuffer,0,this.particleData,0,this.activeParticles*8),this.device.queue.writeBuffer(this.velocityBuffer,0,this.particleVelocities,0,this.activeParticles*4))}catch(t){t&&t.name==="AbortError"||console.error("Error reading back particle data:",t)}}respawnParticle(t,e){!this.emitting||this.currentEmissionTime>=this.effectiveEmissionDuration||this.config.followSystemId||(this.emitter.emitParticle(this.particleData,e,this.particleVelocities),this._applySimTransformToParticle(e))}updateBuffers(){this.destroyed||!this.particleData||this.activeParticles>0&&this.device.queue.writeBuffer(this.instanceBuffer,0,this.particleData,0,this.activeParticles*8)}updateParticleColors(){if(!(this.destroyed||!this.particleData)){for(let t=0;t<this.activeParticles;t++){const e=t*8;if(this.config.randomColorEnabled&&this.config.randomColors.length>0){const i=this.config.randomColors,s=i[Math.floor(Math.random()*i.length)];this.particleData[e+3]=s[0],this.particleData[e+4]=s[1],this.particleData[e+5]=s[2]}else this.config.colorTransitionEnabled?(this.particleData[e+3]=this.config.startColor[0],this.particleData[e+4]=this.config.startColor[1],this.particleData[e+5]=this.config.startColor[2]):(this.particleData[e+3]=this.config.particleColor[0],this.particleData[e+4]=this.config.particleColor[1],this.particleData[e+5]=this.config.particleColor[2])}this.activeParticles>0&&this.device.queue.writeBuffer(this.instanceBuffer,0,this.particleData,0,this.activeParticles*8)}}updateParticleVelocities(){for(let t=0;t<this.activeParticles;t++){const e=t*8,i=t*4,s=this.particleData[e],n=this.particleData[e+1],o=this.particleData[e+2],a=this.particleVelocities[i],c=this.particleVelocities[i+1],l=this.particleVelocities[i+2],u=Math.sqrt(a*a+c*c+l*l);if(u>.001){const f=this.config.particleSpeed*2;this.particleVelocities[i]=a/u*f,this.particleVelocities[i+1]=c/u*f,this.particleVelocities[i+2]=l/u*f}else{const f=Math.sqrt(s*s+n*n+o*o);if(f>.001){const h=this.config.particleSpeed*2;this.particleVelocities[i]=s/f*h,this.particleVelocities[i+1]=n/f*h,this.particleVelocities[i+2]=o/f*h}else this.particleVelocities[i]=0,this.particleVelocities[i+1]=this.config.particleSpeed*2,this.particleVelocities[i+2]=0}}this.activeParticles>0&&this.device.queue.writeBuffer(this.velocityBuffer,0,this.particleVelocities,0,this.activeParticles*4)}async readbackForRendering(t,e){return this.physics.readbackForRendering(this.activeParticles,t,e,this.instanceBuffer,this.velocityBuffer)}destroy(){this.destroyed=!0,this.instanceBuffer.destroy(),this.velocityBuffer.destroy(),this.trailBuffer.destroy(),this.appearanceUniformBuffer.destroy(),this.bloomIntensityBuffer.destroy(),this.physics.destroy(),this.glbVertexBuffer&&(this.glbVertexBuffer.destroy(),this.glbVertexBuffer=null),this.glbIndexBuffer&&(this.glbIndexBuffer.destroy(),this.glbIndexBuffer=null),this.textureManager.destroyTexture(this.particleTexture),this._particleScript&&(this._particleScript.destroy(),this._particleScript=null),this.glbAnimator=null,this.glbMeshData=null,this.glbRawArrayBuffer=null,this.particleData=null,this.particleVelocities=null,this._scriptParticleData=null,this._scriptVelocityData=null}setGravity(t){this.physics.setGravity(t)}setAttractor(t,e){this.physics.setAttractor(t,e)}setConfinement(t){const e=t.center||this.config.confinementCenter||[0,0,0],i=t.space==="local"?[this.config.emissionPositionX||0,this.config.emissionPositionY||0,this.config.emissionPositionZ||0]:[0,0,0],s=[i[0]+(e[0]||0),i[1]+(e[1]||0),i[2]+(e[2]||0)];this.physics.setConfinement({...t,center:s})}setSoftBoundary(t){this.physics.setSoftBoundary(t)}}class Ei{constructor(t){this.device=t,this.particleSystems=[],this.activeSystemIndex=0,this.systemCounter=1,this.onSystemCreated=null,this.loop=void 0,this.ready=!0}createParticleSystem(t={}){const e=this.systemCounter++,i=t.name||`System ${e+1}`,s={...t,name:i,id:e},n=new at(this.device,s);return this.particleSystems.push({system:n,config:s}),this.particleSystems.length===1&&(this.activeSystemIndex=0),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(e,s),e}getActiveSystem(){return this.particleSystems.length===0?null:this.particleSystems[this.activeSystemIndex].system}getActiveConfig(){return this.particleSystems.length===0?null:this.particleSystems[this.activeSystemIndex].config}setActiveSystem(t){return t>=0&&t<this.particleSystems.length?(this.activeSystemIndex=t,!0):!1}getSystemById(t){return this.particleSystems.find(({config:e})=>e.id===t)||null}destroy(){for(const{system:t}of this.particleSystems)t.destroy();this.particleSystems=[],this.activeSystemIndex=0}removeSystem(t){if(t>=0&&t<this.particleSystems.length){const e=this.particleSystems[t].config;this.particleSystems[t].system.destroy(),this.particleSystems.splice(t,1);const i=e.id;for(const{config:s}of this.particleSystems)s.followSystemId===i&&(s.followSystemId=null);return this.particleSystems.length===0?this.activeSystemIndex=0:t<=this.activeSystemIndex&&(this.activeSystemIndex=Math.max(0,this.activeSystemIndex-1)),!0}return!1}respawnAllSystems(){for(const{system:t}of this.particleSystems)t.spawnParticles()}updateAllSystems(t){const e=this.device.createCommandEncoder({label:"BatchedPhysicsEncoder"});let i=!1;for(const{system:s,config:n}of this.particleSystems){if(n.hidden||n.followSystemId)continue;const o=s.activeParticles>0;s.updateParticles(t,e),(o||s.activeParticles>0)&&(i=!0)}for(const{system:s,config:n}of this.particleSystems){if(n.hidden||!n.followSystemId)continue;const o=this.getSystemById(n.followSystemId);o&&(s._pendingFollowEmissions=o.system._newEmissions);const a=s.activeParticles>0;s.updateParticles(t,e),(a||s.activeParticles>0)&&(i=!0)}i&&this.device.queue.submit([e.finish()]);for(const{system:s}of this.particleSystems)s._newEmissions.length=0,s._pendingFollowEmissions=s._emptyEmissions}getSystemsList(){return this.particleSystems.map(({config:t},e)=>({name:t.name,id:t.id,index:e,isActive:e===this.activeSystemIndex,hidden:t.hidden||!1}))}duplicateActiveSystem(){if(this.particleSystems.length===0)return-1;const t=this.getActiveConfig(),e=JSON.parse(JSON.stringify(t));return e.name=`${t.name} (Copy)`,e.onAppearanceChange=null,e.onColorChange=null,e.onSizeChange=null,e.onSpeedChange=null,e.onPhysicsChange=null,e.onBloomIntensityChange=null,e.onRespawn=null,e.getActiveSystem=null,delete e.id,this.createParticleSystem(e)}async replaceSystems(t){var e;if(!t||!t.systems||!Array.isArray(t.systems))return console.error("Invalid scene data provided"),!1;this.ready=!1;try{this.particleSystems=[],this.systemCounter=1;for(const s of t.systems){const n=this.systemCounter++,o={...s,id:n},a=new at(this.device,o);this.particleSystems.push({system:a,config:o})}const i={};t.systems.forEach((s,n)=>{i[s.id]=this.particleSystems[n].config.id});for(const{config:s}of this.particleSystems)s.followSystemId&&i[s.followSystemId]!==void 0&&(s.followSystemId=i[s.followSystemId]);t.activeSystemIndex!==void 0&&t.activeSystemIndex>=0&&t.activeSystemIndex<this.particleSystems.length?this.activeSystemIndex=t.activeSystemIndex:this.activeSystemIndex=0,this.loop=t.loop;for(const{system:s,config:n}of this.particleSystems)if(n.glbModelEnabled)try{let o=null;if(n.glbModelData)o=bi(n.glbModelData);else if(n.glbFileName){const a=await fetch(`/${n.glbFileName}`);a.ok?o=await a.arrayBuffer():console.warn(`GLB file not found: ${n.glbFileName}`)}if(o){if(await s.setGLBModel(o),n.animationIndex!==void 0&&s.glbAnimator&&s.glbAnimator.setAnimation(n.animationIndex),n.animationSpeed!==void 0&&s.glbAnimator&&(s.glbAnimator.speed=n.animationSpeed),n.animationLoop!==void 0&&s.glbAnimator&&(s.glbAnimator.loop=n.animationLoop),n.useGlbTexture&&(n.textureEnabled=!0),n.useGlbTexture&&((e=s.glbMeshData)!=null&&e.hasBaseColorTexture))try{const{extractGLBTexture:a}=await Promise.resolve().then(()=>hi),c=await a(o);if(c){const l=await createImageBitmap(c.imageBlob);await s.setTexture(l),console.log(`GLB embedded texture restored for ${n.name}`)}}catch(a){console.warn(`Failed to restore GLB texture for ${n.name}:`,a),n.useGlbTexture=!1}}else n.glbModelEnabled=!1}catch(o){console.warn(`Failed to load GLB for ${n.name}:`,o),n.glbModelEnabled=!1}for(const{system:s,config:n}of this.particleSystems)if(n.textureEnabled&&!n.glbModelEnabled&&n.textureImageData)try{const o=new Image;await new Promise((c,l)=>{o.onload=c,o.onerror=l,o.src=n.textureImageData});const a=await createImageBitmap(o);await s.setTexture(a)}catch(o){console.warn(`Failed to restore texture for ${n.name}:`,o),n.textureEnabled=!1}for(const{system:s,config:n}of this.particleSystems)s.updateAppearanceUniform(),(n.particleShapeRotationX||n.particleShapeRotationY||n.particleShapeRotationZ)&&console.log(`[replaceSystems] ${n.name}: glbRotation XYZ = ${n.particleShapeRotationX}, ${n.particleShapeRotationY}, ${n.particleShapeRotationZ} | glbModelEnabled=${n.glbModelEnabled} | glbMeshData=${!!s.glbMeshData}`);return this.respawnAllSystems(),!0}catch(i){return console.error("Error replacing systems:",i),!1}finally{this.ready=!0}}async addSystems(t,e=[0,0,0]){var s;if(!t||!t.systems||!Array.isArray(t.systems))return console.error("Invalid scene data provided"),!1;this.ready=!1;const i=[];try{for(const a of t.systems){const c=this.systemCounter++;i.push(c);const l={...a,id:c,emissionPositionX:(a.emissionPositionX||0)+e[0],emissionPositionY:(a.emissionPositionY||0)+e[1],emissionPositionZ:(a.emissionPositionZ||0)+e[2]};a.attractorEnabled&&a.attractorPosition&&(l.attractorPosition=[a.attractorPosition[0]+e[0],a.attractorPosition[1]+e[1],a.attractorPosition[2]+e[2]]);const u=new at(this.device,l);this.particleSystems.push({system:u,config:l}),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(c,l)}const n=this.particleSystems.length-t.systems.length,o={};t.systems.forEach((a,c)=>{o[a.id]=this.particleSystems[n+c].config.id});for(let a=n;a<this.particleSystems.length;a++){const{config:c}=this.particleSystems[a];c.followSystemId&&o[c.followSystemId]!==void 0&&(c.followSystemId=o[c.followSystemId])}for(const{system:a,config:c}of this.particleSystems)if(c.glbModelEnabled&&!a.glbMeshData)try{let l=null;if(c.glbModelData)l=bi(c.glbModelData);else if(c.glbFileName){const u=await fetch(`/${c.glbFileName}`);u.ok?l=await u.arrayBuffer():console.warn(`GLB file not found: ${c.glbFileName}`)}if(l){if(await a.setGLBModel(l),c.animationIndex!==void 0&&a.glbAnimator&&a.glbAnimator.setAnimation(c.animationIndex),c.animationSpeed!==void 0&&a.glbAnimator&&(a.glbAnimator.speed=c.animationSpeed),c.animationLoop!==void 0&&a.glbAnimator&&(a.glbAnimator.loop=c.animationLoop),c.useGlbTexture&&(c.textureEnabled=!0),c.useGlbTexture&&((s=a.glbMeshData)!=null&&s.hasBaseColorTexture))try{const{extractGLBTexture:u}=await Promise.resolve().then(()=>hi),f=await u(l);if(f){const h=await createImageBitmap(f.imageBlob);await a.setTexture(h),console.log(`GLB embedded texture restored for ${c.name}`)}}catch(u){console.warn(`Failed to restore GLB texture for ${c.name}:`,u),c.useGlbTexture=!1}}else c.glbModelEnabled=!1}catch(l){console.warn(`Failed to load GLB for ${c.name}:`,l),c.glbModelEnabled=!1}for(const{system:a,config:c}of this.particleSystems)if(c.textureEnabled&&!c.glbModelEnabled&&c.textureImageData&&!a._textureRestored)try{const l=new Image;await new Promise((f,h)=>{l.onload=f,l.onerror=h,l.src=c.textureImageData});const u=await createImageBitmap(l);await a.setTexture(u),a._textureRestored=!0}catch(l){console.warn(`Failed to restore texture for ${c.name}:`,l),c.textureEnabled=!1}return i}catch(n){return console.error("Error adding systems:",n),!1}finally{this.ready=!0}}}async function Ci(r){if(!r)throw new Error("canvas is required for initWebGPU()");if(!navigator.gpu)throw new Error("WebGPU not supported on this browser.");const t=r.getContext("webgpu"),i=await(await navigator.gpu.requestAdapter()).requestDevice(),s=navigator.gpu.getPreferredCanvasFormat();return t.configure({device:i,format:s,alphaMode:"premultiplied"}),{device:i,context:t,format:s,canvas:r}}const le="rgba16float";function _t(r,t,e,i){const s=r.createTexture({size:[e,i],format:le,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1}),n=r.createTexture({size:[e,i],format:le,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1}),o=r.createTexture({size:[e,i],format:le,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1});return{sceneTexture:s,bloomTexA:n,bloomTexB:o}}function wt(r,t,e){return r.createTexture({size:[t,e],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT})}function Ce(r,t,e){const i=r.createBuffer({size:t.byteLength,usage:e,mappedAtCreation:!0});return new t.constructor(i.getMappedRange()).set(t),i.unmap(),i}const Rt=`
11
11
  struct Uniforms {
12
12
  transform: mat4x4<f32>,
13
13
  cameraPosition: vec3<f32>,
@@ -52,6 +52,14 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
52
52
  simRotZ: f32, // simulation rotation Z (radians)
53
53
  velocityStretchEnabled: f32, // 0=off, 1=on
54
54
  velocityStretchFactor: f32, // multiplier for stretch (0-10)
55
+ noiseDistortEnabled: f32, // 0=off, 1=on — UV distortion by scrolling noise (flames)
56
+ noiseTilingX: f32, // noise tiling along U
57
+ noiseTilingY: f32, // noise tiling along V
58
+ noiseSpeed: f32, // vertical scroll speed (negative = noise rises, flame dances upward)
59
+ noiseAmplitude: f32, // UV distortion amplitude
60
+ systemVelX: f32, // emitter/system world velocity (for velocity-aligned rotation
61
+ systemVelY: f32, // of trail particles that move WITH the emitter, e.g. a ball —
62
+ systemVelZ: f32, // their local velocity is ~0 so they need the system velocity)
55
63
  }
56
64
 
57
65
  @binding(0) @group(0) var<uniform> uniforms : Uniforms;
@@ -73,6 +81,22 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
73
81
  @location(0) color : vec3<f32>,
74
82
  @location(1) alpha : f32,
75
83
  @location(2) texCoord : vec2<f32>,
84
+ @location(3) noiseOffset : vec2<f32>,
85
+ }
86
+
87
+ fn hash21(p: vec2<f32>) -> f32 {
88
+ return fract(sin(dot(p, vec2<f32>(127.1, 311.7))) * 43758.5453);
89
+ }
90
+
91
+ fn valueNoise(p: vec2<f32>) -> f32 {
92
+ let i = floor(p);
93
+ let f = fract(p);
94
+ let u = f * f * (3.0 - 2.0 * f);
95
+ let a = hash21(i);
96
+ let b = hash21(i + vec2<f32>(1.0, 0.0));
97
+ let c = hash21(i + vec2<f32>(0.0, 1.0));
98
+ let d = hash21(i + vec2<f32>(1.0, 1.0));
99
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
76
100
  }
77
101
 
78
102
  @vertex
@@ -150,9 +174,13 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
150
174
  fract(sin(lifetime * 12345.67) * 43758.5453) *
151
175
  (appearance.maxRotation - appearance.minRotation);
152
176
  } else if (appearance.rotationMode == 2.0) {
153
- // Calculate rotation based on velocity direction in screen space
154
- // Transform velocity from world to view space to get correct orientation
155
- let viewVelocity = (uniforms.transform * vec4<f32>(input.particleVelocity, 0.0)).xyz;
177
+ // Calculate rotation based on velocity direction in screen space. Use the COMBINED velocity
178
+ // (particle-local + system/emitter): a trail particle riding a moving emitter (e.g. the driven
179
+ // ball) has ~0 local velocity, so without the system term it would never align to the motion
180
+ // ("la particule ne suit jamais la direction de la vélocité"). Stays a camera-facing billboard,
181
+ // just rotated to point along the movement.
182
+ let combinedVel = input.particleVelocity + vec3<f32>(appearance.systemVelX, appearance.systemVelY, appearance.systemVelZ);
183
+ let viewVelocity = (uniforms.transform * vec4<f32>(combinedVel, 0.0)).xyz;
156
184
 
157
185
  // Calculate the angle from the transformed velocity
158
186
  // We only care about the XY plane in screen space
@@ -215,6 +243,14 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
215
243
  // Convert the quad position to texture coordinates (0,0 to 1,1)
216
244
  output.texCoord = vec2<f32>(input.position.x + 0.5, -input.position.y + 0.5);
217
245
 
246
+ // Per-particle phase (seeded from lifetime) desynchronizes flames sharing
247
+ // the same system; y carries the vertical noise scroll over time.
248
+ let noisePhase = fract(sin(lifetime * 76543.21) * 43758.5453) * 6.283185;
249
+ output.noiseOffset = vec2<f32>(
250
+ noisePhase,
251
+ uniforms.elapsedTime * appearance.noiseSpeed + noisePhase
252
+ );
253
+
218
254
  return output;
219
255
  }
220
256
 
@@ -331,13 +367,27 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
331
367
  }
332
368
 
333
369
  if (appearance.textureEnabled > 0.5) {
334
- let texColor = textureSample(particleTexture, particleSampler, input.texCoord);
370
+ var sampleUV = input.texCoord;
371
+ if (appearance.noiseDistortEnabled > 0.5) {
372
+ // Flame-style distortion: a scrolling noise field offsets the sample UV
373
+ // (n = noise(uv×tiling + (phase, t×speed + phase)) − 0.5)
374
+ let nUV = input.texCoord * vec2<f32>(appearance.noiseTilingX, appearance.noiseTilingY)
375
+ + input.noiseOffset;
376
+ let n1 = valueNoise(nUV) - 0.5;
377
+ let n2 = valueNoise(nUV + vec2<f32>(13.7, 7.3)) - 0.5;
378
+ sampleUV = clamp(
379
+ input.texCoord + vec2<f32>(n1, n2) * appearance.noiseAmplitude,
380
+ vec2<f32>(0.001, 0.001),
381
+ vec2<f32>(0.999, 0.999)
382
+ );
383
+ }
384
+ let texColor = textureSample(particleTexture, particleSampler, sampleUV);
335
385
  return vec4<f32>(input.color * texColor.rgb, alpha * texColor.a);
336
386
  } else {
337
387
  return vec4<f32>(input.color, alpha);
338
388
  }
339
389
  }
340
- `,G=`
390
+ `,Mt=`
341
391
  struct BloomUniforms {
342
392
  direction: vec2<f32>,
343
393
  resolution: vec2<f32>,
@@ -397,7 +447,7 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
397
447
 
398
448
  return result / totalWeight * 1.1;
399
449
  }
400
- `,V=`
450
+ `,Tt=`
401
451
  struct BloomIntensityUniforms {
402
452
  intensity: f32,
403
453
  color: vec3<f32>,
@@ -443,7 +493,7 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
443
493
 
444
494
  return vec4<f32>(originalColor.rgb + (mappedBloom * bloomUniforms.intensity), originalColor.a);
445
495
  }
446
- `,L=`
496
+ `,Et=`
447
497
  struct BloomIntensityUniforms {
448
498
  intensity: f32,
449
499
  color: vec3<f32>,
@@ -484,7 +534,39 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
484
534
  fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
485
535
  return textureSample(originalTexture, texSampler, input.texCoord);
486
536
  }
487
- `,ee=`
537
+ `,Ai=`
538
+ @binding(0) @group(0) var texSampler: sampler;
539
+ @binding(1) @group(0) var originalTexture: texture_2d<f32>;
540
+ @binding(2) @group(0) var blurredTexture: texture_2d<f32>;
541
+ struct BloomIntensityUniforms { intensity: f32, color: vec3<f32> }
542
+ @binding(3) @group(0) var<uniform> bloomUniforms: BloomIntensityUniforms;
543
+
544
+ struct VertexOutput {
545
+ @builtin(position) position: vec4<f32>,
546
+ @location(0) texCoord: vec2<f32>,
547
+ }
548
+
549
+ @vertex
550
+ fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
551
+ var output: VertexOutput;
552
+ let positions = array<vec2<f32>, 3>(vec2<f32>(-1.0, -1.0), vec2<f32>(3.0, -1.0), vec2<f32>(-1.0, 3.0));
553
+ let texCoords = array<vec2<f32>, 3>(vec2<f32>(0.0, 1.0), vec2<f32>(2.0, 1.0), vec2<f32>(0.0, -1.0));
554
+ output.position = vec4<f32>(positions[vertexIndex], 0.0, 1.0);
555
+ output.texCoord = texCoords[vertexIndex];
556
+ return output;
557
+ }
558
+
559
+ fn aces(x: vec3<f32>) -> vec3<f32> {
560
+ let a = 2.51; let b = 0.03; let c = 2.43; let d = 0.59; let e = 0.14;
561
+ return clamp((x * (a * x + b)) / (x * (c * x + d) + e), vec3<f32>(0.0), vec3<f32>(1.0));
562
+ }
563
+
564
+ @fragment
565
+ fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
566
+ let c = textureSample(originalTexture, texSampler, input.texCoord);
567
+ return vec4<f32>(aces(c.rgb), c.a);
568
+ }
569
+ `,Ui=`
488
570
  struct PhysicsUniforms {
489
571
  deltaTime: f32,
490
572
  particleSpeed: f32,
@@ -694,7 +776,7 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
694
776
  particleBuffer[baseIndex + 1u] = newPos.y;
695
777
  particleBuffer[baseIndex + 2u] = newPos.z;
696
778
  }
697
- `,Re=`
779
+ `,Xs=`
698
780
  @group(0) @binding(0) var<storage, read> restData: array<f32>;
699
781
  @group(0) @binding(1) var<storage, read> jointWeightsData: array<f32>;
700
782
  @group(0) @binding(2) var<storage, read> jointIndicesData: array<u32>;
@@ -750,7 +832,7 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
750
832
  outputData[outBase + 6u] = uv_u;
751
833
  outputData[outBase + 7u] = uv_v;
752
834
  }
753
- `,te=Object.freeze(Object.defineProperty({__proto__:null,blurShader:G,compositeShader:V,directRenderShader:L,particlePhysicsShader:ee,particleShader:D,skinningComputeShader:Re},Symbol.toStringTag,{value:"Module"})),ie=`
835
+ `,Ii=Object.freeze(Object.defineProperty({__proto__:null,blurShader:Mt,compositeShader:Tt,directRenderShader:Et,finalCompositeShader:Ai,particlePhysicsShader:Ui,particleShader:Rt,skinningComputeShader:Xs},Symbol.toStringTag,{value:"Module"})),Gi=`
754
836
  struct Uniforms {
755
837
  transform: mat4x4<f32>,
756
838
  cameraPosition: vec3<f32>,
@@ -812,7 +894,7 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
812
894
 
813
895
  return finalColor;
814
896
  }
815
- `,se=`
897
+ `,Di=`
816
898
  struct Uniforms {
817
899
  transform: mat4x4<f32>,
818
900
  cameraPosition: vec3<f32>,
@@ -1047,4 +1129,20 @@ return function(__deltaTime, __time, __currentFrame, __totalFrames, __particles,
1047
1129
 
1048
1130
  return finalColor;
1049
1131
  }
1050
- `;function we(c){const t=c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,sampler:{}}]}),e=c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),i=c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),s=c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]});return{particleBindGroupLayout:t,bloomBindGroupLayout:e,compositeBindGroupLayout:i,object3dBindGroupLayout:s}}function Be(c,t,e,i={}){const{depthCompare:s}=i,a=s||"less",{particleBindGroupLayout:n,bloomBindGroupLayout:o,compositeBindGroupLayout:r,object3dBindGroupLayout:l}=e,d=c.createPipelineLayout({bindGroupLayouts:[n]}),u=c.createPipelineLayout({bindGroupLayouts:[o]}),f=c.createPipelineLayout({bindGroupLayouts:[r]}),h=c.createShaderModule({code:D}),p=c.createShaderModule({code:G}),m=c.createShaderModule({code:V}),b=c.createShaderModule({code:L}),S=c.createShaderModule({code:ie}),y=c.createShaderModule({code:se}),_=c.createRenderPipeline({layout:d,vertex:{module:h,entryPoint:"vs_main",buffers:[{arrayStride:12,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"}]},{arrayStride:32,stepMode:"instance",attributes:[{shaderLocation:1,offset:0,format:"float32x3"},{shaderLocation:2,offset:12,format:"float32x3"},{shaderLocation:3,offset:24,format:"float32x2"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:4,offset:0,format:"float32x3"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:5,offset:0,format:"float32x3"}]}]},fragment:{module:h,entryPoint:"fs_main",targets:[{format:t,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!1,depthCompare:a,format:"depth24plus"}}),g=c.createRenderPipeline({layout:d,vertex:{module:h,entryPoint:"vs_main",buffers:[{arrayStride:12,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"}]},{arrayStride:32,stepMode:"instance",attributes:[{shaderLocation:1,offset:0,format:"float32x3"},{shaderLocation:2,offset:12,format:"float32x3"},{shaderLocation:3,offset:24,format:"float32x2"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:4,offset:0,format:"float32x3"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:5,offset:0,format:"float32x3"}]}]},fragment:{module:h,entryPoint:"fs_main",targets:[{format:t,writeMask:0}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!0,depthCompare:"always",format:"depth24plus"}}),x=c.createRenderPipeline({layout:u,vertex:{module:p,entryPoint:"vs_main"},fragment:{module:p,entryPoint:"fs_main",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),P=c.createRenderPipeline({layout:f,vertex:{module:m,entryPoint:"vs_main"},fragment:{module:m,entryPoint:"fs_main",targets:[{format:t,blend:{color:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list"}}),M=c.createRenderPipeline({layout:f,vertex:{module:b,entryPoint:"vs_main"},fragment:{module:b,entryPoint:"fs_main",targets:[{format:t,blend:{color:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list"}}),w=c.createPipelineLayout({bindGroupLayouts:[l]}),B=c.createRenderPipeline({layout:w,vertex:{module:S,entryPoint:"vs_main",buffers:[{arrayStride:24,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:12,format:"float32x3"}]}]},fragment:{module:S,entryPoint:"fs_main",targets:[{format:t,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:a,format:"depth24plus"}}),R=c.createRenderPipeline({layout:d,vertex:{module:y,entryPoint:"vs_main",buffers:[{arrayStride:32,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:12,format:"float32x3"},{shaderLocation:2,offset:24,format:"float32x2"}]},{arrayStride:32,stepMode:"instance",attributes:[{shaderLocation:3,offset:0,format:"float32x3"},{shaderLocation:4,offset:12,format:"float32x3"},{shaderLocation:5,offset:24,format:"float32x2"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:6,offset:0,format:"float32x3"}]}]},fragment:{module:y,entryPoint:"fs_main",targets:[{format:t,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:a,format:"depth24plus"}});return{particlePipeline:_,particleDepthWritePipeline:g,blurPipeline:x,compositePipeline:P,directRenderPipeline:M,object3dPipeline:B,glbMeshPipeline:R}}function Te(c,t,e,i){const{uniformBuffer:s,appearanceUniformBuffer:a,horizontalBlurUniformBuffer:n,verticalBlurUniformBuffer:o,bloomIntensityBuffer:r}=e,{sceneTexture:l,bloomTexA:d,bloomTexB:u}=i,f=c.createBindGroup({layout:c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:{buffer:s}},{binding:1,resource:{buffer:a}}]}),h=c.createBindGroup({layout:c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:l.createView()},{binding:2,resource:{buffer:n}}]}),p=c.createBindGroup({layout:c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:d.createView()},{binding:2,resource:{buffer:o}}]}),m=c.createBindGroup({layout:c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:l.createView()},{binding:2,resource:u.createView()},{binding:3,resource:{buffer:r}}]}),b=c.createBindGroup({layout:c.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:l.createView()},{binding:2,resource:u.createView()},{binding:3,resource:{buffer:r}}]});return{particleBindGroup:f,horizontalBlurBindGroup:h,verticalBlurBindGroup:p,compositeBindGroup:m,directRenderBindGroup:b}}function Ce(c){return c.createSampler({magFilter:"linear",minFilter:"linear",mipmapFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",maxAnisotropy:16})}function re(){const c=new Float32Array([-.5,-.5,.5,0,0,1,.5,-.5,.5,0,0,1,.5,.5,.5,0,0,1,-.5,.5,.5,0,0,1,.5,-.5,-.5,0,0,-1,-.5,-.5,-.5,0,0,-1,-.5,.5,-.5,0,0,-1,.5,.5,-.5,0,0,-1,-.5,.5,.5,0,1,0,.5,.5,.5,0,1,0,.5,.5,-.5,0,1,0,-.5,.5,-.5,0,1,0,-.5,-.5,-.5,0,-1,0,.5,-.5,-.5,0,-1,0,.5,-.5,.5,0,-1,0,-.5,-.5,.5,0,-1,0,.5,-.5,.5,1,0,0,.5,-.5,-.5,1,0,0,.5,.5,-.5,1,0,0,.5,.5,.5,1,0,0,-.5,-.5,-.5,-1,0,0,-.5,-.5,.5,-1,0,0,-.5,.5,.5,-1,0,0,-.5,.5,-.5,-1,0,0]),t=new Uint16Array([0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23]);return{vertices:c,indices:t}}function ae(c=16,t=16){const e=[],i=[];for(let s=0;s<=c;s++){const a=s*Math.PI/c,n=Math.sin(a),o=Math.cos(a);for(let r=0;r<=t;r++){const l=r*2*Math.PI/t,d=Math.sin(l),f=Math.cos(l)*n,h=o,p=d*n;e.push(f*.5,h*.5,p*.5),e.push(f,h,p)}}for(let s=0;s<c;s++)for(let a=0;a<t;a++){const n=s*(t+1)+a,o=n+t+1;i.push(n),i.push(o),i.push(n+1),i.push(o),i.push(o+1),i.push(n+1)}return{vertices:new Float32Array(e),indices:new Uint16Array(i)}}class Ee{constructor(t,e,i,s,a){this.id=t,this.type=e,this.position=i,this.scale=s,this.color=a,this.rotation=[0,0,0]}getModelMatrix(){const{position:t,scale:e,rotation:i}=this,s=this.createTranslationMatrix(t),a=this.createRotationMatrixX(i[0]),n=this.createRotationMatrixY(i[1]),o=this.createRotationMatrixZ(i[2]),r=this.createScaleMatrix(e);let l=s;return l=this.multiplyMatrices(l,o),l=this.multiplyMatrices(l,n),l=this.multiplyMatrices(l,a),l=this.multiplyMatrices(l,r),l}getNormalMatrix(){return this.getModelMatrix()}createTranslationMatrix([t,e,i]){return new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,t,e,i,1])}createScaleMatrix([t,e,i]){return new Float32Array([t,0,0,0,0,e,0,0,0,0,i,0,0,0,0,1])}createRotationMatrixX(t){const e=Math.cos(t),i=Math.sin(t);return new Float32Array([1,0,0,0,0,e,i,0,0,-i,e,0,0,0,0,1])}createRotationMatrixY(t){const e=Math.cos(t),i=Math.sin(t);return new Float32Array([e,0,-i,0,0,1,0,0,i,0,e,0,0,0,0,1])}createRotationMatrixZ(t){const e=Math.cos(t),i=Math.sin(t);return new Float32Array([e,i,0,0,-i,e,0,0,0,0,1,0,0,0,0,1])}multiplyMatrices(t,e){const i=new Float32Array(16);for(let s=0;s<4;s++)for(let a=0;a<4;a++){let n=0;for(let o=0;o<4;o++)n+=t[s*4+o]*e[o*4+a];i[s*4+a]=n}return i}}class Ae{constructor(t){this.device=t,this.objects=[],this.nextId=0,this.initializeGeometry(),this.onObjectAdded=null,this.onObjectRemoved=null,this.onObjectUpdated=null}initializeGeometry(){const t=re(),e=ae(16,16);this.cubeVertexBuffer=T(this.device,t.vertices,GPUBufferUsage.VERTEX),this.cubeIndexBuffer=T(this.device,t.indices,GPUBufferUsage.INDEX),this.cubeIndexCount=t.indices.length,this.sphereVertexBuffer=T(this.device,e.vertices,GPUBufferUsage.VERTEX),this.sphereIndexBuffer=T(this.device,e.indices,GPUBufferUsage.INDEX),this.sphereIndexCount=e.indices.length}addObject(t,e=[0,0,0],i=[1,1,1],s=[1,1,1,1]){const a=new Ee(this.nextId++,t,e,i,s);return a.uniformBuffer=this.device.createBuffer({size:192,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.objects.push(a),this.onObjectAdded&&this.onObjectAdded(a),a}removeObject(t){const e=this.objects.findIndex(i=>i.id===t);e!==-1&&(this.objects[e].uniformBuffer.destroy(),this.objects.splice(e,1),this.onObjectRemoved&&this.onObjectRemoved(t))}updateObjectPosition(t,e){const i=this.objects.find(s=>s.id===t);i&&(i.position=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectScale(t,e){const i=this.objects.find(s=>s.id===t);i&&(i.scale=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectColor(t,e){const i=this.objects.find(s=>s.id===t);i&&(i.color=e,this.onObjectUpdated&&this.onObjectUpdated(i))}getAllObjects(){return this.objects}getObject(t){return this.objects.find(e=>e.id===t)}updateObjectUniforms(t){const e=t.getModelMatrix(),i=t.getNormalMatrix(),s=new Float32Array(t.color);this.device.queue.writeBuffer(t.uniformBuffer,0,e),this.device.queue.writeBuffer(t.uniformBuffer,64,i),this.device.queue.writeBuffer(t.uniformBuffer,128,s)}renderObjects(t,e,i,s){for(const a of this.objects){this.updateObjectUniforms(a);const n=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:{buffer:s}},{binding:1,resource:{buffer:a.uniformBuffer}}]});let o,r,l;if(a.type==="cube")o=this.cubeVertexBuffer,r=this.cubeIndexBuffer,l=this.cubeIndexCount;else if(a.type==="sphere")o=this.sphereVertexBuffer,r=this.sphereIndexBuffer,l=this.sphereIndexCount;else continue;t.setPipeline(e),t.setBindGroup(0,n),t.setVertexBuffer(0,o),t.setIndexBuffer(r,"uint16"),t.drawIndexed(l)}}}function Ie(c){const t=parseInt(c.slice(1,3),16)/255,e=parseInt(c.slice(3,5),16)/255,i=parseInt(c.slice(5,7),16)/255;return[t,e,i]}function Ue(c){if(!c)return"#ffffff";const t=Math.round(c[0]*255).toString(16).padStart(2,"0"),e=Math.round(c[1]*255).toString(16).padStart(2,"0"),i=Math.round(c[2]*255).toString(16).padStart(2,"0");return`#${t}${e}${i}`}function ze(c,t,e){const i=q([c[0]-t[0],c[1]-t[1],c[2]-t[2]]),s=q(Z(e,i)),a=Z(i,s);return new Float32Array([s[0],a[0],i[0],0,s[1],a[1],i[1],0,s[2],a[2],i[2],0,-I(s,c),-I(a,c),-I(i,c),1])}function Fe(c,t=Math.PI/4){const s=1/Math.tan(t/2);return new Float32Array([s*c,0,0,0,0,s,0,0,0,0,(100+.1)/(.1-100),-1,0,0,200*.1/(.1-100),0])}function q(c){const t=Math.sqrt(c[0]*c[0]+c[1]*c[1]+c[2]*c[2]);return[c[0]/t,c[1]/t,c[2]/t]}function Z(c,t){return[c[1]*t[2]-c[2]*t[1],c[2]*t[0]-c[0]*t[2],c[0]*t[1]-c[1]*t[0]]}function I(c,t){return c[0]*t[0]+c[1]*t[1]+c[2]*t[2]}function De(c,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let s=0;s<4;s++){let a=0;for(let n=0;n<4;n++)a+=c[i+n*4]*t[n+s*4];e[i+s*4]=a}return e}function Ge(c){const t=new Uint8Array(c);let e="";for(let i=0;i<t.byteLength;i++)e+=String.fromCharCode(t[i]);return btoa(e)}function Ve(c,t){if(!c||!c.particleSystems||c.particleSystems.length===0){alert("No particle systems to save.");return}try{const e={version:"1.0",timestamp:new Date().toISOString(),systems:c.particleSystems.map(({config:r,system:l})=>({name:r.name,id:r.id,particleCount:r.particleCount,lifetime:r.lifetime,emissionRate:r.emissionRate,emissionDuration:r.emissionDuration,particleSize:r.particleSize,particleSpeed:r.particleSpeed,emissionShape:r.emissionShape,cubeLength:r.outerLength||r.cubeLength,outerLength:r.outerLength||r.cubeLength,innerLength:r.innerLength,outerRadius:r.outerRadius,innerRadius:r.innerRadius,squareSize:r.squareSize,squareInnerSize:r.squareInnerSize,circleInnerRadius:r.circleInnerRadius,circleOuterRadius:r.circleOuterRadius,fadeEnabled:r.fadeEnabled,colorTransitionEnabled:r.colorTransitionEnabled,particleColor:r.particleColor,startColor:r.startColor,endColor:r.endColor,randomColorEnabled:r.randomColorEnabled||!1,randomColors:r.randomColors||[],particleShape:r.particleShape||"square",particleShapeRotation:r.particleShapeRotation||0,particleShapeRotationX:r.particleShapeRotationX||0,particleShapeRotationY:r.particleShapeRotationY||0,particleShapeRotationZ:r.particleShapeRotationZ||0,pulseEnabled:r.pulseEnabled||!1,pulseAmplitude:r.pulseAmplitude??.5,pulseFrequency:r.pulseFrequency??1,pulsePhaseRandom:r.pulsePhaseRandom??0,pulseOpacity:r.pulseOpacity||!1,bloomEnabled:r.bloomEnabled,bloomIntensity:r.bloomIntensity,burstMode:r.burstMode,gravityEnabled:r.gravityEnabled,gravityStrength:r.gravityStrength,dampingEnabled:r.dampingEnabled,dampingStrength:r.dampingStrength,attractorEnabled:r.attractorEnabled,attractorStrength:r.attractorStrength,attractorPosition:r.attractorPosition,emissionRotationX:r.emissionRotationX,emissionRotationY:r.emissionRotationY,emissionRotationZ:r.emissionRotationZ,emissionTranslationX:r.emissionTranslationX,emissionTranslationY:r.emissionTranslationY,emissionTranslationZ:r.emissionTranslationZ,rotation:r.rotation,rotationMode:r.rotationMode,minRotation:r.minRotation,maxRotation:r.maxRotation,overrideXVelocity:r.overrideXVelocity,overrideYVelocity:r.overrideYVelocity,overrideZVelocity:r.overrideZVelocity,xVelocity:r.xVelocity,yVelocity:r.yVelocity,zVelocity:r.zVelocity,circleVelocityDirection:r.circleVelocityDirection,cylinderVelocityDirection:r.cylinderVelocityDirection,cylinderInnerRadius:r.cylinderInnerRadius,cylinderOuterRadius:r.cylinderOuterRadius,cylinderHeight:r.cylinderHeight,aspectRatio:r.aspectRatio,randomSize:r.randomSize,minSize:r.minSize,maxSize:r.maxSize,fadeSizeEnabled:r.fadeSizeEnabled,increaseSizeEnabled:r.increaseSizeEnabled,sizeLifetimeSpeed:r.sizeLifetimeSpeed,opacity:r.opacity,randomSpeed:r.randomSpeed,minSpeed:r.minSpeed,maxSpeed:r.maxSpeed,textureEnabled:r.textureEnabled,textureType:r.textureType,glbModelEnabled:r.glbModelEnabled,glbFileName:r.glbFileName,glbAnimated:r.glbAnimated,animationIndex:r.animationIndex,animationSpeed:r.animationSpeed,animationLoop:r.animationLoop,useGlbTexture:r.useGlbTexture,oneOnlyMode:r.oneOnlyMode,confinementEnabled:r.confinementEnabled||!1,confinementShape:r.confinementShape||"box",confinementMode:r.confinementMode||"bounce",confinementSpace:r.confinementSpace||"world",confinementBoxHalfSize:r.confinementBoxHalfSize||[2,2,2],confinementSphereRadius:r.confinementSphereRadius??3,confinementRestitution:r.confinementRestitution??.8,confinementFriction:r.confinementFriction??.1,softBoundaryEnabled:r.softBoundaryEnabled||!1,softBoundaryStrength:r.softBoundaryStrength??5,softBoundaryFalloff:r.softBoundaryFalloff??.5,followSystemId:r.followSystemId||null,hidden:r.hidden||!1,emissionTrailEnabled:r.emissionTrailEnabled||!1,emissionTrailDuration:r.emissionTrailDuration??1,emissionTrailWidth:r.emissionTrailWidth??.5,emissionTrailMinDistance:r.emissionTrailMinDistance??.05,emissionTrailMaxPoints:r.emissionTrailMaxPoints??100,emissionTrailSegments:r.emissionTrailSegments??8,emissionTrailShape:r.emissionTrailShape??"straight",emissionTrailShapeAmplitude:r.emissionTrailShapeAmplitude??.1,emissionTrailShapeFrequency:r.emissionTrailShapeFrequency??4,emissionTrailShapeSpeed:r.emissionTrailShapeSpeed??0,shapeDisplay:r.shapeDisplay??!0,followSystemTranslation:r.followSystemTranslation??!0,script:r.script||void 0,textureImageData:r.textureEnabled&&!r.glbModelEnabled&&r.textureImageData?r.textureImageData:void 0,glbModelData:r.glbModelEnabled&&l.glbRawArrayBuffer?Ge(l.glbRawArrayBuffer):void 0})),activeSystemIndex:c.activeSystemIndex},i=JSON.stringify(e,null,2);let s;if(t)s=`${t}.json`;else{const r=new Date;s=`particle-scene_${`${r.getFullYear()}-${(r.getMonth()+1).toString().padStart(2,"0")}-${r.getDate().toString().padStart(2,"0")}_${r.getHours().toString().padStart(2,"0")}${r.getMinutes().toString().padStart(2,"0")}`}.json`}const a=new Blob([i],{type:"application/json"}),n=URL.createObjectURL(a),o=document.createElement("a");o.href=n,o.download=s,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n)}catch(e){console.error("Error saving scene:",e),alert("Error saving scene. See console for details.")}}function Le(c){return new Promise((t,e)=>{try{const i=c.target.files[0];if(!i){e(new Error("No file selected"));return}const s=new FileReader;s.onload=a=>{try{const n=JSON.parse(a.target.result);if(!n.version)throw new Error("Invalid scene file: missing version information");if(!Array.isArray(n.systems)||n.systems.length===0)throw new Error("No valid particle systems found in the file");const o=[];for(const r of n.systems)o.push(r);t({systems:o,activeSystemIndex:n.activeSystemIndex||0})}catch(n){console.error("Error loading scene:",n),alert("Error loading scene: "+n.message),e(n)}c.target.value=""},s.onerror=()=>{alert("Failed to read the file"),e(new Error("Failed to read the file")),c.target.value=""},s.readAsText(i)}catch(i){console.error("Error in loadScene:",i),e(i)}})}async function Oe(c){if(!c||typeof c!="string")throw new Error("[fetchPreset] url must be a non-empty string");const t=await fetch(c);if(!t.ok)throw new Error(`[fetchPreset] HTTP ${t.status}: ${t.statusText}`);const e=await t.json();if(!Array.isArray(e.systems)||e.systems.length===0)throw new Error('[fetchPreset] Invalid preset: "systems" must be a non-empty array');return{version:e.version,systems:e.systems,activeSystemIndex:e.activeSystemIndex??0}}exports.GLBAnimator=Q;exports.Objects3DManager=Ae;exports.ParticleEmitter=$;exports.ParticlePhysics=H;exports.ParticleScript=z;exports.ParticleSystem=E;exports.ParticleSystemManager=ve;exports.ParticleTextureManager=W;exports.blurShader=G;exports.compositeShader=V;exports.createBindGroupLayouts=we;exports.createBindGroups=Te;exports.createBuffer=T;exports.createCubeGeometry=re;exports.createDepthTexture=Me;exports.createLookAtMatrix=ze;exports.createProjectionMatrix=Fe;exports.createRenderPipelines=Be;exports.createRenderTextures=Pe;exports.createSampler=Ce;exports.createSphereGeometry=ae;exports.directRenderShader=L;exports.extractGLBTexture=K;exports.fetchPreset=Oe;exports.glbMeshParticleShader=se;exports.hexToRgb=Ie;exports.initWebGPU=_e;exports.loadScene=Le;exports.multiplyMatrices=De;exports.object3dShader=ie;exports.parseGLB=F;exports.particlePhysicsShader=ee;exports.particleShader=D;exports.rgbToHex=Ue;exports.saveScene=Ve;
1132
+ `;function zi(r){const t=r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,sampler:{}}]}),e=r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),i=r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),s=r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]});return{particleBindGroupLayout:t,bloomBindGroupLayout:e,compositeBindGroupLayout:i,object3dBindGroupLayout:s}}function Vi(r,t,e,i={}){const{depthCompare:s}=i,n=s||"less",{particleBindGroupLayout:o,bloomBindGroupLayout:a,compositeBindGroupLayout:c,object3dBindGroupLayout:l}=e,u=r.createPipelineLayout({bindGroupLayouts:[o]}),f=r.createPipelineLayout({bindGroupLayouts:[a]}),h=r.createPipelineLayout({bindGroupLayouts:[c]}),m=r.createShaderModule({code:Rt}),S=r.createShaderModule({code:Mt}),R=r.createShaderModule({code:Tt}),D=r.createShaderModule({code:Et}),C=r.createShaderModule({code:Gi}),B=r.createShaderModule({code:Di}),A=lt=>r.createRenderPipeline({layout:u,vertex:{module:m,entryPoint:"vs_main",buffers:[{arrayStride:12,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"}]},{arrayStride:32,stepMode:"instance",attributes:[{shaderLocation:1,offset:0,format:"float32x3"},{shaderLocation:2,offset:12,format:"float32x3"},{shaderLocation:3,offset:24,format:"float32x2"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:4,offset:0,format:"float32x3"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:5,offset:0,format:"float32x3"}]}]},fragment:{module:m,entryPoint:"fs_main",targets:[{format:le,blend:lt}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!1,depthCompare:n,format:"depth24plus"}}),P=A({color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}),_=A({color:{srcFactor:"src-alpha",dstFactor:"one",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}),T=r.createRenderPipeline({layout:u,vertex:{module:m,entryPoint:"vs_main",buffers:[{arrayStride:12,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"}]},{arrayStride:32,stepMode:"instance",attributes:[{shaderLocation:1,offset:0,format:"float32x3"},{shaderLocation:2,offset:12,format:"float32x3"},{shaderLocation:3,offset:24,format:"float32x2"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:4,offset:0,format:"float32x3"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:5,offset:0,format:"float32x3"}]}]},fragment:{module:m,entryPoint:"fs_main",targets:[{format:le,writeMask:0}]},primitive:{topology:"triangle-list",cullMode:"none"},depthStencil:{depthWriteEnabled:!0,depthCompare:"always",format:"depth24plus"}}),L=r.createRenderPipeline({layout:f,vertex:{module:S,entryPoint:"vs_main"},fragment:{module:S,entryPoint:"fs_main",targets:[{format:le}]},primitive:{topology:"triangle-list"}}),N=r.createRenderPipeline({layout:h,vertex:{module:R,entryPoint:"vs_main"},fragment:{module:R,entryPoint:"fs_main",targets:[{format:le,blend:{color:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list"}}),k=r.createRenderPipeline({layout:h,vertex:{module:D,entryPoint:"vs_main"},fragment:{module:D,entryPoint:"fs_main",targets:[{format:le,blend:{color:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list"}}),X=r.createShaderModule({code:Ai}),z=r.createRenderPipeline({layout:h,vertex:{module:X,entryPoint:"vs_main"},fragment:{module:X,entryPoint:"fs_main",targets:[{format:t,blend:{color:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list"}}),me=r.createPipelineLayout({bindGroupLayouts:[l]}),De=r.createRenderPipeline({layout:me,vertex:{module:C,entryPoint:"vs_main",buffers:[{arrayStride:24,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:12,format:"float32x3"}]}]},fragment:{module:C,entryPoint:"fs_main",targets:[{format:le,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:n,format:"depth24plus"}}),ze=r.createRenderPipeline({layout:u,vertex:{module:B,entryPoint:"vs_main",buffers:[{arrayStride:32,stepMode:"vertex",attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:12,format:"float32x3"},{shaderLocation:2,offset:24,format:"float32x2"}]},{arrayStride:32,stepMode:"instance",attributes:[{shaderLocation:3,offset:0,format:"float32x3"},{shaderLocation:4,offset:12,format:"float32x3"},{shaderLocation:5,offset:24,format:"float32x2"}]},{arrayStride:16,stepMode:"instance",attributes:[{shaderLocation:6,offset:0,format:"float32x3"}]}]},fragment:{module:B,entryPoint:"fs_main",targets:[{format:le,blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha",operation:"add"},alpha:{srcFactor:"one",dstFactor:"one-minus-src-alpha",operation:"add"}}}]},primitive:{topology:"triangle-list",cullMode:"back"},depthStencil:{depthWriteEnabled:!0,depthCompare:n,format:"depth24plus"}});return{particlePipeline:P,particleAdditivePipeline:_,particleDepthWritePipeline:T,blurPipeline:L,compositePipeline:N,directRenderPipeline:k,finalCompositePipeline:z,object3dPipeline:De,glbMeshPipeline:ze}}function ot(r,t,e,i){const{uniformBuffer:s,appearanceUniformBuffer:n,horizontalBlurUniformBuffer:o,verticalBlurUniformBuffer:a,bloomIntensityBuffer:c}=e,{sceneTexture:l,bloomTexA:u,bloomTexB:f}=i,h=r.createBindGroup({layout:r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.VERTEX|GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:{buffer:s}},{binding:1,resource:{buffer:n}}]}),m=r.createBindGroup({layout:r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:l.createView()},{binding:2,resource:{buffer:o}}]}),S=r.createBindGroup({layout:r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:u.createView()},{binding:2,resource:{buffer:a}}]}),R=r.createBindGroup({layout:r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:l.createView()},{binding:2,resource:f.createView()},{binding:3,resource:{buffer:c}}]}),D=r.createBindGroup({layout:r.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,sampler:{}},{binding:1,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:2,visibility:GPUShaderStage.FRAGMENT,texture:{}},{binding:3,visibility:GPUShaderStage.FRAGMENT,buffer:{type:"uniform"}}]}),entries:[{binding:0,resource:t},{binding:1,resource:l.createView()},{binding:2,resource:f.createView()},{binding:3,resource:{buffer:c}}]});return{particleBindGroup:h,horizontalBlurBindGroup:m,verticalBlurBindGroup:S,compositeBindGroup:R,directRenderBindGroup:D}}function Fi(r){return r.createSampler({magFilter:"linear",minFilter:"linear",mipmapFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",maxAnisotropy:16})}function Oi(){const r=new Float32Array([-.5,-.5,.5,0,0,1,.5,-.5,.5,0,0,1,.5,.5,.5,0,0,1,-.5,.5,.5,0,0,1,.5,-.5,-.5,0,0,-1,-.5,-.5,-.5,0,0,-1,-.5,.5,-.5,0,0,-1,.5,.5,-.5,0,0,-1,-.5,.5,.5,0,1,0,.5,.5,.5,0,1,0,.5,.5,-.5,0,1,0,-.5,.5,-.5,0,1,0,-.5,-.5,-.5,0,-1,0,.5,-.5,-.5,0,-1,0,.5,-.5,.5,0,-1,0,-.5,-.5,.5,0,-1,0,.5,-.5,.5,1,0,0,.5,-.5,-.5,1,0,0,.5,.5,-.5,1,0,0,.5,.5,.5,1,0,0,-.5,-.5,-.5,-1,0,0,-.5,-.5,.5,-1,0,0,-.5,.5,.5,-1,0,0,-.5,.5,-.5,-1,0,0]),t=new Uint16Array([0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23]);return{vertices:r,indices:t}}function Li(r=16,t=16){const e=[],i=[];for(let s=0;s<=r;s++){const n=s*Math.PI/r,o=Math.sin(n),a=Math.cos(n);for(let c=0;c<=t;c++){const l=c*2*Math.PI/t,u=Math.sin(l),h=Math.cos(l)*o,m=a,S=u*o;e.push(h*.5,m*.5,S*.5),e.push(h,m,S)}}for(let s=0;s<r;s++)for(let n=0;n<t;n++){const o=s*(t+1)+n,a=o+t+1;i.push(o),i.push(a),i.push(o+1),i.push(a),i.push(a+1),i.push(o+1)}return{vertices:new Float32Array(e),indices:new Uint16Array(i)}}class ks{constructor(t,e,i,s,n){this.id=t,this.type=e,this.position=i,this.scale=s,this.color=n,this.rotation=[0,0,0]}getModelMatrix(){const{position:t,scale:e,rotation:i}=this,s=this.createTranslationMatrix(t),n=this.createRotationMatrixX(i[0]),o=this.createRotationMatrixY(i[1]),a=this.createRotationMatrixZ(i[2]),c=this.createScaleMatrix(e);let l=s;return l=this.multiplyMatrices(l,a),l=this.multiplyMatrices(l,o),l=this.multiplyMatrices(l,n),l=this.multiplyMatrices(l,c),l}getNormalMatrix(){return this.getModelMatrix()}createTranslationMatrix([t,e,i]){return new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,t,e,i,1])}createScaleMatrix([t,e,i]){return new Float32Array([t,0,0,0,0,e,0,0,0,0,i,0,0,0,0,1])}createRotationMatrixX(t){const e=Math.cos(t),i=Math.sin(t);return new Float32Array([1,0,0,0,0,e,i,0,0,-i,e,0,0,0,0,1])}createRotationMatrixY(t){const e=Math.cos(t),i=Math.sin(t);return new Float32Array([e,0,-i,0,0,1,0,0,i,0,e,0,0,0,0,1])}createRotationMatrixZ(t){const e=Math.cos(t),i=Math.sin(t);return new Float32Array([e,i,0,0,-i,e,0,0,0,0,1,0,0,0,0,1])}multiplyMatrices(t,e){const i=new Float32Array(16);for(let s=0;s<4;s++)for(let n=0;n<4;n++){let o=0;for(let a=0;a<4;a++)o+=t[s*4+a]*e[a*4+n];i[s*4+n]=o}return i}}class js{constructor(t){this.device=t,this.objects=[],this.nextId=0,this.initializeGeometry(),this.onObjectAdded=null,this.onObjectRemoved=null,this.onObjectUpdated=null}initializeGeometry(){const t=Oi(),e=Li(16,16);this.cubeVertexBuffer=Ce(this.device,t.vertices,GPUBufferUsage.VERTEX),this.cubeIndexBuffer=Ce(this.device,t.indices,GPUBufferUsage.INDEX),this.cubeIndexCount=t.indices.length,this.sphereVertexBuffer=Ce(this.device,e.vertices,GPUBufferUsage.VERTEX),this.sphereIndexBuffer=Ce(this.device,e.indices,GPUBufferUsage.INDEX),this.sphereIndexCount=e.indices.length}addObject(t,e=[0,0,0],i=[1,1,1],s=[1,1,1,1]){const n=new ks(this.nextId++,t,e,i,s);return n.uniformBuffer=this.device.createBuffer({size:192,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.objects.push(n),this.onObjectAdded&&this.onObjectAdded(n),n}removeObject(t){const e=this.objects.findIndex(i=>i.id===t);e!==-1&&(this.objects[e].uniformBuffer.destroy(),this.objects.splice(e,1),this.onObjectRemoved&&this.onObjectRemoved(t))}updateObjectPosition(t,e){const i=this.objects.find(s=>s.id===t);i&&(i.position=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectScale(t,e){const i=this.objects.find(s=>s.id===t);i&&(i.scale=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectColor(t,e){const i=this.objects.find(s=>s.id===t);i&&(i.color=e,this.onObjectUpdated&&this.onObjectUpdated(i))}getAllObjects(){return this.objects}getObject(t){return this.objects.find(e=>e.id===t)}updateObjectUniforms(t){const e=t.getModelMatrix(),i=t.getNormalMatrix(),s=new Float32Array(t.color);this.device.queue.writeBuffer(t.uniformBuffer,0,e),this.device.queue.writeBuffer(t.uniformBuffer,64,i),this.device.queue.writeBuffer(t.uniformBuffer,128,s)}renderObjects(t,e,i,s){for(const n of this.objects){this.updateObjectUniforms(n);const o=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:{buffer:s}},{binding:1,resource:{buffer:n.uniformBuffer}}]});let a,c,l;if(n.type==="cube")a=this.cubeVertexBuffer,c=this.cubeIndexBuffer,l=this.cubeIndexCount;else if(n.type==="sphere")a=this.sphereVertexBuffer,c=this.sphereIndexBuffer,l=this.sphereIndexCount;else continue;t.setPipeline(e),t.setBindGroup(0,o),t.setVertexBuffer(0,a),t.setIndexBuffer(c,"uint16"),t.drawIndexed(l)}}}function Ys(r){const t=parseInt(r.slice(1,3),16)/255,e=parseInt(r.slice(3,5),16)/255,i=parseInt(r.slice(5,7),16)/255;return[t,e,i]}function Hs(r){if(!r)return"#ffffff";const t=Math.round(r[0]*255).toString(16).padStart(2,"0"),e=Math.round(r[1]*255).toString(16).padStart(2,"0"),i=Math.round(r[2]*255).toString(16).padStart(2,"0");return`#${t}${e}${i}`}function qs(r,t,e){const i=Si([r[0]-t[0],r[1]-t[1],r[2]-t[2]]),s=Si(xi(e,i)),n=xi(i,s);return new Float32Array([s[0],n[0],i[0],0,s[1],n[1],i[1],0,s[2],n[2],i[2],0,-xt(s,r),-xt(n,r),-xt(i,r),1])}function Zs(r,t=Math.PI/4){const s=1/Math.tan(t/2);return new Float32Array([s*r,0,0,0,0,s,0,0,0,0,(100+.1)/(.1-100),-1,0,0,200*.1/(.1-100),0])}function Si(r){const t=Math.sqrt(r[0]*r[0]+r[1]*r[1]+r[2]*r[2]);return[r[0]/t,r[1]/t,r[2]/t]}function xi(r,t){return[r[1]*t[2]-r[2]*t[1],r[2]*t[0]-r[0]*t[2],r[0]*t[1]-r[1]*t[0]]}function xt(r,t){return r[0]*t[0]+r[1]*t[1]+r[2]*t[2]}function Ni(r,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let s=0;s<4;s++){let n=0;for(let o=0;o<4;o++)n+=r[i+o*4]*t[o+s*4];e[i+s*4]=n}return e}const Ct=1481005640,Xi=1,ki=1313821514,ji=5130562,qe="$hzfxAsset",Yi=r=>typeof atob=="function"?Uint8Array.from(atob(r),t=>t.charCodeAt(0)):new Uint8Array(Buffer.from(r,"base64")),vi=r=>{if(typeof btoa=="function"){let t="";for(let e=0;e<r.length;e++)t+=String.fromCharCode(r[e]);return btoa(t)}return Buffer.from(r).toString("base64")};function $s(r){const t=r.indexOf(","),e=r.slice(5,t),i=e.split(";")[0]||"application/octet-stream",s=r.slice(t+1),o=/;base64/i.test(e)?Yi(s):new TextEncoder().encode(decodeURIComponent(s));return{mime:i,bytes:o}}function Pi(r){return(4-r%4)%4}async function Hi(r,t={}){const{textureFormat:e="keep",quality:i=.85}=t,s=[],n=[];let o=0;const a=(_,T,L)=>{const N=o,k=_.length;s.push({offset:N,length:k,mime:T,kind:L}),n.push(_),o+=k;const X=Pi(k);return X&&(n.push(new Uint8Array(X)),o+=X),s.length-1},c=e==="webp"&&typeof OffscreenCanvas<"u"&&typeof createImageBitmap=="function",l=[];for(const _ of r.systems||[]){const T={..._};if(typeof T.textureImageData=="string"&&T.textureImageData.startsWith("data:")){let{mime:L,bytes:N}=$s(T.textureImageData);if(c&&L!=="image/webp")try{const k=await createImageBitmap(new Blob([N],{type:L})),X=new OffscreenCanvas(k.width,k.height);X.getContext("2d").drawImage(k,0,0);const z=await X.convertToBlob({type:"image/webp",quality:i}),me=new Uint8Array(await z.arrayBuffer());me.length<N.length&&(N=me,L="image/webp")}catch{}T.textureImageData={[qe]:a(N,L,"texture")}}if(typeof T.glbModelData=="string"&&T.glbModelData.length>0){const L=Yi(T.glbModelData);T.glbModelData={[qe]:a(L,"model/gltf-binary","glb")}}l.push(T)}const u={...r,systems:l,assets:s},f=new TextEncoder().encode(JSON.stringify(u)),h=Pi(f.length),m=new Uint8Array(o);let S=0;for(const _ of n)m.set(_,S),S+=_.length;const R=f.length+h,D=20+R+8+o,C=new ArrayBuffer(D),B=new DataView(C),A=new Uint8Array(C);let P=0;B.setUint32(P,Ct,!0),P+=4,B.setUint32(P,Xi,!0),P+=4,B.setUint32(P,D,!0),P+=4,B.setUint32(P,R,!0),P+=4,B.setUint32(P,ki,!0),P+=4,A.set(f,P),P+=f.length;for(let _=0;_<h;_++)A[P++]=32;return B.setUint32(P,o,!0),P+=4,B.setUint32(P,ji,!0),P+=4,A.set(m,P),P+=o,C}function At(r){return!r||r.byteLength<12?!1:new DataView(r).getUint32(0,!0)===Ct}function Ut(r){const t=new DataView(r);if(t.getUint32(0,!0)!==Ct)throw new Error("[unpackHZFX] bad magic — not an .hzfx file");const e=t.getUint32(4,!0);if(e!==Xi)throw new Error(`[unpackHZFX] unsupported version ${e}`);let i=12,s=null,n=-1;const o=new Uint8Array(r);for(;i+8<=r.byteLength;){const h=t.getUint32(i,!0);i+=4;const m=t.getUint32(i,!0);i+=4,m===ki?s=JSON.parse(new TextDecoder().decode(o.subarray(i,i+h))):m===ji&&(n=i),i+=h}if(!s)throw new Error("[unpackHZFX] missing JSON chunk");const a=s.assets||[],c=h=>{const m=a[h];return!m||n<0?null:{...m,bytes:o.subarray(n+m.offset,n+m.offset+m.length)}},l=h=>h&&typeof h=="object"&&typeof h[qe]=="number",u=(s.systems||[]).map(h=>{const m={...h};if(l(m.textureImageData)){const S=c(m.textureImageData[qe]);m.textureImageData=S?`data:${S.mime};base64,${vi(S.bytes)}`:void 0}if(l(m.glbModelData)){const S=c(m.glbModelData[qe]);m.glbModelData=S?vi(S.bytes):void 0}return m}),f={...s,systems:u};return delete f.assets,f}function Ws(r){const t=new Uint8Array(r);let e="";for(let i=0;i<t.byteLength;i++)e+=String.fromCharCode(t[i]);return btoa(e)}function qi(r){return{name:r.name,id:r.id,particleCount:r.particleCount,lifetime:r.lifetime,emissionRate:r.emissionRate,emissionDuration:r.emissionDuration,emissionDurationInfinite:r.emissionDurationInfinite||!1,particleSize:r.particleSize,particleSpeed:r.particleSpeed,emissionShape:r.emissionShape,outerLength:r.outerLength??r.cubeLength,innerLength:r.innerLength,outerRadius:r.outerRadius,innerRadius:r.innerRadius,squareSize:r.squareSize,squareInnerSize:r.squareInnerSize,circleInnerRadius:r.circleInnerRadius,circleOuterRadius:r.circleOuterRadius,fadeEnabled:r.fadeEnabled,colorTransitionEnabled:r.colorTransitionEnabled,particleColor:r.particleColor,startColor:r.startColor,endColor:r.endColor,randomColorEnabled:r.randomColorEnabled||!1,randomColors:r.randomColors||[],particleShape:r.particleShape||"square",particleShapeRotationX:r.particleShapeRotationX||0,particleShapeRotationY:r.particleShapeRotationY||0,particleShapeRotationZ:r.particleShapeRotationZ||0,pulseEnabled:r.pulseEnabled||!1,pulseAmplitude:r.pulseAmplitude??.5,pulseFrequency:r.pulseFrequency??1,pulsePhaseRandom:r.pulsePhaseRandom??0,pulseOpacity:r.pulseOpacity||!1,bloomEnabled:r.bloomEnabled,bloomIntensity:r.bloomIntensity,bloomColor:r.bloomColor,depthWriteEnabled:r.depthWriteEnabled||!1,burstMode:r.burstMode,gravityEnabled:r.gravityEnabled,gravityStrength:r.gravityStrength,dampingEnabled:r.dampingEnabled,dampingStrength:r.dampingStrength,attractorEnabled:r.attractorEnabled,attractorStrength:r.attractorStrength,attractorPosition:r.attractorPosition,emissionRotationX:r.emissionRotationX,emissionRotationY:r.emissionRotationY,emissionRotationZ:r.emissionRotationZ,orientToDirection:r.orientToDirection??!1,emissionPositionX:r.emissionPositionX,emissionPositionY:r.emissionPositionY,emissionPositionZ:r.emissionPositionZ,rotation:r.rotation,rotationMode:r.rotationMode,minRotation:r.minRotation,maxRotation:r.maxRotation,overrideXVelocity:r.overrideXVelocity,overrideYVelocity:r.overrideYVelocity,overrideZVelocity:r.overrideZVelocity,xVelocity:r.xVelocity,yVelocity:r.yVelocity,zVelocity:r.zVelocity,circleVelocityDirection:r.circleVelocityDirection,cylinderVelocityDirection:r.cylinderVelocityDirection,cylinderInnerRadius:r.cylinderInnerRadius,cylinderOuterRadius:r.cylinderOuterRadius,cylinderHeight:r.cylinderHeight,planeWidth:r.planeWidth,planeDepth:r.planeDepth,rectangleWidth:r.rectangleWidth,rectangleHeight:r.rectangleHeight,coneOuterRadius:r.coneOuterRadius,coneInnerRadius:r.coneInnerRadius,coneHeight:r.coneHeight,torusMajorRadius:r.torusMajorRadius,torusMinorRadius:r.torusMinorRadius,lineLength:r.lineLength,hemisphereOuterRadius:r.hemisphereOuterRadius,hemisphereInnerRadius:r.hemisphereInnerRadius,discRadius:r.discRadius,annulusInnerRadius:r.annulusInnerRadius,annulusOuterRadius:r.annulusOuterRadius,capsuleRadius:r.capsuleRadius,capsuleHeight:r.capsuleHeight,arcStartAngle:r.arcStartAngle,arcEndAngle:r.arcEndAngle,arcInnerRadius:r.arcInnerRadius,arcOuterRadius:r.arcOuterRadius,spiralTurns:r.spiralTurns,spiralRadiusStart:r.spiralRadiusStart,spiralRadiusEnd:r.spiralRadiusEnd,spiralHeight:r.spiralHeight,frustumRadiusNear:r.frustumRadiusNear,frustumRadiusFar:r.frustumRadiusFar,frustumHeight:r.frustumHeight,cubeSurfaceSize:r.cubeSurfaceSize,sphereSurfaceRadius:r.sphereSurfaceRadius,boxFrameSize:r.boxFrameSize,polygonSides:r.polygonSides,polygonRadius:r.polygonRadius,aspectRatio:r.aspectRatio,randomSize:r.randomSize,minSize:r.minSize,maxSize:r.maxSize,fadeSizeEnabled:r.fadeSizeEnabled,increaseSizeEnabled:r.increaseSizeEnabled,sizeLifetimeSpeed:r.sizeLifetimeSpeed,opacity:r.opacity,randomSpeed:r.randomSpeed,minSpeed:r.minSpeed,maxSpeed:r.maxSpeed,oneOnlyMode:r.oneOnlyMode,confinementEnabled:r.confinementEnabled||!1,confinementShape:r.confinementShape||"box",confinementMode:r.confinementMode||"bounce",confinementSpace:r.confinementSpace||"world",confinementBoxHalfSize:r.confinementBoxHalfSize||[2,2,2],confinementSphereRadius:r.confinementSphereRadius??3,confinementRestitution:r.confinementRestitution??.8,confinementFriction:r.confinementFriction??.1,confinementCenter:r.confinementCenter,softBoundaryEnabled:r.softBoundaryEnabled||!1,softBoundaryStrength:r.softBoundaryStrength??5,softBoundaryFalloff:r.softBoundaryFalloff??.5,followSystemId:r.followSystemId||null,followSystemTranslation:r.followSystemTranslation??!0,hidden:r.hidden||!1,emissionTrailEnabled:r.emissionTrailEnabled||!1,emissionTrailDuration:r.emissionTrailDuration??1,emissionTrailWidth:r.emissionTrailWidth??.5,emissionTrailMinDistance:r.emissionTrailMinDistance??.05,emissionTrailMaxPoints:r.emissionTrailMaxPoints??100,emissionTrailSegments:r.emissionTrailSegments??8,emissionTrailMode:r.emissionTrailMode??"ribbon",emissionTrailShape:r.emissionTrailShape??"straight",emissionTrailShapeAmplitude:r.emissionTrailShapeAmplitude??.1,emissionTrailShapeFrequency:r.emissionTrailShapeFrequency??4,emissionTrailShapeSpeed:r.emissionTrailShapeSpeed??0,shapeDisplay:r.shapeDisplay??!0,blendMode:r.blendMode??"normal",noiseDistortEnabled:r.noiseDistortEnabled||!1,noiseTilingX:r.noiseTilingX??3,noiseTilingY:r.noiseTilingY??3,noiseSpeed:r.noiseSpeed??-1.5,noiseAmplitude:r.noiseAmplitude??.08,velocityStretchEnabled:r.velocityStretchEnabled||!1,velocityStretchFactor:r.velocityStretchFactor??1,textureEnabled:r.textureEnabled||!1,textureType:r.textureType,textureFileName:r.textureFileName,imageDescription:r.imageDescription,glbModelEnabled:r.glbModelEnabled||!1,glbFileName:r.glbFileName,glbHasTexture:r.glbHasTexture||!1,useGlbTexture:r.useGlbTexture||!1,glbAnimated:r.glbAnimated||!1,animationIndex:r.animationIndex,animationSpeed:r.animationSpeed,animationLoop:r.animationLoop,glbDescription:r.glbDescription,script:r.script||void 0,displayUnit:r.displayUnit||"m"}}async function Js(r,t,e="hzfx"){if(!r||!r.particleSystems||r.particleSystems.length===0){alert("No particle systems to save.");return}try{const i={version:"1.0",timestamp:new Date().toISOString(),systems:r.particleSystems.map(({config:u,system:f})=>({...qi(u),textureImageData:u.textureEnabled&&!u.glbModelEnabled&&u.textureImageData?u.textureImageData:void 0,glbModelData:u.glbModelEnabled&&f.glbRawArrayBuffer?Ws(f.glbRawArrayBuffer):void 0})),activeSystemIndex:r.activeSystemIndex,loop:r.loop||!1},s=e==="json"?"json":"hzfx";let n;if(s==="hzfx"){const u=await Hi(i,{textureFormat:"webp"});n=new Blob([u],{type:"application/octet-stream"})}else n=new Blob([JSON.stringify(i,null,2)],{type:"application/json"});let o;if(t)o=t;else{const u=new Date;o=`particle-scene_${`${u.getFullYear()}-${(u.getMonth()+1).toString().padStart(2,"0")}-${u.getDate().toString().padStart(2,"0")}_${u.getHours().toString().padStart(2,"0")}${u.getMinutes().toString().padStart(2,"0")}`}`}const a=`${o}.${s}`,c=URL.createObjectURL(n),l=document.createElement("a");l.href=c,l.download=a,document.body.appendChild(l),l.click(),document.body.removeChild(l),URL.revokeObjectURL(c)}catch(i){console.error("Error saving scene:",i),alert("Error saving scene. See console for details.")}}function Ks(r){return new Promise((t,e)=>{try{const i=r.target.files[0];if(!i){e(new Error("No file selected"));return}const s=new FileReader;s.onload=n=>{try{const o=n.target.result;let a;if(At(o)?a=Ut(o):a=JSON.parse(new TextDecoder().decode(o)),!Array.isArray(a.systems)||a.systems.length===0)throw new Error("No valid particle systems found in the file");t({systems:a.systems.slice(),activeSystemIndex:a.activeSystemIndex||0})}catch(o){console.error("Error loading scene:",o),alert("Error loading scene: "+o.message),e(o)}r.target.value=""},s.onerror=()=>{alert("Failed to read the file"),e(new Error("Failed to read the file")),r.target.value=""},s.readAsArrayBuffer(i)}catch(i){console.error("Error in loadScene:",i),e(i)}})}async function Qs(r){if(!r||typeof r!="string")throw new Error("[fetchPreset] url must be a non-empty string");const t=await fetch(r);if(!t.ok)throw new Error(`[fetchPreset] HTTP ${t.status}: ${t.statusText}`);const e=await t.arrayBuffer();let i;if(At(e)?i=Ut(e):i=JSON.parse(new TextDecoder().decode(e)),!Array.isArray(i.systems)||i.systems.length===0)throw new Error('[fetchPreset] Invalid preset: "systems" must be a non-empty array');return{version:i.version,systems:i.systems,activeSystemIndex:i.activeSystemIndex??0}}const er=r=>`
1133
+ @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
1134
+ var p = array<vec2f, 3>(vec2f(-1.0, -3.0), vec2f(-1.0, 1.0), vec2f(3.0, 1.0));
1135
+ return vec4f(p[i], 0.0, 1.0);
1136
+ }
1137
+ @group(0) @binding(0) var src: ${r?"texture_depth_multisampled_2d":"texture_depth_2d"};
1138
+ @fragment fn fs(@builtin(position) pos: vec4f) -> @builtin(frag_depth) f32 {
1139
+ return textureLoad(src, vec2i(pos.xy), 0);
1140
+ }
1141
+ `;async function tr(r,t={}){const{getSceneDepth:e=null,autoRespawn:i=!0,respectEffectLoop:s=!0}=t;let n,o,a;const c=!!(r&&r.device&&r.context);c?({device:n,context:o,canvas:a}=r,a||(a=o.canvas)):(a=r,{device:n,context:o}=await Ci(a));const l=navigator.gpu.getPreferredCanvasFormat(),u=t.manager||new Ei(n),f={layouts:{},pipelines:{}};function h(d){const p=d?"ms":"ss";if(!f.pipelines[p]){const b=n.createShaderModule({code:er(d)}),y=n.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.FRAGMENT,texture:{sampleType:"depth",multisampled:d}}]});f.layouts[p]=y,f.pipelines[p]=n.createRenderPipeline({layout:n.createPipelineLayout({bindGroupLayouts:[y]}),vertex:{module:b,entryPoint:"vs"},fragment:{module:b,entryPoint:"fs",targets:[]},primitive:{topology:"triangle-list"},depthStencil:{format:"depth24plus",depthWriteEnabled:!0,depthCompare:"always"}})}return{pipeline:f.pipelines[p],layout:f.layouts[p]}}const m={bloomSourceTextures:{},bloomCompositeTextures:{},combinedTexture:null,getBloomSourceTexture(d,p,b){return this.bloomSourceTextures[d]||(this.bloomSourceTextures[d]=n.createTexture({size:[p,b],format:"rgba16float",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING})),this.bloomSourceTextures[d]},getBloomCompositeTexture(d,p,b){return this.bloomCompositeTextures[d]||(this.bloomCompositeTextures[d]=n.createTexture({size:[p,b],format:"rgba16float",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING})),this.bloomCompositeTextures[d]},getCombinedTexture(d,p){return this.combinedTexture||(this.combinedTexture=n.createTexture({size:[d,p],format:"rgba16float",usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING})),this.combinedTexture},resizeTextures(){Object.values(this.bloomSourceTextures).forEach(d=>d==null?void 0:d.destroy()),Object.values(this.bloomCompositeTextures).forEach(d=>d==null?void 0:d.destroy()),this.combinedTexture&&this.combinedTexture.destroy(),this.bloomSourceTextures={},this.bloomCompositeTextures={},this.combinedTexture=null}},S={systemBindGroups:{},systemBloomHorizontalBindGroups:{},secondHorizontalBindGroups:{},finalBindGroup:null,textureStates:{},textureRefs:{},clear(){this.systemBindGroups={},this.systemBloomHorizontalBindGroups={},this.secondHorizontalBindGroups={},this.finalBindGroup=null,this.textureStates={},this.textureRefs={}}},R=n.createBuffer({size:96,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),D=n.createBuffer({size:208,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),C=n.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),B=n.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),A=n.createBuffer({size:64,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),P=Ce(n,new Uint16Array([0,1,2,0,2,3]),GPUBufferUsage.INDEX),_={},T=()=>Ce(n,new Float32Array([-.5,-.5,0,.5,-.5,0,.5,.5,0,-.5,.5,0]),GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST);u.onSystemCreated=d=>{_[d]||(_[d]=T())};const L=4e4,N=new Float32Array(L*8),k=new Float32Array(L*4),X=new Float32Array(L*4),z=n.createBuffer({size:L*8*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST}),me=n.createBuffer({size:L*4*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST}),De=n.createBuffer({size:L*4*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST}),ze=new Map,lt=8,Q=[];function It(d){for(const p of Q)if(p.ids.has(d))return p;return null}function Zi(d,p){if(!d.pos)return;d.hist.push({t:p,x:d.pos[0],y:d.pos[1],z:d.pos[2]});const b=p-lt;for(;d.hist.length>2&&d.hist[0].t<b;)d.hist.shift()}function Gt(d,p){const b=d.hist;if(b.length===0)return d.pos;if(p>=b[b.length-1].t){const y=b[b.length-1];return[y.x,y.y,y.z]}if(p<=b[0].t)return[b[0].x,b[0].y,b[0].z];for(let y=b.length-1;y>0;y--)if(b[y-1].t<=p){const x=b[y-1],Y=b[y],Z=(p-x.t)/Math.max(1e-6,Y.t-x.t);return[x.x+(Y.x-x.x)*Z,x.y+(Y.y-x.y)*Z,x.z+(Y.z-x.z)*Z]}return[b[0].x,b[0].y,b[0].z]}const $i=.41421356;function Wi(){ze.clear();let d=0,p=0;U.position[0],U.position[1],U.position[2];for(const{system:b,config:y}of u.particleSystems){if(!y.emissionTrailEnabled||y.hidden||y.glbModelEnabled)continue;b.readbackAndProcessParticles();const x=b.particleData,Y=b.particleVelocities,Z=b.activeParticles;if(!x||!Y||Z<=0)continue;const $=y.emissionTrailMode==="particles",W=d,g=y.emissionTrailDuration??1,w=y.opacity??1,G=y.particleSize??.5,H=y.bloomIntensity||1,M=Math.max(1,Math.min(64,y.emissionTrailSegments??8)),J=y.emissionTrailShape||"straight",ee=y.followSystemTranslation??!0,fe=b._simPosition,O=ee&&fe?fe[0]:0,Qe=ee&&fe?fe[1]:0,qt=ee&&fe?fe[2]:0,Ue=b._simVelocity,Zt=Ue?Ue[0]:0,ys=Ue?Ue[1]:0,$t=Ue?Ue[2]:0,Fe=It(y.id),Wt=!!(ee&&Fe&&Fe.hist&&Fe.hist.length>1);for(let et=0;et<Z;et++){const ge=et*8,tt=x[ge],ht=x[ge+1],it=x[ge+2],gs=tt+O,bs=ht+Qe,Ss=it+qt;let Oe=x[ge+3],Le=x[ge+4],Ne=x[ge+5];const Xe=x[ge+6],Ie=x[ge+7];if(Xe>=Ie||Ie<=0)continue;const be=Xe/Ie;if(y.colorTransitionEnabled){const v=y.startColor??[1,0,0],I=y.endColor??[0,0,1];Oe=v[0]+(I[0]-v[0])*be,Le=v[1]+(I[1]-v[1])*be,Ne=v[2]+(I[2]-v[2])*be}Oe=Math.min(1,Oe*H),Le=Math.min(1,Le*H),Ne=Math.min(1,Ne*H);let ke=G;if(y.randomSize){const v=Math.sin(Ie*54321.67)*43758.5453%1,I=v<0?v+1:v;ke=(y.minSize??.1)+((y.maxSize??.5)-(y.minSize??.1))*I}if(y.fadeSizeEnabled){const v=Math.max(.01,Math.min(10,y.sizeLifetimeSpeed??1));ke*=1-Math.pow(be,1/v)}if(y.increaseSizeEnabled){const v=Math.max(.01,Math.min(10,y.sizeLifetimeSpeed??1));ke*=1+Math.pow(be,1/v)}if(ke<=0||be>.9)continue;const Jt=Math.min((.9-be)*(1/.2),1),Kt=.75*ke*$i*Jt;let je=w;if(y.fadeEnabled&&(je*=Math.max(0,1-be)),je*=Jt,je<.01)continue;const mt=et*4,Qt=Y[mt],ei=Y[mt+1],ti=Y[mt+2],st=Qt+Zt,rt=ei+ys,nt=ti+$t,ii=Math.sqrt(st*st+rt*rt+nt*nt);if(ii<.001)continue;const yt=1/ii,_e=st*yt,we=rt*yt,Se=nt*yt,si=U.right[0],ri=U.right[1],ni=U.right[2];let gt=si*_e+ri*we+ni*Se,ne=si-gt*_e,ae=ri-gt*we,oe=ni-gt*Se,Ye=Math.sqrt(ne*ne+ae*ae+oe*oe);if(Ye<.2){const v=U.up[0],I=U.up[1],q=U.up[2],V=v*_e+I*we+q*Se;ne=v-V*_e,ae=I-V*we,oe=q-V*Se,Ye=Math.sqrt(ne*ne+ae*ae+oe*oe)||1}ne/=Ye,ae/=Ye,oe/=Ye;const He=Math.min(g,Xe);if(He<.001)continue;const ai=y.gravityEnabled&&y.gravityStrength||0,Be=new Array(M+1),Re=new Array(M+1),Me=new Array(M+1);if(y.orientToDirection&&y.burstMode&&Wt){const v=b._emitSimRotY||0,I=new Array(M+1),q=new Array(M+1),V=new Array(M+1);for(let E=0;E<=M;E++){const F=Gt(Fe,ye-E/M*He);I[E]=F[0],q[E]=F[1],V[E]=F[2]}for(let E=0;E<=M;E++){const F=E>0?E-1:0,j=E<M?E+1:M;let Te=I[F]-I[j],Ee=V[F]-V[j];const xe=(Math.hypot(Te,Ee)>1e-5?Math.atan2(Te,Ee):Math.atan2(Zt,$t))-v,se=Math.cos(xe),re=Math.sin(xe),he=E/M*He,bt=-.5*ai*he*he;Be[E]=se*tt+re*it+I[E],Re[E]=ht+bt+q[E],Me[E]=-re*tt+se*it+V[E]}}else for(let v=0;v<=M;v++){const I=v/M*He,q=-.5*ai*I*I;if(Wt){const V=Gt(Fe,ye-I);Be[v]=tt-Qt*I+V[0],Re[v]=ht-ei*I+q+V[1],Me[v]=it-ti*I+V[2]}else Be[v]=gs-st*I,Re[v]=bs-rt*I+q,Me[v]=Ss-nt*I}if(J!=="straight"){const v=y.emissionTrailShapeAmplitude??.1,I=y.emissionTrailShapeFrequency??4,q=y.emissionTrailShapeSpeed??0;let V=-Se,E=0,F=_e,j=Math.sqrt(V*V+F*F);j<1e-6&&(V=0,E=Se,F=-we,j=Math.sqrt(V*V+E*E+F*F)||1),V/=j,E/=j,F/=j;const Te=we*F-Se*E,Ee=Se*V-_e*F,pe=_e*E-we*V;for(let K=1;K<=M;K++){const xe=K/M*He,se=2*Math.PI*I*(ye-xe)+q*ye;let re=0,he=0;J==="zigzag"?re=v*Math.sign(Math.sin(se)):J==="sine"?re=v*Math.sin(se):J==="spiral"&&(re=v*Math.sin(se),he=v*Math.cos(se)),Be[K]+=V*re+Te*he,Re[K]+=E*re+Ee*he,Me[K]+=F*re+pe*he}}if($)for(let v=1;v<=M&&d<L;v++){const I=v/M,q=Be[v]-O,V=Re[v]-Qe,E=Me[v]-qt,F=d*8,j=d*4;N[F]=q,N[F+1]=V,N[F+2]=E,N[F+3]=Oe,N[F+4]=Le,N[F+5]=Ne,N[F+6]=Xe+(Ie-Xe)*I,N[F+7]=Ie,k[j]=0,k[j+1]=0,k[j+2]=0,k[j+3]=0,X[j]=q,X[j+1]=V,X[j+2]=E,X[j+3]=0,d++}else for(let v=0;v<M&&!(p+42>ue.length);v++){const I=v/M,q=(v+1)/M,V=Be[v],E=Re[v],F=Me[v],j=Be[v+1],Te=Re[v+1],Ee=Me[v+1],pe=Kt*(1-I),K=Kt*(1-q),xe=je*(1-I)*(1-I),se=je*(1-q)*(1-q),re=V+ne*pe,he=E+ae*pe,bt=F+oe*pe,oi=V-ne*pe,li=E-ae*pe,ci=F-oe*pe,ui=j+ne*K,di=Te+ae*K,fi=Ee+oe*K,xs=j-ne*K,vs=Te-ae*K,Ps=Ee-oe*K,Ge=(_s,ws,Bs,Rs)=>{ue[p++]=_s,ue[p++]=ws,ue[p++]=Bs,ue[p++]=Oe,ue[p++]=Le,ue[p++]=Ne,ue[p++]=Rs};Ge(re,he,bt,xe),Ge(oi,li,ci,xe),Ge(ui,di,fi,se),Ge(oi,li,ci,xe),Ge(xs,vs,Ps,se),Ge(ui,di,fi,se)}}$&&d>W&&ze.set(y.id,{first:W,count:d-W})}d>0&&(n.queue.writeBuffer(z,0,N,0,d*8),n.queue.writeBuffer(me,0,k,0,d*4),n.queue.writeBuffer(De,0,X,0,d*4)),Ve=p/7,Ve>0&&n.queue.writeBuffer(Nt,0,ue,0,p)}const Dt=()=>{n.queue.writeBuffer(C,0,new Float32Array([1,0,a.width,a.height,0,0,0,0])),n.queue.writeBuffer(B,0,new Float32Array([0,1,a.width,a.height,0,0,0,0]))};Dt();const zt=new Float32Array(16).fill(0);zt[0]=1,n.queue.writeBuffer(A,0,zt);const te=Fi(n),ce=zi(n),{particlePipeline:Ji,particleAdditivePipeline:Ki,particleDepthWritePipeline:Qi,blurPipeline:$e,compositePipeline:es,directRenderPipeline:Vt,finalCompositePipeline:ts,glbMeshPipeline:is}=Vi(n,l,ce),Ft=n.createShaderModule({code:`
1142
+ struct U { mvp: mat4x4<f32> };
1143
+ @group(0) @binding(0) var<uniform> u: U;
1144
+ struct VIn { @location(0) pos: vec3<f32>, @location(1) col: vec4<f32> };
1145
+ struct VOut { @builtin(position) pos: vec4<f32>, @location(0) col: vec4<f32> };
1146
+ @vertex fn vs(v: VIn) -> VOut { var o: VOut; o.pos = u.mvp * vec4<f32>(v.pos, 1.0); o.col = v.col; return o; }
1147
+ @fragment fn fs(i: VOut) -> @location(0) vec4<f32> { return i.col; }
1148
+ `}),Ot=n.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.VERTEX,buffer:{type:"uniform"}}]}),ss=n.createRenderPipeline({layout:n.createPipelineLayout({bindGroupLayouts:[Ot]}),vertex:{module:Ft,entryPoint:"vs",buffers:[{arrayStride:28,attributes:[{shaderLocation:0,offset:0,format:"float32x3"},{shaderLocation:1,offset:12,format:"float32x4"}]}]},fragment:{module:Ft,entryPoint:"fs",targets:[{format:"rgba16float",blend:{color:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"},alpha:{srcFactor:"src-alpha",dstFactor:"one-minus-src-alpha"}}}]},primitive:{topology:"triangle-list"},depthStencil:{format:"depth24plus",depthWriteEnabled:!1,depthCompare:"less-equal"}}),Lt=512*64*6,ue=new Float32Array(Lt*7),Nt=n.createBuffer({size:Lt*7*4,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,label:"ribbonBuffer"}),rs=n.createBindGroup({layout:Ot,entries:[{binding:0,resource:{buffer:R}}]});let Ve=0,{sceneTexture:ie,bloomTexA:ve,bloomTexB:de}=_t(n,l,a.width,a.height),Pe=wt(n,a.width,a.height);const ct={uniformBuffer:R,appearanceUniformBuffer:D,horizontalBlurUniformBuffer:C,verticalBlurUniformBuffer:B,bloomIntensityBuffer:A};let We=ot(n,te,ct,{sceneTexture:ie,bloomTexA:ve,bloomTexB:de});const U={mvp:new Float32Array(16),position:new Float32Array([0,0,10]),right:new Float32Array([1,0,0]),up:new Float32Array([0,1,0]),hasCamera:!1};let ye=0,ns=0;const Ae={key:null,ms:!1,bindGroup:null};let Xt=!1,ut=!0,Je=!1,Ke=null,dt=a.width,ft=a.height;function kt(){const d=[ie,ve,de,Pe],p=_t(n,l,a.width,a.height);ie=p.sceneTexture,ve=p.bloomTexA,de=p.bloomTexB,Pe=wt(n,a.width,a.height),Dt(),S.clear(),m.resizeTextures(),We=ot(n,te,ct,{sceneTexture:ie,bloomTexA:ve,bloomTexB:de});let b=!1;const y=()=>{if(!b){b=!0,requestAnimationFrame(y);return}d.forEach(x=>x.destroy())};requestAnimationFrame(y)}function as(d,p,b){U.mvp.set(Ni(d,p)),p&&p.length>=10&&(U.right[0]=p[0],U.right[1]=p[4],U.right[2]=p[8],U.up[0]=p[1],U.up[1]=p[5],U.up[2]=p[9]),b&&(U.position[0]=b.x??b[0],U.position[1]=b.y??b[1],U.position[2]=b.z??b[2]),U.hasCamera=!0}function os(d,p){U.mvp.set(d),p&&(U.position[0]=p.x??p[0],U.position[1]=p.y??p[1],U.position[2]=p.z??p[2]),U.hasCamera=!0}async function pt(d){if(Je){Ke=d;return}Je=!0;try{for(const p in _)delete _[p];S.clear(),m.resizeTextures(),We=ot(n,te,ct,{sceneTexture:ie,bloomTexA:ve,bloomTexB:de}),await u.replaceSystems({systems:[],activeSystemIndex:0});for(const p of d)await u.addSystems(p.preset,p.position||[0,0,0]);for(const{config:p}of u.particleSystems)_[p.id]||(_[p.id]=T());ut=!0,u.respawnAllSystems()}finally{if(Je=!1,Ke){const p=Ke;Ke=null,pt(p)}}}async function ls(d,p=[0,0,0]){return pt([{preset:d,position:p}])}function cs(d){if(Xt||Je||!u.ready||(d>.1&&(d=.1),d<=0)||u.particleSystems.length===0)return;if((a.width!==dt||a.height!==ft)&&(dt=a.width,ft=a.height,kt()),ye+=d,Q.length){for(const g of Q){if(g.getPosition){const w=g.getPosition();g.pos=w?Array.isArray(w)?[w[0],w[1],w[2]]:[w.x,w.y,w.z]:null}g.vel=g.pos&&g.prevPos&&g.wasActive&&d>0?[(g.pos[0]-g.prevPos[0])/d,(g.pos[1]-g.prevPos[1])/d,(g.pos[2]-g.prevPos[2])/d]:[0,0,0],g.justResumed=!!g.pos&&!g.wasActive,g.justResumed&&(g.hist.length=0)}for(const{system:g,config:w}of u.particleSystems){const G=It(w.id);if(!(!G||G.historyOnly)&&(w.hidden=!G.pos,G.pos)){let H=null;if(G.orientToDirection&&G.vel){const M=G.vel[0],J=G.vel[2];Math.hypot(M,J)>1e-4&&(H=[0,0,Math.atan2(M,J)])}g.setSimulationTransform({position:G.pos,velocity:G.vel,rotation:H}),g.updateAppearanceUniform(),(G.justResumed||g.activeParticles===0)&&g.spawnParticles()}}for(const g of Q)g.pos?Zi(g,ye):g.hist.length=0,g.prevPos=g.pos?g.pos.slice():null,g.wasActive=!!g.pos;if(globalThis.__HZFX_DEBUG&&(ns++&63)===0){const g=u.particleSystems.reduce((M,J)=>M+(J.system.activeParticles|0),0),w=Q.find(M=>M.pos),G=w?Math.hypot(U.position[0]-w.pos[0],U.position[1]-w.pos[1],U.position[2]-w.pos[2]).toFixed(1):"-",H=Q.map(M=>`{ids:[${[...M.ids]}],pos:${M.pos?"1":"0"},hist:${M.hist.length}}`).join(",");console.info(`[HZFX] movingGroups(${Q.length})=[${H}] activeParticles=${g} systems=${u.particleSystems.length} ribbonVerts=${Ve} camDist=${G} t=${ye.toFixed(1)}`)}}if(u.updateAllSystems(d),s?u.loop??i:i){const g=u.particleSystems.length>0&&u.particleSystems.every(({system:w})=>w.activeParticles===0&&!w.emitting);g&&ut&&u.respawnAllSystems(),ut=!g}for(const{system:g,config:w}of u.particleSystems)w.glbModelEnabled&&g.glbAnimator&&(g.glbAnimator.update(d),g.updateAnimatedGLBBuffer());n.queue.writeBuffer(R,0,U.mvp),n.queue.writeBuffer(R,64,new Float32Array([U.position[0],U.position[1],U.position[2],a.height/Math.max(1,a.width),ye])),Wi();const b=u.particleSystems.some(({config:g})=>g.bloomEnabled),y=n.createCommandEncoder();let x=!1;if(e)try{const g=e();if(g){let w=null,G=null,H=!1;if(g instanceof GPUTexture?g.width===a.width&&g.height===a.height&&(w=g,G=()=>g.createView({aspect:"depth-only"}),H=g.sampleCount>1):g.view&&(w=g.view,G=()=>g.view,H=!!g.multisampled),w){const{pipeline:M,layout:J}=h(H);(Ae.key!==w||Ae.ms!==H)&&(Ae.key=w,Ae.ms=H,Ae.bindGroup=n.createBindGroup({layout:J,entries:[{binding:0,resource:G()}]}));const ee=y.beginRenderPass({colorAttachments:[],depthStencilAttachment:{view:Pe.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}});ee.setPipeline(M),ee.setBindGroup(0,Ae.bindGroup),ee.draw(3),ee.end(),x=!0}}}catch{}const Y=y.beginRenderPass({colorAttachments:[{view:ie.createView(),loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}],depthStencilAttachment:x?{view:Pe.createView(),depthLoadOp:"load",depthStoreOp:"store"}:{view:Pe.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}});for(const{system:g,config:w}of u.particleSystems)w.bloomEnabled||w.hidden||g.activeParticles===0||jt(Y,g,w,!0);if(Ve>0&&(Y.setPipeline(ss),Y.setBindGroup(0,rs),Y.setVertexBuffer(0,Nt),Y.draw(Ve)),Y.end(),b)for(const{system:g,config:w}of u.particleSystems){if(!w.bloomEnabled||w.hidden||g.activeParticles===0)continue;const G=g.config.id,H=m.getBloomSourceTexture(G,a.width,a.height),M=y.beginRenderPass({colorAttachments:[{view:H.createView(),loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}],depthStencilAttachment:{view:Pe.createView(),depthClearValue:1,depthLoadOp:"load",depthStoreOp:"store"}});jt(M,g,w,!1),M.end();const J=new Float32Array(16).fill(0);J[0]=w.bloomIntensity,n.queue.writeBuffer(A,0,J);const ee={colorAttachments:[{view:ve.createView(),loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]},fe={colorAttachments:[{view:de.createView(),loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]};S.systemBloomHorizontalBindGroups[G]||(S.systemBloomHorizontalBindGroups[G]=n.createBindGroup({layout:ce.bloomBindGroupLayout,entries:[{binding:0,resource:te},{binding:1,resource:H.createView()},{binding:2,resource:{buffer:C}}]}));let O=y.beginRenderPass(ee);O.setPipeline($e),O.setBindGroup(0,S.systemBloomHorizontalBindGroups[G]),O.draw(3),O.end(),O=y.beginRenderPass(fe),O.setPipeline($e),O.setBindGroup(0,We.verticalBlurBindGroup),O.draw(3),O.end(),S.secondHorizontalBindGroups[G]||(S.secondHorizontalBindGroups[G]=n.createBindGroup({layout:ce.bloomBindGroupLayout,entries:[{binding:0,resource:te},{binding:1,resource:de.createView()},{binding:2,resource:{buffer:C}}]})),O=y.beginRenderPass(ee),O.setPipeline($e),O.setBindGroup(0,S.secondHorizontalBindGroups[G]),O.draw(3),O.end(),O=y.beginRenderPass(fe),O.setPipeline($e),O.setBindGroup(0,We.verticalBlurBindGroup),O.draw(3),O.end();const Qe=m.getBloomCompositeTexture(G,a.width,a.height);O=y.beginRenderPass({colorAttachments:[{view:Qe.createView(),loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]}),O.setPipeline(es),O.setBindGroup(0,n.createBindGroup({layout:ce.compositeBindGroupLayout,entries:[{binding:0,resource:te},{binding:1,resource:H.createView()},{binding:2,resource:de.createView()},{binding:3,resource:{buffer:g.bloomIntensityBuffer}}]})),O.draw(3),O.end()}const Z=m.getCombinedTexture(a.width,a.height),$=y.beginRenderPass({colorAttachments:[{view:Z.createView(),loadOp:"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]});$.setPipeline(Vt),$.setBindGroup(0,n.createBindGroup({layout:ce.compositeBindGroupLayout,entries:[{binding:0,resource:te},{binding:1,resource:ie.createView()},{binding:2,resource:ie.createView()},{binding:3,resource:{buffer:A}}]})),$.draw(3);for(const{config:g,system:w}of u.particleSystems){if(!g.bloomEnabled||g.hidden||w.activeParticles===0)continue;const G=w.config.id;$.setPipeline(Vt),$.setBindGroup(0,n.createBindGroup({layout:ce.compositeBindGroupLayout,entries:[{binding:0,resource:te},{binding:1,resource:m.getBloomCompositeTexture(G,a.width,a.height).createView()},{binding:2,resource:ie.createView()},{binding:3,resource:{buffer:A}}]})),$.draw(3)}$.end();const W=y.beginRenderPass({colorAttachments:[{view:o.getCurrentTexture().createView(),loadOp:c?"load":"clear",storeOp:"store",clearValue:{r:0,g:0,b:0,a:0}}]});W.setPipeline(ts),S.finalBindGroup||(S.finalBindGroup=n.createBindGroup({layout:ce.compositeBindGroupLayout,entries:[{binding:0,resource:te},{binding:1,resource:Z.createView()},{binding:2,resource:ie.createView()},{binding:3,resource:{buffer:A}}]})),W.setBindGroup(0,S.finalBindGroup),W.draw(3),W.end(),n.queue.submit([y.finish()])}function jt(d,p,b,y){const x=p.config.id,Y=b.glbModelEnabled&&p.glbMeshData;let Z;if(y){const W=!S.systemBindGroups[x]||S.textureStates[x]!==b.textureEnabled||S.textureRefs[x]!==p.particleTexture;S.textureStates[x]=b.textureEnabled,S.textureRefs[x]=p.particleTexture,W&&(S.systemBindGroups[x]=n.createBindGroup({layout:ce.particleBindGroupLayout,entries:[{binding:0,resource:{buffer:R}},{binding:1,resource:{buffer:p.appearanceUniformBuffer}},{binding:2,resource:p.particleTexture.createView()},{binding:3,resource:te}]})),Z=S.systemBindGroups[x]}else Z=n.createBindGroup({layout:ce.particleBindGroupLayout,entries:[{binding:0,resource:{buffer:R}},{binding:1,resource:{buffer:p.appearanceUniformBuffer}},{binding:2,resource:p.particleTexture.createView()},{binding:3,resource:te}]});const $=b.shapeDisplay!==!1;if(Y)$&&(d.setPipeline(is),d.setBindGroup(0,Z),d.setVertexBuffer(0,p.glbVertexBuffer),d.setVertexBuffer(1,p.instanceBuffer),d.setVertexBuffer(2,p.velocityBuffer),d.setIndexBuffer(p.glbIndexBuffer,p.glbIndexFormat),d.drawIndexed(p.glbIndexCount,p.activeParticles));else{d.setPipeline(b.blendMode==="additive"?Ki:Ji),d.setIndexBuffer(P,"uint16"),_[x]||(_[x]=T()),d.setVertexBuffer(0,_[x]),d.setBindGroup(0,Z),$&&(d.setVertexBuffer(1,p.instanceBuffer),d.setVertexBuffer(2,p.velocityBuffer),d.setVertexBuffer(3,p.trailBuffer),d.drawIndexed(6,p.activeParticles));const W=ze.get(x);W&&(d.setVertexBuffer(1,z),d.setVertexBuffer(2,me),d.setVertexBuffer(3,De),d.drawIndexed(6,W.count,0,0,W.first)),$&&b.depthWriteEnabled&&(d.setPipeline(Qi),d.drawIndexed(6,p.activeParticles))}}function us(){dt=a.width,ft=a.height,kt()}function ds(){S.clear()}function fs(){Xt=!0,u.destroy(),[ie,ve,de,Pe].forEach(d=>d==null?void 0:d.destroy()),m.resizeTextures(),[R,D,C,B,A,P,z,me,De].forEach(d=>d==null?void 0:d.destroy()),Object.values(_).forEach(d=>d==null?void 0:d.destroy())}async function Yt(d,p){const b=await u.addSystems(d,p);for(const{config:y}of u.particleSystems)_[y.id]||(_[y.id]=T());return u.respawnAllSystems(),new Set(Array.isArray(b)?b:[])}function Ht(d){for(const p of d){const b=u.particleSystems.findIndex(y=>y.config.id===p);b>=0&&u.removeSystem(b)}}async function ps(d,p=[0,0,0]){const b=await Yt(d,p);return{remove(){Ht(b)}}}async function hs(d,p={}){const b=await Yt(d,[0,0,0]);globalThis.__HZFX_DEBUG&&console.info(`[HZFX] addMovingEmitter: presetSystems=${(d&&d.systems||[]).length} newIds=[${[...b]}]`);const y={ids:b,pos:null,hist:[],getPosition:p.getPosition||null,orientToDirection:!!p.orientToDirection};return Q.push(y),{setPosition(x){x&&(y.pos=Array.isArray(x)?[x[0],x[1],x[2]]:[x.x,x.y,x.z])},setOrientToDirection(x){y.orientToDirection=!!x},remove(){Ht(b);const x=Q.indexOf(y);x>=0&&Q.splice(x,1)}}}function ms(d,p){const y={ids:d instanceof Set?d:new Set(d),pos:null,hist:[],getPosition:p,historyOnly:!0};return Q.push(y),{remove(){const x=Q.indexOf(y);x>=0&&Q.splice(x,1)},setIds(x){y.ids=x instanceof Set?x:new Set(x)}}}return{manager:u,device:n,context:o,setCamera:as,setCameraMVP:os,setEmitters:pt,loadPreset:ls,addEmitter:ps,addMovingEmitter:hs,render:cs,resize:us,clearCaches:ds,trackHistoryGroup:ms,destroy:fs}}function ir(r){return()=>{var t,e,i,s,n,o;try{const a=r.backend;if(!a)return null;if(r.needsFrameBufferTarget&&r._frameBufferTarget){const u=(i=(e=(t=r._textures)==null?void 0:t.get)==null?void 0:e.call(t,r._frameBufferTarget))==null?void 0:i.depthTexture,f=u?(s=a.get(u))==null?void 0:s.texture:null;if(f&&f.width===r.domElement.width&&f.height===r.domElement.height)return f}const c=r.getCanvasTarget?a.get(r.getCanvasTarget()):null,l=((o=(n=c==null?void 0:c.descriptor)==null?void 0:n.depthStencilAttachment)==null?void 0:o.view)??null;return l?{view:l,multisampled:(r.currentSamples??0)>1}:null}catch{return null}}}exports.GLBAnimator=Ti;exports.Objects3DManager=js;exports.ParticleEmitter=_i;exports.ParticlePhysics=wi;exports.ParticleScript=Pt;exports.ParticleSystem=at;exports.ParticleSystemManager=Ei;exports.ParticleTextureManager=Bi;exports.blurShader=Mt;exports.compositeShader=Tt;exports.createBindGroupLayouts=zi;exports.createBindGroups=ot;exports.createBuffer=Ce;exports.createCubeGeometry=Oi;exports.createDepthTexture=wt;exports.createLookAtMatrix=qs;exports.createProjectionMatrix=Zs;exports.createRenderPipelines=Vi;exports.createRenderTextures=_t;exports.createSampler=Fi;exports.createSphereGeometry=Li;exports.directRenderShader=Et;exports.extractGLBTexture=Mi;exports.fetchPreset=Qs;exports.glbMeshParticleShader=Di;exports.hexToRgb=Ys;exports.initHzFxOverlay=tr;exports.initWebGPU=Ci;exports.isHZFX=At;exports.loadScene=Ks;exports.makeThreeSceneDepth=ir;exports.multiplyMatrices=Ni;exports.object3dShader=Gi;exports.packHZFX=Hi;exports.parseGLB=Bt;exports.particlePhysicsShader=Ui;exports.particleShader=Rt;exports.rgbToHex=Hs;exports.saveScene=Js;exports.serializeSystemConfig=qi;exports.unpackHZFX=Ut;