hz-particles 1.0.13 → 1.0.14

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 Y{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.shapeRotationX||0,e=this.config.shapeRotationY||0,i=this.config.shapeRotationZ||0;if(t===this._cachedRotX&&e===this._cachedRotY&&i===this._cachedRotZ)return;this._cachedRotX=t,this._cachedRotY=e,this._cachedRotZ=i;const a=t*Math.PI/180,r=e*Math.PI/180,n=i*Math.PI/180,o=Math.cos(a),s=Math.sin(a),l=Math.cos(r),u=Math.sin(r),d=Math.cos(n),f=Math.sin(n);this._rotMatrix=[l*d,s*u*d-o*f,o*u*d+s*f,l*f,s*u*f+o*d,o*u*f-s*d,-u,s*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 a=this._posOut;if(this.config.emissionShape==="cube"?this._emitFromCube(a):this.config.emissionShape==="sphere"?this._emitFromSphere(a):this.config.emissionShape==="square"?this._emitFromSquare(a):this.config.emissionShape==="circle"?this._emitFromCircle(a):this.config.emissionShape==="cylinder"?this._emitFromCylinder(a):this.config.emissionShape==="plain"?this._emitFromPlain(a):this.config.emissionShape==="cone"?this._emitFromCone(a):this.config.emissionShape==="torus"?this._emitFromTorus(a):this.config.emissionShape==="line"?this._emitFromLine(a):this.config.emissionShape==="hemisphere"?this._emitFromHemisphere(a):this.config.emissionShape==="disc"?this._emitFromDisc(a):this.config.emissionShape==="annulus"?this._emitFromAnnulus(a):this.config.emissionShape==="capsule"?this._emitFromCapsule(a):this.config.emissionShape==="arc"?this._emitFromArc(a):this.config.emissionShape==="spiral"?this._emitFromSpiral(a):this.config.emissionShape==="frustum"?this._emitFromFrustum(a):this.config.emissionShape==="cubeSurface"?this._emitFromCubeSurface(a):this.config.emissionShape==="sphereSurface"?this._emitFromSphereSurface(a):this.config.emissionShape==="boxFrame"?this._emitFromBoxFrame(a):this.config.emissionShape==="polygon"?this._emitFromPolygon(a):(a[0]=0,a[1]=0,a[2]=0),this.config.shapeRotationX||this.config.shapeRotationY||this.config.shapeRotationZ){this._updateRotationMatrix();const o=this._rotMatrix,s=a[0],l=a[1],u=a[2];a[0]=o[0]*s+o[1]*l+o[2]*u,a[1]=o[3]*s+o[4]*l+o[5]*u,a[2]=o[6]*s+o[7]*l+o[8]*u}(this.config.shapeTranslationX||this.config.shapeTranslationY||this.config.shapeTranslationZ)&&(a[0]+=this.config.shapeTranslationX||0,a[1]+=this.config.shapeTranslationY||0,a[2]+=this.config.shapeTranslationZ||0);const r=e*8;t[r]=a[0],t[r+1]=a[1],t[r+2]=a[2];const n=e*4;this.calculateVelocity(a[0],a[1],a[2],i,n),this.setParticleColor(t,r),this.setParticleLifetime(t,r)}applyRotation(t,e,i){this._updateRotationMatrix();const a=this._rotMatrix;return[a[0]*t+a[1]*e+a[2]*i,a[3]*t+a[4]*e+a[5]*i,a[6]*t+a[7]*e+a[8]*i]}inverseRotation(t,e,i){this._updateRotationMatrix();const a=this._invRotMatrix;return[a[0]*t+a[1]*e+a[2]*i,a[3]*t+a[4]*e+a[5]*i,a[6]*t+a[7]*e+a[8]*i]}_emitFromCube(t){let e=this.config.innerLength||0,i=this.config.outerLength||this.config.cubeLength;if(e>0){const a=Math.floor(Math.random()*6),r=Math.random()-.5,n=Math.random()-.5;let o,s,l;switch(a){case 0:o=r,s=n,l=.5;break;case 1:o=r,s=n,l=-.5;break;case 2:o=.5,s=r,l=n;break;case 3:o=-.5,s=r,l=n;break;case 4:o=r,s=.5,l=n;break;case 5:o=r,s=-.5,l=n;break}const u=Math.random(),d=e+u*(i-e);t[0]=o*d,t[1]=s*d,t[2]=l*d}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),a=Math.sin(i)*Math.cos(e),r=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]=a*o,t[1]=r*o,t[2]=n*o}_emitFromSquare(t){const e=this.config.squareInnerSize||0,i=this.config.squareSize||2;if(e>0){const a=Math.floor(Math.random()*4);let r=e+(i-e)*Math.random();switch(a){case 0:t[0]=(Math.random()*2-1)*r,t[1]=r;break;case 1:t[0]=r,t[1]=(Math.random()*2-1)*r;break;case 2:t[0]=(Math.random()*2-1)*r,t[1]=-r;break;case 3:t[0]=-r,t[1]=(Math.random()*2-1)*r;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,a=Math.random()*Math.PI*2;let r;e>0?r=e+(i-e)*Math.random():r=i*Math.sqrt(Math.random()),t[0]=Math.cos(a)*r,t[1]=Math.sin(a)*r,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,a=this.config.coneHeight||4,r=Math.random()*Math.PI*2,n=Math.random(),o=n*a,s=i*(1-n);let l;if(e>0){const u=e*(1-n);l=u+(s-u)*Math.random()}else l=s*Math.sqrt(Math.random());t[0]=Math.cos(r)*l,t[1]=o,t[2]=Math.sin(r)*l}_emitFromTorus(t){const e=this.config.torusMajorRadius||2,i=this.config.torusMinorRadius||.5,a=Math.random()*Math.PI*2,r=Math.random()*Math.PI*2,n=i*Math.sqrt(Math.random());t[0]=(e+n*Math.cos(r))*Math.cos(a),t[1]=n*Math.sin(r),t[2]=(e+n*Math.cos(r))*Math.sin(a)}_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,a=Math.random()*Math.PI*2,r=Math.acos(Math.random()),n=Math.sin(r)*Math.cos(a),o=Math.cos(r),s=Math.sin(r)*Math.sin(a);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]=s*l}_emitFromDisc(t){const e=this.config.discRadius||2,i=Math.random()*Math.PI*2,a=e*Math.sqrt(Math.random());t[0]=Math.cos(i)*a,t[1]=0,t[2]=Math.sin(i)*a}_emitFromAnnulus(t){const e=this.config.annulusInnerRadius||1,i=this.config.annulusOuterRadius||2,a=Math.random()*Math.PI*2,r=e+(i-e)*Math.random();t[0]=Math.cos(a)*r,t[1]=0,t[2]=Math.sin(a)*r}_emitFromCapsule(t){const e=this.config.capsuleRadius||.5,i=this.config.capsuleHeight||4,a=i*.5,r=Math.PI*e*e*i,n=4/3*Math.PI*e*e*e,o=r/(r+n);if(Math.random()<o){const s=Math.random()*Math.PI*2,l=e*Math.sqrt(Math.random());t[0]=Math.cos(s)*l,t[1]=(Math.random()-.5)*i,t[2]=Math.sin(s)*l}else{const s=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(s),t[1]=u*Math.cos(l),t[2]=u*Math.sin(l)*Math.sin(s),t[1]+=t[1]>=0?a:-a}}_emitFromArc(t){const e=this.config.arcStartAngle||0,i=this.config.arcEndAngle||180,a=this.config.arcInnerRadius||0,r=this.config.arcOuterRadius||2,n=e*Math.PI/180,o=i*Math.PI/180,s=n+Math.random()*(o-n);let l;a>0?l=a+(r-a)*Math.random():l=r*Math.sqrt(Math.random()),t[0]=Math.cos(s)*l,t[1]=Math.sin(s)*l,t[2]=0}_emitFromSpiral(t){const e=this.config.spiralTurns||3,i=this.config.spiralRadiusStart||.5,a=this.config.spiralRadiusEnd||2,r=this.config.spiralHeight||4,n=Math.random(),o=n*e*Math.PI*2,s=i+(a-i)*n;t[0]=Math.cos(o)*s,t[1]=(n-.5)*r,t[2]=Math.sin(o)*s}_emitFromFrustum(t){const e=this.config.frustumRadiusNear||.5,i=this.config.frustumRadiusFar||2,a=this.config.frustumHeight||4,r=Math.random()*Math.PI*2,n=Math.random(),o=n*a,l=(e+(i-e)*n)*Math.sqrt(Math.random());t[0]=Math.cos(r)*l,t[1]=o,t[2]=Math.sin(r)*l}_emitFromCubeSurface(t){const e=this.config.cubeSurfaceSize||2,i=e*.5,a=Math.floor(Math.random()*6),r=(Math.random()-.5)*e,n=(Math.random()-.5)*e;switch(a){case 0:t[0]=r,t[1]=n,t[2]=i;break;case 1:t[0]=r,t[1]=n,t[2]=-i;break;case 2:t[0]=i,t[1]=r,t[2]=n;break;case 3:t[0]=-i,t[1]=r,t[2]=n;break;case 4:t[0]=r,t[1]=i,t[2]=n;break;case 5:t[0]=r,t[1]=-i,t[2]=n;break}}_emitFromSphereSurface(t){const e=this.config.sphereSurfaceRadius||2,i=Math.random()*Math.PI*2,a=Math.acos(2*Math.random()-1);t[0]=e*Math.sin(a)*Math.cos(i),t[1]=e*Math.sin(a)*Math.sin(i),t[2]=e*Math.cos(a)}_emitFromBoxFrame(t){const e=this.config.boxFrameSize||2,i=e*.5,a=Math.floor(Math.random()*12),n=(Math.random()-.5)*e,o=[[-1,-1],[-1,1],[1,-1],[1,1]];if(a<4){const[s,l]=o[a];t[0]=n,t[1]=s*i,t[2]=l*i}else if(a<8){const[s,l]=o[a-4];t[0]=s*i,t[1]=n,t[2]=l*i}else{const[s,l]=o[a-8];t[0]=s*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,a=Math.floor(Math.random()*e),r=a/e*Math.PI*2,n=(a+1)/e*Math.PI*2;let o=Math.random(),s=Math.random();o+s>1&&(o=1-o,s=1-s);const l=o*Math.cos(r)+s*Math.cos(n),u=o*Math.sin(r)+s*Math.sin(n);t[0]=l*i,t[1]=u*i,t[2]=0}_emitFromCylinder(t){const e=this.config.cylinderInnerRadius||0,i=this.config.cylinderOuterRadius||2,a=this.config.cylinderHeight||4,r=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(r)*n,t[1]=(Math.random()-.5)*a,t[2]=Math.sin(r)*n}calculateVelocity(t,e,i,a,r){const n=this.config.shapeTranslationX||0,o=this.config.shapeTranslationY||0,s=this.config.shapeTranslationZ||0,l=t-n,u=e-o,d=i-s,f=Math.sqrt(l*l+u*u+d*d);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,u,d),P=Math.sqrt(y[0]*y[0]+y[1]*y[1]);if(P>1e-4){const g=-y[1]/P,x=y[0]/P,M=this.applyRotation(g,x,0);h=M[0],p=M[1],m=M[2],S=!0}}else if(this.config.emissionShape==="cylinder"&&this.config.cylinderVelocityDirection==="tangential"){const y=this.inverseRotation(l,u,d),P=Math.sqrt(y[0]*y[0]+y[2]*y[2]);if(P>1e-4){const g=-y[2]/P,x=y[0]/P,M=this.applyRotation(g,0,x);h=M[0],p=M[1],m=M[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=u/f,m=d/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,a[r]=this.config.overrideXVelocity?this.config.xVelocity:h*b,a[r+1]=this.config.overrideYVelocity?this.config.yVelocity:p*b,a[r+2]=this.config.overrideZVelocity?this.config.zVelocity:m*b,a[r+3]=0}setParticleColor(t,e){if(this.config.randomColorEnabled&&this.config.randomColors.length>0){const i=this.config.randomColors,a=i[Math.floor(Math.random()*i.length)];t[e+3]=a[0],t[e+4]=a[1],t[e+5]=a[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 Z{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}async initComputePipeline(t,e,i){try{return await this.createComputePipeline(t,e,i),this.computeReady=!0,!0}catch(a){return console.error("Error initializing compute pipeline:",a),!1}}async createComputePipeline(t,e,i){const{particlePhysicsShader:a}=await Promise.resolve().then(()=>J);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:a}),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,a,r,n){if(e<=0||!this.computeReady)return;const o=this._physicsData,s=this.physicsSettings;o[0]=t,o[1]=i.particleSpeed,o[2]=s.gravity,o[3]=s.turbulence,o[4]=s.attractorStrength,o[5]=s.damping,o[6]=s.attractorPosition[0],o[7]=s.attractorPosition[1],o[8]=s.attractorPosition[2],this._physicsDataU32View[9]=e,o[10]=s.confinementEnabled?1:0,o[11]=s.confinementShape==="sphere"?1:0,o[12]=s.confinementMode==="kill"?1:0,o[13]=s.confinementSpace==="local"?1:0,o[14]=s.confinementBoxHalfSize[0],o[15]=s.confinementBoxHalfSize[1],o[16]=s.confinementBoxHalfSize[2],o[17]=s.confinementSphereRadius,o[18]=s.confinementRestitution,o[19]=s.confinementFriction,o[20]=s.confinementCenter[0],o[21]=s.confinementCenter[1],o[22]=s.confinementCenter[2],o[23]=s.softBoundaryEnabled?1:0,o[24]=s.softBoundaryStrength,o[25]=s.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"}),u=l.beginComputePass({label:"ParticlePhysicsPass"});u.setPipeline(this.computePipeline),u.setBindGroup(0,this.computeBindGroup);const d=Math.max(1,Math.ceil(e/64));u.dispatchWorkgroups(d,1,1),u.end(),n||this.device.queue.submit([l.finish()]),this.lastUpdateTime=performance.now()/1e3}async readbackAndProcessParticles(t,e,i,a,r){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(a,0,this._particleDataStagingBuffer,0,o);const s=t*4*4;return n.copyBufferToBuffer(r,0,this._velocityStagingBuffer,0,s),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,s);const l=new Float32Array(this._velocityStagingBuffer.getMappedRange(0,s));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,a,r){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,s=this.device.createCommandEncoder({label:"RenderReadbackEncoder"});return s.copyBufferToBuffer(a,0,this._renderStagingParticleBuffer,0,n),s.copyBufferToBuffer(r,0,this._renderStagingVelocityBuffer,0,o),this.device.queue.submit([s.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}}}destroy(){this.physicsUniformBuffer.destroy(),this._particleDataStagingBuffer.destroy(),this._velocityStagingBuffer.destroy(),this._renderStagingParticleBuffer.destroy(),this._renderStagingVelocityBuffer.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 q{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()}}async function I(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 a=t.getUint32(8,!0);let r=12,n=null,o=null;for(;r<a;){const g=t.getUint32(r,!0),x=t.getUint32(r+4,!0),M=c.slice(r+8,r+8+g);if(x===1313821514){const B=new TextDecoder("utf-8").decode(M);n=JSON.parse(B)}else x===5130562&&(o=M);r+=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 u=l.attributes.POSITION;if(u===void 0)throw new Error("Mesh primitive missing POSITION attribute");const d=_(n,o,u,3,5126);let f;if(l.attributes.NORMAL!==void 0)f=_(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=V(n,o,g);f=ie(d,x)}const h=l.indices;if(h===void 0)throw new Error("Mesh primitive missing indices");const p=V(n,o,h),m=d.length/3,b=p.length;let S=null;l.attributes.TEXCOORD_0!==void 0&&(S=_(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 P=null;if(n.skins&&n.skins.length>0)try{P=le(n,o,l),console.log("Animation data extracted:",P)}catch(g){console.warn("Failed to extract animation data:",g)}return{positions:d,normals:f,indices:p,texCoords:S,vertexCount:m,indexCount:b,animationData:P,hasBaseColorTexture:y}}function _(c,t,e,i,a){const r=c.accessors[e],o={SCALAR:1,VEC2:2,VEC3:3,VEC4:4}[r.type];if(o!==i)throw new Error(`Attribute accessor type mismatch: expected ${i} components, got ${o}`);if(r.componentType!==a)throw new Error(`Attribute component type mismatch: expected ${a}, got ${r.componentType}`);const l=(c.bufferViews[r.bufferView].byteOffset||0)+(r.byteOffset||0),u=r.count,d=new DataView(t,l,u*i*4),f=new Float32Array(u*i);for(let h=0;h<u*i;h++)f[h]=d.getFloat32(h*4,!0);return f}function V(c,t,e){const i=c.accessors[e];if(i.type!=="SCALAR")throw new Error(`Indices accessor must be SCALAR, got ${i.type}`);const r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5123){const o=new DataView(t,r,n*2),s=new Uint16Array(n);for(let l=0;l<n;l++)s[l]=o.getUint16(l*2,!0);return s}else if(i.componentType===5125){const o=new DataView(t,r,n*4),s=new Uint32Array(n);for(let l=0;l<n;l++)s[l]=o.getUint32(l*4,!0);return s}else throw new Error(`Unsupported index component type: ${i.componentType}`)}function ie(c,t){const e=new Float32Array(c.length);for(let i=0;i<t.length;i+=3){const a=t[i]*3,r=t[i+1]*3,n=t[i+2]*3,o=[c[a],c[a+1],c[a+2]],s=[c[r],c[r+1],c[r+2]],l=[c[n],c[n+1],c[n+2]],u=[s[0]-o[0],s[1]-o[1],s[2]-o[2]],d=[l[0]-o[0],l[1]-o[1],l[2]-o[2]],f=[u[1]*d[2]-u[2]*d[1],u[2]*d[0]-u[0]*d[2],u[0]*d[1]-u[1]*d[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[a]=e[r]=e[n]=f[0],e[a+1]=e[r+1]=e[n+1]=f[1],e[a+2]=e[r+2]=e[n+2]=f[2]}return e}function ae(c,t,e){const i=c.accessors[e];if(i.type!=="VEC4")throw new Error(`JOINTS_0 must be VEC4, got ${i.type}`);const r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5121){const o=new DataView(t,r,n*4),s=new Uint8Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getUint8(l);return s}else if(i.componentType===5123){const o=new DataView(t,r,n*8),s=new Uint8Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getUint16(l*2,!0);return s}else throw new Error(`Unsupported JOINTS_0 component type: ${i.componentType}`)}function se(c,t,e){const i=c.accessors[e];if(i.type!=="VEC4")throw new Error(`WEIGHTS_0 must be VEC4, got ${i.type}`);const r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5126){const o=new DataView(t,r,n*16),s=new Float32Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getFloat32(l*4,!0);return s}else if(i.componentType===5121){const o=new DataView(t,r,n*4),s=new Float32Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getUint8(l)/255;return s}else throw new Error(`Unsupported WEIGHTS_0 component type: ${i.componentType}`)}function re(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 r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count,o=new DataView(t,r,n*64),s=new Float32Array(n*16);for(let l=0;l<n*16;l++)s[l]=o.getFloat32(l*4,!0);return s}function ne(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 r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count,o=new DataView(t,r,n*4),s=new Float32Array(n);for(let l=0;l<n;l++)s[l]=o.getFloat32(l*4,!0);return s}function oe(c,t,e){const i=c.accessors[e],r={VEC3:3,VEC4:4}[i.type];if(!r)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),s=i.count,l=new DataView(t,o,s*r*4),u=new Float32Array(s*r);for(let d=0;d<s*r;d++)u[d]=l.getFloat32(d*4,!0);return u}function le(c,t,e){const i=c.skins[0],a=i.joints,r=re(c,t,i.inverseBindMatrices),n=e.attributes.JOINTS_0!==void 0?ae(c,t,e.attributes.JOINTS_0):null,o=e.attributes.WEIGHTS_0!==void 0?se(c,t,e.attributes.WEIGHTS_0):null;if(!n||!o)throw new Error("Mesh missing JOINTS_0 or WEIGHTS_0 attributes");const s=c.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(c.animations&&c.animations.length>0)for(const u of c.animations){const d=[];let f=0;for(const h of u.channels){const p=u.samplers[h.sampler],m=ne(c,t,p.input),b=oe(c,t,p.output),S=m[m.length-1];S>f&&(f=S),d.push({targetNode:h.target.node,targetPath:h.target.path,interpolation:p.interpolation||"LINEAR",timestamps:m,values:b})}l.push({name:u.name||`Animation ${l.length}`,duration:f,channels:d})}return{joints:a,inverseBindMatrices:r,jointIndices:n,jointWeights:o,nodes:s,animations:l}}async function $(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 a=t.getUint32(8,!0);let r=12,n=null,o=null;for(;r<a;){const P=t.getUint32(r,!0),g=t.getUint32(r+4,!0),x=c.slice(r+8,r+8+P);if(g===1313821514){const R=new TextDecoder("utf-8").decode(x);n=JSON.parse(R)}else g===5130562&&(o=x);r+=8+P}if(!n)throw new Error("GLB file missing JSON chunk");if(!n.materials||n.materials.length===0)return null;const s=n.materials[0];if(!s.pbrMetallicRoughness||s.pbrMetallicRoughness.baseColorTexture===void 0)return null;const l=s.pbrMetallicRoughness.baseColorTexture.index;if(!n.textures||!n.textures[l])return null;const d=n.textures[l].source;if(d===void 0||!n.images||!n.images[d])return null;const f=n.images[d],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 D=Object.freeze(Object.defineProperty({__proto__:null,extractGLBTexture:$,parseGLB:I},Symbol.toStringTag,{value:"Module"}));function L(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 O(c,t,e){let i=c[0]*t[0]+c[1]*t[1]+c[2]*t[2]+c[3]*t[3],a=t;if(i<0&&(i=-i,a=[-t[0],-t[1],-t[2],-t[3]]),i>.9995){const l=[c[0]+(a[0]-c[0])*e,c[1]+(a[1]-c[1])*e,c[2]+(a[2]-c[2])*e,c[3]+(a[3]-c[3])*e];return ce(l)}const r=Math.acos(i),n=Math.sin(r),o=Math.sin((1-e)*r)/n,s=Math.sin(e*r)/n;return[c[0]*o+a[0]*s,c[1]*o+a[1]*s,c[2]*o+a[2]*s,c[3]*o+a[3]*s]}function ce(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 ue(c){const t=c[0],e=c[1],i=c[2],a=c[3],r=t+t,n=e+e,o=i+i,s=t*r,l=t*n,u=t*o,d=e*n,f=e*o,h=i*o,p=a*r,m=a*n,b=a*o;return new Float32Array([1-(d+h),l+b,u-m,0,l-b,1-(s+h),f+p,0,u+m,f-p,1-(s+d),0,0,0,0,1])}function de(c,t,e){const i=ue(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 j(c,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let a=0;a<4;a++)e[i*4+a]=c[0+a]*t[i*4+0]+c[4+a]*t[i*4+1]+c[8+a]*t[i*4+2]+c[12+a]*t[i*4+3];return e}class H{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 a=this.restPositions.length/3,r=new Float32Array(a*8);for(let l=0;l<a;l++){const u=l*8,d=l*3,f=l*2;r[u]=this.restPositions[d],r[u+1]=this.restPositions[d+1],r[u+2]=this.restPositions[d+2],r[u+3]=this.restNormals[d],r[u+4]=this.restNormals[d+1],r[u+5]=this.restNormals[d+2],r[u+6]=i?i[f]:0,r[u+7]=i?i[f+1]:0}this._gpuRestDataBuffer=t.createBuffer({size:r.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_restData"}),t.queue.writeBuffer(this._gpuRestDataBuffer,0,r),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(()=>J),s=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:[s]}),compute:{module:t.createShaderModule({code:o}),entryPoint:"main"}}),this._gpuSkinningBindGroup=t.createBindGroup({layout:s,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=a,this._gpuSkinningReady=!0,console.log(`GPU skinning initialized: ${a} vertices, ${this.joints.length} joints`)}catch(a){console.warn("GPU skinning init failed, using CPU fallback:",a),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=r=>{if(t.has(r))return;t.add(r);const n=this.nodes[r];for(const o of n.children)i(o);e.push(r)},a=new Set;for(const r of this.nodes)for(const n of r.children)a.add(n);for(let r=0;r<this.nodes.length;r++)a.has(r)||i(r);this.topologicalOrder=e.reverse()}_sampleChannel(t,e){const{timestamps:i,values:a,interpolation:r,targetPath:n}=t;if(e<=i[0])return this._extractValue(a,0,n);if(e>=i[i.length-1])return this._extractValue(a,i.length-1,n);let o=0,s=i.length-1;for(;s-o>1;){const p=Math.floor((o+s)/2);i[p]<=e?o=p:s=p}const l=i[o],u=i[s],d=(e-l)/(u-l),f=this._extractValue(a,o,n),h=this._extractValue(a,s,n);return r==="STEP"?f:n==="rotation"?O(f,h,d):L(f,h,d)}_extractValue(t,e,i){if(i==="rotation"){const a=e*4;return[t[a],t[a+1],t[a+2],t[a+3]]}else{const a=e*3;return[t[a],t[a+1],t[a+2]]}}_computeLocalTransforms(t){const e=this.animations[this.currentAnimIndex];for(let i=0;i<this.nodes.length;i++){const a=this.nodes[i];let r=a.translation,n=a.rotation,o=a.scale;for(const s of e.channels)if(s.targetNode===i){const l=this._sampleChannel(s,t);s.targetPath==="translation"?r=l:s.targetPath==="rotation"?n=l:s.targetPath==="scale"&&(o=l)}this.jointLocalTransforms[i]=de(r,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 a of i.children)t[a]=e}for(const e of this.topologicalOrder){const i=t[e];i===-1?this.jointGlobalTransforms[e]=this.jointLocalTransforms[e]:this.jointGlobalTransforms[e]=j(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],a=t*16,r=this.inverseBindMatrices.slice(a,a+16);this.jointFinalMatrices[t]=j(i,r)}}_applySkinning(){const t=this.restPositions.length/3,e=this.restPositions,i=this.restNormals,a=this.skinnedPositions,r=this.skinnedNormals,n=this.jointWeights,o=this.jointIndices,s=this.jointFinalMatrices;for(let l=0;l<t;l++){const u=l*3,d=l*4,f=e[u],h=e[u+1],p=e[u+2],m=i[u],b=i[u+1],S=i[u+2];let y=0,P=0,g=0,x=0,M=0,R=0;for(let T=0;T<4;T++){const w=n[d+T];if(w===0)continue;const v=s[o[d+T]];y+=(v[0]*f+v[4]*h+v[8]*p+v[12])*w,P+=(v[1]*f+v[5]*h+v[9]*p+v[13])*w,g+=(v[2]*f+v[6]*h+v[10]*p+v[14])*w,x+=(v[0]*m+v[4]*b+v[8]*S)*w,M+=(v[1]*m+v[5]*b+v[9]*S)*w,R+=(v[2]*m+v[6]*b+v[10]*S)*w}const B=Math.sqrt(x*x+M*M+R*R);B>1e-4&&(r[u]=x/B,r[u+1]=M/B,r[u+2]=R/B),a[u]=y,a[u+1]=P,a[u+2]=g}}}function N(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 C{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.shapeRotationX===void 0&&(e.shapeRotationX=0),e.shapeRotationY===void 0&&(e.shapeRotationY=0),e.shapeRotationZ===void 0&&(e.shapeRotationZ=0),e.shapeTranslationX===void 0&&(e.shapeTranslationX=0),e.shapeTranslationY===void 0&&(e.shapeTranslationY=0),e.shapeTranslationZ===void 0&&(e.shapeTranslationZ=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.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 Y(e),this.physics=new Z(t,this.MAX_PARTICLES),this.textureManager=new q(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.initComputePipeline(t)}async initComputePipeline(t){this.computeReady=await this.physics.initComputePipeline(this.instanceBuffer,this.velocityBuffer,this.trailBuffer)}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 I(t);this.glbMeshData=e,this.config.glbHasTexture=e.hasBaseColorTexture||!1;const i=new Float32Array(e.vertexCount*8);for(let a=0;a<e.vertexCount;a++){const r=a*8,n=a*3,o=a*2;i[r+0]=e.positions[n+0],i[r+1]=e.positions[n+1],i[r+2]=e.positions[n+2],i[r+3]=e.normals[n+0],i[r+4]=e.normals[n+1],i[r+5]=e.normals[n+2],e.texCoords?(i[r+6]=e.texCoords[o+0],i[r+7]=e.texCoords[o+1]):(i[r+6]=0,i[r+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 H(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(a){console.warn("GPU skinning init failed, using CPU fallback:",a)}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),a=Math.cos(this._simRotZ),r=Math.sin(this._simRotZ);this._simRotMatrix=[a,-r*e,r*i,r,a*e,-a*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 a=0;a<this.glbMeshData.vertexCount;a++){const r=a*8,n=a*3,o=a*2;this._glbInterleavedData[r]=t[n],this._glbInterleavedData[r+1]=t[n+1],this._glbInterleavedData[r+2]=t[n+2],this._glbInterleavedData[r+3]=e[n],this._glbInterleavedData[r+4]=e[n+1],this._glbInterleavedData[r+5]=e[n+2],i?(this._glbInterleavedData[r+6]=i[o],this._glbInterleavedData[r+7]=i[o+1]):(this._glbInterleavedData[r+6]=0,this._glbInterleavedData[r+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,a=this._appearanceData;a[0]=this.config.fadeEnabled?1:0,a[1]=this.config.randomColorEnabled?2:this.config.colorTransitionEnabled?1:0,a[2]=this.config.particleSize,a[3]=this.config.textureEnabled?1:0,a[4]=this.config.particleColor[0],a[5]=this.config.particleColor[1],a[6]=this.config.particleColor[2],a[7]=this.config.rotation||0,a[8]=this.config.startColor[0],a[9]=this.config.startColor[1],a[10]=this.config.startColor[2],a[11]=t,a[12]=this.config.endColor[0],a[13]=this.config.endColor[1],a[14]=this.config.endColor[2],a[15]=this.config.minRotation||0,a[16]=this.config.maxRotation||90,a[17]=this.config.aspectRatio||1,a[18]=this.config.randomSize?1:0,a[19]=this.config.minSize||.1,a[20]=this.config.maxSize||.5,a[21]=this.config.fadeSizeEnabled?1:0,a[22]=this.config.opacity!==void 0?this.config.opacity:1,a[23]=this.config.increaseSizeEnabled?1:0,a[24]=this.config.sizeLifetimeSpeed??1,a[25]=i,a[26]=this.config.particleShapeRotation||0,a[27]=this.config.pulseEnabled?1:0,a[28]=this.config.pulseAmplitude??.5,a[29]=this.config.pulseFrequency??1,a[30]=this.config.pulsePhaseRandom??0,a[31]=this.config.pulseOpacity?1:0,a[32]=this.config.particleShapeRotationX||0,a[33]=this.config.particleShapeRotationY||0,a[34]=this.config.particleShapeRotationZ||0,a[35]=0,(a[32]!==0||a[33]!==0||a[34]!==0)&&console.log(`[updateAppearanceUniform] ${this.config.name}: d[32-34] = ${a[32]}, ${a[33]}, ${a[34]}`),a[36]=this._simPosition[0],a[37]=this._simPosition[1],a[38]=this._simPosition[2],a[39]=0,a[40]=this._simRotX,a[41]=this._simRotZ,a[42]=this.config.velocityStretchEnabled?1:0,a[43]=this.config.velocityStretchFactor??1,this.device.queue.writeBuffer(this.appearanceUniformBuffer,0,a)}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.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 a=0;a<t;a++)if(this.emitParticle(),e++,e>=i||a===t-1){const r=a-e+1,n=r*8,o=r*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],a=this.particleData[t+1],r=this.particleData[t+2],n=this.particleVelocities[e],o=this.particleVelocities[e+1],s=this.particleVelocities[e+2];const l=this._simRotMatrix;this.particleData[t]=l[0]*i+l[1]*a+l[2]*r,this.particleData[t+1]=l[3]*i+l[4]*a+l[5]*r,this.particleData[t+2]=l[6]*i+l[7]*a+l[8]*r,this.particleVelocities[e]=l[0]*n+l[1]*o+l[2]*s,this.particleVelocities[e+1]=l[3]*n+l[4]*o+l[5]*s,this.particleVelocities[e+2]=l[6]*n+l[7]*o+l[8]*s}return 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 a=this.activeParticles*8,r=t+(this.config.shapeTranslationX||0),n=e+(this.config.shapeTranslationY||0),o=i+(this.config.shapeTranslationZ||0);this.particleData[a]=r,this.particleData[a+1]=n,this.particleData[a+2]=o;const s=this.activeParticles*4;return this.emitter.calculateVelocity(r,n,o,this.particleVelocities,s),this.emitter.setParticleColor(this.particleData,a),this.emitter.setParticleLifetime(this.particleData,a),this.activeParticles++,!0}updateParticles(t,e){this.physics.physicsAccumulator+=t;const i=performance.now()/1e3,r=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 s=!1;if(this.config.followSystemId){if(this._pendingFollowEmissions.length>0){const l=this._pendingFollowEmissions.length/6;for(let u=0;u<l;u++){const d=u*6;if(this.emitFollowerParticle(this._pendingFollowEmissions[d],this._pendingFollowEmissions[d+1],this._pendingFollowEmissions[d+2]))s=!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&&r&&this.config.emissionRate>0&&this.activeParticles<this.particleCount&&(l=1);for(let u=0;u<l&&this.emitParticle();u++)s=!0}if(s){const l=this.activeParticles-o,u=o*8,d=o*4;this.device.queue.writeBuffer(this.instanceBuffer,u*4,this.particleData,u,l*8),this.device.queue.writeBuffer(this.velocityBuffer,d*4,this.particleVelocities,d,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;r&&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()}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 a=this.particleData[i*8+6],r=this.particleData[i*8+7];if(a>=r){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 s=i*4,l=e*4;this.particleVelocities.copyWithin(l,s,s+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,a=i[Math.floor(Math.random()*i.length)];this.particleData[e+3]=a[0],this.particleData[e+4]=a[1],this.particleData[e+5]=a[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,a=this.particleData[e],r=this.particleData[e+1],n=this.particleData[e+2],o=this.particleVelocities[i],s=this.particleVelocities[i+1],l=this.particleVelocities[i+2],u=Math.sqrt(o*o+s*s+l*l);if(u>.001){const d=this.config.particleSpeed*2;this.particleVelocities[i]=o/u*d,this.particleVelocities[i+1]=s/u*d,this.particleVelocities[i+2]=l/u*d}else{const d=Math.sqrt(a*a+r*r+n*n);if(d>.001){const f=this.config.particleSpeed*2;this.particleVelocities[i]=a/d*f,this.particleVelocities[i+1]=r/d*f,this.particleVelocities[i+2]=n/d*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.glbAnimator=null,this.glbMeshData=null,this.glbRawArrayBuffer=null,this.particleData=null,this.particleVelocities=null}setGravity(t){this.physics.setGravity(t)}setAttractor(t,e){this.physics.setAttractor(t,e)}setConfinement(t){const e=t.space==="local"?[this.config.shapeTranslationX||0,this.config.shapeTranslationY||0,this.config.shapeTranslationZ||0]:[0,0,0];this.physics.setConfinement({...t,center:e})}setSoftBoundary(t){this.physics.setSoftBoundary(t)}}class fe{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}`,a={...t,name:i,id:e},r=new C(this.device,a);return this.particleSystems.push({system:r,config:a}),this.particleSystems.length===1&&(this.activeSystemIndex=0),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(e,a),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:a}of this.particleSystems)a.followSystemId===i&&(a.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:a,config:r}of this.particleSystems){if(r.hidden||r.followSystemId)continue;const n=a.activeParticles>0;a.updateParticles(t,e),(n||a.activeParticles>0)&&(i=!0)}for(const{system:a,config:r}of this.particleSystems){if(r.hidden||!r.followSystemId)continue;const n=this.getSystemById(r.followSystemId);n&&(a._pendingFollowEmissions=n.system._newEmissions);const o=a.activeParticles>0;a.updateParticles(t,e),(o||a.activeParticles>0)&&(i=!0)}i&&this.device.queue.submit([e.finish()]);for(const{system:a}of this.particleSystems)a._newEmissions.length=0,a._pendingFollowEmissions=a._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 a of t.systems){const r=this.systemCounter++,n={...a,id:r},o=new C(this.device,n);this.particleSystems.push({system:o,config:n})}const i={};t.systems.forEach((a,r)=>{i[a.id]=this.particleSystems[r].config.id});for(const{config:a}of this.particleSystems)a.followSystemId&&i[a.followSystemId]!==void 0&&(a.followSystemId=i[a.followSystemId]);t.activeSystemIndex!==void 0&&t.activeSystemIndex>=0&&t.activeSystemIndex<this.particleSystems.length?this.activeSystemIndex=t.activeSystemIndex:this.activeSystemIndex=0;for(const{system:a,config:r}of this.particleSystems)if(r.glbModelEnabled)try{let n=null;if(r.glbModelData)n=N(r.glbModelData);else if(r.glbFileName){const o=await fetch(`/${r.glbFileName}`);o.ok?n=await o.arrayBuffer():console.warn(`GLB file not found: ${r.glbFileName}`)}if(n){if(await a.setGLBModel(n),r.animationIndex!==void 0&&a.glbAnimator&&a.glbAnimator.setAnimation(r.animationIndex),r.animationSpeed!==void 0&&a.glbAnimator&&(a.glbAnimator.speed=r.animationSpeed),r.animationLoop!==void 0&&a.glbAnimator&&(a.glbAnimator.loop=r.animationLoop),r.useGlbTexture&&(r.textureEnabled=!0),r.useGlbTexture&&((e=a.glbMeshData)!=null&&e.hasBaseColorTexture))try{const{extractGLBTexture:o}=await Promise.resolve().then(()=>D),s=await o(n);if(s){const l=await createImageBitmap(s.imageBlob);await a.setTexture(l),console.log(`GLB embedded texture restored for ${r.name}`)}}catch(o){console.warn(`Failed to restore GLB texture for ${r.name}:`,o),r.useGlbTexture=!1}}else r.glbModelEnabled=!1}catch(n){console.warn(`Failed to load GLB for ${r.name}:`,n),r.glbModelEnabled=!1}for(const{system:a,config:r}of this.particleSystems)if(r.textureEnabled&&!r.glbModelEnabled&&r.textureImageData)try{const n=new Image;await new Promise((s,l)=>{n.onload=s,n.onerror=l,n.src=r.textureImageData});const o=await createImageBitmap(n);await a.setTexture(o)}catch(n){console.warn(`Failed to restore texture for ${r.name}:`,n),r.textureEnabled=!1}for(const{system:a,config:r}of this.particleSystems)a.updateAppearanceUniform(),(r.particleShapeRotationX||r.particleShapeRotationY||r.particleShapeRotationZ)&&console.log(`[replaceSystems] ${r.name}: glbRotation XYZ = ${r.particleShapeRotationX}, ${r.particleShapeRotationY}, ${r.particleShapeRotationZ} | glbModelEnabled=${r.glbModelEnabled} | glbMeshData=${!!a.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++,s={...n,id:o,shapeTranslationX:(n.shapeTranslationX||0)+e[0],shapeTranslationY:(n.shapeTranslationY||0)+e[1],shapeTranslationZ:(n.shapeTranslationZ||0)+e[2]};n.attractorEnabled&&n.attractorPosition&&(s.attractorPosition=[n.attractorPosition[0]+e[0],n.attractorPosition[1]+e[1],n.attractorPosition[2]+e[2]]);const l=new C(this.device,s);this.particleSystems.push({system:l,config:s}),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(o,s)}const a=this.particleSystems.length-t.systems.length,r={};t.systems.forEach((n,o)=>{r[n.id]=this.particleSystems[a+o].config.id});for(let n=a;n<this.particleSystems.length;n++){const{config:o}=this.particleSystems[n];o.followSystemId&&r[o.followSystemId]!==void 0&&(o.followSystemId=r[o.followSystemId])}for(const{system:n,config:o}of this.particleSystems)if(o.glbModelEnabled&&!n.glbMeshData)try{let s=null;if(o.glbModelData)s=N(o.glbModelData);else if(o.glbFileName){const l=await fetch(`/${o.glbFileName}`);l.ok?s=await l.arrayBuffer():console.warn(`GLB file not found: ${o.glbFileName}`)}if(s){if(await n.setGLBModel(s),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(()=>D),u=await l(s);if(u){const d=await createImageBitmap(u.imageBlob);await n.setTexture(d),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(s){console.warn(`Failed to load GLB for ${o.name}:`,s),o.glbModelEnabled=!1}for(const{system:n,config:o}of this.particleSystems)if(o.textureEnabled&&!o.glbModelEnabled&&o.textureImageData&&!n._textureRestored)try{const s=new Image;await new Promise((u,d)=>{s.onload=u,s.onerror=d,s.src=o.textureImageData});const l=await createImageBitmap(s);await n.setTexture(l),n._textureRestored=!0}catch(s){console.warn(`Failed to restore texture for ${o.name}:`,s),o.textureEnabled=!1}return!0}catch(a){return console.error("Error adding systems:",a),!1}}}async function he(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(),a=navigator.gpu.getPreferredCanvasFormat();return t.configure({device:i,format:a,alphaMode:"premultiplied"}),{device:i,context:t,format:a,canvas:c}}function pe(c,t,e,i){const a=c.createTexture({size:[e,i],format:t,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1}),r=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:a,bloomTexA:r,bloomTexB:n}}function me(c,t,e){return c.createTexture({size:[t,e],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT})}function E(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 U=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class Y{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.shapeRotationX||0,e=this.config.shapeRotationY||0,i=this.config.shapeRotationZ||0;if(t===this._cachedRotX&&e===this._cachedRotY&&i===this._cachedRotZ)return;this._cachedRotX=t,this._cachedRotY=e,this._cachedRotZ=i;const a=t*Math.PI/180,r=e*Math.PI/180,n=i*Math.PI/180,o=Math.cos(a),s=Math.sin(a),l=Math.cos(r),u=Math.sin(r),d=Math.cos(n),f=Math.sin(n);this._rotMatrix=[l*d,s*u*d-o*f,o*u*d+s*f,l*f,s*u*f+o*d,o*u*f-s*d,-u,s*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 a=this._posOut;if(this.config.emissionShape==="cube"?this._emitFromCube(a):this.config.emissionShape==="sphere"?this._emitFromSphere(a):this.config.emissionShape==="square"?this._emitFromSquare(a):this.config.emissionShape==="circle"?this._emitFromCircle(a):this.config.emissionShape==="cylinder"?this._emitFromCylinder(a):this.config.emissionShape==="plain"?this._emitFromPlain(a):this.config.emissionShape==="cone"?this._emitFromCone(a):this.config.emissionShape==="torus"?this._emitFromTorus(a):this.config.emissionShape==="line"?this._emitFromLine(a):this.config.emissionShape==="hemisphere"?this._emitFromHemisphere(a):this.config.emissionShape==="disc"?this._emitFromDisc(a):this.config.emissionShape==="annulus"?this._emitFromAnnulus(a):this.config.emissionShape==="capsule"?this._emitFromCapsule(a):this.config.emissionShape==="arc"?this._emitFromArc(a):this.config.emissionShape==="spiral"?this._emitFromSpiral(a):this.config.emissionShape==="frustum"?this._emitFromFrustum(a):this.config.emissionShape==="cubeSurface"?this._emitFromCubeSurface(a):this.config.emissionShape==="sphereSurface"?this._emitFromSphereSurface(a):this.config.emissionShape==="boxFrame"?this._emitFromBoxFrame(a):this.config.emissionShape==="polygon"?this._emitFromPolygon(a):(a[0]=0,a[1]=0,a[2]=0),this.config.shapeRotationX||this.config.shapeRotationY||this.config.shapeRotationZ){this._updateRotationMatrix();const o=this._rotMatrix,s=a[0],l=a[1],u=a[2];a[0]=o[0]*s+o[1]*l+o[2]*u,a[1]=o[3]*s+o[4]*l+o[5]*u,a[2]=o[6]*s+o[7]*l+o[8]*u}(this.config.shapeTranslationX||this.config.shapeTranslationY||this.config.shapeTranslationZ)&&(a[0]+=this.config.shapeTranslationX||0,a[1]+=this.config.shapeTranslationY||0,a[2]+=this.config.shapeTranslationZ||0);const r=e*8;t[r]=a[0],t[r+1]=a[1],t[r+2]=a[2];const n=e*4;this.calculateVelocity(a[0],a[1],a[2],i,n),this.setParticleColor(t,r),this.setParticleLifetime(t,r)}applyRotation(t,e,i){this._updateRotationMatrix();const a=this._rotMatrix;return[a[0]*t+a[1]*e+a[2]*i,a[3]*t+a[4]*e+a[5]*i,a[6]*t+a[7]*e+a[8]*i]}inverseRotation(t,e,i){this._updateRotationMatrix();const a=this._invRotMatrix;return[a[0]*t+a[1]*e+a[2]*i,a[3]*t+a[4]*e+a[5]*i,a[6]*t+a[7]*e+a[8]*i]}_emitFromCube(t){let e=this.config.innerLength||0,i=this.config.outerLength||this.config.cubeLength;if(e>0){const a=Math.floor(Math.random()*6),r=Math.random()-.5,n=Math.random()-.5;let o,s,l;switch(a){case 0:o=r,s=n,l=.5;break;case 1:o=r,s=n,l=-.5;break;case 2:o=.5,s=r,l=n;break;case 3:o=-.5,s=r,l=n;break;case 4:o=r,s=.5,l=n;break;case 5:o=r,s=-.5,l=n;break}const u=Math.random(),d=e+u*(i-e);t[0]=o*d,t[1]=s*d,t[2]=l*d}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),a=Math.sin(i)*Math.cos(e),r=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]=a*o,t[1]=r*o,t[2]=n*o}_emitFromSquare(t){const e=this.config.squareInnerSize||0,i=this.config.squareSize||2;if(e>0){const a=Math.floor(Math.random()*4);let r=e+(i-e)*Math.random();switch(a){case 0:t[0]=(Math.random()*2-1)*r,t[1]=r;break;case 1:t[0]=r,t[1]=(Math.random()*2-1)*r;break;case 2:t[0]=(Math.random()*2-1)*r,t[1]=-r;break;case 3:t[0]=-r,t[1]=(Math.random()*2-1)*r;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,a=Math.random()*Math.PI*2;let r;e>0?r=e+(i-e)*Math.random():r=i*Math.sqrt(Math.random()),t[0]=Math.cos(a)*r,t[1]=Math.sin(a)*r,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,a=this.config.coneHeight||4,r=Math.random()*Math.PI*2,n=Math.random(),o=n*a,s=i*(1-n);let l;if(e>0){const u=e*(1-n);l=u+(s-u)*Math.random()}else l=s*Math.sqrt(Math.random());t[0]=Math.cos(r)*l,t[1]=o,t[2]=Math.sin(r)*l}_emitFromTorus(t){const e=this.config.torusMajorRadius||2,i=this.config.torusMinorRadius||.5,a=Math.random()*Math.PI*2,r=Math.random()*Math.PI*2,n=i*Math.sqrt(Math.random());t[0]=(e+n*Math.cos(r))*Math.cos(a),t[1]=n*Math.sin(r),t[2]=(e+n*Math.cos(r))*Math.sin(a)}_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,a=Math.random()*Math.PI*2,r=Math.acos(Math.random()),n=Math.sin(r)*Math.cos(a),o=Math.cos(r),s=Math.sin(r)*Math.sin(a);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]=s*l}_emitFromDisc(t){const e=this.config.discRadius||2,i=Math.random()*Math.PI*2,a=e*Math.sqrt(Math.random());t[0]=Math.cos(i)*a,t[1]=0,t[2]=Math.sin(i)*a}_emitFromAnnulus(t){const e=this.config.annulusInnerRadius||1,i=this.config.annulusOuterRadius||2,a=Math.random()*Math.PI*2,r=e+(i-e)*Math.random();t[0]=Math.cos(a)*r,t[1]=0,t[2]=Math.sin(a)*r}_emitFromCapsule(t){const e=this.config.capsuleRadius||.5,i=this.config.capsuleHeight||4,a=i*.5,r=Math.PI*e*e*i,n=4/3*Math.PI*e*e*e,o=r/(r+n);if(Math.random()<o){const s=Math.random()*Math.PI*2,l=e*Math.sqrt(Math.random());t[0]=Math.cos(s)*l,t[1]=(Math.random()-.5)*i,t[2]=Math.sin(s)*l}else{const s=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(s),t[1]=u*Math.cos(l),t[2]=u*Math.sin(l)*Math.sin(s),t[1]+=t[1]>=0?a:-a}}_emitFromArc(t){const e=this.config.arcStartAngle||0,i=this.config.arcEndAngle||180,a=this.config.arcInnerRadius||0,r=this.config.arcOuterRadius||2,n=e*Math.PI/180,o=i*Math.PI/180,s=n+Math.random()*(o-n);let l;a>0?l=a+(r-a)*Math.random():l=r*Math.sqrt(Math.random()),t[0]=Math.cos(s)*l,t[1]=Math.sin(s)*l,t[2]=0}_emitFromSpiral(t){const e=this.config.spiralTurns||3,i=this.config.spiralRadiusStart||.5,a=this.config.spiralRadiusEnd||2,r=this.config.spiralHeight||4,n=Math.random(),o=n*e*Math.PI*2,s=i+(a-i)*n;t[0]=Math.cos(o)*s,t[1]=(n-.5)*r,t[2]=Math.sin(o)*s}_emitFromFrustum(t){const e=this.config.frustumRadiusNear||.5,i=this.config.frustumRadiusFar||2,a=this.config.frustumHeight||4,r=Math.random()*Math.PI*2,n=Math.random(),o=n*a,l=(e+(i-e)*n)*Math.sqrt(Math.random());t[0]=Math.cos(r)*l,t[1]=o,t[2]=Math.sin(r)*l}_emitFromCubeSurface(t){const e=this.config.cubeSurfaceSize||2,i=e*.5,a=Math.floor(Math.random()*6),r=(Math.random()-.5)*e,n=(Math.random()-.5)*e;switch(a){case 0:t[0]=r,t[1]=n,t[2]=i;break;case 1:t[0]=r,t[1]=n,t[2]=-i;break;case 2:t[0]=i,t[1]=r,t[2]=n;break;case 3:t[0]=-i,t[1]=r,t[2]=n;break;case 4:t[0]=r,t[1]=i,t[2]=n;break;case 5:t[0]=r,t[1]=-i,t[2]=n;break}}_emitFromSphereSurface(t){const e=this.config.sphereSurfaceRadius||2,i=Math.random()*Math.PI*2,a=Math.acos(2*Math.random()-1);t[0]=e*Math.sin(a)*Math.cos(i),t[1]=e*Math.sin(a)*Math.sin(i),t[2]=e*Math.cos(a)}_emitFromBoxFrame(t){const e=this.config.boxFrameSize||2,i=e*.5,a=Math.floor(Math.random()*12),n=(Math.random()-.5)*e,o=[[-1,-1],[-1,1],[1,-1],[1,1]];if(a<4){const[s,l]=o[a];t[0]=n,t[1]=s*i,t[2]=l*i}else if(a<8){const[s,l]=o[a-4];t[0]=s*i,t[1]=n,t[2]=l*i}else{const[s,l]=o[a-8];t[0]=s*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,a=Math.floor(Math.random()*e),r=a/e*Math.PI*2,n=(a+1)/e*Math.PI*2;let o=Math.random(),s=Math.random();o+s>1&&(o=1-o,s=1-s);const l=o*Math.cos(r)+s*Math.cos(n),u=o*Math.sin(r)+s*Math.sin(n);t[0]=l*i,t[1]=u*i,t[2]=0}_emitFromCylinder(t){const e=this.config.cylinderInnerRadius||0,i=this.config.cylinderOuterRadius||2,a=this.config.cylinderHeight||4,r=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(r)*n,t[1]=(Math.random()-.5)*a,t[2]=Math.sin(r)*n}calculateVelocity(t,e,i,a,r){const n=this.config.shapeTranslationX||0,o=this.config.shapeTranslationY||0,s=this.config.shapeTranslationZ||0,l=t-n,u=e-o,d=i-s,f=Math.sqrt(l*l+u*u+d*d);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,u,d),P=Math.sqrt(y[0]*y[0]+y[1]*y[1]);if(P>1e-4){const g=-y[1]/P,x=y[0]/P,M=this.applyRotation(g,x,0);h=M[0],p=M[1],m=M[2],S=!0}}else if(this.config.emissionShape==="cylinder"&&this.config.cylinderVelocityDirection==="tangential"){const y=this.inverseRotation(l,u,d),P=Math.sqrt(y[0]*y[0]+y[2]*y[2]);if(P>1e-4){const g=-y[2]/P,x=y[0]/P,M=this.applyRotation(g,0,x);h=M[0],p=M[1],m=M[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=u/f,m=d/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,a[r]=this.config.overrideXVelocity?this.config.xVelocity:h*b,a[r+1]=this.config.overrideYVelocity?this.config.yVelocity:p*b,a[r+2]=this.config.overrideZVelocity?this.config.zVelocity:m*b,a[r+3]=0}setParticleColor(t,e){if(this.config.randomColorEnabled&&this.config.randomColors.length>0){const i=this.config.randomColors,a=i[Math.floor(Math.random()*i.length)];t[e+3]=a[0],t[e+4]=a[1],t[e+5]=a[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 Z{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}async initComputePipeline(t,e,i){try{return await this.createComputePipeline(t,e,i),this.computeReady=!0,!0}catch(a){return console.error("Error initializing compute pipeline:",a),!1}}async createComputePipeline(t,e,i){const{particlePhysicsShader:a}=await Promise.resolve().then(()=>J);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:a}),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,a,r,n){if(e<=0||!this.computeReady)return;const o=this._physicsData,s=this.physicsSettings;o[0]=t,o[1]=i.particleSpeed,o[2]=s.gravity,o[3]=s.turbulence,o[4]=s.attractorStrength,o[5]=s.damping,o[6]=s.attractorPosition[0],o[7]=s.attractorPosition[1],o[8]=s.attractorPosition[2],this._physicsDataU32View[9]=e,o[10]=s.confinementEnabled?1:0,o[11]=s.confinementShape==="sphere"?1:0,o[12]=s.confinementMode==="kill"?1:0,o[13]=s.confinementSpace==="local"?1:0,o[14]=s.confinementBoxHalfSize[0],o[15]=s.confinementBoxHalfSize[1],o[16]=s.confinementBoxHalfSize[2],o[17]=s.confinementSphereRadius,o[18]=s.confinementRestitution,o[19]=s.confinementFriction,o[20]=s.confinementCenter[0],o[21]=s.confinementCenter[1],o[22]=s.confinementCenter[2],o[23]=s.softBoundaryEnabled?1:0,o[24]=s.softBoundaryStrength,o[25]=s.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"}),u=l.beginComputePass({label:"ParticlePhysicsPass"});u.setPipeline(this.computePipeline),u.setBindGroup(0,this.computeBindGroup);const d=Math.max(1,Math.ceil(e/64));u.dispatchWorkgroups(d,1,1),u.end(),n||this.device.queue.submit([l.finish()]),this.lastUpdateTime=performance.now()/1e3}async readbackAndProcessParticles(t,e,i,a,r){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(a,0,this._particleDataStagingBuffer,0,o);const s=t*4*4;return n.copyBufferToBuffer(r,0,this._velocityStagingBuffer,0,s),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,s);const l=new Float32Array(this._velocityStagingBuffer.getMappedRange(0,s));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,a,r){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,s=this.device.createCommandEncoder({label:"RenderReadbackEncoder"});return s.copyBufferToBuffer(a,0,this._renderStagingParticleBuffer,0,n),s.copyBufferToBuffer(r,0,this._renderStagingVelocityBuffer,0,o),this.device.queue.submit([s.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}}}destroy(){this.physicsUniformBuffer.destroy(),this._particleDataStagingBuffer.destroy(),this._velocityStagingBuffer.destroy(),this._renderStagingParticleBuffer.destroy(),this._renderStagingVelocityBuffer.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 q{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()}}async function I(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 a=t.getUint32(8,!0);let r=12,n=null,o=null;for(;r<a;){const g=t.getUint32(r,!0),x=t.getUint32(r+4,!0),M=c.slice(r+8,r+8+g);if(x===1313821514){const B=new TextDecoder("utf-8").decode(M);n=JSON.parse(B)}else x===5130562&&(o=M);r+=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 u=l.attributes.POSITION;if(u===void 0)throw new Error("Mesh primitive missing POSITION attribute");const d=C(n,o,u,3,5126);let f;if(l.attributes.NORMAL!==void 0)f=C(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=D(n,o,g);f=ie(d,x)}const h=l.indices;if(h===void 0)throw new Error("Mesh primitive missing indices");const p=D(n,o,h),m=d.length/3,b=p.length;let S=null;l.attributes.TEXCOORD_0!==void 0&&(S=C(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 P=null;if(n.skins&&n.skins.length>0)try{P=le(n,o,l),console.log("Animation data extracted:",P)}catch(g){console.warn("Failed to extract animation data:",g)}return{positions:d,normals:f,indices:p,texCoords:S,vertexCount:m,indexCount:b,animationData:P,hasBaseColorTexture:y}}function C(c,t,e,i,a){const r=c.accessors[e],o={SCALAR:1,VEC2:2,VEC3:3,VEC4:4}[r.type];if(o!==i)throw new Error(`Attribute accessor type mismatch: expected ${i} components, got ${o}`);if(r.componentType!==a)throw new Error(`Attribute component type mismatch: expected ${a}, got ${r.componentType}`);const l=(c.bufferViews[r.bufferView].byteOffset||0)+(r.byteOffset||0),u=r.count,d=new DataView(t,l,u*i*4),f=new Float32Array(u*i);for(let h=0;h<u*i;h++)f[h]=d.getFloat32(h*4,!0);return f}function D(c,t,e){const i=c.accessors[e];if(i.type!=="SCALAR")throw new Error(`Indices accessor must be SCALAR, got ${i.type}`);const r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5123){const o=new DataView(t,r,n*2),s=new Uint16Array(n);for(let l=0;l<n;l++)s[l]=o.getUint16(l*2,!0);return s}else if(i.componentType===5125){const o=new DataView(t,r,n*4),s=new Uint32Array(n);for(let l=0;l<n;l++)s[l]=o.getUint32(l*4,!0);return s}else throw new Error(`Unsupported index component type: ${i.componentType}`)}function ie(c,t){const e=new Float32Array(c.length);for(let i=0;i<t.length;i+=3){const a=t[i]*3,r=t[i+1]*3,n=t[i+2]*3,o=[c[a],c[a+1],c[a+2]],s=[c[r],c[r+1],c[r+2]],l=[c[n],c[n+1],c[n+2]],u=[s[0]-o[0],s[1]-o[1],s[2]-o[2]],d=[l[0]-o[0],l[1]-o[1],l[2]-o[2]],f=[u[1]*d[2]-u[2]*d[1],u[2]*d[0]-u[0]*d[2],u[0]*d[1]-u[1]*d[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[a]=e[r]=e[n]=f[0],e[a+1]=e[r+1]=e[n+1]=f[1],e[a+2]=e[r+2]=e[n+2]=f[2]}return e}function ae(c,t,e){const i=c.accessors[e];if(i.type!=="VEC4")throw new Error(`JOINTS_0 must be VEC4, got ${i.type}`);const r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5121){const o=new DataView(t,r,n*4),s=new Uint8Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getUint8(l);return s}else if(i.componentType===5123){const o=new DataView(t,r,n*8),s=new Uint8Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getUint16(l*2,!0);return s}else throw new Error(`Unsupported JOINTS_0 component type: ${i.componentType}`)}function se(c,t,e){const i=c.accessors[e];if(i.type!=="VEC4")throw new Error(`WEIGHTS_0 must be VEC4, got ${i.type}`);const r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count;if(i.componentType===5126){const o=new DataView(t,r,n*16),s=new Float32Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getFloat32(l*4,!0);return s}else if(i.componentType===5121){const o=new DataView(t,r,n*4),s=new Float32Array(n*4);for(let l=0;l<n*4;l++)s[l]=o.getUint8(l)/255;return s}else throw new Error(`Unsupported WEIGHTS_0 component type: ${i.componentType}`)}function re(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 r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count,o=new DataView(t,r,n*64),s=new Float32Array(n*16);for(let l=0;l<n*16;l++)s[l]=o.getFloat32(l*4,!0);return s}function ne(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 r=(c.bufferViews[i.bufferView].byteOffset||0)+(i.byteOffset||0),n=i.count,o=new DataView(t,r,n*4),s=new Float32Array(n);for(let l=0;l<n;l++)s[l]=o.getFloat32(l*4,!0);return s}function oe(c,t,e){const i=c.accessors[e],r={VEC3:3,VEC4:4}[i.type];if(!r)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),s=i.count,l=new DataView(t,o,s*r*4),u=new Float32Array(s*r);for(let d=0;d<s*r;d++)u[d]=l.getFloat32(d*4,!0);return u}function le(c,t,e){const i=c.skins[0],a=i.joints,r=re(c,t,i.inverseBindMatrices),n=e.attributes.JOINTS_0!==void 0?ae(c,t,e.attributes.JOINTS_0):null,o=e.attributes.WEIGHTS_0!==void 0?se(c,t,e.attributes.WEIGHTS_0):null;if(!n||!o)throw new Error("Mesh missing JOINTS_0 or WEIGHTS_0 attributes");const s=c.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(c.animations&&c.animations.length>0)for(const u of c.animations){const d=[];let f=0;for(const h of u.channels){const p=u.samplers[h.sampler],m=ne(c,t,p.input),b=oe(c,t,p.output),S=m[m.length-1];S>f&&(f=S),d.push({targetNode:h.target.node,targetPath:h.target.path,interpolation:p.interpolation||"LINEAR",timestamps:m,values:b})}l.push({name:u.name||`Animation ${l.length}`,duration:f,channels:d})}return{joints:a,inverseBindMatrices:r,jointIndices:n,jointWeights:o,nodes:s,animations:l}}async function $(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 a=t.getUint32(8,!0);let r=12,n=null,o=null;for(;r<a;){const P=t.getUint32(r,!0),g=t.getUint32(r+4,!0),x=c.slice(r+8,r+8+P);if(g===1313821514){const R=new TextDecoder("utf-8").decode(x);n=JSON.parse(R)}else g===5130562&&(o=x);r+=8+P}if(!n)throw new Error("GLB file missing JSON chunk");if(!n.materials||n.materials.length===0)return null;const s=n.materials[0];if(!s.pbrMetallicRoughness||s.pbrMetallicRoughness.baseColorTexture===void 0)return null;const l=s.pbrMetallicRoughness.baseColorTexture.index;if(!n.textures||!n.textures[l])return null;const d=n.textures[l].source;if(d===void 0||!n.images||!n.images[d])return null;const f=n.images[d],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 V=Object.freeze(Object.defineProperty({__proto__:null,extractGLBTexture:$,parseGLB:I},Symbol.toStringTag,{value:"Module"}));function L(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 O(c,t,e){let i=c[0]*t[0]+c[1]*t[1]+c[2]*t[2]+c[3]*t[3],a=t;if(i<0&&(i=-i,a=[-t[0],-t[1],-t[2],-t[3]]),i>.9995){const l=[c[0]+(a[0]-c[0])*e,c[1]+(a[1]-c[1])*e,c[2]+(a[2]-c[2])*e,c[3]+(a[3]-c[3])*e];return ce(l)}const r=Math.acos(i),n=Math.sin(r),o=Math.sin((1-e)*r)/n,s=Math.sin(e*r)/n;return[c[0]*o+a[0]*s,c[1]*o+a[1]*s,c[2]*o+a[2]*s,c[3]*o+a[3]*s]}function ce(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 ue(c){const t=c[0],e=c[1],i=c[2],a=c[3],r=t+t,n=e+e,o=i+i,s=t*r,l=t*n,u=t*o,d=e*n,f=e*o,h=i*o,p=a*r,m=a*n,b=a*o;return new Float32Array([1-(d+h),l+b,u-m,0,l-b,1-(s+h),f+p,0,u+m,f-p,1-(s+d),0,0,0,0,1])}function de(c,t,e){const i=ue(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 j(c,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let a=0;a<4;a++)e[i*4+a]=c[0+a]*t[i*4+0]+c[4+a]*t[i*4+1]+c[8+a]*t[i*4+2]+c[12+a]*t[i*4+3];return e}class H{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 a=this.restPositions.length/3,r=new Float32Array(a*8);for(let l=0;l<a;l++){const u=l*8,d=l*3,f=l*2;r[u]=this.restPositions[d],r[u+1]=this.restPositions[d+1],r[u+2]=this.restPositions[d+2],r[u+3]=this.restNormals[d],r[u+4]=this.restNormals[d+1],r[u+5]=this.restNormals[d+2],r[u+6]=i?i[f]:0,r[u+7]=i?i[f+1]:0}this._gpuRestDataBuffer=t.createBuffer({size:r.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,label:"skinning_restData"}),t.queue.writeBuffer(this._gpuRestDataBuffer,0,r),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(()=>J),s=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:[s]}),compute:{module:t.createShaderModule({code:o}),entryPoint:"main"}}),this._gpuSkinningBindGroup=t.createBindGroup({layout:s,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=a,this._gpuSkinningReady=!0,console.log(`GPU skinning initialized: ${a} vertices, ${this.joints.length} joints`)}catch(a){console.warn("GPU skinning init failed, using CPU fallback:",a),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=r=>{if(t.has(r))return;t.add(r);const n=this.nodes[r];for(const o of n.children)i(o);e.push(r)},a=new Set;for(const r of this.nodes)for(const n of r.children)a.add(n);for(let r=0;r<this.nodes.length;r++)a.has(r)||i(r);this.topologicalOrder=e.reverse()}_sampleChannel(t,e){const{timestamps:i,values:a,interpolation:r,targetPath:n}=t;if(e<=i[0])return this._extractValue(a,0,n);if(e>=i[i.length-1])return this._extractValue(a,i.length-1,n);let o=0,s=i.length-1;for(;s-o>1;){const p=Math.floor((o+s)/2);i[p]<=e?o=p:s=p}const l=i[o],u=i[s],d=(e-l)/(u-l),f=this._extractValue(a,o,n),h=this._extractValue(a,s,n);return r==="STEP"?f:n==="rotation"?O(f,h,d):L(f,h,d)}_extractValue(t,e,i){if(i==="rotation"){const a=e*4;return[t[a],t[a+1],t[a+2],t[a+3]]}else{const a=e*3;return[t[a],t[a+1],t[a+2]]}}_computeLocalTransforms(t){const e=this.animations[this.currentAnimIndex];for(let i=0;i<this.nodes.length;i++){const a=this.nodes[i];let r=a.translation,n=a.rotation,o=a.scale;for(const s of e.channels)if(s.targetNode===i){const l=this._sampleChannel(s,t);s.targetPath==="translation"?r=l:s.targetPath==="rotation"?n=l:s.targetPath==="scale"&&(o=l)}this.jointLocalTransforms[i]=de(r,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 a of i.children)t[a]=e}for(const e of this.topologicalOrder){const i=t[e];i===-1?this.jointGlobalTransforms[e]=this.jointLocalTransforms[e]:this.jointGlobalTransforms[e]=j(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],a=t*16,r=this.inverseBindMatrices.slice(a,a+16);this.jointFinalMatrices[t]=j(i,r)}}_applySkinning(){const t=this.restPositions.length/3,e=this.restPositions,i=this.restNormals,a=this.skinnedPositions,r=this.skinnedNormals,n=this.jointWeights,o=this.jointIndices,s=this.jointFinalMatrices;for(let l=0;l<t;l++){const u=l*3,d=l*4,f=e[u],h=e[u+1],p=e[u+2],m=i[u],b=i[u+1],S=i[u+2];let y=0,P=0,g=0,x=0,M=0,R=0;for(let T=0;T<4;T++){const w=n[d+T];if(w===0)continue;const v=s[o[d+T]];y+=(v[0]*f+v[4]*h+v[8]*p+v[12])*w,P+=(v[1]*f+v[5]*h+v[9]*p+v[13])*w,g+=(v[2]*f+v[6]*h+v[10]*p+v[14])*w,x+=(v[0]*m+v[4]*b+v[8]*S)*w,M+=(v[1]*m+v[5]*b+v[9]*S)*w,R+=(v[2]*m+v[6]*b+v[10]*S)*w}const B=Math.sqrt(x*x+M*M+R*R);B>1e-4&&(r[u]=x/B,r[u+1]=M/B,r[u+2]=R/B),a[u]=y,a[u+1]=P,a[u+2]=g}}}function N(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 _{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.shapeRotationX===void 0&&(e.shapeRotationX=0),e.shapeRotationY===void 0&&(e.shapeRotationY=0),e.shapeRotationZ===void 0&&(e.shapeRotationZ=0),e.shapeTranslationX===void 0&&(e.shapeTranslationX=0),e.shapeTranslationY===void 0&&(e.shapeTranslationY=0),e.shapeTranslationZ===void 0&&(e.shapeTranslationZ=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 Y(e),this.physics=new Z(t,this.MAX_PARTICLES),this.textureManager=new q(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.initComputePipeline(t)}async initComputePipeline(t){this.computeReady=await this.physics.initComputePipeline(this.instanceBuffer,this.velocityBuffer,this.trailBuffer)}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 I(t);this.glbMeshData=e,this.config.glbHasTexture=e.hasBaseColorTexture||!1;const i=new Float32Array(e.vertexCount*8);for(let a=0;a<e.vertexCount;a++){const r=a*8,n=a*3,o=a*2;i[r+0]=e.positions[n+0],i[r+1]=e.positions[n+1],i[r+2]=e.positions[n+2],i[r+3]=e.normals[n+0],i[r+4]=e.normals[n+1],i[r+5]=e.normals[n+2],e.texCoords?(i[r+6]=e.texCoords[o+0],i[r+7]=e.texCoords[o+1]):(i[r+6]=0,i[r+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 H(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(a){console.warn("GPU skinning init failed, using CPU fallback:",a)}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),a=Math.cos(this._simRotZ),r=Math.sin(this._simRotZ);this._simRotMatrix=[a,-r*e,r*i,r,a*e,-a*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 a=0;a<this.glbMeshData.vertexCount;a++){const r=a*8,n=a*3,o=a*2;this._glbInterleavedData[r]=t[n],this._glbInterleavedData[r+1]=t[n+1],this._glbInterleavedData[r+2]=t[n+2],this._glbInterleavedData[r+3]=e[n],this._glbInterleavedData[r+4]=e[n+1],this._glbInterleavedData[r+5]=e[n+2],i?(this._glbInterleavedData[r+6]=i[o],this._glbInterleavedData[r+7]=i[o+1]):(this._glbInterleavedData[r+6]=0,this._glbInterleavedData[r+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,a=this._appearanceData;a[0]=this.config.fadeEnabled?1:0,a[1]=this.config.randomColorEnabled?2:this.config.colorTransitionEnabled?1:0,a[2]=this.config.particleSize,a[3]=this.config.textureEnabled?1:0,a[4]=this.config.particleColor[0],a[5]=this.config.particleColor[1],a[6]=this.config.particleColor[2],a[7]=this.config.rotation||0,a[8]=this.config.startColor[0],a[9]=this.config.startColor[1],a[10]=this.config.startColor[2],a[11]=t,a[12]=this.config.endColor[0],a[13]=this.config.endColor[1],a[14]=this.config.endColor[2],a[15]=this.config.minRotation||0,a[16]=this.config.maxRotation||90,a[17]=this.config.aspectRatio||1,a[18]=this.config.randomSize?1:0,a[19]=this.config.minSize||.1,a[20]=this.config.maxSize||.5,a[21]=this.config.fadeSizeEnabled?1:0,a[22]=this.config.opacity!==void 0?this.config.opacity:1,a[23]=this.config.increaseSizeEnabled?1:0,a[24]=this.config.sizeLifetimeSpeed??1,a[25]=i,a[26]=this.config.particleShapeRotation||0,a[27]=this.config.pulseEnabled?1:0,a[28]=this.config.pulseAmplitude??.5,a[29]=this.config.pulseFrequency??1,a[30]=this.config.pulsePhaseRandom??0,a[31]=this.config.pulseOpacity?1:0,a[32]=this.config.particleShapeRotationX||0,a[33]=this.config.particleShapeRotationY||0,a[34]=this.config.particleShapeRotationZ||0,a[35]=0,(a[32]!==0||a[33]!==0||a[34]!==0)&&console.log(`[updateAppearanceUniform] ${this.config.name}: d[32-34] = ${a[32]}, ${a[33]}, ${a[34]}`);const r=this.config.followSystemTranslation??!0;a[36]=r?this._simPosition[0]:0,a[37]=r?this._simPosition[1]:0,a[38]=r?this._simPosition[2]:0,a[39]=0,a[40]=this._simRotX,a[41]=this._simRotZ,a[42]=this.config.velocityStretchEnabled?1:0,a[43]=this.config.velocityStretchFactor??1,this.device.queue.writeBuffer(this.appearanceUniformBuffer,0,a)}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.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 a=0;a<t;a++)if(this.emitParticle(),e++,e>=i||a===t-1){const r=a-e+1,n=r*8,o=r*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],a=this.particleData[t+1],r=this.particleData[t+2],n=this.particleVelocities[e],o=this.particleVelocities[e+1],s=this.particleVelocities[e+2];const l=this._simRotMatrix;this.particleData[t]=l[0]*i+l[1]*a+l[2]*r,this.particleData[t+1]=l[3]*i+l[4]*a+l[5]*r,this.particleData[t+2]=l[6]*i+l[7]*a+l[8]*r,this.particleVelocities[e]=l[0]*n+l[1]*o+l[2]*s,this.particleVelocities[e+1]=l[3]*n+l[4]*o+l[5]*s,this.particleVelocities[e+2]=l[6]*n+l[7]*o+l[8]*s}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 a=this.activeParticles*8,r=t+(this.config.shapeTranslationX||0),n=e+(this.config.shapeTranslationY||0),o=i+(this.config.shapeTranslationZ||0);this.particleData[a]=r,this.particleData[a+1]=n,this.particleData[a+2]=o;const s=this.activeParticles*4;return this.emitter.calculateVelocity(r,n,o,this.particleVelocities,s),this.emitter.setParticleColor(this.particleData,a),this.emitter.setParticleLifetime(this.particleData,a),this.activeParticles++,!0}updateParticles(t,e){this.physics.physicsAccumulator+=t;const i=performance.now()/1e3,r=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 s=!1;if(this.config.followSystemId){if(this._pendingFollowEmissions.length>0){const l=this._pendingFollowEmissions.length/6;for(let u=0;u<l;u++){const d=u*6;if(this.emitFollowerParticle(this._pendingFollowEmissions[d],this._pendingFollowEmissions[d+1],this._pendingFollowEmissions[d+2]))s=!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&&r&&this.config.emissionRate>0&&this.activeParticles<this.particleCount&&(l=1);for(let u=0;u<l&&this.emitParticle();u++)s=!0}if(s){const l=this.activeParticles-o,u=o*8,d=o*4;this.device.queue.writeBuffer(this.instanceBuffer,u*4,this.particleData,u,l*8),this.device.queue.writeBuffer(this.velocityBuffer,d*4,this.particleVelocities,d,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;r&&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()}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 a=this.particleData[i*8+6],r=this.particleData[i*8+7];if(a>=r){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 s=i*4,l=e*4;this.particleVelocities.copyWithin(l,s,s+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,a=i[Math.floor(Math.random()*i.length)];this.particleData[e+3]=a[0],this.particleData[e+4]=a[1],this.particleData[e+5]=a[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,a=this.particleData[e],r=this.particleData[e+1],n=this.particleData[e+2],o=this.particleVelocities[i],s=this.particleVelocities[i+1],l=this.particleVelocities[i+2],u=Math.sqrt(o*o+s*s+l*l);if(u>.001){const d=this.config.particleSpeed*2;this.particleVelocities[i]=o/u*d,this.particleVelocities[i+1]=s/u*d,this.particleVelocities[i+2]=l/u*d}else{const d=Math.sqrt(a*a+r*r+n*n);if(d>.001){const f=this.config.particleSpeed*2;this.particleVelocities[i]=a/d*f,this.particleVelocities[i+1]=r/d*f,this.particleVelocities[i+2]=n/d*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.glbAnimator=null,this.glbMeshData=null,this.glbRawArrayBuffer=null,this.particleData=null,this.particleVelocities=null}setGravity(t){this.physics.setGravity(t)}setAttractor(t,e){this.physics.setAttractor(t,e)}setConfinement(t){const e=t.space==="local"?[this.config.shapeTranslationX||0,this.config.shapeTranslationY||0,this.config.shapeTranslationZ||0]:[0,0,0];this.physics.setConfinement({...t,center:e})}setSoftBoundary(t){this.physics.setSoftBoundary(t)}}class fe{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}`,a={...t,name:i,id:e},r=new _(this.device,a);return this.particleSystems.push({system:r,config:a}),this.particleSystems.length===1&&(this.activeSystemIndex=0),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(e,a),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:a}of this.particleSystems)a.followSystemId===i&&(a.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:a,config:r}of this.particleSystems){if(r.hidden||r.followSystemId)continue;const n=a.activeParticles>0;a.updateParticles(t,e),(n||a.activeParticles>0)&&(i=!0)}for(const{system:a,config:r}of this.particleSystems){if(r.hidden||!r.followSystemId)continue;const n=this.getSystemById(r.followSystemId);n&&(a._pendingFollowEmissions=n.system._newEmissions);const o=a.activeParticles>0;a.updateParticles(t,e),(o||a.activeParticles>0)&&(i=!0)}i&&this.device.queue.submit([e.finish()]);for(const{system:a}of this.particleSystems)a._newEmissions.length=0,a._pendingFollowEmissions=a._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 a of t.systems){const r=this.systemCounter++,n={...a,id:r},o=new _(this.device,n);this.particleSystems.push({system:o,config:n})}const i={};t.systems.forEach((a,r)=>{i[a.id]=this.particleSystems[r].config.id});for(const{config:a}of this.particleSystems)a.followSystemId&&i[a.followSystemId]!==void 0&&(a.followSystemId=i[a.followSystemId]);t.activeSystemIndex!==void 0&&t.activeSystemIndex>=0&&t.activeSystemIndex<this.particleSystems.length?this.activeSystemIndex=t.activeSystemIndex:this.activeSystemIndex=0;for(const{system:a,config:r}of this.particleSystems)if(r.glbModelEnabled)try{let n=null;if(r.glbModelData)n=N(r.glbModelData);else if(r.glbFileName){const o=await fetch(`/${r.glbFileName}`);o.ok?n=await o.arrayBuffer():console.warn(`GLB file not found: ${r.glbFileName}`)}if(n){if(await a.setGLBModel(n),r.animationIndex!==void 0&&a.glbAnimator&&a.glbAnimator.setAnimation(r.animationIndex),r.animationSpeed!==void 0&&a.glbAnimator&&(a.glbAnimator.speed=r.animationSpeed),r.animationLoop!==void 0&&a.glbAnimator&&(a.glbAnimator.loop=r.animationLoop),r.useGlbTexture&&(r.textureEnabled=!0),r.useGlbTexture&&((e=a.glbMeshData)!=null&&e.hasBaseColorTexture))try{const{extractGLBTexture:o}=await Promise.resolve().then(()=>V),s=await o(n);if(s){const l=await createImageBitmap(s.imageBlob);await a.setTexture(l),console.log(`GLB embedded texture restored for ${r.name}`)}}catch(o){console.warn(`Failed to restore GLB texture for ${r.name}:`,o),r.useGlbTexture=!1}}else r.glbModelEnabled=!1}catch(n){console.warn(`Failed to load GLB for ${r.name}:`,n),r.glbModelEnabled=!1}for(const{system:a,config:r}of this.particleSystems)if(r.textureEnabled&&!r.glbModelEnabled&&r.textureImageData)try{const n=new Image;await new Promise((s,l)=>{n.onload=s,n.onerror=l,n.src=r.textureImageData});const o=await createImageBitmap(n);await a.setTexture(o)}catch(n){console.warn(`Failed to restore texture for ${r.name}:`,n),r.textureEnabled=!1}for(const{system:a,config:r}of this.particleSystems)a.updateAppearanceUniform(),(r.particleShapeRotationX||r.particleShapeRotationY||r.particleShapeRotationZ)&&console.log(`[replaceSystems] ${r.name}: glbRotation XYZ = ${r.particleShapeRotationX}, ${r.particleShapeRotationY}, ${r.particleShapeRotationZ} | glbModelEnabled=${r.glbModelEnabled} | glbMeshData=${!!a.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++,s={...n,id:o,shapeTranslationX:(n.shapeTranslationX||0)+e[0],shapeTranslationY:(n.shapeTranslationY||0)+e[1],shapeTranslationZ:(n.shapeTranslationZ||0)+e[2]};n.attractorEnabled&&n.attractorPosition&&(s.attractorPosition=[n.attractorPosition[0]+e[0],n.attractorPosition[1]+e[1],n.attractorPosition[2]+e[2]]);const l=new _(this.device,s);this.particleSystems.push({system:l,config:s}),this.onSystemCreated&&typeof this.onSystemCreated=="function"&&this.onSystemCreated(o,s)}const a=this.particleSystems.length-t.systems.length,r={};t.systems.forEach((n,o)=>{r[n.id]=this.particleSystems[a+o].config.id});for(let n=a;n<this.particleSystems.length;n++){const{config:o}=this.particleSystems[n];o.followSystemId&&r[o.followSystemId]!==void 0&&(o.followSystemId=r[o.followSystemId])}for(const{system:n,config:o}of this.particleSystems)if(o.glbModelEnabled&&!n.glbMeshData)try{let s=null;if(o.glbModelData)s=N(o.glbModelData);else if(o.glbFileName){const l=await fetch(`/${o.glbFileName}`);l.ok?s=await l.arrayBuffer():console.warn(`GLB file not found: ${o.glbFileName}`)}if(s){if(await n.setGLBModel(s),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(()=>V),u=await l(s);if(u){const d=await createImageBitmap(u.imageBlob);await n.setTexture(d),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(s){console.warn(`Failed to load GLB for ${o.name}:`,s),o.glbModelEnabled=!1}for(const{system:n,config:o}of this.particleSystems)if(o.textureEnabled&&!o.glbModelEnabled&&o.textureImageData&&!n._textureRestored)try{const s=new Image;await new Promise((u,d)=>{s.onload=u,s.onerror=d,s.src=o.textureImageData});const l=await createImageBitmap(s);await n.setTexture(l),n._textureRestored=!0}catch(s){console.warn(`Failed to restore texture for ${o.name}:`,s),o.textureEnabled=!1}return!0}catch(a){return console.error("Error adding systems:",a),!1}}}async function he(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(),a=navigator.gpu.getPreferredCanvasFormat();return t.configure({device:i,format:a,alphaMode:"premultiplied"}),{device:i,context:t,format:a,canvas:c}}function pe(c,t,e,i){const a=c.createTexture({size:[e,i],format:t,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,mipLevelCount:1,sampleCount:1}),r=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:a,bloomTexA:r,bloomTexB:n}}function me(c,t,e){return c.createTexture({size:[t,e],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT})}function E(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 U=`
2
2
  struct Uniforms {
3
3
  transform: mat4x4<f32>,
4
4
  cameraPosition: vec3<f32>,
@@ -1033,4 +1033,4 @@
1033
1033
 
1034
1034
  return finalColor;
1035
1035
  }
1036
- `;function ge(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"}}]}),a=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:a}}function be(c,t,e,i={}){const{depthCompare:a}=i,r=a||"less",{particleBindGroupLayout:n,bloomBindGroupLayout:o,compositeBindGroupLayout:s,object3dBindGroupLayout:l}=e,u=c.createPipelineLayout({bindGroupLayouts:[n]}),d=c.createPipelineLayout({bindGroupLayouts:[o]}),f=c.createPipelineLayout({bindGroupLayouts:[s]}),h=c.createShaderModule({code:U}),p=c.createShaderModule({code:z}),m=c.createShaderModule({code:G}),b=c.createShaderModule({code:F}),S=c.createShaderModule({code:K}),y=c.createShaderModule({code:Q}),P=c.createRenderPipeline({layout:u,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:r,format:"depth24plus"}}),g=c.createRenderPipeline({layout:u,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:d,vertex:{module:p,entryPoint:"vs_main"},fragment:{module:p,entryPoint:"fs_main",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),M=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"}}),R=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"}}),B=c.createPipelineLayout({bindGroupLayouts:[l]}),T=c.createRenderPipeline({layout:B,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:r,format:"depth24plus"}}),w=c.createRenderPipeline({layout:u,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:r,format:"depth24plus"}});return{particlePipeline:P,particleDepthWritePipeline:g,blurPipeline:x,compositePipeline:M,directRenderPipeline:R,object3dPipeline:T,glbMeshPipeline:w}}function Se(c,t,e,i){const{uniformBuffer:a,appearanceUniformBuffer:r,horizontalBlurUniformBuffer:n,verticalBlurUniformBuffer:o,bloomIntensityBuffer:s}=e,{sceneTexture:l,bloomTexA:u,bloomTexB:d}=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:a}},{binding:1,resource:{buffer:r}}]}),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:u.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:d.createView()},{binding:3,resource:{buffer:s}}]}),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:d.createView()},{binding:3,resource:{buffer:s}}]});return{particleBindGroup:f,horizontalBlurBindGroup:h,verticalBlurBindGroup:p,compositeBindGroup:m,directRenderBindGroup:b}}function xe(c){return c.createSampler({magFilter:"linear",minFilter:"linear",mipmapFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",maxAnisotropy:16})}function ee(){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 te(c=16,t=16){const e=[],i=[];for(let a=0;a<=c;a++){const r=a*Math.PI/c,n=Math.sin(r),o=Math.cos(r);for(let s=0;s<=t;s++){const l=s*2*Math.PI/t,u=Math.sin(l),f=Math.cos(l)*n,h=o,p=u*n;e.push(f*.5,h*.5,p*.5),e.push(f,h,p)}}for(let a=0;a<c;a++)for(let r=0;r<t;r++){const n=a*(t+1)+r,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 ve{constructor(t,e,i,a,r){this.id=t,this.type=e,this.position=i,this.scale=a,this.color=r,this.rotation=[0,0,0]}getModelMatrix(){const{position:t,scale:e,rotation:i}=this,a=this.createTranslationMatrix(t),r=this.createRotationMatrixX(i[0]),n=this.createRotationMatrixY(i[1]),o=this.createRotationMatrixZ(i[2]),s=this.createScaleMatrix(e);let l=a;return l=this.multiplyMatrices(l,o),l=this.multiplyMatrices(l,n),l=this.multiplyMatrices(l,r),l=this.multiplyMatrices(l,s),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 a=0;a<4;a++)for(let r=0;r<4;r++){let n=0;for(let o=0;o<4;o++)n+=t[a*4+o]*e[o*4+r];i[a*4+r]=n}return i}}class Pe{constructor(t){this.device=t,this.objects=[],this.nextId=0,this.initializeGeometry(),this.onObjectAdded=null,this.onObjectRemoved=null,this.onObjectUpdated=null}initializeGeometry(){const t=ee(),e=te(16,16);this.cubeVertexBuffer=E(this.device,t.vertices,GPUBufferUsage.VERTEX),this.cubeIndexBuffer=E(this.device,t.indices,GPUBufferUsage.INDEX),this.cubeIndexCount=t.indices.length,this.sphereVertexBuffer=E(this.device,e.vertices,GPUBufferUsage.VERTEX),this.sphereIndexBuffer=E(this.device,e.indices,GPUBufferUsage.INDEX),this.sphereIndexCount=e.indices.length}addObject(t,e=[0,0,0],i=[1,1,1],a=[1,1,1,1]){const r=new ve(this.nextId++,t,e,i,a);return r.uniformBuffer=this.device.createBuffer({size:192,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.objects.push(r),this.onObjectAdded&&this.onObjectAdded(r),r}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(a=>a.id===t);i&&(i.position=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectScale(t,e){const i=this.objects.find(a=>a.id===t);i&&(i.scale=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectColor(t,e){const i=this.objects.find(a=>a.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(),a=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,a)}renderObjects(t,e,i,a){for(const r of this.objects){this.updateObjectUniforms(r);const n=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:{buffer:a}},{binding:1,resource:{buffer:r.uniformBuffer}}]});let o,s,l;if(r.type==="cube")o=this.cubeVertexBuffer,s=this.cubeIndexBuffer,l=this.cubeIndexCount;else if(r.type==="sphere")o=this.sphereVertexBuffer,s=this.sphereIndexBuffer,l=this.sphereIndexCount;else continue;t.setPipeline(e),t.setBindGroup(0,n),t.setVertexBuffer(0,o),t.setIndexBuffer(s,"uint16"),t.drawIndexed(l)}}}function Me(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 Re(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 we(c,t,e){const i=X([c[0]-t[0],c[1]-t[1],c[2]-t[2]]),a=X(k(e,i)),r=k(i,a);return new Float32Array([a[0],r[0],i[0],0,a[1],r[1],i[1],0,a[2],r[2],i[2],0,-A(a,c),-A(r,c),-A(i,c),1])}function Be(c,t=Math.PI/4){const a=1/Math.tan(t/2);return new Float32Array([a*c,0,0,0,0,a,0,0,0,0,(100+.1)/(.1-100),-1,0,0,200*.1/(.1-100),0])}function X(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 k(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 A(c,t){return c[0]*t[0]+c[1]*t[1]+c[2]*t[2]}function Te(c,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let a=0;a<4;a++){let r=0;for(let n=0;n<4;n++)r+=c[i+n*4]*t[n+a*4];e[i+a*4]=r}return e}function Ee(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 Ce(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:s,system:l})=>({name:s.name,id:s.id,particleCount:s.particleCount,lifetime:s.lifetime,emissionRate:s.emissionRate,emissionDuration:s.emissionDuration,particleSize:s.particleSize,particleSpeed:s.particleSpeed,emissionShape:s.emissionShape,cubeLength:s.outerLength||s.cubeLength,outerLength:s.outerLength||s.cubeLength,innerLength:s.innerLength,outerRadius:s.outerRadius,innerRadius:s.innerRadius,squareSize:s.squareSize,squareInnerSize:s.squareInnerSize,circleInnerRadius:s.circleInnerRadius,circleOuterRadius:s.circleOuterRadius,fadeEnabled:s.fadeEnabled,colorTransitionEnabled:s.colorTransitionEnabled,particleColor:s.particleColor,startColor:s.startColor,endColor:s.endColor,randomColorEnabled:s.randomColorEnabled||!1,randomColors:s.randomColors||[],particleShape:s.particleShape||"square",particleShapeRotation:s.particleShapeRotation||0,particleShapeRotationX:s.particleShapeRotationX||0,particleShapeRotationY:s.particleShapeRotationY||0,particleShapeRotationZ:s.particleShapeRotationZ||0,pulseEnabled:s.pulseEnabled||!1,pulseAmplitude:s.pulseAmplitude??.5,pulseFrequency:s.pulseFrequency??1,pulsePhaseRandom:s.pulsePhaseRandom??0,pulseOpacity:s.pulseOpacity||!1,bloomEnabled:s.bloomEnabled,bloomIntensity:s.bloomIntensity,burstMode:s.burstMode,gravityEnabled:s.gravityEnabled,gravityStrength:s.gravityStrength,dampingEnabled:s.dampingEnabled,dampingStrength:s.dampingStrength,attractorEnabled:s.attractorEnabled,attractorStrength:s.attractorStrength,attractorPosition:s.attractorPosition,shapeRotationX:s.shapeRotationX,shapeRotationY:s.shapeRotationY,shapeRotationZ:s.shapeRotationZ,shapeTranslationX:s.shapeTranslationX,shapeTranslationY:s.shapeTranslationY,shapeTranslationZ:s.shapeTranslationZ,rotation:s.rotation,rotationMode:s.rotationMode,minRotation:s.minRotation,maxRotation:s.maxRotation,overrideXVelocity:s.overrideXVelocity,overrideYVelocity:s.overrideYVelocity,overrideZVelocity:s.overrideZVelocity,xVelocity:s.xVelocity,yVelocity:s.yVelocity,zVelocity:s.zVelocity,circleVelocityDirection:s.circleVelocityDirection,cylinderVelocityDirection:s.cylinderVelocityDirection,cylinderInnerRadius:s.cylinderInnerRadius,cylinderOuterRadius:s.cylinderOuterRadius,cylinderHeight:s.cylinderHeight,aspectRatio:s.aspectRatio,randomSize:s.randomSize,minSize:s.minSize,maxSize:s.maxSize,fadeSizeEnabled:s.fadeSizeEnabled,increaseSizeEnabled:s.increaseSizeEnabled,sizeLifetimeSpeed:s.sizeLifetimeSpeed,opacity:s.opacity,randomSpeed:s.randomSpeed,minSpeed:s.minSpeed,maxSpeed:s.maxSpeed,textureEnabled:s.textureEnabled,textureType:s.textureType,glbModelEnabled:s.glbModelEnabled,glbFileName:s.glbFileName,glbAnimated:s.glbAnimated,animationIndex:s.animationIndex,animationSpeed:s.animationSpeed,animationLoop:s.animationLoop,useGlbTexture:s.useGlbTexture,oneOnlyMode:s.oneOnlyMode,confinementEnabled:s.confinementEnabled||!1,confinementShape:s.confinementShape||"box",confinementMode:s.confinementMode||"bounce",confinementSpace:s.confinementSpace||"world",confinementBoxHalfSize:s.confinementBoxHalfSize||[2,2,2],confinementSphereRadius:s.confinementSphereRadius??3,confinementRestitution:s.confinementRestitution??.8,confinementFriction:s.confinementFriction??.1,softBoundaryEnabled:s.softBoundaryEnabled||!1,softBoundaryStrength:s.softBoundaryStrength??5,softBoundaryFalloff:s.softBoundaryFalloff??.5,followSystemId:s.followSystemId||null,hidden:s.hidden||!1,emissionTrailEnabled:s.emissionTrailEnabled||!1,emissionTrailDuration:s.emissionTrailDuration??1,emissionTrailWidth:s.emissionTrailWidth??.5,emissionTrailMinDistance:s.emissionTrailMinDistance??.05,emissionTrailMaxPoints:s.emissionTrailMaxPoints??100,textureImageData:s.textureEnabled&&!s.glbModelEnabled&&s.textureImageData?s.textureImageData:void 0,glbModelData:s.glbModelEnabled&&l.glbRawArrayBuffer?Ee(l.glbRawArrayBuffer):void 0})),activeSystemIndex:c.activeSystemIndex},i=JSON.stringify(e,null,2);let a;if(t)a=`${t}.json`;else{const s=new Date;a=`particle-scene_${`${s.getFullYear()}-${(s.getMonth()+1).toString().padStart(2,"0")}-${s.getDate().toString().padStart(2,"0")}_${s.getHours().toString().padStart(2,"0")}${s.getMinutes().toString().padStart(2,"0")}`}.json`}const r=new Blob([i],{type:"application/json"}),n=URL.createObjectURL(r),o=document.createElement("a");o.href=n,o.download=a,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 _e(c){return new Promise((t,e)=>{try{const i=c.target.files[0];if(!i){e(new Error("No file selected"));return}const a=new FileReader;a.onload=r=>{try{const n=JSON.parse(r.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 s of n.systems)o.push(s);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=""},a.onerror=()=>{alert("Failed to read the file"),e(new Error("Failed to read the file")),c.target.value=""},a.readAsText(i)}catch(i){console.error("Error in loadScene:",i),e(i)}})}async function Ae(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=H;exports.Objects3DManager=Pe;exports.ParticleEmitter=Y;exports.ParticlePhysics=Z;exports.ParticleSystem=C;exports.ParticleSystemManager=fe;exports.ParticleTextureManager=q;exports.blurShader=z;exports.compositeShader=G;exports.createBindGroupLayouts=ge;exports.createBindGroups=Se;exports.createBuffer=E;exports.createCubeGeometry=ee;exports.createDepthTexture=me;exports.createLookAtMatrix=we;exports.createProjectionMatrix=Be;exports.createRenderPipelines=be;exports.createRenderTextures=pe;exports.createSampler=xe;exports.createSphereGeometry=te;exports.directRenderShader=F;exports.extractGLBTexture=$;exports.fetchPreset=Ae;exports.glbMeshParticleShader=Q;exports.hexToRgb=Me;exports.initWebGPU=he;exports.loadScene=_e;exports.multiplyMatrices=Te;exports.object3dShader=K;exports.parseGLB=I;exports.particlePhysicsShader=W;exports.particleShader=U;exports.rgbToHex=Re;exports.saveScene=Ce;
1036
+ `;function ge(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"}}]}),a=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:a}}function be(c,t,e,i={}){const{depthCompare:a}=i,r=a||"less",{particleBindGroupLayout:n,bloomBindGroupLayout:o,compositeBindGroupLayout:s,object3dBindGroupLayout:l}=e,u=c.createPipelineLayout({bindGroupLayouts:[n]}),d=c.createPipelineLayout({bindGroupLayouts:[o]}),f=c.createPipelineLayout({bindGroupLayouts:[s]}),h=c.createShaderModule({code:U}),p=c.createShaderModule({code:z}),m=c.createShaderModule({code:G}),b=c.createShaderModule({code:F}),S=c.createShaderModule({code:K}),y=c.createShaderModule({code:Q}),P=c.createRenderPipeline({layout:u,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:r,format:"depth24plus"}}),g=c.createRenderPipeline({layout:u,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:d,vertex:{module:p,entryPoint:"vs_main"},fragment:{module:p,entryPoint:"fs_main",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),M=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"}}),R=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"}}),B=c.createPipelineLayout({bindGroupLayouts:[l]}),T=c.createRenderPipeline({layout:B,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:r,format:"depth24plus"}}),w=c.createRenderPipeline({layout:u,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:r,format:"depth24plus"}});return{particlePipeline:P,particleDepthWritePipeline:g,blurPipeline:x,compositePipeline:M,directRenderPipeline:R,object3dPipeline:T,glbMeshPipeline:w}}function Se(c,t,e,i){const{uniformBuffer:a,appearanceUniformBuffer:r,horizontalBlurUniformBuffer:n,verticalBlurUniformBuffer:o,bloomIntensityBuffer:s}=e,{sceneTexture:l,bloomTexA:u,bloomTexB:d}=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:a}},{binding:1,resource:{buffer:r}}]}),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:u.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:d.createView()},{binding:3,resource:{buffer:s}}]}),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:d.createView()},{binding:3,resource:{buffer:s}}]});return{particleBindGroup:f,horizontalBlurBindGroup:h,verticalBlurBindGroup:p,compositeBindGroup:m,directRenderBindGroup:b}}function xe(c){return c.createSampler({magFilter:"linear",minFilter:"linear",mipmapFilter:"linear",addressModeU:"clamp-to-edge",addressModeV:"clamp-to-edge",maxAnisotropy:16})}function ee(){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 te(c=16,t=16){const e=[],i=[];for(let a=0;a<=c;a++){const r=a*Math.PI/c,n=Math.sin(r),o=Math.cos(r);for(let s=0;s<=t;s++){const l=s*2*Math.PI/t,u=Math.sin(l),f=Math.cos(l)*n,h=o,p=u*n;e.push(f*.5,h*.5,p*.5),e.push(f,h,p)}}for(let a=0;a<c;a++)for(let r=0;r<t;r++){const n=a*(t+1)+r,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 ve{constructor(t,e,i,a,r){this.id=t,this.type=e,this.position=i,this.scale=a,this.color=r,this.rotation=[0,0,0]}getModelMatrix(){const{position:t,scale:e,rotation:i}=this,a=this.createTranslationMatrix(t),r=this.createRotationMatrixX(i[0]),n=this.createRotationMatrixY(i[1]),o=this.createRotationMatrixZ(i[2]),s=this.createScaleMatrix(e);let l=a;return l=this.multiplyMatrices(l,o),l=this.multiplyMatrices(l,n),l=this.multiplyMatrices(l,r),l=this.multiplyMatrices(l,s),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 a=0;a<4;a++)for(let r=0;r<4;r++){let n=0;for(let o=0;o<4;o++)n+=t[a*4+o]*e[o*4+r];i[a*4+r]=n}return i}}class Pe{constructor(t){this.device=t,this.objects=[],this.nextId=0,this.initializeGeometry(),this.onObjectAdded=null,this.onObjectRemoved=null,this.onObjectUpdated=null}initializeGeometry(){const t=ee(),e=te(16,16);this.cubeVertexBuffer=E(this.device,t.vertices,GPUBufferUsage.VERTEX),this.cubeIndexBuffer=E(this.device,t.indices,GPUBufferUsage.INDEX),this.cubeIndexCount=t.indices.length,this.sphereVertexBuffer=E(this.device,e.vertices,GPUBufferUsage.VERTEX),this.sphereIndexBuffer=E(this.device,e.indices,GPUBufferUsage.INDEX),this.sphereIndexCount=e.indices.length}addObject(t,e=[0,0,0],i=[1,1,1],a=[1,1,1,1]){const r=new ve(this.nextId++,t,e,i,a);return r.uniformBuffer=this.device.createBuffer({size:192,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.objects.push(r),this.onObjectAdded&&this.onObjectAdded(r),r}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(a=>a.id===t);i&&(i.position=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectScale(t,e){const i=this.objects.find(a=>a.id===t);i&&(i.scale=e,this.onObjectUpdated&&this.onObjectUpdated(i))}updateObjectColor(t,e){const i=this.objects.find(a=>a.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(),a=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,a)}renderObjects(t,e,i,a){for(const r of this.objects){this.updateObjectUniforms(r);const n=this.device.createBindGroup({layout:i,entries:[{binding:0,resource:{buffer:a}},{binding:1,resource:{buffer:r.uniformBuffer}}]});let o,s,l;if(r.type==="cube")o=this.cubeVertexBuffer,s=this.cubeIndexBuffer,l=this.cubeIndexCount;else if(r.type==="sphere")o=this.sphereVertexBuffer,s=this.sphereIndexBuffer,l=this.sphereIndexCount;else continue;t.setPipeline(e),t.setBindGroup(0,n),t.setVertexBuffer(0,o),t.setIndexBuffer(s,"uint16"),t.drawIndexed(l)}}}function Me(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 Re(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 we(c,t,e){const i=X([c[0]-t[0],c[1]-t[1],c[2]-t[2]]),a=X(k(e,i)),r=k(i,a);return new Float32Array([a[0],r[0],i[0],0,a[1],r[1],i[1],0,a[2],r[2],i[2],0,-A(a,c),-A(r,c),-A(i,c),1])}function Be(c,t=Math.PI/4){const a=1/Math.tan(t/2);return new Float32Array([a*c,0,0,0,0,a,0,0,0,0,(100+.1)/(.1-100),-1,0,0,200*.1/(.1-100),0])}function X(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 k(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 A(c,t){return c[0]*t[0]+c[1]*t[1]+c[2]*t[2]}function Te(c,t){const e=new Float32Array(16);for(let i=0;i<4;i++)for(let a=0;a<4;a++){let r=0;for(let n=0;n<4;n++)r+=c[i+n*4]*t[n+a*4];e[i+a*4]=r}return e}function Ee(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 _e(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:s,system:l})=>({name:s.name,id:s.id,particleCount:s.particleCount,lifetime:s.lifetime,emissionRate:s.emissionRate,emissionDuration:s.emissionDuration,particleSize:s.particleSize,particleSpeed:s.particleSpeed,emissionShape:s.emissionShape,cubeLength:s.outerLength||s.cubeLength,outerLength:s.outerLength||s.cubeLength,innerLength:s.innerLength,outerRadius:s.outerRadius,innerRadius:s.innerRadius,squareSize:s.squareSize,squareInnerSize:s.squareInnerSize,circleInnerRadius:s.circleInnerRadius,circleOuterRadius:s.circleOuterRadius,fadeEnabled:s.fadeEnabled,colorTransitionEnabled:s.colorTransitionEnabled,particleColor:s.particleColor,startColor:s.startColor,endColor:s.endColor,randomColorEnabled:s.randomColorEnabled||!1,randomColors:s.randomColors||[],particleShape:s.particleShape||"square",particleShapeRotation:s.particleShapeRotation||0,particleShapeRotationX:s.particleShapeRotationX||0,particleShapeRotationY:s.particleShapeRotationY||0,particleShapeRotationZ:s.particleShapeRotationZ||0,pulseEnabled:s.pulseEnabled||!1,pulseAmplitude:s.pulseAmplitude??.5,pulseFrequency:s.pulseFrequency??1,pulsePhaseRandom:s.pulsePhaseRandom??0,pulseOpacity:s.pulseOpacity||!1,bloomEnabled:s.bloomEnabled,bloomIntensity:s.bloomIntensity,burstMode:s.burstMode,gravityEnabled:s.gravityEnabled,gravityStrength:s.gravityStrength,dampingEnabled:s.dampingEnabled,dampingStrength:s.dampingStrength,attractorEnabled:s.attractorEnabled,attractorStrength:s.attractorStrength,attractorPosition:s.attractorPosition,shapeRotationX:s.shapeRotationX,shapeRotationY:s.shapeRotationY,shapeRotationZ:s.shapeRotationZ,shapeTranslationX:s.shapeTranslationX,shapeTranslationY:s.shapeTranslationY,shapeTranslationZ:s.shapeTranslationZ,rotation:s.rotation,rotationMode:s.rotationMode,minRotation:s.minRotation,maxRotation:s.maxRotation,overrideXVelocity:s.overrideXVelocity,overrideYVelocity:s.overrideYVelocity,overrideZVelocity:s.overrideZVelocity,xVelocity:s.xVelocity,yVelocity:s.yVelocity,zVelocity:s.zVelocity,circleVelocityDirection:s.circleVelocityDirection,cylinderVelocityDirection:s.cylinderVelocityDirection,cylinderInnerRadius:s.cylinderInnerRadius,cylinderOuterRadius:s.cylinderOuterRadius,cylinderHeight:s.cylinderHeight,aspectRatio:s.aspectRatio,randomSize:s.randomSize,minSize:s.minSize,maxSize:s.maxSize,fadeSizeEnabled:s.fadeSizeEnabled,increaseSizeEnabled:s.increaseSizeEnabled,sizeLifetimeSpeed:s.sizeLifetimeSpeed,opacity:s.opacity,randomSpeed:s.randomSpeed,minSpeed:s.minSpeed,maxSpeed:s.maxSpeed,textureEnabled:s.textureEnabled,textureType:s.textureType,glbModelEnabled:s.glbModelEnabled,glbFileName:s.glbFileName,glbAnimated:s.glbAnimated,animationIndex:s.animationIndex,animationSpeed:s.animationSpeed,animationLoop:s.animationLoop,useGlbTexture:s.useGlbTexture,oneOnlyMode:s.oneOnlyMode,confinementEnabled:s.confinementEnabled||!1,confinementShape:s.confinementShape||"box",confinementMode:s.confinementMode||"bounce",confinementSpace:s.confinementSpace||"world",confinementBoxHalfSize:s.confinementBoxHalfSize||[2,2,2],confinementSphereRadius:s.confinementSphereRadius??3,confinementRestitution:s.confinementRestitution??.8,confinementFriction:s.confinementFriction??.1,softBoundaryEnabled:s.softBoundaryEnabled||!1,softBoundaryStrength:s.softBoundaryStrength??5,softBoundaryFalloff:s.softBoundaryFalloff??.5,followSystemId:s.followSystemId||null,hidden:s.hidden||!1,emissionTrailEnabled:s.emissionTrailEnabled||!1,emissionTrailDuration:s.emissionTrailDuration??1,emissionTrailWidth:s.emissionTrailWidth??.5,emissionTrailMinDistance:s.emissionTrailMinDistance??.05,emissionTrailMaxPoints:s.emissionTrailMaxPoints??100,emissionTrailSegments:s.emissionTrailSegments??8,emissionTrailShape:s.emissionTrailShape??"straight",emissionTrailShapeAmplitude:s.emissionTrailShapeAmplitude??.1,emissionTrailShapeFrequency:s.emissionTrailShapeFrequency??4,emissionTrailShapeSpeed:s.emissionTrailShapeSpeed??0,shapeDisplay:s.shapeDisplay??!0,followSystemTranslation:s.followSystemTranslation??!0,textureImageData:s.textureEnabled&&!s.glbModelEnabled&&s.textureImageData?s.textureImageData:void 0,glbModelData:s.glbModelEnabled&&l.glbRawArrayBuffer?Ee(l.glbRawArrayBuffer):void 0})),activeSystemIndex:c.activeSystemIndex},i=JSON.stringify(e,null,2);let a;if(t)a=`${t}.json`;else{const s=new Date;a=`particle-scene_${`${s.getFullYear()}-${(s.getMonth()+1).toString().padStart(2,"0")}-${s.getDate().toString().padStart(2,"0")}_${s.getHours().toString().padStart(2,"0")}${s.getMinutes().toString().padStart(2,"0")}`}.json`}const r=new Blob([i],{type:"application/json"}),n=URL.createObjectURL(r),o=document.createElement("a");o.href=n,o.download=a,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 Ce(c){return new Promise((t,e)=>{try{const i=c.target.files[0];if(!i){e(new Error("No file selected"));return}const a=new FileReader;a.onload=r=>{try{const n=JSON.parse(r.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 s of n.systems)o.push(s);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=""},a.onerror=()=>{alert("Failed to read the file"),e(new Error("Failed to read the file")),c.target.value=""},a.readAsText(i)}catch(i){console.error("Error in loadScene:",i),e(i)}})}async function Ae(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=H;exports.Objects3DManager=Pe;exports.ParticleEmitter=Y;exports.ParticlePhysics=Z;exports.ParticleSystem=_;exports.ParticleSystemManager=fe;exports.ParticleTextureManager=q;exports.blurShader=z;exports.compositeShader=G;exports.createBindGroupLayouts=ge;exports.createBindGroups=Se;exports.createBuffer=E;exports.createCubeGeometry=ee;exports.createDepthTexture=me;exports.createLookAtMatrix=we;exports.createProjectionMatrix=Be;exports.createRenderPipelines=be;exports.createRenderTextures=pe;exports.createSampler=xe;exports.createSphereGeometry=te;exports.directRenderShader=F;exports.extractGLBTexture=$;exports.fetchPreset=Ae;exports.glbMeshParticleShader=Q;exports.hexToRgb=Me;exports.initWebGPU=he;exports.loadScene=Ce;exports.multiplyMatrices=Te;exports.object3dShader=K;exports.parseGLB=I;exports.particlePhysicsShader=W;exports.particleShader=U;exports.rgbToHex=Re;exports.saveScene=_e;
@@ -96,6 +96,13 @@ export interface ParticleSystemConfig {
96
96
  emissionTrailWidth?: number;
97
97
  emissionTrailMinDistance?: number;
98
98
  emissionTrailMaxPoints?: number;
99
+ emissionTrailSegments?: number;
100
+ emissionTrailShape?: 'straight' | 'zigzag' | 'sine' | 'spiral';
101
+ emissionTrailShapeAmplitude?: number;
102
+ emissionTrailShapeFrequency?: number;
103
+ emissionTrailShapeSpeed?: number;
104
+ shapeDisplay?: boolean;
105
+ followSystemTranslation?: boolean;
99
106
  followSystemId?: number | null;
100
107
  hidden?: boolean;
101
108
  oneOnlyMode?: boolean;