@hology/core 0.0.259 → 0.0.261

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.
Files changed (59) hide show
  1. package/dist/effects/sequence/sequence-actor.d.ts +3 -1
  2. package/dist/effects/sequence/sequence-actor.js +1 -1
  3. package/dist/effects/sequence/sequence-player.d.ts +11 -0
  4. package/dist/effects/sequence/sequence-player.js +1 -1
  5. package/dist/effects/vfx/gpu-sprite-compiler.js +1 -1
  6. package/dist/effects/vfx/gpu-sprite-runtime.d.ts +3 -1
  7. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  8. package/dist/effects/vfx/trail-renderer.d.ts +2 -0
  9. package/dist/effects/vfx/trail-renderer.js +1 -1
  10. package/dist/effects/vfx/vfx-actor.d.ts +11 -0
  11. package/dist/effects/vfx/vfx-actor.js +1 -1
  12. package/dist/effects/vfx/vfx-asset.d.ts +4 -0
  13. package/dist/effects/vfx/vfx-collision-behaviour.d.ts +4 -1
  14. package/dist/effects/vfx/vfx-collision-behaviour.js +1 -1
  15. package/dist/effects/vfx/vfx-defs.d.ts +1 -0
  16. package/dist/effects/vfx/vfx-defs.js +1 -1
  17. package/dist/effects/vfx/vfx-materializer.d.ts +1 -1
  18. package/dist/effects/vfx/vfx-materializer.js +1 -1
  19. package/dist/effects/vfx/vfx-renderers.d.ts +2 -0
  20. package/dist/effects/vfx/vfx-renderers.js +1 -1
  21. package/dist/gameplay/actors/actor.d.ts +4 -0
  22. package/dist/gameplay/actors/actor.js +1 -1
  23. package/dist/gameplay/actors/builtin/components/actor-transform-persistence.d.ts +29 -0
  24. package/dist/gameplay/actors/builtin/components/actor-transform-persistence.js +4 -0
  25. package/dist/gameplay/ai/navigation.js +1 -1
  26. package/dist/gameplay/index.d.ts +2 -0
  27. package/dist/gameplay/index.js +1 -1
  28. package/dist/gameplay/initiate.d.ts +4 -0
  29. package/dist/gameplay/initiate.js +1 -1
  30. package/dist/gameplay/net/service/net-decorator.d.ts +9 -5
  31. package/dist/gameplay/net/service/net-decorator.js +1 -1
  32. package/dist/gameplay/net/service/net-service.js +1 -1
  33. package/dist/gameplay/services/actor-persistence.d.ts +69 -0
  34. package/dist/gameplay/services/actor-persistence.js +4 -0
  35. package/dist/gameplay/services/render.d.ts +1 -1
  36. package/dist/gameplay/services/scene-transition.js +1 -1
  37. package/dist/gameplay/services/world.d.ts +10 -1
  38. package/dist/gameplay/services/world.js +1 -1
  39. package/dist/rendering/webgpu-experimental-backend.js +1 -1
  40. package/dist/rendering.js +1 -1
  41. package/dist/scene/bootstrap.d.ts +2 -0
  42. package/dist/scene/bootstrap.js +1 -1
  43. package/dist/scene/materializer.d.ts +10 -0
  44. package/dist/scene/materializer.js +1 -1
  45. package/dist/shader-nodes/pom.js +1 -1
  46. package/dist/test/actor-persistence-runtime.test.d.ts +2 -0
  47. package/dist/test/actor-persistence-runtime.test.js +4 -0
  48. package/dist/test/actor-persistence.test.d.ts +2 -0
  49. package/dist/test/actor-persistence.test.js +4 -0
  50. package/dist/test/actor-transform-persistence.test.d.ts +2 -0
  51. package/dist/test/actor-transform-persistence.test.js +4 -0
  52. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  53. package/dist/test/materializer-prefetch.test.js +1 -1
  54. package/dist/test/prefab-instance-params.test.js +1 -1
  55. package/dist/test/world-lifecycle.test.js +1 -1
  56. package/dist/test/world-prefab-spawn.test.js +1 -1
  57. package/docs/actor-persistence.md +87 -0
  58. package/package.json +1 -1
  59. package/tsconfig.tsbuildinfo +1 -1
@@ -17,6 +17,7 @@ export declare class Trail extends THREE.Object3D {
17
17
  tangent: THREE.Vector3;
18
18
  transformMatrix: THREE.Matrix4;
19
19
  id: number;
20
+ distance: number;
20
21
  }>;
21
22
  renderNodeCount: number;
22
23
  subdivisions: number;
@@ -57,6 +58,7 @@ export declare class Trail extends THREE.Object3D {
57
58
  tangent: THREE.Vector3;
58
59
  transformMatrix: THREE.Matrix4;
59
60
  id: number;
61
+ distance: number;
60
62
  };
61
63
  rebuildGeometry(): void;
62
64
  currentTime(): number;
@@ -1,4 +1,4 @@
1
- import{timeUniforms as t}from"../../shader-nodes/index.js";import*as e from"three";import{NodeShaderMaterial as i,uniformBool as r,uniformFloat as o,uniformVec2 as s,mix as a,uniformVec4 as n,attributeFloat as h,attributeVec3 as l,select as d,float as u,textureSampler2d as c,attributes as m,uniforms as y,rgba as g,vec4 as p,varying as x,vec2 as f,vec3 as v,cross as b,max as T,length as C}from"three-shader-graph";import{markMaterialUniformValuesNeedUpdate as V}from"../../rendering/node-material-webgpu-resolver.js";o("trailLength");const P=o("verticesPerNode"),w=o("minID"),F=o("maxID"),I=(o("dragTexture"),o("maxTrailLength")),D=s("textureTileFactor",new e.Vector2(1,1)),N=n("headColor",new e.Vector4),U=n("tailColor",new e.Vector4),A=r("taper",!1),M=(o("scale",1),h("nodeID")),z=h("nodeVertexID"),B=l("nodeCenter"),S=u(1e-4),H=F.subtract(M).divide(T(F.subtract(w),S)),j=d(A,H,u(0)),q=x(u(1).subtract(H).multiplyVec4(N).add(H.multiplyVec4(U))),L=y.cameraPosition.subtract(B),G=d(C(L).gt(S),L.divideScalar(T(C(L),S)),v(0,0,1)),O=l("nodeTangent"),Q=d(C(O).gt(S),O.divideScalar(T(C(O),S)),v(1,0,0)),R=o("width",1),W=b(Q,G),_=b(Q,v(0,1,0)),k=d(C(_).gt(S),_,b(Q,v(1,0,0))),E=d(C(W).gt(S),W.divideScalar(T(C(W),S)),k.divideScalar(T(C(k),S))).multiplyScalar(z.subtract(u(.5))).multiplyScalar(R),J=p(u(1).subtract(j).multiplyVec3(E).add(T(j,u(1)).multiplyVec3(B)),1),K=p(u(1).subtract(j).multiplyVec3(m.position).add(j.multiplyVec3(B)),1),X=y.projectionMatrix.multiply(y.viewMatrix).multiplyVec(J),Y=y.projectionMatrix.multiply(y.viewMatrix).multiplyVec(K);export const trailUV=x(f(H.multiply(D.x),z.divide(P).multiply(D.y).multiply(2)));export const trailDragUV=x(f(M.divide(I).multiply(D.x),z.divide(P).multiply(D.y).multiply(2)));const Z={position:new e.Vector3,direction:new e.Vector3,offset:new e.Vector3,worldOrientation:new e.Vector3,matrix4:new e.Matrix4,quat1:new e.Quaternion,quat2:new e.Quaternion,quaternion:new e.Quaternion,quaternion2:new e.Quaternion,boundingBox:new e.Box3,localHeadGeometry:Array.from({length:128},()=>new e.Vector3)};export class Trail extends e.Object3D{constructor(t,i){super(),this.historyCount=0,this.historyHeadIndex=-1,this.history=[],this.renderNodeCount=0,this.subdivisions=4,this.currentNodeID=0,this.advance=function(){const t=new e.Matrix4;return function(){this.targetObject.updateMatrixWorld(),t.copy(this.targetObject.matrixWorld),this.advanceWithTransform(t),this.updateUniforms()}}(),this.connectNodes=(()=>{const t={attribute:null,offset:0,count:-1};return(e,i)=>{const r=this.geometry.getIndex();for(let t=0;t<this.localHeadGeometry.length-1;t++){const o=this.VerticesPerNode*e+t,s=this.VerticesPerNode*i+t,a=(e*this.FacesPerNode+t*Trail.FacesPerQuad)*Trail.IndicesPerFace;r.array[a]=o,r.array[a+1]=s,r.array[a+2]=o+1,r.array[a+3]=s,r.array[a+4]=s+1,r.array[a+5]=o+1}return r.needsUpdate=!0,r.clearUpdateRanges(),t.attribute=r,t.offset=e*this.FacesPerNode*Trail.IndicesPerFace,t.count=this.FacesPerNode*Trail.IndicesPerFace,t}})(),this.disconnectNodes=(()=>{const t={attribute:null,offset:0,count:-1};return e=>{const i=this.geometry.getIndex();for(let t=0;t<this.localHeadGeometry.length-1;t++){const r=(e*this.FacesPerNode+t*Trail.FacesPerQuad)*Trail.IndicesPerFace;i.array[r]=0,i.array[r+1]=0,i.array[r+2]=0,i.array[r+3]=0,i.array[r+4]=0,i.array[r+5]=0}return i.needsUpdate=!0,i.clearUpdateRanges(),t.attribute=i,t.offset=e*this.FacesPerNode*Trail.IndicesPerFace,t.count=this.FacesPerNode*Trail.IndicesPerFace,t}})(),this.active=!1,this.orientToMovement=!1,i&&(this.orientToMovement=!0),this.scene=t,this.geometry=null,this.mesh=null,this.historyCount=0,this.historyHeadIndex=-1,this.history=[],this.renderNodeCount=0,this.currentNodeID=0,this.advanceFrequency=60,this.advancePeriod=1/this.advanceFrequency,this.lastAdvanceTime=0,this.paused=!1,this.pauseAdvanceUpdateTimeDiff=0}setAdvanceFrequency(t){this.advanceFrequency=t,this.advancePeriod=1/this.advanceFrequency}initialize(t,i,r,o,s,a,n=!1){this.deactivate(),this.destroyMesh(),this.length=i>0?i+1:0,this.dragTexture=r?1:0,this.targetObject=a,this.billboard=n,this.initializeLocalHeadGeometry(o,s),null!=t.uniforms.width&&(t.uniforms.width.value=o),this.renderNodeCount=this.length*this.subdivisions,this.historyCount=0,this.historyHeadIndex=-1,this.history=[];for(let t=0;t<this.length;t++)this.history.push({position:new e.Vector3,tangent:new e.Vector3(1,0,0),transformMatrix:new e.Matrix4,id:-1});this.setAllNodesToCurrentTargetPosition(),this.material=t,this.initializeGeometry(),this.initializeMesh(),this.material.uniforms.dragTexture&&(this.material.uniforms.trailLength.value=0),this.material.uniforms.minID.value=0,this.material.uniforms.maxID.value=0,this.material.uniforms.dragTexture&&(this.material.uniforms.dragTexture.value=this.dragTexture),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode),this.material.uniforms.textureTileFactor&&(this.material.uniforms.textureTileFactor.value=new e.Vector2(1,1)),this.material.uniforms.scale&&(this.material.uniforms.scale.value=1),this.reset()}initializeLocalHeadGeometry(t,i){if(this.localHeadGeometry=[],i){this.VerticesPerNode=0;for(let t=0;t<i.length&&t<Trail.MaxHeadVertices;t++){const r=i[t];if(r&&r instanceof e.Vector3){const t=new e.Vector3;t.copy(r),this.localHeadGeometry.push(t),this.VerticesPerNode++}}}else{const i=(t||1)/2;this.localHeadGeometry.push(new e.Vector3(-i,0,0)),this.localHeadGeometry.push(new e.Vector3(i,0,0)),this.VerticesPerNode=2}this.FacesPerNode=2*(this.VerticesPerNode-1),this.FaceIndicesPerNode=3*this.FacesPerNode}initializeGeometry(){this.vertexCount=this.renderNodeCount*this.VerticesPerNode,this.faceCount=this.renderNodeCount*this.FacesPerNode;const t=new e.BufferGeometry,i=new Float32Array(this.vertexCount),r=new Float32Array(this.vertexCount*this.VerticesPerNode),o=new Float32Array(this.vertexCount*Trail.PositionComponentCount),s=new Float32Array(this.vertexCount*Trail.PositionComponentCount),a=new Float32Array(this.vertexCount*Trail.UVComponentCount),n=new Uint32Array(this.faceCount*Trail.IndicesPerFace),h=new Float32Array(3*this.vertexCount),l=new e.BufferAttribute(h,3);l.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeTangent",l);const d=new e.BufferAttribute(i,1);d.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeID",d);const u=new e.BufferAttribute(r,1);u.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeVertexID",u);const c=new e.BufferAttribute(s,Trail.PositionComponentCount);c.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeCenter",c);const m=new e.BufferAttribute(o,Trail.PositionComponentCount);m.setUsage(e.DynamicDrawUsage),t.setAttribute("position",m);const y=new e.BufferAttribute(a,Trail.UVComponentCount);y.setUsage(e.DynamicDrawUsage),t.setAttribute("uv",y);const g=new e.BufferAttribute(n,1);g.setUsage(e.DynamicDrawUsage),t.setIndex(g),this.geometry=t}zeroVertices(){const t=this.geometry.getAttribute("position");for(let e=0;e<this.vertexCount;e++){const i=3*e;t.array[i]=0,t.array[i+1]=0,t.array[i+2]=0}t.needsUpdate=!0}zeroIndices(){if(null==this.geometry)throw"Geometry not initialized";const t=this.geometry.getIndex();for(let e=0;e<this.faceCount;e++){const i=3*e;t.array[i]=0,t.array[i+1]=0,t.array[i+2]=0}t.needsUpdate=!0,t.clearUpdateRanges()}formInitialFaces(){this.zeroIndices();const t=this.geometry.getIndex();for(let t=0;t<this.renderNodeCount-1;t++)this.connectNodes(t,t+1);t.needsUpdate=!0,t.clearUpdateRanges()}initializeMesh(){if(null==this.geometry)throw"Geometry not initialized";this.mesh=new e.Mesh(this.geometry,this.material),this.mesh.matrixAutoUpdate=!1,this.mesh.visible=!1}destroyMesh(){this.mesh&&(this.scene.remove(this.mesh),this.mesh=null)}reset(){this.historyCount=0,this.historyHeadIndex=-1,this.currentNodeID=0,this.formInitialFaces(),this.zeroVertices(),this.geometry.setDrawRange(0,0),this.setAllNodesToCurrentTargetPosition(),this.mesh&&(this.mesh.visible=!0)}setAllNodesToCurrentTargetPosition(){if(!this.targetObject)return;this.targetObject.updateMatrixWorld();const t=this.targetObject.matrixWorld,i=(new e.Vector3).setFromMatrixPosition(t),r=new e.Vector3(1,0,0).transformDirection(t);for(let e=0;e<this.length;e++)this.history[e].position.copy(i),this.history[e].tangent.copy(r),this.history[e].transformMatrix.copy(t),this.history[e].id=-1;this.historyCount=0,this.historyHeadIndex=-1}updateUniforms(){if(0===this.historyCount)return;const t=this.getControlPoint(0).id,e=this.getControlPoint(this.historyCount-1).id;this.material.uniforms.minID.value=t,this.material.uniforms.maxID.value=e,this.material.uniforms.trailLength&&(this.material.uniforms.trailLength.value=this.historyCount),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode),V(this.material)}advanceWithTransform(t){this.historyCount<this.length&&this.historyCount++,this.historyHeadIndex=(this.historyHeadIndex+1)%this.length;const e=this.history[this.historyHeadIndex];if(e.id=this.currentNodeID++,Z.position.set(0,0,0).applyMatrix4(t),e.position.copy(Z.position),e.transformMatrix.copy(t),this.billboard){const i=this.getControlPoint(this.historyCount-2);i&&!i.position.equals(Z.position)?e.tangent.copy(Z.position).sub(i.position).normalize():e.tangent.set(1,0,0).transformDirection(t)}this.rebuildGeometry()}updateHead(){if(0===this.historyCount)return;this.targetObject.updateMatrixWorld();const t=this.targetObject.matrixWorld,e=this.history[this.historyHeadIndex];if(Z.position.set(0,0,0).applyMatrix4(t),e.position.copy(Z.position),e.transformMatrix.copy(t),this.billboard){const i=this.getControlPoint(this.historyCount-2);i&&!i.position.equals(Z.position)?e.tangent.copy(Z.position).sub(i.position).normalize():e.tangent.set(1,0,0).transformDirection(t)}this.rebuildGeometry()}getControlPoint(t){if(t<0)return this.history[(this.historyHeadIndex-this.historyCount+1+this.length)%this.length];t>=this.historyCount&&(t=this.historyCount-1);const e=(this.historyHeadIndex-this.historyCount+1+this.length)%this.length;return this.history[(e+t)%this.length]}rebuildGeometry(){if(this.historyCount<2)return this.geometry.setDrawRange(0,0),void(this.mesh&&(this.mesh.visible=!1));const t=this.geometry.getAttribute("position"),i=this.geometry.getAttribute("nodeID"),r=this.geometry.getAttribute("nodeVertexID"),o=this.geometry.getAttribute("nodeCenter"),s=this.geometry.getAttribute("nodeTangent"),a=this.historyCount-1,n=a*this.subdivisions+1;let h=0;Z.boundingBox.makeEmpty();for(let e=0;e<a;e++){const n=this.getControlPoint(e-1),l=this.getControlPoint(e),d=this.getControlPoint(e+1),u=this.getControlPoint(e+2),c=e===a-1?this.subdivisions+1:this.subdivisions;for(let e=0;e<c;e++){const a=e/this.subdivisions,c=n.position,m=l.position,y=d.position,g=u.position,p=a*a,x=p*a,f=.5*(y.x-c.x),v=.5*(g.x-m.x),b=(2*(m.x-y.x)+f+v)*x+(-3*(m.x-y.x)-2*f-v)*p+f*a+m.x,T=.5*(y.y-c.y),C=.5*(g.y-m.y),V=(2*(m.y-y.y)+T+C)*x+(-3*(m.y-y.y)-2*T-C)*p+T*a+m.y,P=.5*(y.z-c.z),w=.5*(g.z-m.z),F=(2*(m.z-y.z)+P+w)*x+(-3*(m.z-y.z)-2*P-w)*p+P*a+m.z;Z.position.set(b,V,F);const I=l.id+(d.id-l.id)*a,D=Z.direction.copy(l.tangent).lerp(d.tangent,a).normalize();Z.matrix4.copy(l.transformMatrix),Z.quat1.setFromRotationMatrix(l.transformMatrix),Z.quat2.setFromRotationMatrix(d.transformMatrix),Z.quaternion.copy(Z.quat1).slerp(Z.quat2,a),Z.matrix4.makeRotationFromQuaternion(Z.quaternion),Z.matrix4.setPosition(Z.position);for(let e=0;e<this.VerticesPerNode;e++){const n=h*this.VerticesPerNode+e;i.array[n]=I,r.array[n]=e,o.array[3*n]=Z.position.x,o.array[3*n+1]=Z.position.y,o.array[3*n+2]=Z.position.z;const l=Z.localHeadGeometry[e].copy(this.localHeadGeometry[e]);if(this.billboard)s.array[3*n]=D.x,s.array[3*n+1]=D.y,s.array[3*n+2]=D.z,Z.boundingBox.expandByPoint(Z.position);else{if(l.applyMatrix4(Z.matrix4),this.orientToMovement){Z.worldOrientation.set(0,0,-1).applyQuaternion(Z.quaternion);const t=(3*p-2*a)*(m.x-y.x)+(x-p)*v+(3*p-4*a+1)*f,e=(3*p-2*a)*(m.y-y.y)+(x-p)*C+(3*p-4*a+1)*T,i=(3*p-2*a)*(m.z-y.z)+(x-p)*w+(3*p-4*a+1)*P;Z.direction.set(t,e,i).normalize(),Z.direction.lengthSq()>1e-4&&(Z.quaternion2.setFromUnitVectors(Z.worldOrientation,Z.direction),l.sub(Z.position).applyQuaternion(Z.quaternion2).add(Z.position))}t.array[3*n]=l.x,t.array[3*n+1]=l.y,t.array[3*n+2]=l.z,Z.boundingBox.expandByPoint(l)}}h++}}if(i.needsUpdate=!0,r.needsUpdate=!0,o.needsUpdate=!0,this.billboard){s.needsUpdate=!0,this.mesh.frustumCulled=!1;const t=this.material.uniforms.width?.5*this.material.uniforms.width.value:.5;Z.boundingBox.min.subScalar(t),Z.boundingBox.max.addScalar(t)}else t.needsUpdate=!0;this.geometry.boundingBox=this.geometry.boundingBox||new e.Box3,this.geometry.boundingBox.copy(Z.boundingBox),this.geometry.boundingSphere=this.geometry.boundingSphere||new e.Sphere,this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere),this.mesh.visible=!Z.boundingBox.isEmpty(),this.geometry.setDrawRange(0,(n-1)*this.FaceIndicesPerNode)}currentTime(){return performance.now()/1e3}pause(){this.paused||(this.paused=!0,this.pauseAdvanceUpdateTimeDiff=this.currentTime()-this.lastAdvanceTime)}resume(){this.paused&&(this.paused=!1,this.lastAdvanceTime=this.currentTime()-this.pauseAdvanceUpdateTimeDiff)}update(){if(!this.paused){const t=this.currentTime();this.lastAdvanceTime||(this.lastAdvanceTime=t),t-this.lastAdvanceTime>this.advancePeriod?(this.advance(),this.lastAdvanceTime=t):this.updateHead()}}deactivate(){this.active&&(this.scene.remove(this.mesh),this.active=!1)}activate(){this.active||(this.scene.add(this.mesh),this.active=!0)}static getTrailShaderNodes(t){return{position:t?X:Y,color:q,fraction:H}}static applyTrailShaderParameters(t){t.transparent=!0,t.alphaTest=1e-4,t.blending=e.CustomBlending,t.blendSrc=e.SrcAlphaFactor,t.blendDst=e.OneMinusSrcAlphaFactor,t.blendEquation=e.AddEquation,t.depthTest=!0,t.depthWrite=!1,t.side=e.DoubleSide}static createBaseMaterial(e,r,o,s=!1){let{position:n}=Trail.getTrailShaderNodes(s),h=a(N,U,H).rgba,l=h.a;if(null!=e){let i=trailUV;null!=r&&(i=i.add(f(t.elapsed.multiply(-r),0)));const s=c(e).sample(i);switch(o??"red"){case"none":break;case"red":l=l.multiply(s.r);break;case"alpha":l=l.multiply(s.a)}h=g(h.rgb.multiply(s.rgb),l)}const d=new i({position:n,opacity:l,color:h});return Trail.applyTrailShaderParameters(d),d}static get MaxHeadVertices(){return 128}static get LocalOrientationTangent(){return Trail._LocalOrientationTangent}static get LocalHeadOrigin(){return Trail._LocalHeadOrigin}static get PositionComponentCount(){return 3}static get UVComponentCount(){return 2}static get IndicesPerFace(){return 3}static get FacesPerQuad(){return 2}}Trail._LocalOrientationTangent=new e.Vector3(1,0,0),Trail._LocalHeadOrigin=new e.Vector3(0,0,0),Trail.Shader={get BaseVertexVars(){return["attribute float nodeID;","attribute float nodeVertexID;","attribute vec3 nodeCenter;","uniform float minID;","uniform float maxID;","uniform float trailLength;","uniform float maxTrailLength;","uniform float verticesPerNode;","uniform vec2 textureTileFactor;","uniform bool taper;","uniform vec4 headColor;","uniform vec4 tailColor;","varying vec4 vColor;"].join("\n")},get TexturedVertexVars(){return[this.BaseVertexVars,"varying vec2 vUV;","uniform float dragTexture;"].join("\n")},BaseFragmentVars:["varying vec4 vColor;","uniform sampler2D trailTexture;"].join("\n"),get TexturedFragmentVars(){return[this.BaseFragmentVars,"varying vec2 vUV;"].join("\n")},get VertexShaderCore(){return["float fraction = (maxID - nodeID) / (maxID - minID);","float fractionSize = taper ? fraction : 0.0;","vColor = (1.0 - fraction) * headColor + fraction * tailColor;","vec4 realPosition = vec4((1.0 - fractionSize) * position.xyz + fractionSize * nodeCenter.xyz, 1.0); "].join("\n")},get BaseVertexShader(){return[this.BaseVertexVars,"void main() { ",this.VertexShaderCore,"gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get BaseFragmentShader(){return[this.BaseFragmentVars,"void main() { ","gl_FragColor = vColor;","}"].join("\n")},get TexturedVertexShader(){return[this.TexturedVertexVars,"void main() { ",this.VertexShaderCore,"float s = 0.0;","float t = 0.0;","if (dragTexture == 1.0) { "," s = fraction * textureTileFactor.s; "," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","} else { "," s = nodeID / maxTrailLength * textureTileFactor.s;"," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","}","vUV = vec2(s, t); ","gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get TexturedFragmentShader(){return[this.TexturedFragmentVars,"void main() { ","vec4 textureColor = texture2D(trailTexture, vUV);","gl_FragColor = vColor * textureColor;","}"].join("\n")}};/*
1
+ import{timeUniforms as t}from"../../shader-nodes/index.js";import*as e from"three";import{NodeShaderMaterial as i,uniformBool as r,uniformFloat as o,uniformVec2 as s,mix as a,uniformVec4 as n,attributeFloat as h,attributeVec3 as l,select as d,float as c,textureSampler2d as u,attributes as m,uniforms as y,rgba as g,vec4 as p,varying as x,vec2 as f,vec3 as v,cross as b,max as C,length as T}from"three-shader-graph";import{markMaterialUniformValuesNeedUpdate as V}from"../../rendering/node-material-webgpu-resolver.js";o("trailLength");const P=o("verticesPerNode"),w=o("minID"),D=o("maxID"),F=(o("dragTexture"),o("maxTrailLength")),I=s("textureTileFactor",new e.Vector2(1,1)),U=n("headColor",new e.Vector4),A=n("tailColor",new e.Vector4),N=r("taper",!1),M=(o("scale",1),h("nodeID")),z=h("nodeDistance"),B=o("trailUvMode",0),S=o("unitsPerRepeat",1),H=h("nodeVertexID"),j=l("nodeCenter"),q=c(1e-4),L=D.subtract(M).divide(C(D.subtract(w),q)),G=d(N,L,c(0)),O=x(c(1).subtract(L).multiplyVec4(U).add(L.multiplyVec4(A))),R=y.cameraPosition.subtract(j),Q=d(T(R).gt(q),R.divideScalar(C(T(R),q)),v(0,0,1)),W=l("nodeTangent"),_=d(T(W).gt(q),W.divideScalar(C(T(W),q)),v(1,0,0)),k=o("width",1),E=b(_,Q),J=b(_,v(0,1,0)),K=d(T(J).gt(q),J,b(_,v(1,0,0))),X=d(T(E).gt(q),E.divideScalar(C(T(E),q)),K.divideScalar(C(T(K),q))).multiplyScalar(H.subtract(c(.5))).multiplyScalar(k),Y=p(c(1).subtract(G).multiplyVec3(X).add(C(G,c(1)).multiplyVec3(j)),1),Z=p(c(1).subtract(G).multiplyVec3(m.position).add(G.multiplyVec3(j)),1),$=y.projectionMatrix.multiply(y.viewMatrix).multiplyVec(Y),tt=y.projectionMatrix.multiply(y.viewMatrix).multiplyVec(Z);export const trailUV=x(f(d(B.gt(c(.5)),z.divide(S),L).multiply(I.x),H.divide(P).multiply(I.y).multiply(2)));export const trailDragUV=x(f(M.divide(F).multiply(I.x),H.divide(P).multiply(I.y).multiply(2)));const et={position:new e.Vector3,direction:new e.Vector3,offset:new e.Vector3,worldOrientation:new e.Vector3,matrix4:new e.Matrix4,quat1:new e.Quaternion,quat2:new e.Quaternion,quaternion:new e.Quaternion,quaternion2:new e.Quaternion,boundingBox:new e.Box3,localHeadGeometry:Array.from({length:128},()=>new e.Vector3)};export class Trail extends e.Object3D{constructor(t,i){super(),this.historyCount=0,this.historyHeadIndex=-1,this.history=[],this.renderNodeCount=0,this.subdivisions=4,this.currentNodeID=0,this.advance=function(){const t=new e.Matrix4;return function(){this.targetObject.updateMatrixWorld(),t.copy(this.targetObject.matrixWorld),this.advanceWithTransform(t),this.updateUniforms()}}(),this.connectNodes=(()=>{const t={attribute:null,offset:0,count:-1};return(e,i)=>{const r=this.geometry.getIndex();for(let t=0;t<this.localHeadGeometry.length-1;t++){const o=this.VerticesPerNode*e+t,s=this.VerticesPerNode*i+t,a=(e*this.FacesPerNode+t*Trail.FacesPerQuad)*Trail.IndicesPerFace;r.array[a]=o,r.array[a+1]=s,r.array[a+2]=o+1,r.array[a+3]=s,r.array[a+4]=s+1,r.array[a+5]=o+1}return r.needsUpdate=!0,r.clearUpdateRanges(),t.attribute=r,t.offset=e*this.FacesPerNode*Trail.IndicesPerFace,t.count=this.FacesPerNode*Trail.IndicesPerFace,t}})(),this.disconnectNodes=(()=>{const t={attribute:null,offset:0,count:-1};return e=>{const i=this.geometry.getIndex();for(let t=0;t<this.localHeadGeometry.length-1;t++){const r=(e*this.FacesPerNode+t*Trail.FacesPerQuad)*Trail.IndicesPerFace;i.array[r]=0,i.array[r+1]=0,i.array[r+2]=0,i.array[r+3]=0,i.array[r+4]=0,i.array[r+5]=0}return i.needsUpdate=!0,i.clearUpdateRanges(),t.attribute=i,t.offset=e*this.FacesPerNode*Trail.IndicesPerFace,t.count=this.FacesPerNode*Trail.IndicesPerFace,t}})(),this.active=!1,this.orientToMovement=!1,i&&(this.orientToMovement=!0),this.scene=t,this.geometry=null,this.mesh=null,this.historyCount=0,this.historyHeadIndex=-1,this.history=[],this.renderNodeCount=0,this.currentNodeID=0,this.advanceFrequency=60,this.advancePeriod=1/this.advanceFrequency,this.lastAdvanceTime=0,this.paused=!1,this.pauseAdvanceUpdateTimeDiff=0}setAdvanceFrequency(t){this.advanceFrequency=t,this.advancePeriod=1/this.advanceFrequency}initialize(t,i,r,o,s,a,n=!1){this.deactivate(),this.destroyMesh(),this.length=i>0?i+1:0,this.dragTexture=r?1:0,this.targetObject=a,this.billboard=n,this.initializeLocalHeadGeometry(o,s),null!=t.uniforms.width&&(t.uniforms.width.value=o),this.renderNodeCount=this.length*this.subdivisions,this.historyCount=0,this.historyHeadIndex=-1,this.history=[];for(let t=0;t<this.length;t++)this.history.push({position:new e.Vector3,tangent:new e.Vector3(1,0,0),transformMatrix:new e.Matrix4,id:-1,distance:0});this.setAllNodesToCurrentTargetPosition(),this.material=t,this.initializeGeometry(),this.initializeMesh(),this.material.uniforms.dragTexture&&(this.material.uniforms.trailLength.value=0),this.material.uniforms.minID.value=0,this.material.uniforms.maxID.value=0,this.material.uniforms.dragTexture&&(this.material.uniforms.dragTexture.value=this.dragTexture),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode),this.material.uniforms.textureTileFactor&&(this.material.uniforms.textureTileFactor.value=new e.Vector2(1,1)),this.material.uniforms.scale&&(this.material.uniforms.scale.value=1),this.reset()}initializeLocalHeadGeometry(t,i){if(this.localHeadGeometry=[],i){this.VerticesPerNode=0;for(let t=0;t<i.length&&t<Trail.MaxHeadVertices;t++){const r=i[t];if(r&&r instanceof e.Vector3){const t=new e.Vector3;t.copy(r),this.localHeadGeometry.push(t),this.VerticesPerNode++}}}else{const i=(t||1)/2;this.localHeadGeometry.push(new e.Vector3(-i,0,0)),this.localHeadGeometry.push(new e.Vector3(i,0,0)),this.VerticesPerNode=2}this.FacesPerNode=2*(this.VerticesPerNode-1),this.FaceIndicesPerNode=3*this.FacesPerNode}initializeGeometry(){this.vertexCount=this.renderNodeCount*this.VerticesPerNode,this.faceCount=this.renderNodeCount*this.FacesPerNode;const t=new e.BufferGeometry,i=new Float32Array(this.vertexCount),r=new Float32Array(this.vertexCount*this.VerticesPerNode),o=new Float32Array(this.vertexCount*Trail.PositionComponentCount),s=new Float32Array(this.vertexCount*Trail.PositionComponentCount),a=new Float32Array(this.vertexCount*Trail.UVComponentCount),n=new Uint32Array(this.faceCount*Trail.IndicesPerFace),h=new Float32Array(3*this.vertexCount),l=new e.BufferAttribute(h,3);l.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeTangent",l);const d=new e.BufferAttribute(i,1);d.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeID",d);const c=new e.BufferAttribute(new Float32Array(this.vertexCount),1);c.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeDistance",c);const u=new e.BufferAttribute(r,1);u.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeVertexID",u);const m=new e.BufferAttribute(s,Trail.PositionComponentCount);m.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeCenter",m);const y=new e.BufferAttribute(o,Trail.PositionComponentCount);y.setUsage(e.DynamicDrawUsage),t.setAttribute("position",y);const g=new e.BufferAttribute(a,Trail.UVComponentCount);g.setUsage(e.DynamicDrawUsage),t.setAttribute("uv",g);const p=new e.BufferAttribute(n,1);p.setUsage(e.DynamicDrawUsage),t.setIndex(p),this.geometry=t}zeroVertices(){const t=this.geometry.getAttribute("position");for(let e=0;e<this.vertexCount;e++){const i=3*e;t.array[i]=0,t.array[i+1]=0,t.array[i+2]=0}t.needsUpdate=!0}zeroIndices(){if(null==this.geometry)throw"Geometry not initialized";const t=this.geometry.getIndex();for(let e=0;e<this.faceCount;e++){const i=3*e;t.array[i]=0,t.array[i+1]=0,t.array[i+2]=0}t.needsUpdate=!0,t.clearUpdateRanges()}formInitialFaces(){this.zeroIndices();const t=this.geometry.getIndex();for(let t=0;t<this.renderNodeCount-1;t++)this.connectNodes(t,t+1);t.needsUpdate=!0,t.clearUpdateRanges()}initializeMesh(){if(null==this.geometry)throw"Geometry not initialized";this.mesh=new e.Mesh(this.geometry,this.material),this.mesh.matrixAutoUpdate=!1,this.mesh.visible=!1}destroyMesh(){this.mesh&&(this.scene.remove(this.mesh),this.mesh=null)}reset(){this.historyCount=0,this.historyHeadIndex=-1,this.currentNodeID=0,this.formInitialFaces(),this.zeroVertices(),this.geometry.setDrawRange(0,0),this.setAllNodesToCurrentTargetPosition(),this.mesh&&(this.mesh.visible=!0)}setAllNodesToCurrentTargetPosition(){if(!this.targetObject)return;this.targetObject.updateMatrixWorld();const t=this.targetObject.matrixWorld,i=(new e.Vector3).setFromMatrixPosition(t),r=new e.Vector3(1,0,0).transformDirection(t);for(let e=0;e<this.length;e++)this.history[e].position.copy(i),this.history[e].tangent.copy(r),this.history[e].transformMatrix.copy(t),this.history[e].id=-1,this.history[e].distance=0;this.historyCount=0,this.historyHeadIndex=-1}updateUniforms(){if(0===this.historyCount)return;const t=this.getControlPoint(0).id,e=this.getControlPoint(this.historyCount-1).id;this.material.uniforms.minID.value=t,this.material.uniforms.maxID.value=e,this.material.uniforms.trailLength&&(this.material.uniforms.trailLength.value=this.historyCount),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode),V(this.material)}advanceWithTransform(t){this.historyCount<this.length&&this.historyCount++,this.historyHeadIndex=(this.historyHeadIndex+1)%this.length;const e=this.history[this.historyHeadIndex];e.id=this.currentNodeID++,et.position.set(0,0,0).applyMatrix4(t),e.position.copy(et.position);const i=this.getControlPoint(this.historyCount-2);if(e.distance=i&&i!==e?i.distance+i.position.distanceTo(e.position):0,e.transformMatrix.copy(t),this.billboard){const i=this.getControlPoint(this.historyCount-2);i&&!i.position.equals(et.position)?e.tangent.copy(et.position).sub(i.position).normalize():e.tangent.set(1,0,0).transformDirection(t)}this.rebuildGeometry()}updateHead(){if(0===this.historyCount)return;this.targetObject.updateMatrixWorld();const t=this.targetObject.matrixWorld,e=this.history[this.historyHeadIndex];et.position.set(0,0,0).applyMatrix4(t),e.position.copy(et.position);const i=this.getControlPoint(this.historyCount-2);if(e.distance=i&&i!==e?i.distance+i.position.distanceTo(e.position):0,e.transformMatrix.copy(t),this.billboard){const i=this.getControlPoint(this.historyCount-2);i&&!i.position.equals(et.position)?e.tangent.copy(et.position).sub(i.position).normalize():e.tangent.set(1,0,0).transformDirection(t)}this.rebuildGeometry()}getControlPoint(t){if(t<0)return this.history[(this.historyHeadIndex-this.historyCount+1+this.length)%this.length];t>=this.historyCount&&(t=this.historyCount-1);const e=(this.historyHeadIndex-this.historyCount+1+this.length)%this.length;return this.history[(e+t)%this.length]}rebuildGeometry(){if(this.historyCount<2)return this.geometry.setDrawRange(0,0),void(this.mesh&&(this.mesh.visible=!1));const t=this.geometry.getAttribute("position"),i=this.geometry.getAttribute("nodeID"),r=this.geometry.getAttribute("nodeDistance"),o=1===this.material.uniforms.trailUvMode?.value,s=this.geometry.getAttribute("nodeVertexID"),a=this.geometry.getAttribute("nodeCenter"),n=this.geometry.getAttribute("nodeTangent"),h=this.historyCount-1,l=h*this.subdivisions+1,d=this.getControlPoint(this.historyCount-1).distance;let c=0;et.boundingBox.makeEmpty();for(let e=0;e<h;e++){const l=this.getControlPoint(e-1),u=this.getControlPoint(e),m=this.getControlPoint(e+1),y=this.getControlPoint(e+2),g=e===h-1?this.subdivisions+1:this.subdivisions;for(let e=0;e<g;e++){const h=e/this.subdivisions,g=l.position,p=u.position,x=m.position,f=y.position,v=h*h,b=v*h,C=.5*(x.x-g.x),T=.5*(f.x-p.x),V=(2*(p.x-x.x)+C+T)*b+(-3*(p.x-x.x)-2*C-T)*v+C*h+p.x,P=.5*(x.y-g.y),w=.5*(f.y-p.y),D=(2*(p.y-x.y)+P+w)*b+(-3*(p.y-x.y)-2*P-w)*v+P*h+p.y,F=.5*(x.z-g.z),I=.5*(f.z-p.z),U=(2*(p.z-x.z)+F+I)*b+(-3*(p.z-x.z)-2*F-I)*v+F*h+p.z;et.position.set(V,D,U);const A=u.id+(m.id-u.id)*h,N=et.direction.copy(u.tangent).lerp(m.tangent,h).normalize();et.matrix4.copy(u.transformMatrix),et.quat1.setFromRotationMatrix(u.transformMatrix),et.quat2.setFromRotationMatrix(m.transformMatrix),et.quaternion.copy(et.quat1).slerp(et.quat2,h),et.matrix4.makeRotationFromQuaternion(et.quaternion),et.matrix4.setPosition(et.position);for(let e=0;e<this.VerticesPerNode;e++){const l=c*this.VerticesPerNode+e;i.array[l]=A,o&&(r.array[l]=d-(u.distance+(m.distance-u.distance)*h)),s.array[l]=e,a.array[3*l]=et.position.x,a.array[3*l+1]=et.position.y,a.array[3*l+2]=et.position.z;const y=et.localHeadGeometry[e].copy(this.localHeadGeometry[e]);if(this.billboard)n.array[3*l]=N.x,n.array[3*l+1]=N.y,n.array[3*l+2]=N.z,et.boundingBox.expandByPoint(et.position);else{if(y.applyMatrix4(et.matrix4),this.orientToMovement){et.worldOrientation.set(0,0,-1).applyQuaternion(et.quaternion);const t=(3*v-2*h)*(p.x-x.x)+(b-v)*T+(3*v-4*h+1)*C,e=(3*v-2*h)*(p.y-x.y)+(b-v)*w+(3*v-4*h+1)*P,i=(3*v-2*h)*(p.z-x.z)+(b-v)*I+(3*v-4*h+1)*F;et.direction.set(t,e,i).normalize(),et.direction.lengthSq()>1e-4&&(et.quaternion2.setFromUnitVectors(et.worldOrientation,et.direction),y.sub(et.position).applyQuaternion(et.quaternion2).add(et.position))}t.array[3*l]=y.x,t.array[3*l+1]=y.y,t.array[3*l+2]=y.z,et.boundingBox.expandByPoint(y)}}c++}}if(i.needsUpdate=!0,o&&(r.needsUpdate=!0),s.needsUpdate=!0,a.needsUpdate=!0,this.billboard){n.needsUpdate=!0,this.mesh.frustumCulled=!1;const t=this.material.uniforms.width?.5*this.material.uniforms.width.value:.5;et.boundingBox.min.subScalar(t),et.boundingBox.max.addScalar(t)}else t.needsUpdate=!0;this.geometry.boundingBox=this.geometry.boundingBox||new e.Box3,this.geometry.boundingBox.copy(et.boundingBox),this.geometry.boundingSphere=this.geometry.boundingSphere||new e.Sphere,this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere),this.mesh.visible=!et.boundingBox.isEmpty(),this.geometry.setDrawRange(0,(l-1)*this.FaceIndicesPerNode)}currentTime(){return performance.now()/1e3}pause(){this.paused||(this.paused=!0,this.pauseAdvanceUpdateTimeDiff=this.currentTime()-this.lastAdvanceTime)}resume(){this.paused&&(this.paused=!1,this.lastAdvanceTime=this.currentTime()-this.pauseAdvanceUpdateTimeDiff)}update(){if(!this.paused){const t=this.currentTime();this.lastAdvanceTime||(this.lastAdvanceTime=t),t-this.lastAdvanceTime>this.advancePeriod?(this.advance(),this.lastAdvanceTime=t):this.updateHead()}}deactivate(){this.active&&(this.scene.remove(this.mesh),this.active=!1)}activate(){this.active||(this.scene.add(this.mesh),this.active=!0)}static getTrailShaderNodes(t){return{position:t?$:tt,color:O,fraction:L}}static applyTrailShaderParameters(t){t.transparent=!0,t.alphaTest=1e-4,t.blending=e.CustomBlending,t.blendSrc=e.SrcAlphaFactor,t.blendDst=e.OneMinusSrcAlphaFactor,t.blendEquation=e.AddEquation,t.depthTest=!0,t.depthWrite=!1,t.side=e.DoubleSide}static createBaseMaterial(e,r,o,s=!1){let{position:n}=Trail.getTrailShaderNodes(s),h=a(U,A,L).rgba,l=h.a;if(null!=e){let i=trailUV;null!=r&&(i=i.add(f(t.elapsed.multiply(-r),0)));const s=u(e).sample(i);switch(o??"red"){case"none":break;case"red":l=l.multiply(s.r);break;case"alpha":l=l.multiply(s.a)}h=g(h.rgb.multiply(s.rgb),l)}const d=new i({position:n,opacity:l,color:h});return Trail.applyTrailShaderParameters(d),d}static get MaxHeadVertices(){return 128}static get LocalOrientationTangent(){return Trail._LocalOrientationTangent}static get LocalHeadOrigin(){return Trail._LocalHeadOrigin}static get PositionComponentCount(){return 3}static get UVComponentCount(){return 2}static get IndicesPerFace(){return 3}static get FacesPerQuad(){return 2}}Trail._LocalOrientationTangent=new e.Vector3(1,0,0),Trail._LocalHeadOrigin=new e.Vector3(0,0,0),Trail.Shader={get BaseVertexVars(){return["attribute float nodeID;","attribute float nodeVertexID;","attribute vec3 nodeCenter;","uniform float minID;","uniform float maxID;","uniform float trailLength;","uniform float maxTrailLength;","uniform float verticesPerNode;","uniform vec2 textureTileFactor;","uniform bool taper;","uniform vec4 headColor;","uniform vec4 tailColor;","varying vec4 vColor;"].join("\n")},get TexturedVertexVars(){return[this.BaseVertexVars,"varying vec2 vUV;","uniform float dragTexture;"].join("\n")},BaseFragmentVars:["varying vec4 vColor;","uniform sampler2D trailTexture;"].join("\n"),get TexturedFragmentVars(){return[this.BaseFragmentVars,"varying vec2 vUV;"].join("\n")},get VertexShaderCore(){return["float fraction = (maxID - nodeID) / (maxID - minID);","float fractionSize = taper ? fraction : 0.0;","vColor = (1.0 - fraction) * headColor + fraction * tailColor;","vec4 realPosition = vec4((1.0 - fractionSize) * position.xyz + fractionSize * nodeCenter.xyz, 1.0); "].join("\n")},get BaseVertexShader(){return[this.BaseVertexVars,"void main() { ",this.VertexShaderCore,"gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get BaseFragmentShader(){return[this.BaseFragmentVars,"void main() { ","gl_FragColor = vColor;","}"].join("\n")},get TexturedVertexShader(){return[this.TexturedVertexVars,"void main() { ",this.VertexShaderCore,"float s = 0.0;","float t = 0.0;","if (dragTexture == 1.0) { "," s = fraction * textureTileFactor.s; "," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","} else { "," s = nodeID / maxTrailLength * textureTileFactor.s;"," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","}","vUV = vec2(s, t); ","gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get TexturedFragmentShader(){return[this.TexturedFragmentVars,"void main() { ","vec4 textureColor = texture2D(trailTexture, vUV);","gl_FragColor = vColor * textureColor;","}"].join("\n")}};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,10 +1,21 @@
1
+ import * as THREE from "three";
1
2
  import { BaseActor } from '../../gameplay/actors/actor.js';
2
3
  import { Asset } from '../../scene/model.js';
3
4
  import type { VfxClipEndBehavior } from '../sequence/sequence-data.js';
4
5
  import { Subject } from 'rxjs';
5
6
  import { type VfxBackendPreference } from './gpu-sprite-compiler.js';
7
+ /** Reused for every CPU collision. Copy vectors if they are needed after the callback returns. */
8
+ export interface VfxCollisionEvent {
9
+ readonly emitterId: string;
10
+ readonly emitterName: string;
11
+ readonly position: THREE.Vector3;
12
+ readonly normal: THREE.Vector3;
13
+ }
6
14
  export declare class VfxActor extends BaseActor {
7
15
  readonly onComplete: Subject<void>;
16
+ /** Synchronous CPU collision callback. The event and its vectors are reused. */
17
+ onCollision?: (event: VfxCollisionEvent) => void;
18
+ private readonly collisionEvent;
8
19
  /**
9
20
  * A multiplier for the speed of the visual effect.
10
21
  */
@@ -1,4 +1,4 @@
1
- import{__decorate as t,__metadata as e}from"tslib";import*as s from"three";import{Rate as i}from"@hology/nebula";import{Actor as r,BaseActor as a}from"../../gameplay/actors/actor.js";import{inject as n}from"../../gameplay/inject.js";import{AssetLoader as o}from"../../gameplay/services/asset-loader.js";import{ViewController as l}from"../../gameplay/services/render.js";import{World as p}from"../../gameplay/services/world.js";import{DelayRate as h}from"./rates.js";import{materializeVfx as u}from"./vfx-materializer.js";import{PhysicsSystem as m}from"../../gameplay/services/physics/physics-system.js";import{ShaderProvider as d}from"../../gameplay/services/shader-provider.js";import{AssetResourceLoader as c}from"../../scene/asset-resource-loader.js";import{AssetsProvider as f}from"../../scene/assets-provider.js";import{VfxInputRuntime as g}from"./vfx-input-runtime.js";import{Subject as y}from"rxjs";import{EventGraphCallable as v}from"../../gameplay/event-graph/decorators.js";import{EVENT_GRAPH_VOID_TYPE as b}from"../../gameplay/event-graph/types.js";import{VFX_ACTOR_TYPE_ID as w}from"../../gameplay/event-graph/asset-actor-types.js";import{GpuVfxWorldService as P}from"./gpu-vfx-world-service.js";import{compileGpuSpriteEmitters as S,requiresCpuVfxBackend as j}from"./gpu-sprite-compiler.js";import{withSeededRandom as E}from"./seeded-random.js";let x=class extends a{constructor(){super(...arguments),this.onComplete=new y,this._timescale=1,this.paused=!0,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.profilingEnabled=!1,this.simulationCpuMs=0,this.system=null,this.disposeSystem=null,this.assetLoader=n(o),this.assetManagerService=n(c),this.assetService=n(f),this.world=n(p),this.view=n(l),this.gpuWorld=n(P),this.particleSystemContainer=null,this.gpuPrepared=null,this.gpuHandle=null,this.physics=n(m),this.shaderProvider=n(d),this.inputRuntime=new g,this.inputOverrides=new Map,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this._worldPos=new s.Vector3,this._worldRot=new s.Quaternion,this._worldEul=new s.Euler,this._worldScale=new s.Vector3,this.previewStepSeconds=1/60,this.maxPreviewSteps=240,this.max=0}get timescale(){return this._timescale}set timescale(t){this._timescale=Math.max(0,t),this.gpuHandle?.setTimescale(this._timescale)}async fromAsset(t,e,i,r){if("vfx"!==t.type)throw"Asset must be a VFX asset but is "+t.type;null!=this.system&&(this.system.destroy(),this.system.emitters.forEach(t=>t.reset())),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.simulationCpuMs=0,this.sourceAsset=t,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this.disposeSystem&&this.disposeSystem(),null==this.object.parent&&this.world.scene.add(this.object),this.inputRuntime.setDefinitions(this.sourceAsset.vfx.inputs??[]);for(const t of this.inputRuntime.getDefinitions()){if("mesh"!==t.type||"string"!=typeof t.defaultValue||0===t.defaultValue.length)continue;const e=await this.assetService.getAsset(t.defaultValue);if(null==e)continue;const s=await this.assetManagerService.getMesh(e,{applyMaterials:!0,rescale:!0});this.inputRuntime.setInput(t.id,s.scene)}for(const[t,e]of this.inputOverrides)this.inputRuntime.setInput(t,e);null!=e&&this.setInputs(e);const a=i??this.view.vfxBackendPreference,n=j(this.sourceAsset);if("cpu"===a&&(this.backendFallbackReasons=["GPU VFX was not requested; the selected VFX backend preference is CPU."]),"cpu"!==a&&!n){const t=new Map;for(const e of this.inputRuntime.getDefinitions()){if("mesh"!==e.type)continue;const s=this.inputRuntime.getMesh(e.id);null!=s&&t.set(e.id,s)}if(this.gpuPrepared=await this.gpuWorld.prepare(this.sourceAsset,r,t),null!=this.gpuPrepared)return this.runtimeBackend="gpu",this.system=null,this.disposeSystem=null,this.particleSystemContainer=null,this.object.visible=!1,this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,void(this.inputsMaterialized=!0);if(this.backendFallbackReasons=this.gpuWorld.getFallbackReasons(this.sourceAsset,r),"gpu"===a){const t=S(this.sourceAsset,[new s.Vector3]).compatibility;this.backendFallbackReasons=t.issues.filter(t=>"warning"!==t.severity).map(t=>`${t.emitter}: ${t.message}`),0===this.backendFallbackReasons.length&&(this.backendFallbackReasons=["GPU template or material preparation failed; inspect earlier shader diagnostics."])}}const{system:o,dispose:l,container:p}=await u(this.sourceAsset,this.object,{getAsset:t=>this.assetLoader.getAsset(t),getMaterial:t=>this.assetLoader.getMaterialByAssetId(t),getTexture:t=>this.assetLoader.getTextureByAssetId(t),getMesh:async t=>(await this.assetManagerService.getMesh(await this.assetService.getAsset(t),{applyMaterials:!0,rescale:!0})).scene},this.view,this.physics,this.shaderProvider,this.assetService,this.assetManagerService,this.inputRuntime);this.system=o,this.disposeSystem=l,this.particleSystemContainer=p,this.inputsMaterialized=!0,this.object.visible=!1,this.object.matrixAutoUpdate=!1,this.object.matrixWorldAutoUpdate=!1,this.particleSystemContainer.matrixAutoUpdate=!1,this.particleSystemContainer.matrixWorldAutoUpdate=!1}setInput(t,e){const i=this.inputRuntime.getDefinition(t);if(this.inputsMaterialized&&"mesh"===i?.type)return void console.warn(`VFX mesh input "${i.name}" is creation-time only; recreate the VFX to replace it.`);this.inputOverrides.set(t,function(t){if(t instanceof s.Vector3||t instanceof s.Color)return t.clone();if(Array.isArray(t))return[...t];return t}(e)),this.inputRuntime.setInput(t,e);const r=this.inputRuntime.getDefinition(t);null!=r&&this.gpuHandle?.setInput(r.id,this.inputRuntime.getValue(r.id))}setInputs(t){for(const[e,s]of Object.entries(t))this.setInput(e,s)}play(){if(this.prepareForPlayback(),this.paused=!1,null!=this.gpuPrepared){if(this.object.getWorldPosition(this._worldPos),null!=this.gpuHandle&&this.gpuHandle.active)this.gpuHandle.play();else{this.gpuHandle=this.gpuPrepared.spawn(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),this.gpuHandle?.setTimescale(this._timescale);for(const t of this.inputRuntime.getDefinitions())this.gpuHandle?.setInput(t.id,this.inputRuntime.getValue(t.id))}return}this.system.emitters.every(t=>t.dead)&&this.restart()}pause(){this.paused=!0,this.gpuHandle?.pause()}previewAt(t,e,s,i,r=0){null!=this.system&&(this.prepareForPlayback(),E(r,()=>{this.restart(),this.paused=!0;const r=Math.max(0,t),a=Math.min(r,Math.max(0,e)),n=r-a,o=Number(a>0)+Number(n>0),l=Math.max(o,Math.min(this.maxPreviewSteps,Math.max(1,Math.ceil(r/this.previewStepSeconds)))),p=a<=0?0:n<=0?l:Math.min(l-1,Math.max(1,Math.round(l*a/r)));this.simulatePreview(a,p),n>0&&(this.applyClipEndBehavior(s,i),this.simulatePreview(n,l-p))}))}clearPreview(){this.restart(),this.pause(),this.object.visible=!1,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!1)}stop(){this.finishRequested=!0,null==this.gpuPrepared?null!=this.system?.emitters&&this.system.emitters.forEach(t=>{this.stopEmitterEmission(t)}):this.gpuHandle?.stop()}applyClipEndBehavior(t,e){const s=t??"finish";if("finish"!==s){if(null!=this.gpuPrepared)return this.finishRequested=!0,void("kill"===s?this.gpuHandle?.kill():this.gpuHandle?.expire(Math.max(0,e??0)));if(null!=this.system&&null!=this.system.emitters)for(const t of this.system.emitters)this.applyEmitterClipEndBehavior(t,s,e)}else this.stop()}restart(){if(null==this.gpuPrepared){if(null!=this.system&&null!=this.system.emitters){this.finishRequested=!1,this.completionEmitted=!1;for(const t of this.system.emitters)this.restartEmitter(t)}}else if(this.finishRequested=!1,this.completionEmitted=!1,null!=this.gpuHandle){if(!this.gpuHandle.active&&!this.paused)return void this.play();this.gpuHandle.restart()}}restartEmitter(t){const e=t.rate;e instanceof h?e.restart():e instanceof i&&(e.nextTime=0),null==t.clearParticlesRecursive?this.removeEmitterParticlesRecursive(t):t.clearParticlesRecursive()}removeEmitterParticlesRecursive(t){const e=t.childEmitters??[];for(const t of e)this.removeEmitterParticlesRecursive(t);t.removeAllParticles?.()}onUpdate(t){if(this.paused)null!=this.gpuHandle&&(this.object.getWorldPosition(this._worldPos),this.gpuHandle.setPosition(this._worldPos),this.gpuHandle.setTransform(this.object.matrixWorld));else{if(null!=this.gpuPrepared)return this.object.getWorldPosition(this._worldPos),this.gpuHandle?.setPosition(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),void this.updateCompletionState();this.updateWorldSpaceEmitterTransforms(),this.updateSystem(t*this.timescale),this.updateCompletionState()}}prepareForPlayback(){null==this.gpuPrepared?(null!=this.particleSystemContainer&&null==this.particleSystemContainer.parent&&this.world.scene.add(this.particleSystemContainer),this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.matrixAutoUpdate=!0,this.particleSystemContainer.matrixWorldAutoUpdate=!0),this.object.visible=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!0)):this.object.visible=!0}simulatePreview(t,e){if(t<=0)return;const s=t/e;for(let t=0;t<e;t++)this.updateWorldSpaceEmitterTransforms(),this.updateSystem(s)}updateWorldSpaceEmitterTransforms(){this.object.getWorldPosition(this._worldPos),this.object.getWorldQuaternion(this._worldRot),this.object.getWorldScale(this._worldScale),this._worldEul.setFromQuaternion(this._worldRot),this.system?.emitters.forEach(t=>{if("world"===t._space){t.setPosition(this._worldPos),t.setRotation(this._worldEul);(t._worldScale??(t._worldScale=new s.Vector3)).copy(this._worldScale)}})}getParticleCount(){return null!=this.gpuPrepared?0:this.system?.getCount()??0}getProfilingStats(){let t=0,e=0;return this.particleSystemContainer?.traverse(i=>{const r=i,a=r.geometry;if(null==a||!1===r.visible)return;const n=r instanceof s.InstancedMesh?r.count:1,o=a.index?.count??a.getAttribute("position")?.count??0;n<=0||o<=0||(t++,e+=Math.floor(o/3)*n)}),{particles:this.system?.getCount()??0,drawCalls:t,triangles:e,cpuTimeMs:this.simulationCpuMs}}onEndPlay(){this.stop(),null!=this.disposeSystem&&this.disposeSystem(),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.onComplete.complete()}updateCompletionState(){if(null!=this.gpuPrepared){if(this.completionEmitted||!1!==this.gpuHandle?.active)return;return this.completionEmitted=!0,void this.onComplete.next()}if(this.completionEmitted||null==this.system||!this.onComplete.observed)return;const t=this.system.emitters.every(t=>t.dead),e=this.finishRequested&&0===this.system.getCount();(t||e)&&(this.completionEmitted=!0,this.onComplete.next())}updateSystem(t){if(null==this.system)return;if(!this.profilingEnabled)return void this.system.update(t);const e=performance.now();this.system.update(t),this.simulationCpuMs=performance.now()-e}applyEmitterClipEndBehavior(t,e,s,i=!1){this.stopEmitterEmission(t,i);const r=t.particles??[];if("kill"===e)t.removeAllParticles?.();else{const t=Math.max(0,s??0);for(const e of r)e.life=Math.min(e.life,e.age+t)}const a=t.childEmitters??[];for(const t of a)this.applyEmitterClipEndBehavior(t,e,s,!0)}stopEmitterEmission(t,e=!1){const s=t.rate;s instanceof i&&(s.nextTime=1/0),e&&t.stopEmit?.()}};t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"play",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"pause",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"stop",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"restart",null),x=t([r({typeId:w})],x);export{x as VfxActor};/*
1
+ import{__decorate as t,__metadata as e}from"tslib";import*as s from"three";import{Rate as i}from"@hology/nebula";import{Actor as r,BaseActor as a}from"../../gameplay/actors/actor.js";import{inject as n}from"../../gameplay/inject.js";import{AssetLoader as o}from"../../gameplay/services/asset-loader.js";import{ViewController as l}from"../../gameplay/services/render.js";import{World as p}from"../../gameplay/services/world.js";import{DelayRate as h}from"./rates.js";import{materializeVfx as u}from"./vfx-materializer.js";import{PhysicsSystem as m}from"../../gameplay/services/physics/physics-system.js";import{ShaderProvider as c}from"../../gameplay/services/shader-provider.js";import{AssetResourceLoader as d}from"../../scene/asset-resource-loader.js";import{AssetsProvider as f}from"../../scene/assets-provider.js";import{VfxInputRuntime as g}from"./vfx-input-runtime.js";import{Subject as y}from"rxjs";import{EventGraphCallable as v}from"../../gameplay/event-graph/decorators.js";import{EVENT_GRAPH_VOID_TYPE as b}from"../../gameplay/event-graph/types.js";import{VFX_ACTOR_TYPE_ID as w}from"../../gameplay/event-graph/asset-actor-types.js";import{GpuVfxWorldService as P}from"./gpu-vfx-world-service.js";import{compileGpuSpriteEmitters as S,requiresCpuVfxBackend as j}from"./gpu-sprite-compiler.js";import{withSeededRandom as E}from"./seeded-random.js";let x=class extends a{constructor(){super(...arguments),this.onComplete=new y,this.collisionEvent={emitterId:"",emitterName:"",position:new s.Vector3,normal:new s.Vector3},this._timescale=1,this.paused=!0,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.profilingEnabled=!1,this.simulationCpuMs=0,this.system=null,this.disposeSystem=null,this.assetLoader=n(o),this.assetManagerService=n(d),this.assetService=n(f),this.world=n(p),this.view=n(l),this.gpuWorld=n(P),this.particleSystemContainer=null,this.gpuPrepared=null,this.gpuHandle=null,this.physics=n(m),this.shaderProvider=n(c),this.inputRuntime=new g,this.inputOverrides=new Map,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this._worldPos=new s.Vector3,this._worldRot=new s.Quaternion,this._worldEul=new s.Euler,this._worldScale=new s.Vector3,this.previewStepSeconds=1/60,this.maxPreviewSteps=240,this.max=0}get timescale(){return this._timescale}set timescale(t){this._timescale=Math.max(0,t),this.gpuHandle?.setTimescale(this._timescale)}async fromAsset(t,e,i,r){if("vfx"!==t.type)throw"Asset must be a VFX asset but is "+t.type;null!=this.system&&(this.system.destroy(),this.system.emitters.forEach(t=>t.reset())),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.runtimeBackend="cpu",this.backendFallbackReasons=[],this.simulationCpuMs=0,this.sourceAsset=t,this.finishRequested=!1,this.completionEmitted=!1,this.inputsMaterialized=!1,this.disposeSystem&&this.disposeSystem(),null==this.object.parent&&this.world.scene.add(this.object),this.inputRuntime.setDefinitions(this.sourceAsset.vfx.inputs??[]);for(const t of this.inputRuntime.getDefinitions()){if("mesh"!==t.type||"string"!=typeof t.defaultValue||0===t.defaultValue.length)continue;const e=await this.assetService.getAsset(t.defaultValue);if(null==e)continue;const s=await this.assetManagerService.getMesh(e,{applyMaterials:!0,rescale:!0});this.inputRuntime.setInput(t.id,s.scene)}for(const[t,e]of this.inputOverrides)this.inputRuntime.setInput(t,e);null!=e&&this.setInputs(e);const a=i??this.view.vfxBackendPreference,n=j(this.sourceAsset);if("cpu"===a&&(this.backendFallbackReasons=["GPU VFX was not requested; the selected VFX backend preference is CPU."]),"cpu"!==a&&!n){const t=new Map;for(const e of this.inputRuntime.getDefinitions()){if("mesh"!==e.type)continue;const s=this.inputRuntime.getMesh(e.id);null!=s&&t.set(e.id,s)}if(this.gpuPrepared=await this.gpuWorld.prepare(this.sourceAsset,r,t),null!=this.gpuPrepared)return this.runtimeBackend="gpu",this.system=null,this.disposeSystem=null,this.particleSystemContainer=null,this.object.visible=!1,this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,void(this.inputsMaterialized=!0);if(this.backendFallbackReasons=this.gpuWorld.getFallbackReasons(this.sourceAsset,r),"gpu"===a){const t=S(this.sourceAsset,[new s.Vector3]).compatibility;this.backendFallbackReasons=t.issues.filter(t=>"warning"!==t.severity).map(t=>`${t.emitter}: ${t.message}`),0===this.backendFallbackReasons.length&&(this.backendFallbackReasons=["GPU template or material preparation failed; inspect earlier shader diagnostics."])}}const{system:o,dispose:l,container:p}=await u(this.sourceAsset,this.object,{getAsset:t=>this.assetLoader.getAsset(t),getMaterial:t=>this.assetLoader.getMaterialByAssetId(t),getTexture:t=>this.assetLoader.getTextureByAssetId(t),getMesh:async t=>(await this.assetManagerService.getMesh(await this.assetService.getAsset(t),{applyMaterials:!0,rescale:!0})).scene},this.view,this.physics,this.shaderProvider,this.assetService,this.assetManagerService,this.inputRuntime,(t,e,s,i,r)=>{if(null==this.onCollision)return;const a=this.collisionEvent;a.emitterId=t,a.emitterName=e,a.position.copy(s),a.normal.copy(i),r&&(a.position.applyMatrix4(this.object.matrixWorld),a.normal.transformDirection(this.object.matrixWorld)),this.onCollision(a)});this.system=o,this.disposeSystem=l,this.particleSystemContainer=p,this.inputsMaterialized=!0,this.object.visible=!1,this.object.matrixAutoUpdate=!1,this.object.matrixWorldAutoUpdate=!1,this.particleSystemContainer.matrixAutoUpdate=!1,this.particleSystemContainer.matrixWorldAutoUpdate=!1}setInput(t,e){const i=this.inputRuntime.getDefinition(t);if(this.inputsMaterialized&&"mesh"===i?.type)return void console.warn(`VFX mesh input "${i.name}" is creation-time only; recreate the VFX to replace it.`);this.inputOverrides.set(t,function(t){if(t instanceof s.Vector3||t instanceof s.Color)return t.clone();if(Array.isArray(t))return[...t];return t}(e)),this.inputRuntime.setInput(t,e);const r=this.inputRuntime.getDefinition(t);null!=r&&this.gpuHandle?.setInput(r.id,this.inputRuntime.getValue(r.id))}setInputs(t){for(const[e,s]of Object.entries(t))this.setInput(e,s)}play(){if(this.prepareForPlayback(),this.paused=!1,null!=this.gpuPrepared){if(this.object.getWorldPosition(this._worldPos),null!=this.gpuHandle&&this.gpuHandle.active)this.gpuHandle.play();else{this.gpuHandle=this.gpuPrepared.spawn(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),this.gpuHandle?.setTimescale(this._timescale);for(const t of this.inputRuntime.getDefinitions())this.gpuHandle?.setInput(t.id,this.inputRuntime.getValue(t.id))}return}this.system.emitters.every(t=>t.dead)&&this.restart()}pause(){this.paused=!0,this.gpuHandle?.pause()}previewAt(t,e,s,i,r=0){null!=this.system&&(this.prepareForPlayback(),E(r,()=>{this.restart(),this.paused=!0;const r=Math.max(0,t),a=Math.min(r,Math.max(0,e)),n=r-a,o=Number(a>0)+Number(n>0),l=Math.max(o,Math.min(this.maxPreviewSteps,Math.max(1,Math.ceil(r/this.previewStepSeconds)))),p=a<=0?0:n<=0?l:Math.min(l-1,Math.max(1,Math.round(l*a/r)));this.simulatePreview(a,p),n>0&&(this.applyClipEndBehavior(s,i),this.simulatePreview(n,l-p))}))}clearPreview(){this.restart(),this.pause(),this.object.visible=!1,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!1)}stop(){this.finishRequested=!0,null==this.gpuPrepared?null!=this.system?.emitters&&this.system.emitters.forEach(t=>{this.stopEmitterEmission(t)}):this.gpuHandle?.stop()}applyClipEndBehavior(t,e){const s=t??"finish";if("finish"!==s){if(null!=this.gpuPrepared)return this.finishRequested=!0,void("kill"===s?this.gpuHandle?.kill():this.gpuHandle?.expire(Math.max(0,e??0)));if(null!=this.system&&null!=this.system.emitters)for(const t of this.system.emitters)this.applyEmitterClipEndBehavior(t,s,e)}else this.stop()}restart(){if(null==this.gpuPrepared){if(null!=this.system&&null!=this.system.emitters){this.finishRequested=!1,this.completionEmitted=!1;for(const t of this.system.emitters)this.restartEmitter(t)}}else if(this.finishRequested=!1,this.completionEmitted=!1,null!=this.gpuHandle){if(!this.gpuHandle.active&&!this.paused)return void this.play();this.gpuHandle.restart()}}restartEmitter(t){const e=t.rate;e instanceof h?e.restart():e instanceof i&&(e.nextTime=0),null==t.clearParticlesRecursive?this.removeEmitterParticlesRecursive(t):t.clearParticlesRecursive()}removeEmitterParticlesRecursive(t){const e=t.childEmitters??[];for(const t of e)this.removeEmitterParticlesRecursive(t);t.removeAllParticles?.()}onUpdate(t){if(this.paused)null!=this.gpuHandle&&(this.object.getWorldPosition(this._worldPos),this.gpuHandle.setPosition(this._worldPos),this.gpuHandle.setTransform(this.object.matrixWorld));else{if(null!=this.gpuPrepared)return this.object.getWorldPosition(this._worldPos),this.gpuHandle?.setPosition(this._worldPos),this.gpuHandle?.setTransform(this.object.matrixWorld),void this.updateCompletionState();this.updateWorldSpaceEmitterTransforms(),this.updateSystem(t*this.timescale),this.updateCompletionState()}}prepareForPlayback(){null==this.gpuPrepared?(null!=this.particleSystemContainer&&null==this.particleSystemContainer.parent&&this.world.scene.add(this.particleSystemContainer),this.object.matrixAutoUpdate=!0,this.object.matrixWorldAutoUpdate=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.matrixAutoUpdate=!0,this.particleSystemContainer.matrixWorldAutoUpdate=!0),this.object.visible=!0,null!=this.particleSystemContainer&&(this.particleSystemContainer.visible=!0)):this.object.visible=!0}simulatePreview(t,e){if(t<=0)return;const s=t/e;for(let t=0;t<e;t++)this.updateWorldSpaceEmitterTransforms(),this.updateSystem(s)}updateWorldSpaceEmitterTransforms(){this.object.getWorldPosition(this._worldPos),this.object.getWorldQuaternion(this._worldRot),this.object.getWorldScale(this._worldScale),this._worldEul.setFromQuaternion(this._worldRot),this.system?.emitters.forEach(t=>{if("world"===t._space){t.setPosition(this._worldPos),t.setRotation(this._worldEul);(t._worldScale??(t._worldScale=new s.Vector3)).copy(this._worldScale)}})}getParticleCount(){return null!=this.gpuPrepared?0:this.system?.getCount()??0}getProfilingStats(){let t=0,e=0;return this.particleSystemContainer?.traverse(i=>{const r=i,a=r.geometry;if(null==a||!1===r.visible)return;const n=r instanceof s.InstancedMesh?r.count:1,o=a.index?.count??a.getAttribute("position")?.count??0;n<=0||o<=0||(t++,e+=Math.floor(o/3)*n)}),{particles:this.system?.getCount()??0,drawCalls:t,triangles:e,cpuTimeMs:this.simulationCpuMs}}onEndPlay(){this.stop(),null!=this.disposeSystem&&this.disposeSystem(),this.gpuHandle?.release(),this.gpuPrepared?.release(),this.gpuHandle=null,this.gpuPrepared=null,this.onComplete.complete()}updateCompletionState(){if(null!=this.gpuPrepared){if(this.completionEmitted||!1!==this.gpuHandle?.active)return;return this.completionEmitted=!0,void this.onComplete.next()}if(this.completionEmitted||null==this.system||!this.onComplete.observed)return;const t=this.system.emitters.every(t=>t.dead),e=this.finishRequested&&0===this.system.getCount();(t||e)&&(this.completionEmitted=!0,this.onComplete.next())}updateSystem(t){if(null==this.system)return;if(!this.profilingEnabled)return void this.system.update(t);const e=performance.now();this.system.update(t),this.simulationCpuMs=performance.now()-e}applyEmitterClipEndBehavior(t,e,s,i=!1){this.stopEmitterEmission(t,i);const r=t.particles??[];if("kill"===e)t.removeAllParticles?.();else{const t=Math.max(0,s??0);for(const e of r)e.life=Math.min(e.life,e.age+t)}const a=t.childEmitters??[];for(const t of a)this.applyEmitterClipEndBehavior(t,e,s,!0)}stopEmitterEmission(t,e=!1){const s=t.rate;s instanceof i&&(s.nextTime=1/0),e&&t.stopEmit?.()}};t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"play",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"pause",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"stop",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],x.prototype,"restart",null),x=t([r({typeId:w})],x);export{x as VfxActor};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -136,6 +136,10 @@ export type TrailOutput = {
136
136
  opacityEnd: number;
137
137
  bloom: boolean;
138
138
  scrollSpeed?: number;
139
+ /** How U coordinates are mapped along the trail. Defaults to stretch. */
140
+ uvMode?: 'stretch' | 'repeat';
141
+ /** World units per texture repeat when uvMode is repeat. */
142
+ unitsPerRepeat?: number;
139
143
  width?: number;
140
144
  billboard?: boolean;
141
145
  } & CommonOutput & Partial<OutputCustomShader> & OutputTextureSetting & OutputMaterialSourceSettings;
@@ -1,11 +1,14 @@
1
1
  import type { Particle } from "@hology/nebula";
2
2
  import { Behaviour, Emitter } from "@hology/nebula";
3
3
  import type { PhysicsSystem } from "../../gameplay/services/physics/physics-system.js";
4
+ import { Vector3 } from "three";
4
5
  export declare class WorldCollisionBehaviour extends Behaviour {
5
6
  private physics;
6
7
  private bounce;
7
8
  private friction;
8
9
  private lifeLoss;
10
+ emitEvents: boolean;
11
+ onCollision?: (position: Vector3, normal: Vector3) => void;
9
12
  /**
10
13
  *
11
14
  * @param physics
@@ -13,7 +16,7 @@ export declare class WorldCollisionBehaviour extends Behaviour {
13
16
  * @param friction - If bounce is 0, friction can be used to control how much the particles slide
14
17
  * against the surface. Low friction results in more sliding.
15
18
  */
16
- constructor(physics: PhysicsSystem, bounce?: number, friction?: number, lifeLoss?: number);
19
+ constructor(physics: PhysicsSystem, bounce?: number, friction?: number, lifeLoss?: number, emitEvents?: boolean, onCollision?: (position: Vector3, normal: Vector3) => void);
17
20
  initialize(particle: Particle): void;
18
21
  mutate(particle: Particle | Emitter, time: number, index: number): void;
19
22
  }
@@ -1,4 +1,4 @@
1
- import{Behaviour as o,Emitter as t}from"@hology/nebula";import{RayTestResult as i}from"../../gameplay/services/physics/physics-system.js";import{Color as l,Vector3 as e}from"three";const s={debug:!1,resolveActor:!1};export class WorldCollisionBehaviour extends o{constructor(o,t=0,l=0,e=0){super(),this.physics=o,this.bounce=t,this.friction=l,this.lifeLoss=e,null==r&&(r=new i)}initialize(o){null==o.old.rayFrom?o.old.rayFrom=new e:o.old.rayFrom.set(0,0,0),o.old.rayLength=-1,null==o.old.hitNormal?o.old.hitNormal=new e:o.old.hitNormal.set(0,0,0),o.old.hitDistance=-1}mutate(o,i,l){if(0===o.velocity.length())return;const e=h(),r=.5*o.scale*.5;a.copy(o.velocity).normalize(),n.copy(o.velocity).multiplyScalar(i);const p=d.copy(o.old.velocity).normalize(),m=o.old.rayFrom,u=o.old.hitDistance,f=o.old.hitNormal,v=o.old.rayLength;if(p.dot(a)>.99&&o.position.distanceTo(m)+r<v)u>0?(e.hasHit=!0,e.distance=u-m.distanceTo(o.position),e.hitNormal.copy(f)):e.hasHit=!1;else{const t=15;c.copy(o.position).addScaledVector(o.velocity,i*t).addScaledVector(a,r),this.physics.rayTest(o.position,c,e,s),o.old.rayFrom.copy(o.position),o.old.hitDistance=e.hasHit?e.distance:-1,o.old.hitNormal.copy(e.hitNormal),o.old.rayLength=o.position.distanceTo(c)}var w,N,L;e.hasHit&&n.length()+r>e.distance&&(o.acceleration.set(0,0,0),this.bounce>0?(w=o.velocity,N=e.hitNormal,L=this.bounce,o.velocity.copy(w).sub(y.copy(N).multiplyScalar(2*w.dot(N))).multiplyScalar(L)):function(o,t,i=.95,l){const e=y.copy(t).multiplyScalar(o.dot(t)),s=l.sub(e).multiplyScalar(1-i)}(o.velocity,e.hitNormal,this.friction,o.velocity),o.old.hitDistance=-1,o.parent instanceof t&&o.parent.dispatch("PARTICLE_COLLISION",o),this.lifeLoss>0&&(o.life-=this.lifeLoss))}}const n=new e,a=new e,c=new e;let r=null;function h(){return null===r&&(r=new i),r}new e;const d=new e,y=new e;(new l).setRGB(Math.random(),Math.random(),Math.random());/*
1
+ import{Behaviour as o,Emitter as t}from"@hology/nebula";import{RayTestResult as i}from"../../gameplay/services/physics/physics-system.js";import{Color as l,Vector3 as e}from"three";const s={debug:!1,resolveActor:!1};export class WorldCollisionBehaviour extends o{constructor(o,t=0,l=0,e=0,s=!1,n){super(),this.physics=o,this.bounce=t,this.friction=l,this.lifeLoss=e,this.emitEvents=s,this.onCollision=n,null==h&&(h=new i)}initialize(o){null==o.old.rayFrom?o.old.rayFrom=new e:o.old.rayFrom.set(0,0,0),o.old.rayLength=-1,null==o.old.hitNormal?o.old.hitNormal=new e:o.old.hitNormal.set(0,0,0),o.old.hitDistance=-1}mutate(o,i,l){if(0===o.velocity.length())return;const e=d(),h=.5*o.scale*.5;a.copy(o.velocity).normalize(),n.copy(o.velocity).multiplyScalar(i);const p=y.copy(o.old.velocity).normalize(),u=o.old.rayFrom,v=o.old.hitDistance,f=o.old.hitNormal,w=o.old.rayLength;if(p.dot(a)>.99&&o.position.distanceTo(u)+h<w)v>0?(e.hasHit=!0,e.distance=v-u.distanceTo(o.position),e.hitNormal.copy(f)):e.hasHit=!1;else{const t=15;c.copy(o.position).addScaledVector(o.velocity,i*t).addScaledVector(a,h),this.physics.rayTest(o.position,c,e,s),o.old.rayFrom.copy(o.position),o.old.hitDistance=e.hasHit?e.distance:-1,o.old.hitNormal.copy(e.hitNormal),o.old.rayLength=o.position.distanceTo(c)}var N,L,S;e.hasHit&&n.length()+h>e.distance&&(this.emitEvents&&null!=this.onCollision&&(r.copy(o.position).addScaledVector(a,Math.max(0,e.distance)),this.onCollision(r,e.hitNormal)),o.acceleration.set(0,0,0),this.bounce>0?(N=o.velocity,L=e.hitNormal,S=this.bounce,o.velocity.copy(N).sub(m.copy(L).multiplyScalar(2*N.dot(L))).multiplyScalar(S)):function(o,t,i=.95,l){const e=m.copy(t).multiplyScalar(o.dot(t)),s=l.sub(e).multiplyScalar(1-i)}(o.velocity,e.hitNormal,this.friction,o.velocity),o.old.hitDistance=-1,o.parent instanceof t&&o.parent.dispatch("PARTICLE_COLLISION",o),this.lifeLoss>0&&(o.life-=this.lifeLoss))}}const n=new e,a=new e,c=new e,r=new e;let h=null;function d(){return null===h&&(h=new i),h}new e;const y=new e,m=new e;(new l).setRGB(Math.random(),Math.random(),Math.random());/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -402,6 +402,7 @@ declare class WorldCollisionDef extends BaseBevDef<WorldCollisionDef> {
402
402
  method: SelectParameterDef<string>;
403
403
  friction: FloatParameterDef;
404
404
  bounce: FloatParameterDef;
405
+ emitEvents: ShapeParameterDef<boolean>;
405
406
  lifeLoss: FloatParameterDef;
406
407
  };
407
408
  make(params?: ParamsType<this>): Behaviour;
@@ -1,4 +1,4 @@
1
- import{LoopOnce as e,LoopPingPong as t,LoopRepeat as n,MathUtils as s,Vector2 as r,Vector3 as a}from"three";import{Alpha as i,Attraction as o,BoxZone as c,CircleZone as p,Color as u,ease as d,Force as l,Gravity as m,Life as w,LineZone as f,Mass as h,Position as x,RadialVelocity as g,RandomDrift as b,Repulsion as y,Rotate as v,Vector3D as k}from"@hology/nebula";import{AnimationBehavior as A,AxisDirection as z,AxisPlane as R,Disperse as S,FollowParent as V,LinearDamping as L,MoveOverLife as D,OrientAlongVelocity as j,RotatePosition as C,Scale as T,ScaleComponents as P}from"./behaviours.js";import{AdditiveVelocity as M,AlignRotation as Y,alignRotationAxes as B,alignRotationModes as O,InitialScale as F,InitialScaleComponents as X,MeshPositionInitializer as Z,RandomColor as q,RandomDirection as I,RandomRotation as N,randomRotationAxis as K,RandomScale as W,Rotation as E}from"./initializsers.js";import{VfxMeshSampler as G}from"./vfx-mesh-sampler.js";import{PointZone as H,SphereZone as J}from"./zones.js";import{WorldCollisionBehaviour as Q}from"./vfx-collision-behaviour.js";import{Curve2 as U}from"../../utils/curve.js";import{liveBindingAdapter as $,spawnBindingAdapter as _}from"./vfx-binding-runtime.js";import{WorldCollisionMethod as ee}from"./vfx-asset.js";class te{build(e={}){const t=le(e,this.parameters);return this.make(t)}}class ne{build(e={}){const t=le(e,this.parameters);return this.make(t)}}function se(e,t,n){return{type:"number",default:e,float:!0,min:t,max:n}}function re(e,t,n,s){return{...se(e,n,s),bindable:t}}function ae(e){return{type:"boolean",default:e}}function ie(e){return{type:"vec3",default:(new a).fromArray(e)}}function oe(e,t){return{...ie(e),bindable:t}}function ce(e){return{type:"color",default:e}}function pe(e,t){return{...ce(e),bindable:t}}function ue(e,t,n){return{type:"select",opts:e,default:t,optionNames:n}}function de(){return{type:"curve",default:U.linear()}}function le(e,t){const n={};for(let s in t)null==e[s]?n[s]=t[s].default:n[s]=e[s];return n}function me(e){return new k(e.x,e.y,e.z)}function we(e){return new a(s.degToRad(e.x),s.degToRad(e.y),s.degToRad(e.z))}function fe(e){const{x:t,y:n,z:s}=e;return new H(t,n,s)}function he(e,t){const{x:n,y:s,z:r}=e,{x:a,y:i,z:o}=t;return new c(n,s,r,a,i,o)}function xe(e,t,n=!1){const{x:s,y:r,z:a}=e;return new J(s,r,a,t,n)}function ge(e,t){return new f(e.x,e.y,e.z,t.x,t.y,t.z)}function be(e,t,n,r=0,a=360){return new p(e.x,e.y,e.z,n,r,s.degToRad(t.x),s.degToRad(t.y),s.degToRad(t.z),s.degToRad(a))}function ye(e){const t=e.mesh,n=!0===t?.isObject3D?new G(t):null;return new Z(n?.valid?n:null,e.sampling,e.position,e.rotation,e.scale,e.alignNormal,e.alignmentAxis,e.normalVelocity,e.normalVelocityMin,e.normalVelocityMax,e.normalVelocitySpread)}function ve(e){return t=>e.getY(t)}const ke={lifetime:new class extends ne{constructor(){super(...arguments),this.parameters={duration:re(1,"spawn",0,1e5)},this.bindingAdapter=_((e,t)=>{e.resetLife(t.duration)})}make(e={}){return new w(e.duration)}},randomLifetime:new class extends ne{constructor(){super(...arguments),this.parameters={minDuration:re(1,"spawn",0,1e5),maxDuration:re(2,"spawn",0,1e5)},this.bindingAdapter=_((e,t)=>{e.resetLife(t.minDuration,t.maxDuration)})}make(e={}){return new w(e.minDuration,e.maxDuration)}},positionPoint:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(fe(t.position))})}make(e={}){return new x(fe(e.position))}},positionBox:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),dimensions:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(he(t.position,t.dimensions))})}make(e={}){return new x(he(e.position,e.dimensions))}},positionSphere:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),radius:re(1,"spawn"),surface:ae(!1)},this.bindingAdapter=_((e,t)=>{e.reset(xe(t.position,t.radius,t.surface))})}make(e={}){return new x(xe(e.position,e.radius,e.surface))}},positionLine:new class extends ne{constructor(){super(...arguments),this.parameters={a:oe([0,0,0],"spawn"),b:oe([0,0,1],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(ge(t.a,t.b))})}make(e={}){return new x(ge(e.a,e.b))}},positionCircle:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),rotation:oe([0,0,0],"spawn"),radius:re(1,"spawn",0,1e4),angle:re(360,"spawn",0,360)},this.bindingAdapter=_((e,t)=>{e.reset(be(t.position,t.rotation,t.radius,0,t.angle))})}make(e={}){return new x(be(e.position,e.rotation,e.radius,0,e.angle))}},positionRing:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),rotation:oe([0,0,0],"spawn"),radius:re(1,"spawn",0,1e4),thickness:re(.2,"spawn",0,1e4),angle:re(360,"spawn",0,360)},this.bindingAdapter=_((e,t)=>{e.reset(be(t.position,t.rotation,t.radius,Math.max(t.thickness,1e-4),t.angle))})}make(e={}){return new x(be(e.position,e.rotation,e.radius,Math.max(e.thickness,1e-4),e.angle))}},positionMesh:new class extends ne{constructor(){var e;super(...arguments),this.parameters={mesh:(e="spawn",{type:"mesh",default:null,bindable:e}),sampling:ue(["surface","vertices"],"surface"),position:ie([0,0,0]),rotation:ie([0,0,0]),scale:ie([1,1,1]),alignNormal:ae(!1),alignmentAxis:ue(B,"+Y"),normalVelocity:ae(!1),normalVelocityMin:{...se(1),requires:{normalVelocity:!0}},normalVelocityMax:{...se(1),requires:{normalVelocity:!0}},normalVelocitySpread:{...se(0,0,180),requires:{normalVelocity:!0}}},this.bindingAdapter={buildBound:e=>ye(e.resolveAll())}}make(e={}){return ye(e)}},rotation:new class extends ne{constructor(){super(...arguments),this.parameters={rotation:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.setRotation(we(t.rotation))})}make(e={}){return new E(we(e.rotation))}},randomRotation:new class extends ne{constructor(){super(...arguments),this.parameters={axis:ue(K,"XYZ")}}make(e={}){return new N(e.axis)}},scale:new class extends ne{constructor(){super(...arguments),this.parameters={scale:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setScale(t.scale)})}make(e={}){return new F(e.scale)}},scaleComponents:new class extends ne{constructor(){super(...arguments),this.parameters={scale:oe([1,1,1],"spawn")},this.bindingAdapter=_((e,t)=>{e.setScaleComponents(t.scale)})}make(e={}){return new X(e.scale)}},randomScale:new class extends ne{constructor(){super(...arguments),this.parameters={min:re(1,"spawn"),max:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setRange(t.min,t.max)})}make(e={}){return new W(e.min,e.max)}},randomColor:new class extends ne{constructor(){super(...arguments),this.parameters={a:pe("#ffffff","spawn"),b:pe("#ffffff","spawn")},this.bindingAdapter=_((e,t)=>{e.setRange(t.a,t.b)})}make(e={}){return new q(e.a,e.b)}},mass:new class extends ne{constructor(){super(...arguments),this.parameters={min:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.resetMass(t.min)})}make(e={}){return new h(e.min)}},velocity:new class extends ne{constructor(){super(...arguments),this.parameters={velocity:oe([0,0,0],"spawn")},this.bindingAdapter={buildBound:e=>new M(()=>e.get("velocity"))}}make(e={}){const{x:t,y:n,z:s}=e.velocity;return new M(new a(t,n,s))}},randomVelocity:new class extends ne{constructor(){super(...arguments),this.parameters={min:oe([0,0,0],"spawn"),max:oe([0,0,0],"spawn")},this.bindingAdapter={buildBound:e=>new M(()=>e.get("min"),()=>e.get("max"))}}make(e={}){return new M(e.min,e.max)}},radialVelocity:new class extends ne{constructor(){super(...arguments),this.parameters={speed:re(1,"spawn"),direction:oe([0,1,0],"spawn"),spread:re(0,"spawn")},this.bindingAdapter=_((e,t)=>{e.resetRadialVelocity(t.speed,me(t.direction),t.spread)})}make(e={}){return new g(e.speed,me(e.direction),e.spread)}},randomDirection:new class extends ne{constructor(){super(...arguments),this.parameters={speed:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setSpeed(t.speed)})}make(e={}){return new I(e.speed)}},alignRotation:new class extends ne{constructor(){super(...arguments),this.parameters={mode:ue(O,"AwayFromCenter"),axis:ue(B,"+Y"),offset:ie([0,0,0]),center:ie([0,0,0])}}make(e={}){return new Y(e.axis,e.mode,we(e.offset),e.center)}}},Ae={force:new class extends te{constructor(){super(...arguments),this.parameters={force:oe([0,0,0],"live"),ease:de()},this.bindingAdapter=$((e,t)=>{const n=t.force;e.setForce(n.x,n.y,n.z)})}make(e={}){return new l(e.force.x,e.force.y,e.force.z,void 0,ve(e.ease))}},gravity:new class extends te{constructor(){super(...arguments),this.parameters={gravity:re(8,"live"),easing:de()},this.bindingAdapter=$((e,t)=>{e.setForce(0,-t.gravity,0)})}make(e={}){return new m(e.gravity,void 0,ve(e.easing))}},repulsion:new class extends te{constructor(){super(...arguments),this.parameters={target:oe([0,0,0],"live"),force:re(1,"live"),radius:re(1,"live"),easing:de()},this.bindingAdapter=$((e,t)=>{e.resetAttraction(me(t.target),t.force,t.radius)})}make(e={}){const t=me(e.target);return new y(t,e.force,e.radius,void 0,ve(e.easing))}},attraction:new class extends te{constructor(){super(...arguments),this.parameters={target:oe([0,0,0],"live"),force:re(1,"live"),radius:re(1,"live"),easing:de()},this.bindingAdapter=$((e,t)=>{e.resetAttraction(me(t.target),t.force,t.radius)})}make(e={}){const t=me(e.target);return new o(t,e.force,e.radius,void 0,ve(e.easing))}},scale:new class extends te{constructor(){super(...arguments),this.parameters={a:re(1,"spawn"),b:re(1,"spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{e.setScaleRange(t.a,t.b)})}make(e={}){return new T(e.a,e.b,ve(e.ease))}},scaleComponents:new class extends te{constructor(){super(...arguments),this.parameters={a:oe([1,1,1],"spawn"),b:oe([1,1,1],"spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{e.setScaleRange(t.a,t.b)})}make(e={}){return new P(e.a,e.b,ve(e.ease))}},randomDrift:new class extends te{constructor(){super(...arguments),this.parameters={drift:oe([1,1,1],"live"),delay:re(0,"live"),ease:de()},this.bindingAdapter=$((e,t)=>{const n=t.drift;e.setDrift(n.x,n.y,n.z,t.delay)})}make(e={}){return new b(e.drift.x,e.drift.y,e.drift.z,e.delay,void 0,ve(e.ease))}},disperse:new class extends te{constructor(){super(...arguments),this.parameters={distance:re(1,"spawn"),axis:ue(["XYZ","XZ","XY","YZ"],"XYZ"),ease:de()},this.bindingAdapter=_((e,t)=>{e.setDistance(t.distance)})}make(e={}){return new S(e.distance,R[e.axis.toLowerCase()],ve(e.ease))}},rotate:new class extends te{constructor(){super(...arguments),this.parameters={rotation:oe([0,0,0],"spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{const n=we(t.rotation);e.resetRotation(n.x,n.y,n.z)})}make(e={}){const t=we(e.rotation);return new v(t.x,t.y,t.z,void 0,ve(e.ease))}},rotateAdd:new class extends te{constructor(){super(...arguments),this.parameters={rotation:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{const n=we(t.rotation);e.resetRotation(n.x,n.y,n.z)})}make(e={}){const t=we(e.rotation),n=new v(t.x,t.y,t.z,void 0);return n.rotationType="add",n}},changeColor:new class extends te{constructor(){super(...arguments),this.parameters={a:pe("#ffffff","spawn"),b:pe("#ffffff","spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{e.resetColor(t.a,t.b)})}make(e={}){return new u(e.a,e.b,void 0,ve(e.ease))}},changeOpacity:new class extends te{constructor(){super(...arguments),this.parameters={a:re(1,"spawn",0,1),b:re(0,"spawn",0,1),ease:de()},this.bindingAdapter=_((e,t)=>{e.resetAlpha(t.a,t.b)})}make(e={}){return new i(e.a,e.b,void 0,ve(e.ease))}},vortex:new class extends te{constructor(){super(...arguments),this.parameters={axis:oe([0,1,0],"live"),amount:re(1,"live")},this.bindingAdapter=$((e,t)=>{e.setAxisAngle(t.axis,t.amount)})}make(e={}){return new C(e.axis,e.amount)}},moveTo:new class extends te{constructor(){super(...arguments),this.parameters={target:oe([0,1,0],"live"),ease:de()},this.bindingAdapter=$((e,t)=>{const n=t.target;e.setTarget(n.x,n.y,n.z)})}make(e={}){return new D(e.target.x,e.target.y,e.target.z,ve(e.ease))}},linearDamping:new class extends te{constructor(){super(...arguments),this.parameters={factor:re(.1,"live",0,1e3)},this.bindingAdapter=$((e,t)=>{e.setFactor(t.factor)})}make(e={}){return new L(e.factor)}},followParent:new class extends te{constructor(){super(...arguments),this.parameters={speed:re(0,"live")},this.bindingAdapter=$((e,t)=>{e.setSpeed(t.speed)})}make(e={}){return new V(e.speed)}},worldCollision:new class extends te{constructor(){super(...arguments),this.parameters={method:ue([ee.ScreenSpace,ee.PhysicsRaycast],ee.ScreenSpace,{[ee.ScreenSpace]:"Screen Space",[ee.PhysicsRaycast]:"Physics Raycast"}),friction:se(1,0,1),bounce:se(1,0,1),lifeLoss:se(0,0)}}make(e={}){return new Q(null,e.bounce,e.friction,e.lifeLoss)}},animation:new class extends te{constructor(){super(...arguments),this.parameters={clip:{type:"animationclip",default:null},timeScale:se(1,0,10),weight:se(1,0,1),loop:ue(["Once","Repeat","PingPong"],"Once"),clampWhenFinished:{...ae(!0),requires:{loop:"Once"}}}}make(s={}){let r=e;return"Repeat"===s.loop?r=n:"PingPong"===s.loop&&(r=t),new A(s.clip,s.timeScale,s.weight,r,s.clampWhenFinished,d.easeLinear)}}};export const VfxInitializserLibrary=ke;export const VfxInitializserLibraryKeys=Object.keys(VfxInitializserLibrary);export const VfxBehaviourLibrary=Ae;export const VfxBehaviourLibraryKeys=Object.keys(VfxBehaviourLibrary);/*
1
+ import{LoopOnce as e,LoopPingPong as t,LoopRepeat as n,MathUtils as s,Vector2 as r,Vector3 as a}from"three";import{Alpha as i,Attraction as o,BoxZone as c,CircleZone as p,Color as u,ease as d,Force as l,Gravity as m,Life as w,LineZone as f,Mass as h,Position as x,RadialVelocity as g,RandomDrift as b,Repulsion as y,Rotate as v,Vector3D as k}from"@hology/nebula";import{AnimationBehavior as A,AxisDirection as z,AxisPlane as R,Disperse as S,FollowParent as V,LinearDamping as L,MoveOverLife as D,OrientAlongVelocity as j,RotatePosition as C,Scale as T,ScaleComponents as P}from"./behaviours.js";import{AdditiveVelocity as M,AlignRotation as Y,alignRotationAxes as B,alignRotationModes as O,InitialScale as F,InitialScaleComponents as X,MeshPositionInitializer as Z,RandomColor as q,RandomDirection as I,RandomRotation as N,randomRotationAxis as E,RandomScale as K,Rotation as W}from"./initializsers.js";import{VfxMeshSampler as G}from"./vfx-mesh-sampler.js";import{PointZone as H,SphereZone as J}from"./zones.js";import{WorldCollisionBehaviour as Q}from"./vfx-collision-behaviour.js";import{Curve2 as U}from"../../utils/curve.js";import{liveBindingAdapter as $,spawnBindingAdapter as _}from"./vfx-binding-runtime.js";import{WorldCollisionMethod as ee}from"./vfx-asset.js";class te{build(e={}){const t=le(e,this.parameters);return this.make(t)}}class ne{build(e={}){const t=le(e,this.parameters);return this.make(t)}}function se(e,t,n){return{type:"number",default:e,float:!0,min:t,max:n}}function re(e,t,n,s){return{...se(e,n,s),bindable:t}}function ae(e){return{type:"boolean",default:e}}function ie(e){return{type:"vec3",default:(new a).fromArray(e)}}function oe(e,t){return{...ie(e),bindable:t}}function ce(e){return{type:"color",default:e}}function pe(e,t){return{...ce(e),bindable:t}}function ue(e,t,n){return{type:"select",opts:e,default:t,optionNames:n}}function de(){return{type:"curve",default:U.linear()}}function le(e,t){const n={};for(let s in t)null==e[s]?n[s]=t[s].default:n[s]=e[s];return n}function me(e){return new k(e.x,e.y,e.z)}function we(e){return new a(s.degToRad(e.x),s.degToRad(e.y),s.degToRad(e.z))}function fe(e){const{x:t,y:n,z:s}=e;return new H(t,n,s)}function he(e,t){const{x:n,y:s,z:r}=e,{x:a,y:i,z:o}=t;return new c(n,s,r,a,i,o)}function xe(e,t,n=!1){const{x:s,y:r,z:a}=e;return new J(s,r,a,t,n)}function ge(e,t){return new f(e.x,e.y,e.z,t.x,t.y,t.z)}function be(e,t,n,r=0,a=360){return new p(e.x,e.y,e.z,n,r,s.degToRad(t.x),s.degToRad(t.y),s.degToRad(t.z),s.degToRad(a))}function ye(e){const t=e.mesh,n=!0===t?.isObject3D?new G(t):null;return new Z(n?.valid?n:null,e.sampling,e.position,e.rotation,e.scale,e.alignNormal,e.alignmentAxis,e.normalVelocity,e.normalVelocityMin,e.normalVelocityMax,e.normalVelocitySpread)}function ve(e){return t=>e.getY(t)}const ke={lifetime:new class extends ne{constructor(){super(...arguments),this.parameters={duration:re(1,"spawn",0,1e5)},this.bindingAdapter=_((e,t)=>{e.resetLife(t.duration)})}make(e={}){return new w(e.duration)}},randomLifetime:new class extends ne{constructor(){super(...arguments),this.parameters={minDuration:re(1,"spawn",0,1e5),maxDuration:re(2,"spawn",0,1e5)},this.bindingAdapter=_((e,t)=>{e.resetLife(t.minDuration,t.maxDuration)})}make(e={}){return new w(e.minDuration,e.maxDuration)}},positionPoint:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(fe(t.position))})}make(e={}){return new x(fe(e.position))}},positionBox:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),dimensions:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(he(t.position,t.dimensions))})}make(e={}){return new x(he(e.position,e.dimensions))}},positionSphere:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),radius:re(1,"spawn"),surface:ae(!1)},this.bindingAdapter=_((e,t)=>{e.reset(xe(t.position,t.radius,t.surface))})}make(e={}){return new x(xe(e.position,e.radius,e.surface))}},positionLine:new class extends ne{constructor(){super(...arguments),this.parameters={a:oe([0,0,0],"spawn"),b:oe([0,0,1],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(ge(t.a,t.b))})}make(e={}){return new x(ge(e.a,e.b))}},positionCircle:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),rotation:oe([0,0,0],"spawn"),radius:re(1,"spawn",0,1e4),angle:re(360,"spawn",0,360)},this.bindingAdapter=_((e,t)=>{e.reset(be(t.position,t.rotation,t.radius,0,t.angle))})}make(e={}){return new x(be(e.position,e.rotation,e.radius,0,e.angle))}},positionRing:new class extends ne{constructor(){super(...arguments),this.parameters={position:oe([0,0,0],"spawn"),rotation:oe([0,0,0],"spawn"),radius:re(1,"spawn",0,1e4),thickness:re(.2,"spawn",0,1e4),angle:re(360,"spawn",0,360)},this.bindingAdapter=_((e,t)=>{e.reset(be(t.position,t.rotation,t.radius,Math.max(t.thickness,1e-4),t.angle))})}make(e={}){return new x(be(e.position,e.rotation,e.radius,Math.max(e.thickness,1e-4),e.angle))}},positionMesh:new class extends ne{constructor(){var e;super(...arguments),this.parameters={mesh:(e="spawn",{type:"mesh",default:null,bindable:e}),sampling:ue(["surface","vertices"],"surface"),position:ie([0,0,0]),rotation:ie([0,0,0]),scale:ie([1,1,1]),alignNormal:ae(!1),alignmentAxis:ue(B,"+Y"),normalVelocity:ae(!1),normalVelocityMin:{...se(1),requires:{normalVelocity:!0}},normalVelocityMax:{...se(1),requires:{normalVelocity:!0}},normalVelocitySpread:{...se(0,0,180),requires:{normalVelocity:!0}}},this.bindingAdapter={buildBound:e=>ye(e.resolveAll())}}make(e={}){return ye(e)}},rotation:new class extends ne{constructor(){super(...arguments),this.parameters={rotation:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.setRotation(we(t.rotation))})}make(e={}){return new W(we(e.rotation))}},randomRotation:new class extends ne{constructor(){super(...arguments),this.parameters={axis:ue(E,"XYZ")}}make(e={}){return new N(e.axis)}},scale:new class extends ne{constructor(){super(...arguments),this.parameters={scale:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setScale(t.scale)})}make(e={}){return new F(e.scale)}},scaleComponents:new class extends ne{constructor(){super(...arguments),this.parameters={scale:oe([1,1,1],"spawn")},this.bindingAdapter=_((e,t)=>{e.setScaleComponents(t.scale)})}make(e={}){return new X(e.scale)}},randomScale:new class extends ne{constructor(){super(...arguments),this.parameters={min:re(1,"spawn"),max:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setRange(t.min,t.max)})}make(e={}){return new K(e.min,e.max)}},randomColor:new class extends ne{constructor(){super(...arguments),this.parameters={a:pe("#ffffff","spawn"),b:pe("#ffffff","spawn")},this.bindingAdapter=_((e,t)=>{e.setRange(t.a,t.b)})}make(e={}){return new q(e.a,e.b)}},mass:new class extends ne{constructor(){super(...arguments),this.parameters={min:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.resetMass(t.min)})}make(e={}){return new h(e.min)}},velocity:new class extends ne{constructor(){super(...arguments),this.parameters={velocity:oe([0,0,0],"spawn")},this.bindingAdapter={buildBound:e=>new M(()=>e.get("velocity"))}}make(e={}){const{x:t,y:n,z:s}=e.velocity;return new M(new a(t,n,s))}},randomVelocity:new class extends ne{constructor(){super(...arguments),this.parameters={min:oe([0,0,0],"spawn"),max:oe([0,0,0],"spawn")},this.bindingAdapter={buildBound:e=>new M(()=>e.get("min"),()=>e.get("max"))}}make(e={}){return new M(e.min,e.max)}},radialVelocity:new class extends ne{constructor(){super(...arguments),this.parameters={speed:re(1,"spawn"),direction:oe([0,1,0],"spawn"),spread:re(0,"spawn")},this.bindingAdapter=_((e,t)=>{e.resetRadialVelocity(t.speed,me(t.direction),t.spread)})}make(e={}){return new g(e.speed,me(e.direction),e.spread)}},randomDirection:new class extends ne{constructor(){super(...arguments),this.parameters={speed:re(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setSpeed(t.speed)})}make(e={}){return new I(e.speed)}},alignRotation:new class extends ne{constructor(){super(...arguments),this.parameters={mode:ue(O,"AwayFromCenter"),axis:ue(B,"+Y"),offset:ie([0,0,0]),center:ie([0,0,0])}}make(e={}){return new Y(e.axis,e.mode,we(e.offset),e.center)}}},Ae={force:new class extends te{constructor(){super(...arguments),this.parameters={force:oe([0,0,0],"live"),ease:de()},this.bindingAdapter=$((e,t)=>{const n=t.force;e.setForce(n.x,n.y,n.z)})}make(e={}){return new l(e.force.x,e.force.y,e.force.z,void 0,ve(e.ease))}},gravity:new class extends te{constructor(){super(...arguments),this.parameters={gravity:re(8,"live"),easing:de()},this.bindingAdapter=$((e,t)=>{e.setForce(0,-t.gravity,0)})}make(e={}){return new m(e.gravity,void 0,ve(e.easing))}},repulsion:new class extends te{constructor(){super(...arguments),this.parameters={target:oe([0,0,0],"live"),force:re(1,"live"),radius:re(1,"live"),easing:de()},this.bindingAdapter=$((e,t)=>{e.resetAttraction(me(t.target),t.force,t.radius)})}make(e={}){const t=me(e.target);return new y(t,e.force,e.radius,void 0,ve(e.easing))}},attraction:new class extends te{constructor(){super(...arguments),this.parameters={target:oe([0,0,0],"live"),force:re(1,"live"),radius:re(1,"live"),easing:de()},this.bindingAdapter=$((e,t)=>{e.resetAttraction(me(t.target),t.force,t.radius)})}make(e={}){const t=me(e.target);return new o(t,e.force,e.radius,void 0,ve(e.easing))}},scale:new class extends te{constructor(){super(...arguments),this.parameters={a:re(1,"spawn"),b:re(1,"spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{e.setScaleRange(t.a,t.b)})}make(e={}){return new T(e.a,e.b,ve(e.ease))}},scaleComponents:new class extends te{constructor(){super(...arguments),this.parameters={a:oe([1,1,1],"spawn"),b:oe([1,1,1],"spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{e.setScaleRange(t.a,t.b)})}make(e={}){return new P(e.a,e.b,ve(e.ease))}},randomDrift:new class extends te{constructor(){super(...arguments),this.parameters={drift:oe([1,1,1],"live"),delay:re(0,"live"),ease:de()},this.bindingAdapter=$((e,t)=>{const n=t.drift;e.setDrift(n.x,n.y,n.z,t.delay)})}make(e={}){return new b(e.drift.x,e.drift.y,e.drift.z,e.delay,void 0,ve(e.ease))}},disperse:new class extends te{constructor(){super(...arguments),this.parameters={distance:re(1,"spawn"),axis:ue(["XYZ","XZ","XY","YZ"],"XYZ"),ease:de()},this.bindingAdapter=_((e,t)=>{e.setDistance(t.distance)})}make(e={}){return new S(e.distance,R[e.axis.toLowerCase()],ve(e.ease))}},rotate:new class extends te{constructor(){super(...arguments),this.parameters={rotation:oe([0,0,0],"spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{const n=we(t.rotation);e.resetRotation(n.x,n.y,n.z)})}make(e={}){const t=we(e.rotation);return new v(t.x,t.y,t.z,void 0,ve(e.ease))}},rotateAdd:new class extends te{constructor(){super(...arguments),this.parameters={rotation:oe([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{const n=we(t.rotation);e.resetRotation(n.x,n.y,n.z)})}make(e={}){const t=we(e.rotation),n=new v(t.x,t.y,t.z,void 0);return n.rotationType="add",n}},changeColor:new class extends te{constructor(){super(...arguments),this.parameters={a:pe("#ffffff","spawn"),b:pe("#ffffff","spawn"),ease:de()},this.bindingAdapter=_((e,t)=>{e.resetColor(t.a,t.b)})}make(e={}){return new u(e.a,e.b,void 0,ve(e.ease))}},changeOpacity:new class extends te{constructor(){super(...arguments),this.parameters={a:re(1,"spawn",0,1),b:re(0,"spawn",0,1),ease:de()},this.bindingAdapter=_((e,t)=>{e.resetAlpha(t.a,t.b)})}make(e={}){return new i(e.a,e.b,void 0,ve(e.ease))}},vortex:new class extends te{constructor(){super(...arguments),this.parameters={axis:oe([0,1,0],"live"),amount:re(1,"live")},this.bindingAdapter=$((e,t)=>{e.setAxisAngle(t.axis,t.amount)})}make(e={}){return new C(e.axis,e.amount)}},moveTo:new class extends te{constructor(){super(...arguments),this.parameters={target:oe([0,1,0],"live"),ease:de()},this.bindingAdapter=$((e,t)=>{const n=t.target;e.setTarget(n.x,n.y,n.z)})}make(e={}){return new D(e.target.x,e.target.y,e.target.z,ve(e.ease))}},linearDamping:new class extends te{constructor(){super(...arguments),this.parameters={factor:re(.1,"live",0,1e3)},this.bindingAdapter=$((e,t)=>{e.setFactor(t.factor)})}make(e={}){return new L(e.factor)}},followParent:new class extends te{constructor(){super(...arguments),this.parameters={speed:re(0,"live")},this.bindingAdapter=$((e,t)=>{e.setSpeed(t.speed)})}make(e={}){return new V(e.speed)}},worldCollision:new class extends te{constructor(){super(...arguments),this.parameters={method:ue([ee.ScreenSpace,ee.PhysicsRaycast],ee.ScreenSpace,{[ee.ScreenSpace]:"Screen Space",[ee.PhysicsRaycast]:"Physics Raycast"}),friction:se(1,0,1),bounce:se(1,0,1),emitEvents:ae(!1),lifeLoss:se(0,0)}}make(e={}){return new Q(null,e.bounce,e.friction,e.lifeLoss,e.emitEvents)}},animation:new class extends te{constructor(){super(...arguments),this.parameters={clip:{type:"animationclip",default:null},timeScale:se(1,0,10),weight:se(1,0,1),loop:ue(["Once","Repeat","PingPong"],"Once"),clampWhenFinished:{...ae(!0),requires:{loop:"Once"}}}}make(s={}){let r=e;return"Repeat"===s.loop?r=n:"PingPong"===s.loop&&(r=t),new A(s.clip,s.timeScale,s.weight,r,s.clampWhenFinished,d.easeLinear)}}};export const VfxInitializserLibrary=ke;export const VfxInitializserLibraryKeys=Object.keys(VfxInitializserLibrary);export const VfxBehaviourLibrary=Ae;export const VfxBehaviourLibraryKeys=Object.keys(VfxBehaviourLibrary);/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -17,7 +17,7 @@ export type VfxAssetProvider = {
17
17
  getMesh(assetId: string): Promise<THREE.Object3D>;
18
18
  getMaterial(assetId: string): Promise<THREE.Material>;
19
19
  };
20
- export declare function materializeVfx(asset: VfxAsset, target: Object3D, assetProvider: VfxAssetProvider, view: ViewController, physics: PhysicsSystem, shaderProvider: ShaderProvider, assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, inputRuntime?: VfxInputRuntime): Promise<{
20
+ export declare function materializeVfx(asset: VfxAsset, target: Object3D, assetProvider: VfxAssetProvider, view: ViewController, physics: PhysicsSystem, shaderProvider: ShaderProvider, assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, inputRuntime?: VfxInputRuntime, onCollision?: (emitterId: string, emitterName: string, position: THREE.Vector3, normal: THREE.Vector3, localSpace: boolean) => void): Promise<{
21
21
  container: THREE.Object3D<THREE.Object3DEventMap, Event>;
22
22
  system: System;
23
23
  dispose: () => void;
@@ -1,4 +1,4 @@
1
- import e,{Behaviour as t,Body as a,Emitter as r,Rate as s}from"@hology/nebula";import*as i from"three";import{Object3D as n}from"three";import{AttributeVec3Node as l,AttributeVec4Node as o,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as h,Vec3ExpressionNode as d,attributeVec3 as m,attributeVec4 as f,attributes as y,clamp as w,cross as g,float as b,lambertMaterial as M,length as v,log as E,normalize as A,pow as x,rgb as S,rgba as I,smoothstep as P,standardMaterial as T,textureSampler2d as C,uniforms as R,varying as G,varyingAttributes as B,varyingVec3 as j,varyingVec4 as k,vec2 as D,vec3 as F,vec4 as V}from"three-shader-graph";import{prepareClassParameters as L,prepareShaderGraphParameters as O,prepareShapeParameters as W}from"../../scene/materializer.js";import{SerializedParamType as N}from"../../scene/model.js";import{ShapeLibrary as U}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as Q,linearEyeDepth as H}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as q,particleTimeUniformName as z,particleUniforms as J,particleVelcoityUniformName as X}from"../../shader-nodes/particle.js";import{sampleFlipbook as _}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as K,WorldSpaceEmitterTransformInitializer as Y}from"./initializsers.js";import{DelayRate as Z,OnceRate as $}from"./rates.js";import{StretchedSprite as ee}from"./stretched-sprite.js";import{ThreeBlendingMode as te}from"./vfx-asset.js";import{VfxBehaviourLibrary as ae,VfxInitializserLibrary as re}from"./vfx-defs.js";import{MultiRenderer as se}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ie}from"./vfx-collision-behaviour.js";import{getSpritePosition as ne,SpriteNodeShader as le,SpriteNodeShaderMaterial as oe}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ce}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as pe}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as ue,createBoundInitializer as he}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as de}from"../../shader/graph/index.js";import{markMaterialUniformValuesNeedUpdate as me,setMaterialUniformValuesAutoUpdate as fe}from"../../rendering/node-material-webgpu-resolver.js";import{applyMeshWorldTransformToGeometry as ye}from"./vfx-mesh-transform.js";import{createGpuMeshAssetMaterial as we}from"./vfx-gpu-material.js";export async function materializeVfx(t,a,r,s,l,o,c,p,u){let h=a;for(;null!=h.parent;)h=h.parent;const d=new n;d.name="particle system local",a.add(d);const m=new n;m.name="particle system world";const f=new se(m,d,i,s),y=new e;return(await Promise.all(t.vfx.emitters.slice().sort((e,t)=>(t.output.renderOrder??0)-(e.output.renderOrder??0)).map(async e=>{const t=await be(e,r,c,p,y,l,o,u,a);return t.setParentRecursive(y),t.emit()}))).forEach(e=>y.addEmitter(e)),y.addRenderer(f).emit({onEnd:()=>{}}),{container:m,system:y,dispose:()=>{m.removeFromParent(),d.removeFromParent(),f.dispose()}}}function ge(e,t){let a;const r=function(e,t){const a=Math.max(0,e.rate.delay??0),r=e.rate.delayBinding;if("vfxInput"!==r?.type||null==t)return a;const s=t.getDefinition(r.inputId);return"number"!==s?.type?a:Math.max(0,t.getNumber(r.inputId,a))}(e,t);switch(e.rate.type){case"continuous":a=new Z(r,e.rate.count,e.rate.time,e.rate.duration);break;case"once":a=new $(r,e.rate.count);break;default:console.warn(`Failed to configure rate for emitter: ${JSON.stringify(e)}`),a=new s(0,1/0)}return a}async function be(e,t,r,s,p,x,S,T,D){const F=ge(e,T);let L;switch(e.output.type){case"decal":L=new a(await async function(e,t,a,r,s){if("shaderGraph"===ve(e)){const t=await createShaderGraphMaterial(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return Ae(a,e),a}}const n=!1!==e.unlit?new ce:new pe;n.color=new i.Color(e.color),n instanceof ce?n.intensity=e.intensity??1:n.emissiveIntensity=e.intensity??1;if(e.colorMap){const a=await t.getTexture(e.colorMap);n.colorMap=a}if(e.alphaMap){const a=await t.getTexture(e.alphaMap);n.alphaMap=a}const l=n.build();l.blending=te[e.blendingMode]??i.NormalBlending,l.transparent=!0,l.side=i.BackSide,l.depthTest=!1,null!=l&&!0===e.bloom&&(l.userData.hasBloom=!0);l.defines.IS_PARTICLE="";const o=new i.BoxGeometry(1,1,1),c=new i.Mesh(o,l);return Ae(c,e),c}(e.output,t,r,s,S));break;case"sprite":L=new a(await async function(e,t,a,r,s){let n=null;const l=ve(e);"shaderGraph"===l&&(n=await createShaderGraphMaterial(e,"sprite",a,r,s));null==n&&"shader"===l&&null!=e.shader&&(n=await createShaderMaterial(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):Me,r=C(a);let s=r.sample(B.uv);e.flipbook?.enabled&&(s=_(r,y.uv,e.flipbook.columns,e.flipbook.rows,J.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),l=new h("color").rgb,o=j(new d("instanceColor")).rgb,c=H.subtract(Q).divide(H);let p=J.opacity;switch(e.opacityChannel??"red"){case"none":break;case"red":p=p.multiply(s.r);break;case"alpha":p=p.multiply(s.a)}if("number"==typeof e.softness&&e.softness>0){const t=w(c,0,1e3);p=p.multiply(P(0,.2*e.softness,t))}const m=ne(n,void 0,void 0,!0),f=I(l.multiply(o).multiply(s.rgb).multiplyScalar(e.intensity??1),p);var g=new oe({color:f,emissive:f.rgb.multiplyScalar(p),transparent:!0,position:m,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});g.alphaHash=!0,null!=g&&!0===e.bloom&&(g.userData.hasBloom=!0);return g.blending=te[e.blendingMode]??i.NormalBlending,g}(e,t));n.depthWrite=!1,Ee(n,e);const o=new i.Mesh(new i.PlaneGeometry(1,1),n);return o.name="sprite",Ae(o,e),o}(e.output,t,r,s,S));break;case"stretchedSprite":L=new a(await async function(e,t){"shaderGraph"===ve(e)&&console.warn("Shader graph materials are not supported for stretched sprite VFX outputs yet. Falling back to the default stretched sprite material.");const a=null!=e.texture?await t.getTexture(e.texture):Me,r=C(a).sample(B.uv),s=k(new o("particleColor")),n=s.rgb.multiply(r.rgb);let l=s.w;switch(e.opacityChannel??"red"){case"none":break;case"red":l=l.multiply(r.r);break;case"alpha":l=l.multiply(r.a)}if("number"==typeof e.softness&&e.softness>0){const t=H.subtract(Q).divide(E(H)),a=w(t,0,1e3);l=l.multiply(P(0,.2*e.softness,a))}const c=m("offset"),p=f("velocity"),u=m("size"),h=p.w,d=u.x.add(u.y).multiply(.5),M=R.modelViewMatrix.multiplyVec(V(c,1)),x=R.normalMatrix.multiplyVec(p.xyz),S=A(g(M.xyz,x)).multiplyScalar(y.position.y.multiply(d)),T=x.multiplyScalar(y.position.x.add(.5).multiply(b(1).add(h.divide(v(x)))).multiply(d)),G=R.projectionMatrix.multiplyVec(V(M.xyz.add(S).subtract(T),M.w));var j=new oe({color:I(n.multiplyScalar(e.intensity??1),l),alphaTest:.1,transparent:!0,position:G,uniforms:{color:{value:new i.Color(e.color)}}});null!=j&&!0===e.bloom&&(j.userData.hasBloom=!0);j.blending=te[e.blendingMode]??i.NormalBlending;const D=new ee(new i.PlaneGeometry(1,1),j);return D.scaleFactor=e.scale,Ae(D,e),D}(e.output,t));break;case"shape":L=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const o=U[e.shape];if(null==o)return console.error(`No shape with type ${e.shape}`),new n;const p=W(e.params??{}),u=o.geometry(p);let h=null;const m=ve(e);"shaderGraph"===m&&(h=await createShaderGraphMaterial(e,"surface",a,r,s));null==h&&"shader"===m&&null!=e.shader&&(h=await createShaderMaterial(e,t,s));null==h&&(h="material"===m&&null!=e.material?xe(await t.getMaterial(e.material)):function(){const e=G(new d("instanceColor")).rgb,t=G(new l("particleData")).x;return new c({color:M({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());Ee(h,e);const f=new i.Mesh(u,h);return Ae(f,e),f}(e.output,t,r,s,S));break;case"mesh":L=new a(await async function(e,t,a,r,s){if(null==e.assetId)return console.warn("Can't use mesh as particle without asset id"),new n;const l=await t.getMesh(e.assetId),o=await t.getAsset(e.assetId),c=ve(e);if("shaderGraph"===c||"shader"===c&&null!=e.shader||"material"===c&&null!=e.material){let n;"shaderGraph"===c?n=await createShaderGraphMaterial(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await createShaderMaterial(e,t,s):"material"===c&&null!=e.material&&(n=xe(await t.getMaterial(e.material))),n?.transparent&&(n.depthWrite=!1),null!=n&&Ee(n,e),l.traverse(e=>{e instanceof i.Mesh&&null!=n&&(e.material=n)})}else{const e=[];if(null!=o.materialAssignments)for(const a of o.materialAssignments)null!=a.materialId&&l.traverse(r=>{r instanceof i.Mesh&&r.material instanceof i.Material&&r.material.color instanceof i.Color&&(r.material.name!=a.name&&null!=a.name||"#"+r.material.color.getHexString()!==a.color||e.push(t.getMaterial(a.materialId).then(e=>r.material=e)))});await Promise.all(e)}const p=[];if(l.traverse(e=>{e instanceof i.Mesh&&p.push(e)}),Ae(l,e),1===p.length){const t=p[0];return!0!==e.useLegacyTransform&&function(e){e.geometry=e.geometry.clone(),ye(e,e.geometry),e.position.set(0,0,0),e.quaternion.identity(),e.scale.set(1,1,1),e.updateMatrix(),e.matrixWorld.identity()}(t),t.removeFromParent(),t}return l}(e.output,t,r,s,S));break;case"trail":{const n="shaderGraph"===ve(e.output)?await createShaderGraphMaterial(e.output,"trail",r,s,S,{trailBillboard:e.output.billboard??!1}):null;L=new a({type:"trail",taper:e.output.taper,headGeometry:null,material:n instanceof i.ShaderMaterial?n:void 0,dragTexture:!1,texture:null!=e.output.texture?await t.getTexture(e.output.texture):null,opacityChannel:e.output.opacityChannel,color:e.output.color,colorEnd:e.output.colorEnd,intensity:e.output.intensity??1,intensityEnd:e.output.intensityEnd??1,length:e.output.length,opacityStart:e.output.opacityStart,opacityEnd:e.output.opacityEnd,bloom:e.output.bloom,scrollSpeed:e.output.scrollSpeed,width:e.output.width,billboard:e.output.billboard??!1,renderOrder:e.output.renderOrder});break}default:console.error("Failed to create particly system body: "+JSON.stringify(e))}const O=new Ie(D);O.parent=p,O.setRate(F),O._space=e.output.space;const q=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=re[e.type]).map(async e=>{const t=re[e.type],a=await W(e.params??{},r,s);return he(t,e.params??{},a,T)}));"world"===e.output.space&&q.push(new Y("shape"===e.output.type||"mesh"===e.output.type)),q.push(L,new K),O.addInitializers(q);const z=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=ae[e.type]).map(async e=>{const t=ae[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==N.Curve&&(r.type=N.Curve);const a=await W(e.params??{},r,s);return ue(t,e.params??{},a,T)}));z.sort((e,t)=>Number(t instanceof ie)-Number(e instanceof ie)),z.push(new Se);for(const e of z)e instanceof ie&&(e.physics=x);O.addBehaviours(z);for(const a of e.children??[]){const e=await be(a,t,r,s,p,x,S,T,D),i=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=O.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&O.childEmitters.splice(e,1),null!=t.parentParticle&&(l.delete(t.parentParticle.id),t.parentParticle=null),i.release(t)},t}),n=O.eventDispatcher,l=new Map;O.bindEmitterEvent=!0,n.addEventListener("PARTICLE_DEAD",e=>{const t=l.get(e.id);null!=t&&(O.detachChildEmitterFromParticle(t,e),l.delete(e.id))});let o="PARTICLE_CREATED";if("spawnEvent"in a)switch(a.spawnEvent){case"collision":o="PARTICLE_COLLISION";break;case"start":o="PARTICLE_CREATED"}n.addEventListener(o,e=>{const t=i.get();t.age=0,t.totalEmitTimes=-1,t.particles.length=0,t.currentEmitTime=0,t.cID=0,t.eventDispatcher.removeAllEventListeners(),O.childEmitters.push(t),l.set(e.id,t),t.parentParticle=e,t.system=O.system,t.emit()})}return O}const Me=(new i.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=");export async function createShaderMaterial(e,t,a){const r=a.get(e.shader);if(null==r)return console.error("No shader exists with name "+e.shader),new i.Material;const s=new r.type;"sprite"===e.type&&s instanceof le&&(s.instanced=!0);const n=await L(e.shaderParams??{},r.type,t,{getTexture:e=>t.getTexture(e.id),getMaterial:e=>t.getMaterial(e.id),getMesh:e=>t.getMesh(e.id)},void 0,void 0,void 0,void 0,void 0,s);return Object.assign(s,n),s.build()}export async function createShaderGraphMaterial(e,t,a,r,s,i={}){const n=e.shaderGraph;if("asset"!==n?.source||null==n.assetId)return console.warn(`Missing shader graph asset reference for ${e.type} VFX output`),null;const l=await a.getAsset(n.assetId),o=l?.shaderGraph;if(null==o)return console.warn(`Missing shader graph asset "${n.assetId}" for ${e.type} VFX output`),null;if(o.target!==t)return console.warn(`Shader graph "${l.name}" targets "${o.target}" but ${e.type} VFX output expects "${t}"`),null;try{const t=await O(e.shaderGraphParams??{},o,a,r,void 0,s.shaders),l=de(o,{parameters:t,trailBillboard:i.trailBillboard});return l.userData.customShaderName=`shaderGraph:${n.assetId}`,Ee(l,e),l}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}export function createGpuSpriteShaderGraphResolver(e,t,a,r){return async s=>{const n=ve(s);let l=null;if("shaderGraph"===n)l=await createShaderGraphMaterial(s,"sprite"===s.type?"sprite":"decal"===s.type?"decal":"trail"===s.type?"trail":"surface",e,t,a,"trail"===s.type?{trailBillboard:s.billboard??!1}:void 0);else if("shader"===n&&"decal"!==s.type&&null!=r)l=await createShaderMaterial(s,r,a);else if("material"!==n||"mesh"!==s.type&&"shape"!==s.type||null==s.material||null==r){if("default"===n&&"mesh"===s.type&&null!=s.assetId&&null!=r){const e=await r.getAsset(s.assetId),t=e.materialAssignments?.find(e=>null!=e.materialId);null!=t&&(l=await we(t.materialId,r))}else if("default"===n&&"decal"===s.type&&null!=r){const e=!1!==s.unlit?new ce:new pe;e.color=new i.Color(s.color),e instanceof ce?e.intensity=s.intensity??1:e.emissiveIntensity=s.intensity??1,s.colorMap&&(e.colorMap=await r.getTexture(s.colorMap)),s.alphaMap&&(e.alphaMap=await r.getTexture(s.alphaMap)),l=e.build(),l.transparent=!0}}else l="mesh"===s.type?await we(s.material,r):xe(await r.getMaterial(s.material));return null==l?null:("mesh"!==s.type&&"shape"!==s.type||!l.transparent||(l.depthWrite=!1),l instanceof c?l:(console.warn(`GPU ${s.type} materials must compile to NodeShaderMaterial; using CPU fallback`),null))}}function ve(e){return null!=e.materialSource?("material"!==e.materialSource||"mesh"!==e.type&&"shape"!==e.type||null!=e.material)&&("shaderGraph"!==e.materialSource||"asset"===e.shaderGraph?.source&&null!=e.shaderGraph.assetId)&&("shader"!==e.materialSource||"shader"in e&&null!=e.shader)?e.materialSource:"default":"asset"===e.shaderGraph?.source?"shaderGraph":"shader"in e&&null!=e.shader?"shader":"mesh"!==e.type&&"shape"!==e.type||null==e.material?"default":"material"}function Ee(e,t){null!=e&&(fe(e,!1),"bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,!0===t.lockY&&e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.LOCK_Y_AXIS="")):"decal"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,e.transparent=!0,e.side=i.BackSide,e.depthTest=!1,e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE="")):"shape"!==t.type&&"mesh"!==t.type||e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE=""))}function Ae(e,t){const a=t.renderOrder;null!=a&&e.traverse(e=>e.renderOrder=a)}function xe(e){const t=G(new d("instanceColor")).rgb;let a,r=G(new l("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(S(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(B.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(B.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:S(e.emissive),emissiveIntensity:b(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:S(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:M({color:s}).rgb.rgba(r),emissive:S(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshBasicMaterial&&(a=new c({color:s.rgb.rgba(r),emissive:s.rgb,transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}))}else e instanceof c&&(a=e.clone(),a.defines.IS_PARTICLE="");return null!=a&&(!0===e.userData?.hasBloom&&null!=a&&(a.userData.hasBloom=!0),a.side=e.side,a.transparent=e.transparent),a??e}class Se extends t{initialize(e){e.body instanceof i.Object3D&&e.body.traverse(e=>{if(e instanceof i.Mesh){const t=e.material;t instanceof c&&(null!=t.uniforms[q]||null!=t.uniforms[z]||t.uniforms[X])}})}mutate(e,t,a){this.energize(e,t),e.target instanceof n&&e.target.traverse(t=>{if(t instanceof i.Mesh){const a=t.material;if(a instanceof c){let t=!1;null!=a.uniforms[q]&&(a.uniforms[q].value=this.energy,t=!0),null!=a.uniforms[z]&&(a.uniforms[z].value=e.age,t=!0),null!=a.uniforms[X]&&(a.uniforms[X].value=e.velocity,t=!0),t&&me(a)}}})}}class Ie extends r{constructor(e){super(),this.transformRoot=e,this.childEmitters=[],this.bindEmitterEvent=!1,this.onExpired=()=>{}}clearParticlesRecursive(){let e=this.childEmitters.length;for(;e--;){const t=this.childEmitters[e];t.stopEmit(),t.clearParticlesRecursive(),t.onExpired()}this.childEmitters.length=0;let t=this.particles.length;for(;t--;){const e=this.particles[t];this.system?.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),null!=this.system?this.system.pool.expire(e.reset()):e.reset()}this.particles.length=0}detachChildEmitterFromParticle(e,t){this.copyPositionToChildSpace(e,t.position),e.parentParticle=null,e.stopEmit()}update(e){if(!this.isEmitting&&0===this.particles.length&&0===this.childEmitters.length)return;this.age+=e,(this.dead||this.age>=this.life)&&this.destroy(),this.isEmitting&&this.generate(e),this.integrate(e);let t=this.particles.length;for(;t--;){const e=this.particles[t];e.dead&&(this.system&&this.system.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),this.system.pool.expire(e.reset()),this.particles.splice(t,1))}this.updateEmitterBehaviours(e),this.updateChildren(e),this.isEmitting||0!==this.particles.length||0!==this.childEmitters.length||this.onExpired()}updateChildren(e){for(const t of this.childEmitters)null!=t.parentParticle&&this.copyPositionToChildSpace(t,t.parentParticle.position),t.update(e)}copyPositionToChildSpace(e,t){const a=this._space??"world",r=e._space??"world";a!==r&&null!=this.transformRoot?(Pe.copy(t),"local"===a&&"world"===r?Pe.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(Te.copy(this.transformRoot.matrixWorld).invert(),Pe.applyMatrix4(Te)),e.position.copy(Pe)):e.position.copy(t)}clone(){const e=new Ie(this.transformRoot);return e.setRate(this.rate.clone()),e.behaviours=this.behaviours,e.initializers=this.initializers,e._space=this._space,e.body=this.body,e.parent=this.parent,e.system=this.system,e}setParentRecursive(e){this.system=e,this.childEmitters.forEach(t=>t.setParentRecursive(e))}}const Pe=new i.Vector3,Te=new i.Matrix4;export class EmitterPool{constructor(e){this.creator=e,this.instances=[]}get(){0==this.instances.length&&this.instances.push(this.creator());return this.instances.pop()}release(e){this.instances.push(e)}dispose(){this.instances.length=0}}/*
1
+ import e,{Behaviour as t,Body as a,Emitter as r,Rate as s}from"@hology/nebula";import*as i from"three";import{Object3D as n}from"three";import{AttributeVec3Node as l,AttributeVec4Node as o,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as d,Vec3ExpressionNode as h,attributeVec3 as m,attributeVec4 as f,attributes as y,clamp as w,cross as g,float as b,lambertMaterial as M,length as v,log as E,normalize as A,pow as x,rgb as S,rgba as I,smoothstep as P,standardMaterial as T,textureSampler2d as C,uniforms as R,varying as G,varyingAttributes as B,varyingVec3 as j,varyingVec4 as k,vec2 as D,vec3 as F,vec4 as V}from"three-shader-graph";import{prepareClassParameters as L,prepareShaderGraphParameters as O,prepareShapeParameters as W}from"../../scene/materializer.js";import{SerializedParamType as U}from"../../scene/model.js";import{ShapeLibrary as N}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as Q,linearEyeDepth as H}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as q,particleTimeUniformName as z,particleUniforms as J,particleVelcoityUniformName as X}from"../../shader-nodes/particle.js";import{sampleFlipbook as _}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as K,WorldSpaceEmitterTransformInitializer as Y}from"./initializsers.js";import{DelayRate as Z,OnceRate as $}from"./rates.js";import{StretchedSprite as ee}from"./stretched-sprite.js";import{ThreeBlendingMode as te}from"./vfx-asset.js";import{VfxBehaviourLibrary as ae,VfxInitializserLibrary as re}from"./vfx-defs.js";import{MultiRenderer as se}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ie}from"./vfx-collision-behaviour.js";import{getSpritePosition as ne,SpriteNodeShader as le,SpriteNodeShaderMaterial as oe}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ce}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as pe}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as ue,createBoundInitializer as de}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as he}from"../../shader/graph/index.js";import{markMaterialUniformValuesNeedUpdate as me,setMaterialUniformValuesAutoUpdate as fe}from"../../rendering/node-material-webgpu-resolver.js";import{applyMeshWorldTransformToGeometry as ye}from"./vfx-mesh-transform.js";import{createGpuMeshAssetMaterial as we}from"./vfx-gpu-material.js";export async function materializeVfx(t,a,r,s,l,o,c,p,u,d){let h=a;for(;null!=h.parent;)h=h.parent;const m=new n;m.name="particle system local",a.add(m);const f=new n;f.name="particle system world";const y=new se(f,m,i,s),w=new e;return(await Promise.all(t.vfx.emitters.slice().sort((e,t)=>(t.output.renderOrder??0)-(e.output.renderOrder??0)).map(async e=>{const t=await be(e,r,c,p,w,l,o,u,a,d);return t.setParentRecursive(w),t.emit()}))).forEach(e=>w.addEmitter(e)),w.addRenderer(y).emit({onEnd:()=>{}}),{container:f,system:w,dispose:()=>{f.removeFromParent(),m.removeFromParent(),y.dispose()}}}function ge(e,t){let a;const r=function(e,t){const a=Math.max(0,e.rate.delay??0),r=e.rate.delayBinding;if("vfxInput"!==r?.type||null==t)return a;const s=t.getDefinition(r.inputId);return"number"!==s?.type?a:Math.max(0,t.getNumber(r.inputId,a))}(e,t);switch(e.rate.type){case"continuous":a=new Z(r,e.rate.count,e.rate.time,e.rate.duration);break;case"once":a=new $(r,e.rate.count);break;default:console.warn(`Failed to configure rate for emitter: ${JSON.stringify(e)}`),a=new s(0,1/0)}return a}async function be(e,t,r,s,p,x,S,T,D,F){const L=ge(e,T);let O;switch(e.output.type){case"decal":O=new a(await async function(e,t,a,r,s){if("shaderGraph"===ve(e)){const t=await createShaderGraphMaterial(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return Ae(a,e),a}}const n=!1!==e.unlit?new ce:new pe;n.color=new i.Color(e.color),n instanceof ce?n.intensity=e.intensity??1:n.emissiveIntensity=e.intensity??1;if(e.colorMap){const a=await t.getTexture(e.colorMap);n.colorMap=a}if(e.alphaMap){const a=await t.getTexture(e.alphaMap);n.alphaMap=a}const l=n.build();l.blending=te[e.blendingMode]??i.NormalBlending,l.transparent=!0,l.side=i.BackSide,l.depthTest=!1,null!=l&&!0===e.bloom&&(l.userData.hasBloom=!0);l.defines.IS_PARTICLE="";const o=new i.BoxGeometry(1,1,1),c=new i.Mesh(o,l);return Ae(c,e),c}(e.output,t,r,s,S));break;case"sprite":O=new a(await async function(e,t,a,r,s){let n=null;const l=ve(e);"shaderGraph"===l&&(n=await createShaderGraphMaterial(e,"sprite",a,r,s));null==n&&"shader"===l&&null!=e.shader&&(n=await createShaderMaterial(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):Me,r=C(a);let s=r.sample(B.uv);e.flipbook?.enabled&&(s=_(r,y.uv,e.flipbook.columns,e.flipbook.rows,J.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),l=new d("color").rgb,o=j(new h("instanceColor")).rgb,c=H.subtract(Q).divide(H);let p=J.opacity;switch(e.opacityChannel??"red"){case"none":break;case"red":p=p.multiply(s.r);break;case"alpha":p=p.multiply(s.a)}if("number"==typeof e.softness&&e.softness>0){const t=w(c,0,1e3);p=p.multiply(P(0,.2*e.softness,t))}const m=ne(n,void 0,void 0,!0),f=I(l.multiply(o).multiply(s.rgb).multiplyScalar(e.intensity??1),p);var g=new oe({color:f,emissive:f.rgb.multiplyScalar(p),transparent:!0,position:m,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});g.alphaHash=!0,null!=g&&!0===e.bloom&&(g.userData.hasBloom=!0);return g.blending=te[e.blendingMode]??i.NormalBlending,g}(e,t));n.depthWrite=!1,Ee(n,e);const o=new i.Mesh(new i.PlaneGeometry(1,1),n);return o.name="sprite",Ae(o,e),o}(e.output,t,r,s,S));break;case"stretchedSprite":O=new a(await async function(e,t){"shaderGraph"===ve(e)&&console.warn("Shader graph materials are not supported for stretched sprite VFX outputs yet. Falling back to the default stretched sprite material.");const a=null!=e.texture?await t.getTexture(e.texture):Me,r=C(a).sample(B.uv),s=k(new o("particleColor")),n=s.rgb.multiply(r.rgb);let l=s.w;switch(e.opacityChannel??"red"){case"none":break;case"red":l=l.multiply(r.r);break;case"alpha":l=l.multiply(r.a)}if("number"==typeof e.softness&&e.softness>0){const t=H.subtract(Q).divide(E(H)),a=w(t,0,1e3);l=l.multiply(P(0,.2*e.softness,a))}const c=m("offset"),p=f("velocity"),u=m("size"),d=p.w,h=u.x.add(u.y).multiply(.5),M=R.modelViewMatrix.multiplyVec(V(c,1)),x=R.normalMatrix.multiplyVec(p.xyz),S=A(g(M.xyz,x)).multiplyScalar(y.position.y.multiply(h)),T=x.multiplyScalar(y.position.x.add(.5).multiply(b(1).add(d.divide(v(x)))).multiply(h)),G=R.projectionMatrix.multiplyVec(V(M.xyz.add(S).subtract(T),M.w));var j=new oe({color:I(n.multiplyScalar(e.intensity??1),l),alphaTest:.1,transparent:!0,position:G,uniforms:{color:{value:new i.Color(e.color)}}});null!=j&&!0===e.bloom&&(j.userData.hasBloom=!0);j.blending=te[e.blendingMode]??i.NormalBlending;const D=new ee(new i.PlaneGeometry(1,1),j);return D.scaleFactor=e.scale,Ae(D,e),D}(e.output,t));break;case"shape":O=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const o=N[e.shape];if(null==o)return console.error(`No shape with type ${e.shape}`),new n;const p=W(e.params??{}),u=o.geometry(p);let d=null;const m=ve(e);"shaderGraph"===m&&(d=await createShaderGraphMaterial(e,"surface",a,r,s));null==d&&"shader"===m&&null!=e.shader&&(d=await createShaderMaterial(e,t,s));null==d&&(d="material"===m&&null!=e.material?xe(await t.getMaterial(e.material)):function(){const e=G(new h("instanceColor")).rgb,t=G(new l("particleData")).x;return new c({color:M({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());Ee(d,e);const f=new i.Mesh(u,d);return Ae(f,e),f}(e.output,t,r,s,S));break;case"mesh":O=new a(await async function(e,t,a,r,s){if(null==e.assetId)return console.warn("Can't use mesh as particle without asset id"),new n;const l=await t.getMesh(e.assetId),o=await t.getAsset(e.assetId),c=ve(e);if("shaderGraph"===c||"shader"===c&&null!=e.shader||"material"===c&&null!=e.material){let n;"shaderGraph"===c?n=await createShaderGraphMaterial(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await createShaderMaterial(e,t,s):"material"===c&&null!=e.material&&(n=xe(await t.getMaterial(e.material))),n?.transparent&&(n.depthWrite=!1),null!=n&&Ee(n,e),l.traverse(e=>{e instanceof i.Mesh&&null!=n&&(e.material=n)})}else{const e=[];if(null!=o.materialAssignments)for(const a of o.materialAssignments)null!=a.materialId&&l.traverse(r=>{r instanceof i.Mesh&&r.material instanceof i.Material&&r.material.color instanceof i.Color&&(r.material.name!=a.name&&null!=a.name||"#"+r.material.color.getHexString()!==a.color||e.push(t.getMaterial(a.materialId).then(e=>r.material=e)))});await Promise.all(e)}const p=[];if(l.traverse(e=>{e instanceof i.Mesh&&p.push(e)}),Ae(l,e),1===p.length){const t=p[0];return!0!==e.useLegacyTransform&&function(e){e.geometry=e.geometry.clone(),ye(e,e.geometry),e.position.set(0,0,0),e.quaternion.identity(),e.scale.set(1,1,1),e.updateMatrix(),e.matrixWorld.identity()}(t),t.removeFromParent(),t}return l}(e.output,t,r,s,S));break;case"trail":{const n=e.output,l="shaderGraph"===ve(e.output)?await createShaderGraphMaterial(e.output,"trail",r,s,S,{trailBillboard:e.output.billboard??!1}):null;O=new a({type:"trail",taper:e.output.taper,headGeometry:null,material:l instanceof i.ShaderMaterial?l:void 0,dragTexture:!1,texture:null!=e.output.texture?await t.getTexture(e.output.texture).then(e=>{if("repeat"!==n.uvMode)return e;const t=e.clone();return t.wrapS=i.RepeatWrapping,t.needsUpdate=!0,t}):null,opacityChannel:e.output.opacityChannel,color:e.output.color,colorEnd:e.output.colorEnd,intensity:e.output.intensity??1,intensityEnd:e.output.intensityEnd??1,length:e.output.length,opacityStart:e.output.opacityStart,opacityEnd:e.output.opacityEnd,bloom:e.output.bloom,scrollSpeed:e.output.scrollSpeed,uvMode:e.output.uvMode,unitsPerRepeat:e.output.unitsPerRepeat,width:e.output.width,billboard:e.output.billboard??!1,renderOrder:e.output.renderOrder});break}default:console.error("Failed to create particly system body: "+JSON.stringify(e))}const q=new Ie(D);q.parent=p,q.setRate(L),q._space=e.output.space;const z=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=re[e.type]).map(async e=>{const t=re[e.type],a=await W(e.params??{},r,s);return de(t,e.params??{},a,T)}));"world"===e.output.space&&z.push(new Y("shape"===e.output.type||"mesh"===e.output.type)),z.push(O,new K),q.addInitializers(z);const X=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=ae[e.type]).map(async e=>{const t=ae[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==U.Curve&&(r.type=U.Curve);const a=await W(e.params??{},r,s);return ue(t,e.params??{},a,T)}));X.sort((e,t)=>Number(t instanceof ie)-Number(e instanceof ie)),X.push(new Se);for(const t of X)t instanceof ie&&(t.physics=x,t.emitEvents&&null!=F&&(t.onCollision=(t,a)=>F(e.id,e.name,t,a,"local"===e.output.space)));q.addBehaviours(X);for(const a of e.children??[]){const e=await be(a,t,r,s,p,x,S,T,D,F),i=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=q.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&q.childEmitters.splice(e,1),null!=t.parentParticle&&(l.delete(t.parentParticle.id),t.parentParticle=null),i.release(t)},t}),n=q.eventDispatcher,l=new Map;q.bindEmitterEvent=!0,n.addEventListener("PARTICLE_DEAD",e=>{const t=l.get(e.id);null!=t&&(q.detachChildEmitterFromParticle(t,e),l.delete(e.id))});let o="PARTICLE_CREATED";if("spawnEvent"in a)switch(a.spawnEvent){case"collision":o="PARTICLE_COLLISION";break;case"start":o="PARTICLE_CREATED"}n.addEventListener(o,e=>{const t=i.get();t.age=0,t.totalEmitTimes=-1,t.particles.length=0,t.currentEmitTime=0,t.cID=0,t.eventDispatcher.removeAllEventListeners(),q.childEmitters.push(t),l.set(e.id,t),t.parentParticle=e,t.system=q.system,t.emit()})}return q}const Me=(new i.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=");export async function createShaderMaterial(e,t,a){const r=a.get(e.shader);if(null==r)return console.error("No shader exists with name "+e.shader),new i.Material;const s=new r.type;"sprite"===e.type&&s instanceof le&&(s.instanced=!0);const n=await L(e.shaderParams??{},r.type,t,{getTexture:e=>t.getTexture(e.id),getMaterial:e=>t.getMaterial(e.id),getMesh:e=>t.getMesh(e.id)},void 0,void 0,void 0,void 0,void 0,s);return Object.assign(s,n),s.build()}export async function createShaderGraphMaterial(e,t,a,r,s,i={}){const n=e.shaderGraph;if("asset"!==n?.source||null==n.assetId)return console.warn(`Missing shader graph asset reference for ${e.type} VFX output`),null;const l=await a.getAsset(n.assetId),o=l?.shaderGraph;if(null==o)return console.warn(`Missing shader graph asset "${n.assetId}" for ${e.type} VFX output`),null;if(o.target!==t)return console.warn(`Shader graph "${l.name}" targets "${o.target}" but ${e.type} VFX output expects "${t}"`),null;try{const t=await O(e.shaderGraphParams??{},o,a,r,void 0,s.shaders),l=he(o,{parameters:t,trailBillboard:i.trailBillboard});return l.userData.customShaderName=`shaderGraph:${n.assetId}`,Ee(l,e),l}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}export function createGpuSpriteShaderGraphResolver(e,t,a,r){return async s=>{const n=ve(s);let l=null;if("shaderGraph"===n)l=await createShaderGraphMaterial(s,"sprite"===s.type?"sprite":"decal"===s.type?"decal":"trail"===s.type?"trail":"surface",e,t,a,"trail"===s.type?{trailBillboard:s.billboard??!1}:void 0);else if("shader"===n&&"decal"!==s.type&&null!=r)l=await createShaderMaterial(s,r,a);else if("material"!==n||"mesh"!==s.type&&"shape"!==s.type||null==s.material||null==r){if("default"===n&&"mesh"===s.type&&null!=s.assetId&&null!=r){const e=await r.getAsset(s.assetId),t=e.materialAssignments?.find(e=>null!=e.materialId);null!=t&&(l=await we(t.materialId,r))}else if("default"===n&&"decal"===s.type&&null!=r){const e=!1!==s.unlit?new ce:new pe;e.color=new i.Color(s.color),e instanceof ce?e.intensity=s.intensity??1:e.emissiveIntensity=s.intensity??1,s.colorMap&&(e.colorMap=await r.getTexture(s.colorMap)),s.alphaMap&&(e.alphaMap=await r.getTexture(s.alphaMap)),l=e.build(),l.transparent=!0}}else l="mesh"===s.type?await we(s.material,r):xe(await r.getMaterial(s.material));return null==l?null:("mesh"!==s.type&&"shape"!==s.type||!l.transparent||(l.depthWrite=!1),l instanceof c?l:(console.warn(`GPU ${s.type} materials must compile to NodeShaderMaterial; using CPU fallback`),null))}}function ve(e){return null!=e.materialSource?("material"!==e.materialSource||"mesh"!==e.type&&"shape"!==e.type||null!=e.material)&&("shaderGraph"!==e.materialSource||"asset"===e.shaderGraph?.source&&null!=e.shaderGraph.assetId)&&("shader"!==e.materialSource||"shader"in e&&null!=e.shader)?e.materialSource:"default":"asset"===e.shaderGraph?.source?"shaderGraph":"shader"in e&&null!=e.shader?"shader":"mesh"!==e.type&&"shape"!==e.type||null==e.material?"default":"material"}function Ee(e,t){null!=e&&(fe(e,!1),"bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,!0===t.lockY&&e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.LOCK_Y_AXIS="")):"decal"===t.type?(e.blending=te[t.blendingMode]??i.NormalBlending,e.transparent=!0,e.side=i.BackSide,e.depthTest=!1,e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE="")):"shape"!==t.type&&"mesh"!==t.type||e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE=""))}function Ae(e,t){const a=t.renderOrder;null!=a&&e.traverse(e=>e.renderOrder=a)}function xe(e){const t=G(new h("instanceColor")).rgb;let a,r=G(new l("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(S(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(B.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(B.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:S(e.emissive),emissiveIntensity:b(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:S(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:M({color:s}).rgb.rgba(r),emissive:S(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshBasicMaterial&&(a=new c({color:s.rgb.rgba(r),emissive:s.rgb,transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}))}else e instanceof c&&(a=e.clone(),a.defines.IS_PARTICLE="");return null!=a&&(!0===e.userData?.hasBloom&&null!=a&&(a.userData.hasBloom=!0),a.side=e.side,a.transparent=e.transparent),a??e}class Se extends t{initialize(e){e.body instanceof i.Object3D&&e.body.traverse(e=>{if(e instanceof i.Mesh){const t=e.material;t instanceof c&&(null!=t.uniforms[q]||null!=t.uniforms[z]||t.uniforms[X])}})}mutate(e,t,a){this.energize(e,t),e.target instanceof n&&e.target.traverse(t=>{if(t instanceof i.Mesh){const a=t.material;if(a instanceof c){let t=!1;null!=a.uniforms[q]&&(a.uniforms[q].value=this.energy,t=!0),null!=a.uniforms[z]&&(a.uniforms[z].value=e.age,t=!0),null!=a.uniforms[X]&&(a.uniforms[X].value=e.velocity,t=!0),t&&me(a)}}})}}class Ie extends r{constructor(e){super(),this.transformRoot=e,this.childEmitters=[],this.bindEmitterEvent=!1,this.onExpired=()=>{}}clearParticlesRecursive(){let e=this.childEmitters.length;for(;e--;){const t=this.childEmitters[e];t.stopEmit(),t.clearParticlesRecursive(),t.onExpired()}this.childEmitters.length=0;let t=this.particles.length;for(;t--;){const e=this.particles[t];this.system?.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),null!=this.system?this.system.pool.expire(e.reset()):e.reset()}this.particles.length=0}detachChildEmitterFromParticle(e,t){this.copyPositionToChildSpace(e,t.position),e.parentParticle=null,e.stopEmit()}update(e){if(!this.isEmitting&&0===this.particles.length&&0===this.childEmitters.length)return;this.age+=e,(this.dead||this.age>=this.life)&&this.destroy(),this.isEmitting&&this.generate(e),this.integrate(e);let t=this.particles.length;for(;t--;){const e=this.particles[t];e.dead&&(this.system&&this.system.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),this.system.pool.expire(e.reset()),this.particles.splice(t,1))}this.updateEmitterBehaviours(e),this.updateChildren(e),this.isEmitting||0!==this.particles.length||0!==this.childEmitters.length||this.onExpired()}updateChildren(e){for(const t of this.childEmitters)null!=t.parentParticle&&this.copyPositionToChildSpace(t,t.parentParticle.position),t.update(e)}copyPositionToChildSpace(e,t){const a=this._space??"world",r=e._space??"world";a!==r&&null!=this.transformRoot?(Pe.copy(t),"local"===a&&"world"===r?Pe.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(Te.copy(this.transformRoot.matrixWorld).invert(),Pe.applyMatrix4(Te)),e.position.copy(Pe)):e.position.copy(t)}clone(){const e=new Ie(this.transformRoot);return e.setRate(this.rate.clone()),e.behaviours=this.behaviours,e.initializers=this.initializers,e._space=this._space,e.body=this.body,e.parent=this.parent,e.system=this.system,e}setParentRecursive(e){this.system=e,this.childEmitters.forEach(t=>t.setParentRecursive(e))}}const Pe=new i.Vector3,Te=new i.Matrix4;export class EmitterPool{constructor(e){this.creator=e,this.instances=[]}get(){0==this.instances.length&&this.instances.push(this.creator());return this.instances.pop()}release(e){this.instances.push(e)}dispose(){this.instances.length=0}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -36,6 +36,8 @@ export type TrailTemplate = {
36
36
  width?: number;
37
37
  billboard?: boolean;
38
38
  scrollSpeed?: number;
39
+ uvMode?: 'stretch' | 'repeat';
40
+ unitsPerRepeat?: number;
39
41
  opacityStart: number;
40
42
  opacityEnd: number;
41
43
  bloom: boolean;
@@ -1,4 +1,4 @@
1
- import{CustomRenderer as e,MeshRenderer as t,PUID as r}from"@hology/nebula";import*as a from"three";import{InstancedBufferAttribute as o,Object3D as n}from"three";import{NodeShaderMaterial as i}from"three-shader-graph";import{StretchedSprite as s}from"./stretched-sprite.js";import{Trail as l}from"./trail-renderer.js";import{SpriteNodeShaderMaterial as c}from"../../shader/sprite-shader.js";import{particleEnergyUniformName as d}from"../../shader-nodes/particle.js";import{AssetMeshInstance as m}from"../../scene/asset-resource-loader.js";import{markMaterialUniformValuesNeedUpdate as u}from"../../rendering/node-material-webgpu-resolver.js";var h;!function(e){e[e.mesh=0]="mesh",e[e.instanced=1]="instanced",e[e.sprite=2]="sprite",e[e.stretchedBillboard=3]="stretchedBillboard",e[e.trail=4]="trail"}(h||(h={}));export class MultiRenderer extends e{constructor(e,t,r,a){super(),this.worldContainer=e,this.localContainer=t,this.three=r,this.view=a,this.localRenderers=[],this.worldRenderers=[]}onSystemUpdate(){for(const e of this.worldRenderers)e?.onSystemUpdate();for(const e of this.localRenderers)e?.onSystemUpdate()}onParticleCreated(e){e.target=null,this.getRenderer(e)?.onParticleCreated(e)}onParticleUpdate(e){this.getRenderer(e)?.onParticleUpdate(e)}onParticleDead(e){this.getRenderer(e)?.onParticleDead(e),e._renderer=null}getRenderer(e){if(e._renderer)return e._renderer;const t=(null!=e?.parent?e?.parent._space:null)??"world",r="world"===t?this.worldContainer:this.localContainer,o="world"===t?this.worldRenderers:this.localRenderers;return"trail"===e.body.type?(null==o[h.trail]&&(o[h.trail]=new TrailRenderer(r,this.three)),e._renderer=o[h.trail]):e.body instanceof s?(null==o[h.stretchedBillboard]&&(o[h.stretchedBillboard]=new StretchedSpriteInstancedRenderer(r,this.three,this.view)),e._renderer=o[h.stretchedBillboard]):e.body instanceof a.Sprite?(null==o[h.sprite]&&(o[h.sprite]=new CombinedRenderer(r,this.three)),e._renderer=o[h.sprite]):e.body instanceof a.Mesh&&0==e.body.children.length&&e.body.material instanceof i?(null==o[h.instanced]&&(o[h.instanced]=new InstancedRenderer(r,this.three,this.view)),e._renderer=o[h.instanced]):e.body instanceof a.Object3D?(null==o[h.mesh]&&(o[h.mesh]=new CombinedRenderer(r,this.three)),e._renderer=o[h.mesh]):void 0}dispose(){this.localRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()}),this.worldRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()})}}export class TrailRenderer extends t{constructor(){super(...arguments),this.trails=[]}dispose(){}onSystemUpdate(){for(const e of this.trails)e.update()}onParticleCreated(e){const t=e.body,r=new l(this.container,!1),o=new n;this.container.add(o),o.updateMatrixWorld(),o.updateWorldMatrix(!0,!0);const i=t.material?.clone()??l.createBaseMaterial(t.texture,t.scrollSpeed,t.opacityChannel,t.billboard??!1);i.uniforms.taper&&(i.uniforms.taper.value=t.taper??!1);const s=new a.Color(t.color??0).multiplyScalar(t.intensity??1),c=new a.Color(t.colorEnd??0).multiplyScalar(t.intensityEnd??t.intensity??1);i.uniforms.headColor&&i.uniforms.tailColor&&(i.uniforms.headColor.value=new a.Vector4(s.r,s.g,s.b,t.opacityStart??1),i.uniforms.tailColor.value=new a.Vector4(c.r,c.g,c.b,t.opacityEnd??1)),i.uniforms.color&&null==i.uniforms.headColor&&(i.uniforms.color.value=s),i.uniforms.opacity&&null==i.uniforms.headColor&&(i.uniforms.opacity.value=t.opacityStart??1),t.bloom&&(i.userData.hasBloom=!0),r.initialize(i,Math.round(t.length??10),!1,t.width,null,o,t.billboard??!1),null!=t.renderOrder&&null!=r.mesh&&(r.mesh.renderOrder=t.renderOrder);const d=e.rotation;o.rotation.set(d.x,d.y,d.z);e.scale;r.activate(),this.trails.push(r),e.target=o}onParticleUpdate(e){const t=e.target;t.position.copy(e.position);const r=e.body;let a=v;e.old&&e.old.position?a.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z):a.copy(e.velocity),a.lengthSq()>1e-8?a.normalize():a.copy(U);const o=P;o.setFromUnitVectors(a,U),t.rotation.set(0,0,0),t.rotation.set(e.rotation.x,e.rotation.y,e.rotation.z),t.applyQuaternion(o);const n=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=n){const t=this.trails[n];if(e.useAlpha){if(t.material.uniforms.headColor&&t.material.uniforms.tailColor){t.material.uniforms.headColor.value.setW((r.opacityStart??1)*e.alpha);t.material.uniforms.tailColor.value.setW((r.opacityEnd??1)*e.alpha)}null!=t.material.uniforms.opacity&&(t.material.uniforms.opacity.value=e.alpha)}e.useColor&&null!=t.material.uniforms.color&&t.material.uniforms.color.value.copy(e.color),null!=t.material.uniforms[d]&&(t.material.uniforms[d].value=e.energy),u(t.material)}}onParticleDead(e){const t=e.target,r=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=r){const e=this.trails[r];e.removeFromParent(),e.mesh.removeFromParent(),e.targetObject.removeFromParent(),t.removeFromParent(),this.trails.splice(r,1)}}}export class CombinedRenderer extends t{dispose(){}scale(e){const t=e.transform.initialScale;e.target instanceof a.Sprite?null!=t?e.target.scale.set(t.x*e.scale*e.radius,t.y*e.scale*e.radius,1):e.target.scale.set(e.scale*e.radius,e.scale*e.radius,1):null!=t?e.target.scale.set(t.x*e.scale,t.y*e.scale,t.z*e.scale):super.scale(e)}rotate(e){e.target.material.rotation=e.rotation.z}onParticleCreated(e){e.target||(e.target=this._targetPool.get(e.body),(e.useAlpha||e.useColor)&&(e.target instanceof a.Mesh||e.target instanceof a.Sprite&&e.target.material instanceof a.Material)&&(e.target.material.__puid=r.id(e.body.material),e.target.material=this._materialPool.get(e.target.material))),e.target&&e.target instanceof n&&(e.target.position.set(e.position.x,e.position.y,e.position.z),this.container.add(e.target))}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:o,rotation:i}=e;if(t){if(t.position.copy(e.position),this.isThreeSprite(e)||(t instanceof a.Mesh&&t.material instanceof c?e.target.material.rotation=e.rotation.z:t.rotation.set(i.x,i.y,i.z)),this.scale(e),e.transform&&e.transform.orientAlongVelocity&&t instanceof n){const r=p.set(e.velocity.x,e.velocity.y,e.velocity.z).normalize(),a=t.getWorldDirection(f);a.applyAxisAngle(y,Math.PI/-2),g.setFromUnitVectors(a,r),t.quaternion.copy(g)}(r||o)&&this.applyUniforms(t,e)}}applyUniforms(e,t){if(e instanceof m&&e.traverse(r=>r!==e&&this.applyUniforms(r,t)),e instanceof a.Mesh){let r=!1;t.useAlpha&&(e.material instanceof c&&null!=e.material.uniforms.opacity&&(e.material.uniforms.opacity.value=t.alpha,r=!0),e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.opacity?(e.material.uniforms.opacity.value=t.alpha,r=!0):(e.material.opacity=t.alpha,r=!0),e.material.transparent=!0),t.useColor&&(null!=e.material.color?(e.material.color.copy(t.color),r=!0):e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.color&&(e.material.uniforms.color.value=t.color,r=!0)),r&&u(e.material)}}onParticleDead(e){e.target&&(e.target.material&&(e.useAlpha||e.useColor)&&this._materialPool.expire(e.target.material),this._targetPool.expire(e.target),this.container.remove(e.target),e.target=null)}}export class StretchedSpriteInstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>e.mesh.geometry.dispose())}onSystemUpdate(){for(const e of this.meshes){const t=e.mesh.geometry.getAttribute("offset"),r=e.mesh.geometry.getAttribute("size"),o=e.mesh.geometry.getAttribute("velocity"),n=e.mesh.geometry.getAttribute("rotation"),i=e.mesh.geometry.getAttribute("particleColor");let s=0;for(const l of e.particles){if(null==l||l.dead)continue;if(l.useColor||l.color instanceof a.Color){const e=S.copy(l.color).getRGB(z);i.setXYZW(s,e.r,e.g,e.b,1),i.needsUpdate=!0}l.useAlpha&&(i.setW(s,l.alpha),i.needsUpdate=!0),"number"==typeof l.rotation?n.setX(s,l.rotation):n.setX(s,l.rotation.x);const e=l.position;if(t.setXYZ(s,e.x,e.y,e.z),"number"!=typeof l.scale)throw new Error("Particle scale is not a number");r.setXYZ(s,l.scale,l.scale,l.scale);let c=l.body.scaleFactor;0===c&&(c=.001);const d=1,m=l.velocity;o.setXYZW(s,m.x*c,m.y*c,m.z*c,d),s++}s>0&&(t.clearUpdateRanges(),t.addUpdateRange(0,3*s),t.needsUpdate=!0,r.clearUpdateRanges(),r.addUpdateRange(0,3*s),r.needsUpdate=!0,i.clearUpdateRanges(),i.addUpdateRange(0,4*s),i.needsUpdate=!0,o.clearUpdateRanges(),o.addUpdateRange(0,4*s),o.needsUpdate=!0,n.clearUpdateRanges(),n.addUpdateRange(0,s),n.needsUpdate=!0)}}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a;if(!Number.isFinite(r)||r<=0)return t.numPan.b*this.calcMaxCount(e.parent.parentParticle);return Math.min(t.numPan.b*Math.ceil(e.life/Math.min(Math.max(t.timePan.a,.01),1)),1e5)*this.calcMaxCount(e.parent.parentParticle)}onParticleCreated(e){if(e.body instanceof s&&null==e.target){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(null==r){const n=this.calcMaxCount(e),i=new a.InstancedBufferGeometry;i.setIndex(t.geometry.getIndex()),i.setAttribute("position",t.geometry.getAttribute("position")),t.geometry.hasAttribute("normal")&&i.setAttribute("normal",t.geometry.getAttribute("normal")),i.setAttribute("uv",t.geometry.getAttribute("uv"));const s=new o(new Float32Array(3*n),3);s.setUsage(a.DynamicDrawUsage),i.setAttribute("offset",s);const l=new o(new Float32Array(4*n),4);if(l.setUsage(a.DynamicDrawUsage),i.setAttribute("particleColor",l),t.material instanceof c){const e=new a.Color(t.material.color);for(let t=0;t<l.count;t++)l.setXYZW(t,e.r,e.g,e.b,1)}const d=new o(new Float32Array(3*n),3);d.setUsage(a.DynamicDrawUsage),i.setAttribute("size",d);const m=new o(new Float32Array(4*n),4);m.setUsage(a.DynamicDrawUsage),i.setAttribute("velocity",m);const u=new o(new Float32Array(4*n),1);u.setUsage(a.DynamicDrawUsage),i.setAttribute("rotation",u),r={mesh:new a.Mesh(i,t.material),indices:new Float32Array(n),particles:[]},r.mesh.renderOrder=t.renderOrder,this.meshes.push(r),this.container.add(r.mesh)}let n=r.indices.findIndex(e=>0===e);n<0&&(n=function(e){let t=e[0],r=0;for(let a=1;a<e.length;a++)e[a]<t&&(t=e[a],r=a);return r}(r.indices)),r.indices[n]=performance.now(),e.target=n,r.particles[n]=e}}onParticleUpdate(e){}onParticleDead(e){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(r){const t=r.mesh.geometry.getAttribute("size");t.setXYZ(e.target,0,0,0),t.needsUpdate=!0,r.particles[e.target]=null,r.indices[e.target]=0}e.target=null}}const p=new a.Vector3,f=new a.Vector3,g=new a.Quaternion,y=new a.Vector3(1,0,0),b=1e5;function w(e){return Number.isFinite(e)?Math.min(Math.max(Math.ceil(e),1),b):b}export class InstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>{e.mesh.geometry.dispose(),e.mesh.dispose()})}onSystemUpdate(){for(const e of this.meshes)e.mesh.material.transparent&&e.mesh.material.blending===a.NormalBlending&&F(e,this.view.getCamera())}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a,a=t.numPan.b,o=e.parent.parentParticle;if(!Number.isFinite(r)||r<=0)return w(a*this.calcMaxCount(o));return w(a*Math.ceil(e.life/Math.min(Math.max(r,.01),1))*this.calcMaxCount(o))}onParticleCreated(e){if(e.body instanceof a.Sprite)return;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r){const o=this.calcMaxCount(e);r={mesh:new a.InstancedMesh(t.geometry,t.material,o),indices:new Array(o).fill(null),particles:[],sortOrder:new Array(o),sortDistances:new Float32Array(o),sortedMatrices:new Float32Array(16*o),sortedColors:new Float32Array(4*o),sortedParticleData:new Float32Array(3*o),sortedRotations:new Float32Array(o),sortedParticles:new Array(o),sortedIndices:new Array(o)},r.mesh.renderOrder=t.renderOrder,r.mesh.userData.webGpuCacheMaterial=!0;const n=new Float32Array(4*o);n.fill(1),r.mesh.instanceColor=new a.InstancedBufferAttribute(n,4),r.mesh.setColorAt(0,S.setScalar(1)),r.mesh.instanceColor.needsUpdate=!0,r.mesh.material.defines.USE_INSTANCING="",r.mesh.material.needsUpdate=!0;const i=new Float32Array(3*o);M.makeScale(0,0,0);for(let e=0;e<o;e++)i[3*e+0]=1,i[3*e+1]=1,i[3*e+2]=1,r.mesh.instanceMatrix.array.set(M.elements,16*e);r.mesh.instanceMatrix.needsUpdate=!0,r.mesh.geometry.setAttribute("particleData",new a.InstancedBufferAttribute(i,3));const s=new a.InstancedBufferAttribute(new Float32Array(o),1);s.setUsage(a.DynamicDrawUsage),r.mesh.geometry.setAttribute("rotation",s),this.meshes.push(r),this.container.add(r.mesh)}let o=r.indices.findIndex(e=>null==e);if(o<0&&(o=r.indices.indexOf(Math.min(...r.indices))),o<0||o>=r.mesh.instanceMatrix.count)return void(e.target=null);const n=r.particles[o];if(null!=n&&n!==e&&(n.target=null),r.indices[o]=performance.now(),e.target=o,r.particles[o]=e,r.mesh.count<=o&&(r.mesh.count=o+1),"number"==typeof e.target){e.transform.initialScale;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);C(e,r.mesh),e.useAlpha&&(r.mesh.material.transparent||(r.mesh.material.transparent=!0,r.mesh.material.needsUpdate=!0))}}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:a,rotation:o}=e;if(null==t)return;const n=e.body,i=this.meshes.find(e=>e.mesh.geometry.uuid===n.geometry.uuid&&e.mesh.material.uuid===n.material.uuid);if(null==i)return;if(!A(i,e))return void(e.target=null);if(i.mesh.frustumCulled=!1,C(e,i.mesh),a){S.copy(e.color);const t=i.mesh.instanceColor.array,r=e.target*i.mesh.instanceColor.itemSize;t[r+0]=S.r,t[r+1]=S.g,t[r+2]=S.b,i.mesh.instanceColor.itemSize>=4&&(t[r+3]=1),i.mesh.instanceColor.needsUpdate=!0}const s=i.mesh.geometry.getAttribute("particleData");r&&s.setX(e.target,e.alpha),s.setY(e.target,e.energy),s.needsUpdate=!0;const l=i.mesh.geometry.getAttribute("rotation");l.setX(e.target,o.z),l.needsUpdate=!0}onParticleDead(e){if(null!=e.target){const t=e.body,r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r)return;if(!A(r,e))return void(e.target=null);r.indices[e.target]=null,r.particles[e.target]=null,e.scale=0,C(e,r.mesh),r.mesh.instanceMatrix.needsUpdate=!0,e.target=null}}}const x=new n;function A(e,t){const r=t.target;return"number"==typeof r&&Number.isInteger(r)&&r>=0&&r<e.mesh.instanceMatrix.count&&e.particles[r]===t}function C(e,t){if(!Number.isInteger(e.target)||e.target<0||e.target>=t.instanceMatrix.count)return;if(v.set(e.position.x,e.position.y,e.position.z),e.transform&&e.transform.orientAlongVelocity){const r=p.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z).normalize();t.getMatrixAt(e.target,x.matrix);const a=x.getWorldDirection(R);a.applyAxisAngle(y,Math.PI/-2),P.setFromUnitVectors(a,r)}else D.set(e.rotation.x,e.rotation.y,e.rotation.z),P.setFromEuler(D);const r=e.transform.initialScale;null!=r?R.set(r.x*e.scale,r.y*e.scale,r.z*e.scale):R.set(e.scale,e.scale,e.scale),M.compose(v,P,R),t.instanceMatrix.array.set(M.elements,16*e.target),t.instanceMatrix.needsUpdate=!0}const U=new a.Vector3(0,0,-1),M=new a.Matrix4,P=new a.Quaternion,v=new a.Vector3,R=new a.Vector3,D=new a.Euler,S=new a.Color(0),z={r:0,g:0,b:0};function F(e,t){const r=e.mesh,a=r.instanceMatrix.array,o=r.instanceColor.array,n=r.geometry.getAttribute("particleData"),i=n.array,s=r.geometry.getAttribute("rotation"),l=s.array,c=r.worldToLocal(t.getWorldPosition(I));let d=0;for(let t=0;t<e.particles.length;t++){if(null==e.particles[t])continue;const r=16*t,o=a[r+12]-c.x,n=a[r+13]-c.y,i=a[r+14]-c.z;e.sortDistances[t]=o*o+n*n+i*i,e.sortOrder[d++]=t}e.sortOrder.length=d,e.sortOrder.sort((t,r)=>e.sortDistances[r]-e.sortDistances[t]);for(let t=0;t<d;t++){const r=e.sortOrder[t];for(let o=0;o<16;o++)e.sortedMatrices[16*t+o]=a[16*r+o];for(let a=0;a<4;a++)e.sortedColors[4*t+a]=o[4*r+a];for(let a=0;a<3;a++)e.sortedParticleData[3*t+a]=i[3*r+a];e.sortedRotations[t]=l[r],e.sortedParticles[t]=e.particles[r],e.sortedIndices[t]=e.indices[r]}for(let t=0;t<d;t++){const r=e.sortedParticles[t];e.particles[t]=r,e.indices[t]=e.sortedIndices[t],l[t]=e.sortedRotations[t],r.target=t}for(let t=d;t<e.indices.length;t++)e.particles[t]=null,e.indices[t]=null;for(let t=0;t<16*d;t++)a[t]=e.sortedMatrices[t];for(let t=0;t<4*d;t++)o[t]=e.sortedColors[t];for(let t=0;t<3*d;t++)i[t]=e.sortedParticleData[t];r.count=d,r.instanceMatrix.needsUpdate=!0,r.instanceColor.needsUpdate=!0,n.needsUpdate=!0,s.needsUpdate=!0}export{F as sortInstancedMeshByDistance};const I=new a.Vector3;/*
1
+ import{CustomRenderer as e,MeshRenderer as t,PUID as r}from"@hology/nebula";import*as a from"three";import{InstancedBufferAttribute as o,Object3D as n}from"three";import{NodeShaderMaterial as i}from"three-shader-graph";import{StretchedSprite as s}from"./stretched-sprite.js";import{Trail as l}from"./trail-renderer.js";import{SpriteNodeShaderMaterial as c}from"../../shader/sprite-shader.js";import{particleEnergyUniformName as d}from"../../shader-nodes/particle.js";import{AssetMeshInstance as m}from"../../scene/asset-resource-loader.js";import{markMaterialUniformValuesNeedUpdate as u}from"../../rendering/node-material-webgpu-resolver.js";var h;!function(e){e[e.mesh=0]="mesh",e[e.instanced=1]="instanced",e[e.sprite=2]="sprite",e[e.stretchedBillboard=3]="stretchedBillboard",e[e.trail=4]="trail"}(h||(h={}));export class MultiRenderer extends e{constructor(e,t,r,a){super(),this.worldContainer=e,this.localContainer=t,this.three=r,this.view=a,this.localRenderers=[],this.worldRenderers=[]}onSystemUpdate(){for(const e of this.worldRenderers)e?.onSystemUpdate();for(const e of this.localRenderers)e?.onSystemUpdate()}onParticleCreated(e){e.target=null,this.getRenderer(e)?.onParticleCreated(e)}onParticleUpdate(e){this.getRenderer(e)?.onParticleUpdate(e)}onParticleDead(e){this.getRenderer(e)?.onParticleDead(e),e._renderer=null}getRenderer(e){if(e._renderer)return e._renderer;const t=(null!=e?.parent?e?.parent._space:null)??"world",r="world"===t?this.worldContainer:this.localContainer,o="world"===t?this.worldRenderers:this.localRenderers;return"trail"===e.body.type?(null==o[h.trail]&&(o[h.trail]=new TrailRenderer(r,this.three)),e._renderer=o[h.trail]):e.body instanceof s?(null==o[h.stretchedBillboard]&&(o[h.stretchedBillboard]=new StretchedSpriteInstancedRenderer(r,this.three,this.view)),e._renderer=o[h.stretchedBillboard]):e.body instanceof a.Sprite?(null==o[h.sprite]&&(o[h.sprite]=new CombinedRenderer(r,this.three)),e._renderer=o[h.sprite]):e.body instanceof a.Mesh&&0==e.body.children.length&&e.body.material instanceof i?(null==o[h.instanced]&&(o[h.instanced]=new InstancedRenderer(r,this.three,this.view)),e._renderer=o[h.instanced]):e.body instanceof a.Object3D?(null==o[h.mesh]&&(o[h.mesh]=new CombinedRenderer(r,this.three)),e._renderer=o[h.mesh]):void 0}dispose(){this.localRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()}),this.worldRenderers.forEach(e=>{e instanceof InstancedRenderer&&e.dispose()})}}export class TrailRenderer extends t{constructor(){super(...arguments),this.trails=[]}dispose(){}onSystemUpdate(){for(const e of this.trails)e.update()}onParticleCreated(e){const t=e.body,r=new l(this.container,!1),o=new n;this.container.add(o),o.updateMatrixWorld(),o.updateWorldMatrix(!0,!0);const i=t.material?.clone()??l.createBaseMaterial(t.texture,t.scrollSpeed,t.opacityChannel,t.billboard??!1);i.uniforms.trailUvMode&&(i.uniforms.trailUvMode.value="repeat"===t.uvMode?1:0),i.uniforms.unitsPerRepeat&&(i.uniforms.unitsPerRepeat.value=Math.max(.001,t.unitsPerRepeat??1)),i.uniforms.taper&&(i.uniforms.taper.value=t.taper??!1);const s=new a.Color(t.color??0).multiplyScalar(t.intensity??1),c=new a.Color(t.colorEnd??0).multiplyScalar(t.intensityEnd??t.intensity??1);i.uniforms.headColor&&i.uniforms.tailColor&&(i.uniforms.headColor.value=new a.Vector4(s.r,s.g,s.b,t.opacityStart??1),i.uniforms.tailColor.value=new a.Vector4(c.r,c.g,c.b,t.opacityEnd??1)),i.uniforms.color&&null==i.uniforms.headColor&&(i.uniforms.color.value=s),i.uniforms.opacity&&null==i.uniforms.headColor&&(i.uniforms.opacity.value=t.opacityStart??1),t.bloom&&(i.userData.hasBloom=!0),r.initialize(i,Math.round(t.length??10),!1,t.width,null,o,t.billboard??!1),null!=t.renderOrder&&null!=r.mesh&&(r.mesh.renderOrder=t.renderOrder);const d=e.rotation;o.rotation.set(d.x,d.y,d.z);e.scale;r.activate(),this.trails.push(r),e.target=o}onParticleUpdate(e){const t=e.target;t.position.copy(e.position);const r=e.body;let a=v;e.old&&e.old.position?a.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z):a.copy(e.velocity),a.lengthSq()>1e-8?a.normalize():a.copy(C);const o=P;o.setFromUnitVectors(a,C),t.rotation.set(0,0,0),t.rotation.set(e.rotation.x,e.rotation.y,e.rotation.z),t.applyQuaternion(o);const n=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=n){const t=this.trails[n];if(e.useAlpha){if(t.material.uniforms.headColor&&t.material.uniforms.tailColor){t.material.uniforms.headColor.value.setW((r.opacityStart??1)*e.alpha);t.material.uniforms.tailColor.value.setW((r.opacityEnd??1)*e.alpha)}null!=t.material.uniforms.opacity&&(t.material.uniforms.opacity.value=e.alpha)}e.useColor&&null!=t.material.uniforms.color&&t.material.uniforms.color.value.copy(e.color),null!=t.material.uniforms[d]&&(t.material.uniforms[d].value=e.energy),u(t.material)}}onParticleDead(e){const t=e.target,r=this.trails.findIndex(e=>e.targetObject.id===t.id);if(-1!=r){const e=this.trails[r];e.removeFromParent(),e.mesh.removeFromParent(),e.targetObject.removeFromParent(),t.removeFromParent(),this.trails.splice(r,1)}}}export class CombinedRenderer extends t{dispose(){}scale(e){const t=e.transform.initialScale;e.target instanceof a.Sprite?null!=t?e.target.scale.set(t.x*e.scale*e.radius,t.y*e.scale*e.radius,1):e.target.scale.set(e.scale*e.radius,e.scale*e.radius,1):null!=t?e.target.scale.set(t.x*e.scale,t.y*e.scale,t.z*e.scale):super.scale(e)}rotate(e){e.target.material.rotation=e.rotation.z}onParticleCreated(e){e.target||(e.target=this._targetPool.get(e.body),(e.useAlpha||e.useColor)&&(e.target instanceof a.Mesh||e.target instanceof a.Sprite&&e.target.material instanceof a.Material)&&(e.target.material.__puid=r.id(e.body.material),e.target.material=this._materialPool.get(e.target.material))),e.target&&e.target instanceof n&&(e.target.position.set(e.position.x,e.position.y,e.position.z),this.container.add(e.target))}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:o,rotation:i}=e;if(t){if(t.position.copy(e.position),this.isThreeSprite(e)||(t instanceof a.Mesh&&t.material instanceof c?e.target.material.rotation=e.rotation.z:t.rotation.set(i.x,i.y,i.z)),this.scale(e),e.transform&&e.transform.orientAlongVelocity&&t instanceof n){const r=p.set(e.velocity.x,e.velocity.y,e.velocity.z).normalize(),a=t.getWorldDirection(f);a.applyAxisAngle(y,Math.PI/-2),g.setFromUnitVectors(a,r),t.quaternion.copy(g)}(r||o)&&this.applyUniforms(t,e)}}applyUniforms(e,t){if(e instanceof m&&e.traverse(r=>r!==e&&this.applyUniforms(r,t)),e instanceof a.Mesh){let r=!1;t.useAlpha&&(e.material instanceof c&&null!=e.material.uniforms.opacity&&(e.material.uniforms.opacity.value=t.alpha,r=!0),e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.opacity?(e.material.uniforms.opacity.value=t.alpha,r=!0):(e.material.opacity=t.alpha,r=!0),e.material.transparent=!0),t.useColor&&(null!=e.material.color?(e.material.color.copy(t.color),r=!0):e.material instanceof a.ShaderMaterial&&null!=e.material.uniforms.color&&(e.material.uniforms.color.value=t.color,r=!0)),r&&u(e.material)}}onParticleDead(e){e.target&&(e.target.material&&(e.useAlpha||e.useColor)&&this._materialPool.expire(e.target.material),this._targetPool.expire(e.target),this.container.remove(e.target),e.target=null)}}export class StretchedSpriteInstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>e.mesh.geometry.dispose())}onSystemUpdate(){for(const e of this.meshes){const t=e.mesh.geometry.getAttribute("offset"),r=e.mesh.geometry.getAttribute("size"),o=e.mesh.geometry.getAttribute("velocity"),n=e.mesh.geometry.getAttribute("rotation"),i=e.mesh.geometry.getAttribute("particleColor");let s=0;for(const l of e.particles){if(null==l||l.dead)continue;if(l.useColor||l.color instanceof a.Color){const e=S.copy(l.color).getRGB(z);i.setXYZW(s,e.r,e.g,e.b,1),i.needsUpdate=!0}l.useAlpha&&(i.setW(s,l.alpha),i.needsUpdate=!0),"number"==typeof l.rotation?n.setX(s,l.rotation):n.setX(s,l.rotation.x);const e=l.position;if(t.setXYZ(s,e.x,e.y,e.z),"number"!=typeof l.scale)throw new Error("Particle scale is not a number");r.setXYZ(s,l.scale,l.scale,l.scale);let c=l.body.scaleFactor;0===c&&(c=.001);const d=1,m=l.velocity;o.setXYZW(s,m.x*c,m.y*c,m.z*c,d),s++}s>0&&(t.clearUpdateRanges(),t.addUpdateRange(0,3*s),t.needsUpdate=!0,r.clearUpdateRanges(),r.addUpdateRange(0,3*s),r.needsUpdate=!0,i.clearUpdateRanges(),i.addUpdateRange(0,4*s),i.needsUpdate=!0,o.clearUpdateRanges(),o.addUpdateRange(0,4*s),o.needsUpdate=!0,n.clearUpdateRanges(),n.addUpdateRange(0,s),n.needsUpdate=!0)}}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a;if(!Number.isFinite(r)||r<=0)return t.numPan.b*this.calcMaxCount(e.parent.parentParticle);return Math.min(t.numPan.b*Math.ceil(e.life/Math.min(Math.max(t.timePan.a,.01),1)),1e5)*this.calcMaxCount(e.parent.parentParticle)}onParticleCreated(e){if(e.body instanceof s&&null==e.target){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(null==r){const n=this.calcMaxCount(e),i=new a.InstancedBufferGeometry;i.setIndex(t.geometry.getIndex()),i.setAttribute("position",t.geometry.getAttribute("position")),t.geometry.hasAttribute("normal")&&i.setAttribute("normal",t.geometry.getAttribute("normal")),i.setAttribute("uv",t.geometry.getAttribute("uv"));const s=new o(new Float32Array(3*n),3);s.setUsage(a.DynamicDrawUsage),i.setAttribute("offset",s);const l=new o(new Float32Array(4*n),4);if(l.setUsage(a.DynamicDrawUsage),i.setAttribute("particleColor",l),t.material instanceof c){const e=new a.Color(t.material.color);for(let t=0;t<l.count;t++)l.setXYZW(t,e.r,e.g,e.b,1)}const d=new o(new Float32Array(3*n),3);d.setUsage(a.DynamicDrawUsage),i.setAttribute("size",d);const m=new o(new Float32Array(4*n),4);m.setUsage(a.DynamicDrawUsage),i.setAttribute("velocity",m);const u=new o(new Float32Array(4*n),1);u.setUsage(a.DynamicDrawUsage),i.setAttribute("rotation",u),r={mesh:new a.Mesh(i,t.material),indices:new Float32Array(n),particles:[]},r.mesh.renderOrder=t.renderOrder,this.meshes.push(r),this.container.add(r.mesh)}let n=r.indices.findIndex(e=>0===e);n<0&&(n=function(e){let t=e[0],r=0;for(let a=1;a<e.length;a++)e[a]<t&&(t=e[a],r=a);return r}(r.indices)),r.indices[n]=performance.now(),e.target=n,r.particles[n]=e}}onParticleUpdate(e){}onParticleDead(e){const t=e.body;let r=this.meshes.find(e=>e.mesh.material.uuid===t.material.uuid);if(r){const t=r.mesh.geometry.getAttribute("size");t.setXYZ(e.target,0,0,0),t.needsUpdate=!0,r.particles[e.target]=null,r.indices[e.target]=0}e.target=null}}const p=new a.Vector3,f=new a.Vector3,g=new a.Quaternion,y=new a.Vector3(1,0,0),b=1e5;function w(e){return Number.isFinite(e)?Math.min(Math.max(Math.ceil(e),1),b):b}export class InstancedRenderer extends t{constructor(e,t,r){super(e,t),this.view=r,this.meshes=[]}dispose(){this.meshes.forEach(e=>{e.mesh.geometry.dispose(),e.mesh.dispose()})}onSystemUpdate(){for(const e of this.meshes)e.mesh.material.transparent&&e.mesh.material.blending===a.NormalBlending&&F(e,this.view.getCamera())}calcMaxCount(e){if(null==e)return 1;const t=e.parent.rate,r=t.timePan.a,a=t.numPan.b,o=e.parent.parentParticle;if(!Number.isFinite(r)||r<=0)return w(a*this.calcMaxCount(o));return w(a*Math.ceil(e.life/Math.min(Math.max(r,.01),1))*this.calcMaxCount(o))}onParticleCreated(e){if(e.body instanceof a.Sprite)return;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r){const o=this.calcMaxCount(e);r={mesh:new a.InstancedMesh(t.geometry,t.material,o),indices:new Array(o).fill(null),particles:[],sortOrder:new Array(o),sortDistances:new Float32Array(o),sortedMatrices:new Float32Array(16*o),sortedColors:new Float32Array(4*o),sortedParticleData:new Float32Array(3*o),sortedRotations:new Float32Array(o),sortedParticles:new Array(o),sortedIndices:new Array(o)},r.mesh.renderOrder=t.renderOrder,r.mesh.userData.webGpuCacheMaterial=!0;const n=new Float32Array(4*o);n.fill(1),r.mesh.instanceColor=new a.InstancedBufferAttribute(n,4),r.mesh.setColorAt(0,S.setScalar(1)),r.mesh.instanceColor.needsUpdate=!0,r.mesh.material.defines.USE_INSTANCING="",r.mesh.material.needsUpdate=!0;const i=new Float32Array(3*o);M.makeScale(0,0,0);for(let e=0;e<o;e++)i[3*e+0]=1,i[3*e+1]=1,i[3*e+2]=1,r.mesh.instanceMatrix.array.set(M.elements,16*e);r.mesh.instanceMatrix.needsUpdate=!0,r.mesh.geometry.setAttribute("particleData",new a.InstancedBufferAttribute(i,3));const s=new a.InstancedBufferAttribute(new Float32Array(o),1);s.setUsage(a.DynamicDrawUsage),r.mesh.geometry.setAttribute("rotation",s),this.meshes.push(r),this.container.add(r.mesh)}let o=r.indices.findIndex(e=>null==e);if(o<0&&(o=r.indices.indexOf(Math.min(...r.indices))),o<0||o>=r.mesh.instanceMatrix.count)return void(e.target=null);const n=r.particles[o];if(null!=n&&n!==e&&(n.target=null),r.indices[o]=performance.now(),e.target=o,r.particles[o]=e,r.mesh.count<=o&&(r.mesh.count=o+1),"number"==typeof e.target){e.transform.initialScale;const t=e.body;let r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);A(e,r.mesh),e.useAlpha&&(r.mesh.material.transparent||(r.mesh.material.transparent=!0,r.mesh.material.needsUpdate=!0))}}onParticleUpdate(e){const{target:t,useAlpha:r,useColor:a,rotation:o}=e;if(null==t)return;const n=e.body,i=this.meshes.find(e=>e.mesh.geometry.uuid===n.geometry.uuid&&e.mesh.material.uuid===n.material.uuid);if(null==i)return;if(!U(i,e))return void(e.target=null);if(i.mesh.frustumCulled=!1,A(e,i.mesh),a){S.copy(e.color);const t=i.mesh.instanceColor.array,r=e.target*i.mesh.instanceColor.itemSize;t[r+0]=S.r,t[r+1]=S.g,t[r+2]=S.b,i.mesh.instanceColor.itemSize>=4&&(t[r+3]=1),i.mesh.instanceColor.needsUpdate=!0}const s=i.mesh.geometry.getAttribute("particleData");r&&s.setX(e.target,e.alpha),s.setY(e.target,e.energy),s.needsUpdate=!0;const l=i.mesh.geometry.getAttribute("rotation");l.setX(e.target,o.z),l.needsUpdate=!0}onParticleDead(e){if(null!=e.target){const t=e.body,r=this.meshes.find(e=>e.mesh.geometry.uuid===t.geometry.uuid&&e.mesh.material.uuid===t.material.uuid);if(null==r)return;if(!U(r,e))return void(e.target=null);r.indices[e.target]=null,r.particles[e.target]=null,e.scale=0,A(e,r.mesh),r.mesh.instanceMatrix.needsUpdate=!0,e.target=null}}}const x=new n;function U(e,t){const r=t.target;return"number"==typeof r&&Number.isInteger(r)&&r>=0&&r<e.mesh.instanceMatrix.count&&e.particles[r]===t}function A(e,t){if(!Number.isInteger(e.target)||e.target<0||e.target>=t.instanceMatrix.count)return;if(v.set(e.position.x,e.position.y,e.position.z),e.transform&&e.transform.orientAlongVelocity){const r=p.set(e.position.x-e.old.position.x,e.position.y-e.old.position.y,e.position.z-e.old.position.z).normalize();t.getMatrixAt(e.target,x.matrix);const a=x.getWorldDirection(R);a.applyAxisAngle(y,Math.PI/-2),P.setFromUnitVectors(a,r)}else D.set(e.rotation.x,e.rotation.y,e.rotation.z),P.setFromEuler(D);const r=e.transform.initialScale;null!=r?R.set(r.x*e.scale,r.y*e.scale,r.z*e.scale):R.set(e.scale,e.scale,e.scale),M.compose(v,P,R),t.instanceMatrix.array.set(M.elements,16*e.target),t.instanceMatrix.needsUpdate=!0}const C=new a.Vector3(0,0,-1),M=new a.Matrix4,P=new a.Quaternion,v=new a.Vector3,R=new a.Vector3,D=new a.Euler,S=new a.Color(0),z={r:0,g:0,b:0};function F(e,t){const r=e.mesh,a=r.instanceMatrix.array,o=r.instanceColor.array,n=r.geometry.getAttribute("particleData"),i=n.array,s=r.geometry.getAttribute("rotation"),l=s.array,c=r.worldToLocal(t.getWorldPosition(I));let d=0;for(let t=0;t<e.particles.length;t++){if(null==e.particles[t])continue;const r=16*t,o=a[r+12]-c.x,n=a[r+13]-c.y,i=a[r+14]-c.z;e.sortDistances[t]=o*o+n*n+i*i,e.sortOrder[d++]=t}e.sortOrder.length=d,e.sortOrder.sort((t,r)=>e.sortDistances[r]-e.sortDistances[t]);for(let t=0;t<d;t++){const r=e.sortOrder[t];for(let o=0;o<16;o++)e.sortedMatrices[16*t+o]=a[16*r+o];for(let a=0;a<4;a++)e.sortedColors[4*t+a]=o[4*r+a];for(let a=0;a<3;a++)e.sortedParticleData[3*t+a]=i[3*r+a];e.sortedRotations[t]=l[r],e.sortedParticles[t]=e.particles[r],e.sortedIndices[t]=e.indices[r]}for(let t=0;t<d;t++){const r=e.sortedParticles[t];e.particles[t]=r,e.indices[t]=e.sortedIndices[t],l[t]=e.sortedRotations[t],r.target=t}for(let t=d;t<e.indices.length;t++)e.particles[t]=null,e.indices[t]=null;for(let t=0;t<16*d;t++)a[t]=e.sortedMatrices[t];for(let t=0;t<4*d;t++)o[t]=e.sortedColors[t];for(let t=0;t<3*d;t++)i[t]=e.sortedParticleData[t];r.count=d,r.instanceMatrix.needsUpdate=!0,r.instanceColor.needsUpdate=!0,n.needsUpdate=!0,s.needsUpdate=!0}export{F as sortInstancedMeshByDistance};const I=new a.Vector3;/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -12,6 +12,8 @@ export declare enum ActorLifetime {
12
12
  game = "game"
13
13
  }
14
14
  export type ActorOptions = {
15
+ /** Opt this class into persistence when an authored or explicit spawn identity exists. */
16
+ persistent?: boolean;
15
17
  /** Stable serialized identity. Defaults to the class name for backwards compatibility. */
16
18
  typeId?: string;
17
19
  /** Tabler icon name used by editor UI, for example `flag` or `camera`. */
@@ -33,6 +35,8 @@ export type ActorId = number;
33
35
  * An actor needs to inherit from the Base actor class to be able to be added to a scene.
34
36
  */
35
37
  export declare abstract class BaseActor {
38
+ /** Evaluated after authored parameters and initialization. Override for per-instance policy. */
39
+ get persistenceEnabled(): boolean;
36
40
  readonly id: ActorId;
37
41
  /**
38
42
  * The net role is used for networked games to understand what
@@ -1,4 +1,4 @@
1
- import{__decorate as t,__metadata as e}from"tslib";import o,{ignore as i}from"@plumier/reflect";import{Subject as r,skipWhile as n}from"rxjs";import{Group as s}from"three";import a,{Service as p}from"typedi";import{ActorComponent as c}from"./component.js";import{initComponentsSync as l}from"./internal/component-init.js";import{activeContainerInstance as m,containerRefMap as d}from"./internal/container-map.js";import{randomString as f}from"../../utils/math.js";import{inject as h}from"../inject.js";import{ViewController as u}from"../services/render.js";import{actorConstructContext as y}from"./factory.js";import{NetRole as g}from"../net/service/net-actor-role.js";import{registerActorClass as j}from"./type-registry.js";export{getActorClassById,getActorClassId,getRegisteredActorClasses}from"./type-registry.js";export const $actorOptions=Symbol("actor-options");export var ActorLifetime;!function(t){t.scene="scene",t.game="game"}(ActorLifetime||(ActorLifetime={}));export function getActorOptions(t){return t[$actorOptions]??b}const b={lifetime:ActorLifetime.scene,replicate:!1};export function Actor(t={}){const e=p({transient:!0});return function(i){const r=arguments[1],n=t.typeId??r?.name??i.name,s=j(n,i);null!=s&&s!==i&&console.warn(`Duplicate actor class name ${n}`),i.__actorId=n,i.__isActor=!0,e(i),o.noop()(i),o.parameterProperties()(i);const a=getActorOptions(Object.getPrototypeOf(i)),{typeId:p,...c}=a,l=null==c.relevancy&&null==t.relevancy?void 0:{...c.relevancy,...t.relevancy};i[$actorOptions]={...c,...t,...null==l?{}:{relevancy:l}}}}let U=0;export class BaseActor{get position(){return this.object?.position}get quaternion(){return this.object?.quaternion}get rotation(){return this.object?.rotation}onInit(){}onBeginPlay(){}onEndPlay(){}applySceneParameters(t,e){return!1}onUpdate(t){}onLateUpdate(t){}constructor(){this.id=++U,this.netRole=g.authority,this.__isInitialised=!1,this.object=new s,this.disposed=new r,this.attachedComponents=[],y.actor=this,this.onUpdate!==BaseActor.prototype.onUpdate&&h(u).onUpdate(this).pipe(n(()=>!this.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==BaseActor.prototype.onLateUpdate&&h(u).onLateUpdate(this).pipe(n(()=>!this.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}attach(t,e){const o=m.value,i=d.get(this)??m.value??a.of("default"),r=f(),n=y.actor;let s;try{m.value=i,y.actor=this,i.set({id:r,type:t,transient:!0}),s=i.get(r)}finally{y.actor=n,m.value=o}if(s.actor=this,null!=e)for(const t of Object.keys(e))s[t]=e[t];return this.__isInitialised&&(s.onInit(),l(s,this)),this.attachedComponents.push(s),s}getComponent(t){for(const e of Object.values(this))if(e instanceof t)return e;for(const e of this.attachedComponents)if(e instanceof t)return e}}t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"position",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"quaternion",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"rotation",null);export function _setupActorUpdateEventHandlers(){this.onUpdate!==c.prototype.onUpdate&&h(u).onUpdate(this.actor).pipe(n(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==c.prototype.onLateUpdate&&h(u).onLateUpdate(this.actor).pipe(n(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}/*
1
+ import{__decorate as t,__metadata as e}from"tslib";import o,{ignore as i}from"@plumier/reflect";import{Subject as r,skipWhile as n}from"rxjs";import{Group as s}from"three";import a,{Service as p}from"typedi";import{ActorComponent as c}from"./component.js";import{initComponentsSync as l}from"./internal/component-init.js";import{activeContainerInstance as m,containerRefMap as d}from"./internal/container-map.js";import{randomString as u}from"../../utils/math.js";import{inject as h}from"../inject.js";import{ViewController as f}from"../services/render.js";import{actorConstructContext as y}from"./factory.js";import{NetRole as g}from"../net/service/net-actor-role.js";import{registerActorClass as j}from"./type-registry.js";export{getActorClassById,getActorClassId,getRegisteredActorClasses}from"./type-registry.js";export const $actorOptions=Symbol("actor-options");export var ActorLifetime;!function(t){t.scene="scene",t.game="game"}(ActorLifetime||(ActorLifetime={}));export function getActorOptions(t){return t[$actorOptions]??b}const b={lifetime:ActorLifetime.scene,replicate:!1};export function Actor(t={}){const e=p({transient:!0});return function(i){const r=arguments[1],n=t.typeId??r?.name??i.name,s=j(n,i);null!=s&&s!==i&&console.warn(`Duplicate actor class name ${n}`),i.__actorId=n,i.__isActor=!0,e(i),o.noop()(i),o.parameterProperties()(i);const a=getActorOptions(Object.getPrototypeOf(i)),{typeId:p,...c}=a,l=null==c.relevancy&&null==t.relevancy?void 0:{...c.relevancy,...t.relevancy};i[$actorOptions]={...c,...t,...null==l?{}:{relevancy:l}}}}let A=0;export class BaseActor{get persistenceEnabled(){return!0===getActorOptions(this.constructor).persistent}get position(){return this.object?.position}get quaternion(){return this.object?.quaternion}get rotation(){return this.object?.rotation}onInit(){}onBeginPlay(){}onEndPlay(){}applySceneParameters(t,e){return!1}onUpdate(t){}onLateUpdate(t){}constructor(){this.id=++A,this.netRole=g.authority,this.__isInitialised=!1,this.object=new s,this.disposed=new r,this.attachedComponents=[],y.actor=this,this.onUpdate!==BaseActor.prototype.onUpdate&&h(f).onUpdate(this).pipe(n(()=>!this.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==BaseActor.prototype.onLateUpdate&&h(f).onLateUpdate(this).pipe(n(()=>!this.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}attach(t,e){const o=m.value,i=d.get(this)??m.value??a.of("default"),r=u(),n=y.actor;let s;try{m.value=i,y.actor=this,i.set({id:r,type:t,transient:!0}),s=i.get(r)}finally{y.actor=n,m.value=o}if(s.actor=this,null!=e)for(const t of Object.keys(e))s[t]=e[t];return this.__isInitialised&&(s.onInit(),l(s,this)),this.attachedComponents.push(s),s}getComponent(t){for(const e of Object.values(this))if(e instanceof t)return e;for(const e of this.attachedComponents)if(e instanceof t)return e}}t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"position",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"quaternion",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"rotation",null);export function _setupActorUpdateEventHandlers(){this.onUpdate!==c.prototype.onUpdate&&h(f).onUpdate(this.actor).pipe(n(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==c.prototype.onLateUpdate&&h(f).onLateUpdate(this.actor).pipe(n(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */