@hology/core 0.0.258 → 0.0.259

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.
@@ -23,7 +23,7 @@ export type GpuSpriteCompileResult = {
23
23
  unsupported: string[];
24
24
  };
25
25
  export type GpuSpriteCompatibilityIssue = {
26
- severity: 'warning' | 'error';
26
+ severity: 'warning' | 'requirement' | 'error';
27
27
  code: string;
28
28
  emitter: string;
29
29
  message: string;
@@ -55,4 +55,6 @@ export declare function materializeGpuSpriteRenderClasses(sources: readonly GpuS
55
55
  renderClasses: GpuSpriteRenderClass[];
56
56
  unsupported: string[];
57
57
  }>;
58
+ /** Whether authored behavior semantics intentionally require CPU simulation. */
59
+ export declare function requiresCpuVfxBackend(asset: VfxAsset): boolean;
58
60
  //# sourceMappingURL=gpu-sprite-compiler.d.ts.map
@@ -1,4 +1,4 @@
1
- import*as e from"three";import{applyMeshWorldTransformToGeometry as t}from"./vfx-mesh-transform.js";import{attributes as a,clamp as r,lambertMaterial as s,NodeShaderMaterial as o,rgba as n,smoothstep as i,textureSampler2d as l,varyingAttributes as p}from"three-shader-graph";import{SerializedParamType as c}from"../../scene/model.js";import{particleUniforms as u}from"../../shader-nodes/particle.js";import{sampleFlipbook as m}from"../../shader-nodes/texture-sequence.js";import{fragmentLinearEyeDepth as d,linearEyeDepth as h}from"../../shader-nodes/depth.js";import{ThreeBlendingMode as y}from"./vfx-asset.js";import{getDefaultVfxSpriteTexture as f}from"./vfx-default-sprite-texture.js";import{ShapeLibrary as b}from"../../scene/objects/shapes.js";export class GpuSpriteRenderClassCache{constructor(){this.entries=new Map}resolve(e,t){let a=this.entries.get(e);return null==a&&(a=t().catch(t=>{throw this.entries.delete(e),t}),this.entries.set(e,a)),a}clear(){this.entries.clear()}}export function hasGpuUnsupportedVfxInputBindings(e){const t=new Map((e.vfx.inputs??[]).map(e=>[e.id,e.type])),a=e=>{for(const a of[...e.initializers,...e.behaviours])if(!1!==a.enabled)for(const[r,s]of Object.entries(a.params)){if("vfxInput"!==s?.binding?.type)continue;const o=s.type===c.Number?"number":s.type===c.Vector3?"vec3":s.type===c.Color?"color":s.type===c.Object3D?"mesh":void 0;if(null==o||t.get(s.binding.inputId)!==o)return!0;if("lifetime"===a.type&&"duration"===r&&"continuous"===e.rate.type)return!0}return(e.children??[]).some(a)};return e.vfx.emitters.some(a)}export function selectVfxBackend(e,t="auto"){if("cpu"===t)return{backend:"cpu",reasons:["CPU backend explicitly requested"]};const a=e.issues.filter(e=>"error"===e.severity).map(e=>e.message);return a.length>0&&"gpu"!==t?{backend:"cpu",reasons:a}:a.length>0?{backend:"gpu",reasons:["GPU backend explicitly forced despite incompatibilities",...a]}:{backend:"gpu",reasons:e.issues.filter(e=>"warning"===e.severity).map(e=>e.message)}}export function compileGpuSpriteEmitters(t,a,r="emitter-major"){const s=[],o=[],n=new Map,i=[],l=[],p=new Map((t.vfx.inputs??[]).map(e=>[e.id,e.type])),u=new Map((t.vfx.inputs??[]).filter(e=>"number"===e.type).map(e=>[e.id,"number"==typeof e.defaultValue?e.defaultValue:0]));hasGpuUnsupportedVfxInputBindings(t)&&i.push({severity:"error",code:"vfx-input-binding",emitter:"effect",message:"this VFX input binding target is not supported on GPU yet"});const m=t.vfx.emitters.slice().sort((e,t)=>(e.output.renderOrder??0)-(t.output.renderOrder??0)),d=(t,r,m)=>{const h="vfxInput"===t.rate.delayBinding?.type?u.get(t.rate.delayBinding.inputId):void 0,y=null==h?t:{...t,rate:{...t.rate,delay:Math.max(0,h)}};if("sprite"!==t.output.type&&"mesh"!==t.output.type&&"stretchedSprite"!==t.output.type&&"decal"!==t.output.type&&"shape"!==t.output.type&&"trail"!==t.output.type)return void w(i,t,"error","output-type","this output type is not supported by the GPU sprite backend");if("mesh"===t.output.type&&null==t.output.assetId)return;if(t.rate.count<=0)return;const f="trail"===(b=t.output).type?JSON.stringify(b):"mesh"===b.type?JSON.stringify({type:b.type,assetId:b.assetId,renderOrder:b.renderOrder??0,useLegacyTransform:!0===b.useLegacyTransform,materialSource:b.materialSource??null,material:b.material??null,shader:b.shader??null,shaderParams:b.shaderParams??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space}):"decal"===b.type?JSON.stringify({type:b.type,colorMap:b.colorMap,alphaMap:b.alphaMap,color:b.color,unlit:b.unlit,intensity:b.intensity,opacityChannel:b.opacityChannel??"red",blendingMode:b.blendingMode,renderOrder:b.renderOrder??0,materialSource:b.materialSource??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space}):"shape"===b.type?JSON.stringify({type:b.type,shape:b.shape,params:b.params,material:b.material,renderOrder:b.renderOrder??0,materialSource:b.materialSource??null,shader:b.shader??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space}):JSON.stringify({type:b.type,texture:b.texture,opacityChannel:b.opacityChannel??"red",blendingMode:b.blendingMode,softness:b.softness,renderOrder:b.renderOrder??0,bloom:b.bloom,materialSource:b.materialSource??null,shader:b.shader??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space,lockY:"sprite"===b.type&&!0===b.lockY,stretchScale:"stretchedSprite"===b.type?b.scale:null});var b;let x=n.get(f);null==x&&(x=o.length,n.set(f,x),o.push({key:f,output:t.output}));const v=[];for(let o=0;o<a.length;o++){const n=g(y,null==r?a[o]:new e.Vector3,x,i);if(null!=n){if(null!=r){const e=s[r]?.instances[o];if(null==e)continue;const a=n.capacity,l=e.capacity*a;if(l>25e4){w(i,t,"error","child-particle-capacity",`child emitter expansion requires ${l} particles, exceeding the GPU per-emitter limit`);continue}n.capacity=l,n.parentEmitter=r,n.childParticlesPerParent=a,n.childSpawnEvent="collision"===t.spawnEvent?2:1,n.childLevel=m,!0===n.localSpace&&!0!==e.localSpace&&w(i,t,"error","child-emitter-local-space","GPU child emitters do not yet support a world-space parent with local-space child output"),"trail"===t.output.type&&w(i,t,"error","child-emitter-trail","GPU child emitters do not yet support trail output")}v.push(n)}}if(v.length>0){const e=s.length;s.push({instances:v,parentSource:r});for(const a of[...t.initializers,...t.behaviours])if(!1!==a.enabled)for(const[r,s]of Object.entries(a.params)){const o=s?.binding;if("vfxInput"!==o?.type)continue;const n=s.type===c.Number?"number":s.type===c.Vector3?"vec3":s.type===c.Color?"color":s.type===c.Object3D?"mesh":void 0;null!=n&&p.get(o.inputId)===n&&("mesh"!==n&&("lifetime"===a.type&&"duration"===r&&"continuous"===t.rate.type||l.push({inputId:o.inputId,emitterIndex:e,target:`${t.initializers.includes(a)?"initializer":"behaviour"}:${a.type}:${r}`,authoredScalar:"number"==typeof s.value?s.value:void 0,baseScaleStart:[...v[0].scaleStart],baseScaleEnd:[...v[0].scaleEnd]})))}for(const a of t.children??[])d(a,e,m+1)}};for(const e of m)d(e,null,0);const h="instance-major"===r?a.flatMap((e,t)=>s.flatMap(e=>null==e.instances[t]?[]:[e.instances[t]])):s.flatMap(e=>e.instances);for(let e=0;e<s.length;e++){const t=s[e];if(null!=t.parentSource)for(let e=0;e<t.instances.length;e++)t.instances[e].parentEmitter="instance-major"===r?e*s.length+t.parentSource:t.parentSource*a.length+e}const y=o.map((e,t)=>({renderClass:e,oldIndex:t})).sort((e,t)=>(e.renderClass.output.renderOrder??0)-(t.renderClass.output.renderOrder??0)),f=new Array(o.length);for(let e=0;e<y.length;e++)f[y[e].oldIndex]=e;for(const e of h)e.renderClass=f[e.renderClass??0]??0;const b={compatible:!i.some(e=>"error"===e.severity),issues:i};return{emitters:h,inputBindings:l,renderClasses:y.map(e=>e.renderClass),compatibility:b,unsupported:[...new Set(i.map(e=>`${e.emitter}: ${e.message}`))]}}export async function materializeGpuSpriteRenderClasses(c,g,w,x){const v=async c=>{const x=c.output;if("trail"===x.type){const t=x.materialSource??("asset"===x.shaderGraph?.source?"shaderGraph":"default"),a="default"===t?null:await(w?.(x))??null;if(null==a&&"default"!==t)throw new Error(`${t} trail material requires a compatible GPU material resolver`);return{texture:null!=x.texture?await g.getTexture(x.texture):f(),material:a??void 0,localSpace:"local"===x.space,trail:{historyLength:Math.max(2,Math.round(x.length)+1),width:x.width??1,taper:x.taper,colorStart:new e.Color(x.color).multiplyScalar(x.intensity),colorEnd:new e.Color(x.colorEnd).multiplyScalar(x.intensityEnd),opacityStart:x.opacityStart,opacityEnd:x.opacityEnd,scrollSpeed:x.scrollSpeed??0,opacityChannel:x.opacityChannel??"red",blendingMode:x.blendingMode??"normal",billboard:x.billboard??!1}}}if("mesh"===x.type){if(null==g.getMesh)throw new Error("GPU mesh particles require a mesh asset provider");const a=await g.getMesh(x.assetId);a.updateWorldMatrix(!0,!0);const r=[];if(a.traverse(t=>{t instanceof e.Mesh&&r.push(t)}),1!==r.length)throw new Error(`GPU mesh particles require exactly one mesh geometry; asset ${x.assetId} resolved to ${r.length}`);const s=null==r[0].geometry.index?r[0].geometry.clone():r[0].geometry.toNonIndexed();!0!==x.useLegacyTransform&&t(r[0],s);const n=s.getAttribute("position");if(null==n)throw new Error(`GPU mesh particle asset ${x.assetId} has no position attribute`);const i=s.getAttribute("normal"),l=s.getAttribute("uv"),p=new Float32Array(8*n.count);for(let e=0;e<n.count;e++){const t=8*e;p[t]=n.getX(e),p[t+1]=n.getY(e),p[t+2]=n.getZ(e),p[t+3]=i?.getX(e)??0,p[t+4]=i?.getY(e)??1,p[t+5]=i?.getZ(e)??0,p[t+6]=l?.getX(e)??0,p[t+7]=l?.getY(e)??0}s.dispose();const c=Array.isArray(r[0].material)?r[0].material[0]:r[0].material,m="material"===x.materialSource&&null==x.material||"shaderGraph"===x.materialSource&&("asset"!==x.shaderGraph?.source||null==x.shaderGraph.assetId)||"shader"===x.materialSource&&null==x.shader?"default":x.materialSource??("asset"===x.shaderGraph?.source?"shaderGraph":null!=x.shader?"shader":null!=x.material?"material":"default"),d="default"===m?await(w?.(x))??function(){const e=u.opacity;return new o({color:u.color.rgb.rgba(e),opacity:e,transparent:!0})}():await(w?.(x))??null;if(null==d&&"default"!==m)throw new Error(`${m} mesh material requires a compatible GPU material resolver`);const h=null!=c&&"color"in c&&c.color instanceof e.Color?c.color.clone():new e.Color(16777215);return{texture:f(),meshVertices:p,meshColor:h,meshOpacity:c?.opacity??1,localSpace:"local"===x.space,material:d??void 0}}if("decal"===x.type){const t=await(w?.(x))??null;if(null==t)throw new Error("GPU decal output requires a compatible GPU decal material resolver");const a=new e.BoxGeometry(1,1,1).toNonIndexed(),r=a.getAttribute("position"),s=a.getAttribute("normal"),o=a.getAttribute("uv"),n=new Float32Array(8*r.count);for(let e=0;e<r.count;e++){const t=8*e;n[t]=r.getX(e),n[t+1]=r.getY(e),n[t+2]=r.getZ(e),n[t+3]=s.getX(e),n[t+4]=s.getY(e),n[t+5]=s.getZ(e),n[t+6]=o.getX(e),n[t+7]=o.getY(e)}return a.dispose(),{texture:f(),meshVertices:n,meshColor:new e.Color(16777215),meshOpacity:1,localSpace:"local"===x.space,material:t}}if("shape"===x.type){const t=b[x.shape];if(null==t)throw new Error(`GPU shape output has unknown shape ${x.shape}`);const a=x.materialSource??("asset"===x.shaderGraph?.source?"shaderGraph":null!=x.shader?"shader":null!=x.material?"material":"default"),r="default"===a?function(){const e=u.opacity;return new o({color:s({color:u.color.rgb}).rgb.rgba(e),opacity:e,transparent:!0})}():await(w?.(x))??null;if(null==r&&"default"!==a)throw new Error(`${a} shape material requires a compatible GPU material resolver`);const n=Object.fromEntries(Object.entries(x.params??{}).map(([e,t])=>[e,t.value])),i=t.geometry(n),l=null==i.index?i:i.toNonIndexed(),p=l.getAttribute("position"),c=l.getAttribute("normal"),m=l.getAttribute("uv"),d=new Float32Array(8*p.count);for(let e=0;e<p.count;e++){const t=8*e;d[t]=p.getX(e),d[t+1]=p.getY(e),d[t+2]=p.getZ(e),d[t+3]=c?.getX(e)??0,d[t+4]=c?.getY(e)??1,d[t+5]=c?.getZ(e)??0,d[t+6]=m?.getX(e)??0,d[t+7]=m?.getY(e)??0}return l!==i&&l.dispose(),i.dispose(),{texture:f(),meshVertices:d,meshColor:new e.Color(16777215),meshOpacity:1,localSpace:"local"===x.space,material:r??void 0}}const v=null!=x.texture?await g.getTexture(x.texture):f(),S="stretchedSprite"===x.type?"default":x.materialSource??("asset"===x.shaderGraph?.source?"shaderGraph":"default");let M="default"===S?null:await(w?.(x))??null;if(null==M&&"default"!==S)throw new Error(`${S} material requires a compatible GPU material resolver`);return M??(M=function(t,s){const c=l(s),f="sprite"===t.type&&!0===t.flipbook?.enabled?m(c,a.uv,t.flipbook.columns,t.flipbook.rows,u.time,t.flipbook.fps,t.flipbook.mode):c.sample(p.uv);let b=u.opacity;"red"===(t.opacityChannel??"red")?b=b.multiply(f.r):"alpha"===t.opacityChannel&&(b=b.multiply(f.a));if(t.softness>0){const e=h.subtract(d).divide(h);b=b.multiply(i(0,.2*t.softness,r(e,0,1e3)))}const g=new o({color:n(u.color.multiply(f.rgb),b),transparent:!0,lights:!1,fog:!1,alphaTest:1e-4});return g.blending=y[t.blendingMode]??e.NormalBlending,g.depthWrite=!1,g}(x,v)),M.transparent&&(M.depthWrite=!1),{texture:v,material:M,lockY:"sprite"===x.type&&!0===x.lockY,localSpace:"local"===x.space,stretchScale:"stretchedSprite"===x.type?0===x.scale?.001:x.scale:void 0}};return{renderClasses:await Promise.all(c.map(e=>x?.resolve(e.key,()=>v(e))??v(e))),unsupported:[]}}function g(t,a,r,s){if("sprite"!==t.output.type&&"mesh"!==t.output.type&&"decal"!==t.output.type&&"shape"!==t.output.type&&"trail"!==t.output.type&&"stretchedSprite"!==t.output.type)return null;const o="mesh"===t.output.type||"decal"===t.output.type||"shape"===t.output.type;let n=99999,i=99999,l=0,p=0;const c=new e.Vector4,u=new e.Vector4,m=new e.Vector3,d=new e.Vector3,h=new e.Vector3;let y=0,f=1;const b=new e.Vector3;let g=0,k=0,G=!1,V=0,C=!1;const I=new e.Vector3;let P,O=0,E=!1,U=!1,A=0,R=0,N=0,B=!1,T=[1,1],z=1,$=1,j=new e.Color("sprite"===t.output.type||"stretchedSprite"===t.output.type?t.output.color:"#ffffff"),F=j.clone(),Y=!1,X=1,Z=1,D=0,q=0;const L=new e.Quaternion,Q=new e.Vector3,J=new e.Vector3;let W=0;const H=new e.Vector3(0,1,0);let K=0,_=0,ee=!1;const te=new e.Vector3;let ae=0,re=0,se=!1;const oe=new e.Vector3(0,1,0);let ne=0;const ie=new e.Vector3,le=new e.Vector3,pe=new e.Vector3(0,1,0);let ce=0,ue=!1,me=0,de=0,he=0,ye=!1;const fe=new e.Vector4(0,0,0,0),be=new e.Vector3(1,1,1),ge=new e.Vector3(1,1,1),we=new e.Vector3(1,1,1);let xe,ve,Se,Me,ke,Ge="surface";for(const a of t.initializers.filter(e=>!1!==e.enabled))switch(a.type){case"lifetime":i=n=x(a.params.duration,1);break;case"randomLifetime":{const e=x(a.params.minDuration,1),t=x(a.params.maxDuration,2);i=Math.min(e,t),n=Math.max(e,t);break}case"velocity":{const e=S(a.params.velocity);m.copy(e),d.copy(e);break}case"randomVelocity":m.copy(S(a.params.min)),d.copy(S(a.params.max));break;case"randomDirection":{const e=x(a.params.speed,1);m.setScalar(-e),d.setScalar(e);break}case"radialVelocity":H.copy(S(a.params.direction)).normalize(),K=x(a.params.speed,1),_=e.MathUtils.degToRad(x(a.params.spread,0)),ee=!0;break;case"mass":f=Math.max(1e-6,x(a.params.min,1));break;case"positionPoint":c.copy(new e.Vector4(...S(a.params.position).toArray(),0));break;case"positionSphere":{l=x(a.params.radius,1);const e=S(a.params.position);p=1,c.set(e.x,e.y,e.z,!0===a.params.surface?.value?1:0);break}case"positionBox":{const e=S(a.params.position),t=S(a.params.dimensions);p=2,c.set(e.x,e.y,e.z,0),u.set(t.x,t.y,t.z,0);break}case"positionLine":{const e=S(a.params.a),t=S(a.params.b);p=3,c.set(e.x,e.y,e.z,0),u.set(t.x,t.y,t.z,0);break}case"positionCircle":case"positionRing":{const t=S(a.params.position),r=S(a.params.rotation).multiplyScalar(Math.PI/180);l=x(a.params.radius,1);const s="positionRing"===a.type?Math.max(x(a.params.thickness,.2),1e-4):0;p=4,c.set(t.x,t.y,t.z,s),u.set(r.x,r.y,r.z,e.MathUtils.degToRad(Math.max(0,Math.min(360,x(a.params.angle,360)))));break}case"positionMesh":{const r=a.params.mesh?.value,o=a.params.mesh?.binding;if("vfxInput"===o?.type&&(ve=o.inputId),("string"!=typeof r||0===r.length)&&null==ve){w(s,t,"error","mesh-sampler-source","GPU mesh sampling requires a selected fallback mesh asset");break}if(xe="string"==typeof r&&r.length>0?r:void 0,Ge="vertices"===a.params.sampling?.value?"vertices":"surface",Se=(new e.Matrix4).compose(S(a.params.position),(new e.Quaternion).setFromEuler((new e.Euler).setFromVector3(S(a.params.rotation).multiplyScalar(Math.PI/180))),null==a.params.scale?new e.Vector3(1,1,1):S(a.params.scale)),!0===a.params.alignNormal?.value){const t=a.params.alignmentAxis?.value;Me="+X"===t?new e.Vector3(1,0,0):"-X"===t?new e.Vector3(-1,0,0):"-Y"===t?new e.Vector3(0,-1,0):"+Z"===t?new e.Vector3(0,0,1):"-Z"===t?new e.Vector3(0,0,-1):new e.Vector3(0,1,0)}!0===a.params.normalVelocity?.value&&(ke=new e.Vector4(x(a.params.normalVelocityMin,1),x(a.params.normalVelocityMax,1),e.MathUtils.degToRad(e.MathUtils.clamp(x(a.params.normalVelocitySpread,0),0,180)),1)),p=5;break}case"scale":{const e=x(a.params.scale,1);T=[e,e];break}case"scaleComponents":be.copy(S(a.params.scale));break;case"randomScale":T=[x(a.params.min,1),x(a.params.max,1)];break;case"randomColor":j=M(a.params.a,j),F=M(a.params.b,j),Y=!0;break;case"rotation":{const t=S(a.params.rotation);D=q=e.MathUtils.degToRad(t.z),Q.set(e.MathUtils.degToRad(t.x),e.MathUtils.degToRad(t.y),e.MathUtils.degToRad(t.z)),L.setFromEuler(new e.Euler(Q.x,Q.y,Q.z));break}case"randomRotation":{if(o){const e=a.params.axis?.value;W="X"===e?2:"Y"===e?3:"Z"===e?4:1;break}const e=a.params.axis?.value;"XYZ"!==e&&"Z"!==e&&null!=e||(q=2*Math.PI);break}case"alignRotation":{if(!o)break;const e=a.params.axis?.value;"+X"===e?oe.set(1,0,0):"-X"===e?oe.set(-1,0,0):"-Y"===e?oe.set(0,-1,0):"+Z"===e?oe.set(0,0,1):"-Z"===e?oe.set(0,0,-1):oe.set(0,1,0);const t=a.params.mode?.value;ne="TowardsCenter"===t?2:"AlongVelocity"===t?3:1,ie.copy(S(a.params.center)),le.copy(S(a.params.offset)).multiplyScalar(Math.PI/180);break}default:w(s,t,"error",`initializer:${a.type}`,`initializer ${a.type} is not supported on GPU`)}for(const e of t.behaviours.filter(e=>!1!==e.enabled))switch(e.type){case"force":h.add(S(e.params.force));break;case"gravity":h.y-=x(e.params.gravity,8);break;case"linearDamping":y+=x(e.params.factor,.1);break;case"randomDrift":b.copy(S(e.params.drift)),g=Math.max(0,x(e.params.delay,0)),k=v(e.params.ease?.value),G=!0;break;case"followParent":V=x(e.params.speed,0),C=!0;break;case"moveTo":I.copy(S(e.params.target)),O=v(e.params.ease?.value),E=!0;break;case"attraction":case"repulsion":if(se){w(s,t,"error","multiple-attraction-behaviours","multiple attraction or repulsion behaviours are not supported in one GPU emitter");break}te.copy(S(e.params.target)),ae=x(e.params.force,1)*("repulsion"===e.type?-1:1),re=Math.max(0,x(e.params.radius,1)),se=!0;break;case"vortex":if(ue){w(s,t,"error","multiple-vortex-behaviours","multiple vortex behaviours are not supported in one GPU emitter");break}pe.copy(S(e.params.axis)),ce=x(e.params.amount,1),ue=!0;break;case"disperse":{if(ye){w(s,t,"error","multiple-disperse-behaviours","multiple disperse behaviours are not supported in one GPU emitter");break}me=x(e.params.distance,1);const a=e.params.axis?.value;de="XY"===a?1:"XZ"===a?2:"YZ"===a?3:0,he=v(e.params.ease?.value),ye=!0;break}case"worldCollision":U=!0,A=Math.max(0,x(e.params.bounce,0)),R=Math.max(0,Math.min(1,x(e.params.friction,0))),N=Math.max(0,x(e.params.lifeLoss,0)),B=!0===e.params.debug?.value;break;case"scale":z=x(e.params.a,1),$=x(e.params.b,1),fe.x=v(e.params.ease?.value);break;case"scaleComponents":ge.copy(be).multiply(S(e.params.a)),we.copy(be).multiply(S(e.params.b)),fe.w=v(e.params.ease?.value);break;case"changeColor":j=M(e.params.a,j),F=M(e.params.b,F),fe.y=v(e.params.ease?.value),Y=!1;break;case"changeOpacity":X=x(e.params.a,1),Z=x(e.params.b,0),fe.z=v(e.params.ease?.value);break;case"rotate":case"rotateAdd":{const t=S(e.params.rotation);t.multiplyScalar(Math.PI/180*Math.PI/180),o?J.add(t):P=(P??0)+t.z;break}default:w(s,t,"error",`behaviour:${e.type}`,`behaviour ${e.type} is not supported on GPU`)}const Ve=Math.max(0,Math.floor(t.rate.count)),Ce="sprite"!==t.output.type&&"stretchedSprite"!==t.output.type||!Number.isFinite(t.output.intensity)?1:t.output.intensity;j.multiplyScalar(Ce),F.multiplyScalar(Ce);const Ie="once"===t.rate.type?Ve:Math.max(Ve,Math.ceil(n/Math.max(t.rate.time,1e-4))*Ve),Pe=Math.min(25e4,Ie);return Pe!==Ie&&w(s,t,"warning","particle-capacity-clamped",`particle capacity ${Ie} exceeds the current GPU per-emitter limit of ${Pe}`),t.behaviours.some(e=>!1!==e.enabled&&"scaleComponents"===e.type)||(ge.copy(be),we.copy(be)),U&&"local"===t.output.space&&w(s,t,"error","world-collision-local-space","GPU screen-space world collision currently requires world-space output"),{position:(new e.Vector3).fromArray(t.position).add("local"===t.output.space?new e.Vector3:a),localSpace:"local"===t.output.space,capacity:Pe,rate:"once"===t.rate.type?{type:"once",count:Ve,delay:Math.max(0,t.rate.delay??0)}:{type:"continuous",count:Ve,interval:Math.max(t.rate.time,1e-4),delay:Math.max(0,t.rate.delay??0),duration:(t.rate.duration??0)>0?t.rate.duration:-1},life:n,lifeMin:i,positionRadius:l,spawnZoneType:p,spawnZoneA:c,spawnZoneB:u,meshSamplerAssetId:xe,meshSamplerInputId:ve,meshSamplerMode:Ge,meshSamplerTransform:Se,meshSamplerAlignAxis:Me,meshNormalVelocity:ke,velocityMin:m,velocityMax:d,force:h,damping:y,mass:f,randomDrift:b,randomDriftDelay:g,randomDriftEasing:k,hasRandomDrift:G,followParentSpeed:V,hasFollowParent:C,moveToTarget:I,moveToEasing:O,hasMoveTo:E,hasWorldCollision:U,collisionBounce:A,collisionFriction:R,collisionLifeLoss:N,collisionDebug:B,orientAlongVelocity:!1,scaleStart:[T[0]*z,T[1]*z],scaleEnd:[T[0]*$,T[1]*$],colorStart:j,colorEnd:F,randomColor:Y,alphaStart:X,alphaEnd:Z,rotationMin:D,rotationMax:q,spriteRotationStep:P,meshRotation:L,meshRotationEuler:Q,meshRotationStep:J,randomMeshRotationAxis:W,radialVelocityDirection:H,radialVelocitySpeed:K,radialVelocitySpread:_,hasRadialVelocity:ee,attractionTarget:te,attractionForce:ae,attractionRadius:re,hasAttraction:se,alignRotationAxis:oe,alignRotationMode:ne,alignRotationCenter:ie,alignRotationOffset:le,vortexAxis:pe,vortexAmount:ce,hasVortex:ue,disperseDistance:me,dispersePlane:de,disperseEasing:he,hasDisperse:ye,curveEasing:fe,meshScaleStart:ge,meshScaleEnd:we,renderClass:r}}function w(e,t,a,r,s){e.some(e=>e.emitter===t.name&&e.code===r)||e.push({severity:a,code:r,emitter:t.name||t.id,message:s})}function x(e,t){const a=e?.value;if("number"==typeof a)return Number.isFinite(a)?a:t;if("string"==typeof a&&""!==a.trim()){const e=Number(a);if(Number.isFinite(e))return e}return t}function v(e){switch(e){case"InQuad":return 1;case"OutQuad":return 2;case"InOutQuad":return 3;case"InCubic":return 4;case"OutCubic":return 5;case"InOutCubic":return 6;case"InQuart":return 7;case"OutQuart":return 8;case"InOutQuart":return 9;case"InSine":return 10;case"OutSine":return 11;case"InOutSine":return 12;case"InExpo":return 13;case"OutExpo":return 14;case"InOutExpo":return 15;case"InCirc":return 16;case"InBack":return 17;case"OutBack":return 18;case"Bump":return 19;case"BumpSharp":return 20;case"BumpFlat":return 21;case"SpikeFade":return 22;case"OutCirc":return 23;case"InOutCirc":return 24;case"InOutBack":return 25;case"BumpFade":return 26;case"BumpFall":return 27;default:return 0}}function S(t){const a=t?.value;return Array.isArray(a)?new e.Vector3(Number(a[0]),Number(a[1]),Number(a[2])):new e.Vector3}function M(t,a){const r=t?.value;if("string"==typeof r){if(null!=/^#([A-Fa-f0-9]{6})$/.exec(r))return new e.Color(r);const t=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/.exec(r);if(null!=t)return(new e.Color).setRGB(Math.min(255,Number.parseInt(t[1],10))/255,Math.min(255,Number.parseInt(t[2],10))/255,Math.min(255,Number.parseInt(t[3],10))/255,e.SRGBColorSpace)}if("number"==typeof r&&Number.isFinite(r))return new e.Color(Math.floor(r));if(null!=r&&"object"==typeof r&&"r"in r&&"g"in r&&"b"in r){const t=r;return(new e.Color).setRGB(t.r,t.g,t.b)}return a.clone()}/*
1
+ import*as e from"three";import{applyMeshWorldTransformToGeometry as t}from"./vfx-mesh-transform.js";import{attributes as a,clamp as r,lambertMaterial as s,NodeShaderMaterial as o,rgba as n,smoothstep as i,textureSampler2d as l,varyingAttributes as c}from"three-shader-graph";import{SerializedParamType as p}from"../../scene/model.js";import{particleUniforms as u}from"../../shader-nodes/particle.js";import{sampleFlipbook as m}from"../../shader-nodes/texture-sequence.js";import{fragmentLinearEyeDepth as d,linearEyeDepth as h}from"../../shader-nodes/depth.js";import{ThreeBlendingMode as y,WorldCollisionMethod as f}from"./vfx-asset.js";import{getDefaultVfxSpriteTexture as b}from"./vfx-default-sprite-texture.js";import{ShapeLibrary as g}from"../../scene/objects/shapes.js";export class GpuSpriteRenderClassCache{constructor(){this.entries=new Map}resolve(e,t){let a=this.entries.get(e);return null==a&&(a=t().catch(t=>{throw this.entries.delete(e),t}),this.entries.set(e,a)),a}clear(){this.entries.clear()}}export function hasGpuUnsupportedVfxInputBindings(e){const t=new Map((e.vfx.inputs??[]).map(e=>[e.id,e.type])),a=e=>{for(const a of[...e.initializers,...e.behaviours])if(!1!==a.enabled)for(const[r,s]of Object.entries(a.params)){if("vfxInput"!==s?.binding?.type)continue;const o=s.type===p.Number?"number":s.type===p.Vector3?"vec3":s.type===p.Color?"color":s.type===p.Object3D?"mesh":void 0;if(null==o||t.get(s.binding.inputId)!==o)return!0;if("lifetime"===a.type&&"duration"===r&&"continuous"===e.rate.type)return!0}return(e.children??[]).some(a)};return e.vfx.emitters.some(a)}export function selectVfxBackend(e,t="auto"){if("cpu"===t)return{backend:"cpu",reasons:["CPU backend explicitly requested"]};const a=e.issues.filter(e=>"requirement"===e.severity).map(e=>e.message);if(a.length>0)return{backend:"cpu",reasons:a};const r=e.issues.filter(e=>"error"===e.severity).map(e=>e.message);return r.length>0&&"gpu"!==t?{backend:"cpu",reasons:r}:r.length>0?{backend:"gpu",reasons:["GPU backend explicitly forced despite incompatibilities",...r]}:{backend:"gpu",reasons:e.issues.filter(e=>"warning"===e.severity).map(e=>e.message)}}export function compileGpuSpriteEmitters(t,a,r="emitter-major"){const s=[],o=[],n=new Map,i=[],l=[],c=new Map((t.vfx.inputs??[]).map(e=>[e.id,e.type])),u=new Map((t.vfx.inputs??[]).filter(e=>"number"===e.type).map(e=>[e.id,"number"==typeof e.defaultValue?e.defaultValue:0]));hasGpuUnsupportedVfxInputBindings(t)&&i.push({severity:"error",code:"vfx-input-binding",emitter:"effect",message:"this VFX input binding target is not supported on GPU yet"});const m=t.vfx.emitters.slice().sort((e,t)=>(e.output.renderOrder??0)-(t.output.renderOrder??0)),d=(t,r,m)=>{const h="vfxInput"===t.rate.delayBinding?.type?u.get(t.rate.delayBinding.inputId):void 0,y=null==h?t:{...t,rate:{...t.rate,delay:Math.max(0,h)}};if("sprite"!==t.output.type&&"mesh"!==t.output.type&&"stretchedSprite"!==t.output.type&&"decal"!==t.output.type&&"shape"!==t.output.type&&"trail"!==t.output.type)return void v(i,t,"error","output-type","this output type is not supported by the GPU sprite backend");if("mesh"===t.output.type&&null==t.output.assetId)return;if(t.rate.count<=0)return;const f="trail"===(b=t.output).type?JSON.stringify(b):"mesh"===b.type?JSON.stringify({type:b.type,assetId:b.assetId,renderOrder:b.renderOrder??0,useLegacyTransform:!0===b.useLegacyTransform,materialSource:b.materialSource??null,material:b.material??null,shader:b.shader??null,shaderParams:b.shaderParams??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space}):"decal"===b.type?JSON.stringify({type:b.type,colorMap:b.colorMap,alphaMap:b.alphaMap,color:b.color,unlit:b.unlit,intensity:b.intensity,opacityChannel:b.opacityChannel??"red",blendingMode:b.blendingMode,renderOrder:b.renderOrder??0,materialSource:b.materialSource??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space}):"shape"===b.type?JSON.stringify({type:b.type,shape:b.shape,params:b.params,material:b.material,renderOrder:b.renderOrder??0,materialSource:b.materialSource??null,shader:b.shader??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space}):JSON.stringify({type:b.type,texture:b.texture,opacityChannel:b.opacityChannel??"red",blendingMode:b.blendingMode,softness:b.softness,renderOrder:b.renderOrder??0,bloom:b.bloom,materialSource:b.materialSource??null,shader:b.shader??null,shaderGraph:b.shaderGraph??null,shaderGraphParams:b.shaderGraphParams??null,space:b.space,lockY:"sprite"===b.type&&!0===b.lockY,stretchScale:"stretchedSprite"===b.type?b.scale:null});var b;let g=n.get(f);null==g&&(g=o.length,n.set(f,g),o.push({key:f,output:t.output}));const x=[];for(let o=0;o<a.length;o++){const n=w(y,null==r?a[o]:new e.Vector3,g,i);if(null!=n){if(null!=r){const e=s[r]?.instances[o];if(null==e)continue;const a=n.capacity,l=e.capacity*a;if(l>25e4){v(i,t,"error","child-particle-capacity",`child emitter expansion requires ${l} particles, exceeding the GPU per-emitter limit`);continue}n.capacity=l,n.parentEmitter=r,n.childParticlesPerParent=a,n.childSpawnEvent="collision"===t.spawnEvent?2:1,n.childLevel=m,!0===n.localSpace&&!0!==e.localSpace&&v(i,t,"error","child-emitter-local-space","GPU child emitters do not yet support a world-space parent with local-space child output"),"trail"===t.output.type&&v(i,t,"error","child-emitter-trail","GPU child emitters do not yet support trail output")}x.push(n)}}if(x.length>0){const e=s.length;s.push({instances:x,parentSource:r});for(const a of[...t.initializers,...t.behaviours])if(!1!==a.enabled)for(const[r,s]of Object.entries(a.params)){const o=s?.binding;if("vfxInput"!==o?.type)continue;const n=s.type===p.Number?"number":s.type===p.Vector3?"vec3":s.type===p.Color?"color":s.type===p.Object3D?"mesh":void 0;null!=n&&c.get(o.inputId)===n&&("mesh"!==n&&("lifetime"===a.type&&"duration"===r&&"continuous"===t.rate.type||l.push({inputId:o.inputId,emitterIndex:e,target:`${t.initializers.includes(a)?"initializer":"behaviour"}:${a.type}:${r}`,authoredScalar:"number"==typeof s.value?s.value:void 0,baseScaleStart:[...x[0].scaleStart],baseScaleEnd:[...x[0].scaleEnd]})))}for(const a of t.children??[])d(a,e,m+1)}};for(const e of m)d(e,null,0);const h="instance-major"===r?a.flatMap((e,t)=>s.flatMap(e=>null==e.instances[t]?[]:[e.instances[t]])):s.flatMap(e=>e.instances);for(let e=0;e<s.length;e++){const t=s[e];if(null!=t.parentSource)for(let e=0;e<t.instances.length;e++)t.instances[e].parentEmitter="instance-major"===r?e*s.length+t.parentSource:t.parentSource*a.length+e}const y=o.map((e,t)=>({renderClass:e,oldIndex:t})).sort((e,t)=>(e.renderClass.output.renderOrder??0)-(t.renderClass.output.renderOrder??0)),f=new Array(o.length);for(let e=0;e<y.length;e++)f[y[e].oldIndex]=e;for(const e of h)e.renderClass=f[e.renderClass??0]??0;const b={compatible:!i.some(e=>"warning"!==e.severity),issues:i};return{emitters:h,inputBindings:l,renderClasses:y.map(e=>e.renderClass),compatibility:b,unsupported:[...new Set(i.map(e=>`${e.emitter}: ${e.message}`))]}}export async function materializeGpuSpriteRenderClasses(p,f,w,v){const x=async p=>{const v=p.output;if("trail"===v.type){const t=v.materialSource??("asset"===v.shaderGraph?.source?"shaderGraph":"default"),a="default"===t?null:await(w?.(v))??null;if(null==a&&"default"!==t)throw new Error(`${t} trail material requires a compatible GPU material resolver`);return{texture:null!=v.texture?await f.getTexture(v.texture):b(),material:a??void 0,localSpace:"local"===v.space,trail:{historyLength:Math.max(2,Math.round(v.length)+1),width:v.width??1,taper:v.taper,colorStart:new e.Color(v.color).multiplyScalar(v.intensity),colorEnd:new e.Color(v.colorEnd).multiplyScalar(v.intensityEnd),opacityStart:v.opacityStart,opacityEnd:v.opacityEnd,scrollSpeed:v.scrollSpeed??0,opacityChannel:v.opacityChannel??"red",blendingMode:v.blendingMode??"normal",billboard:v.billboard??!1}}}if("mesh"===v.type){if(null==f.getMesh)throw new Error("GPU mesh particles require a mesh asset provider");const a=await f.getMesh(v.assetId);a.updateWorldMatrix(!0,!0);const r=[];if(a.traverse(t=>{t instanceof e.Mesh&&r.push(t)}),1!==r.length)throw new Error(`GPU mesh particles require exactly one mesh geometry; asset ${v.assetId} resolved to ${r.length}`);const s=null==r[0].geometry.index?r[0].geometry.clone():r[0].geometry.toNonIndexed();!0!==v.useLegacyTransform&&t(r[0],s);const n=s.getAttribute("position");if(null==n)throw new Error(`GPU mesh particle asset ${v.assetId} has no position attribute`);const i=s.getAttribute("normal"),l=s.getAttribute("uv"),c=new Float32Array(8*n.count);for(let e=0;e<n.count;e++){const t=8*e;c[t]=n.getX(e),c[t+1]=n.getY(e),c[t+2]=n.getZ(e),c[t+3]=i?.getX(e)??0,c[t+4]=i?.getY(e)??1,c[t+5]=i?.getZ(e)??0,c[t+6]=l?.getX(e)??0,c[t+7]=l?.getY(e)??0}s.dispose();const p=Array.isArray(r[0].material)?r[0].material[0]:r[0].material,m="material"===v.materialSource&&null==v.material||"shaderGraph"===v.materialSource&&("asset"!==v.shaderGraph?.source||null==v.shaderGraph.assetId)||"shader"===v.materialSource&&null==v.shader?"default":v.materialSource??("asset"===v.shaderGraph?.source?"shaderGraph":null!=v.shader?"shader":null!=v.material?"material":"default"),d="default"===m?await(w?.(v))??function(){const e=u.opacity;return new o({color:u.color.rgb.rgba(e),opacity:e,transparent:!0})}():await(w?.(v))??null;if(null==d&&"default"!==m)throw new Error(`${m} mesh material requires a compatible GPU material resolver`);const h=null!=p&&"color"in p&&p.color instanceof e.Color?p.color.clone():new e.Color(16777215);return{texture:b(),meshVertices:c,meshColor:h,meshOpacity:p?.opacity??1,localSpace:"local"===v.space,material:d??void 0}}if("decal"===v.type){const t=await(w?.(v))??null;if(null==t)throw new Error("GPU decal output requires a compatible GPU decal material resolver");const a=new e.BoxGeometry(1,1,1).toNonIndexed(),r=a.getAttribute("position"),s=a.getAttribute("normal"),o=a.getAttribute("uv"),n=new Float32Array(8*r.count);for(let e=0;e<r.count;e++){const t=8*e;n[t]=r.getX(e),n[t+1]=r.getY(e),n[t+2]=r.getZ(e),n[t+3]=s.getX(e),n[t+4]=s.getY(e),n[t+5]=s.getZ(e),n[t+6]=o.getX(e),n[t+7]=o.getY(e)}return a.dispose(),{texture:b(),meshVertices:n,meshColor:new e.Color(16777215),meshOpacity:1,localSpace:"local"===v.space,material:t}}if("shape"===v.type){const t=g[v.shape];if(null==t)throw new Error(`GPU shape output has unknown shape ${v.shape}`);const a=v.materialSource??("asset"===v.shaderGraph?.source?"shaderGraph":null!=v.shader?"shader":null!=v.material?"material":"default"),r="default"===a?function(){const e=u.opacity;return new o({color:s({color:u.color.rgb}).rgb.rgba(e),opacity:e,transparent:!0})}():await(w?.(v))??null;if(null==r&&"default"!==a)throw new Error(`${a} shape material requires a compatible GPU material resolver`);const n=Object.fromEntries(Object.entries(v.params??{}).map(([e,t])=>[e,t.value])),i=t.geometry(n),l=null==i.index?i:i.toNonIndexed(),c=l.getAttribute("position"),p=l.getAttribute("normal"),m=l.getAttribute("uv"),d=new Float32Array(8*c.count);for(let e=0;e<c.count;e++){const t=8*e;d[t]=c.getX(e),d[t+1]=c.getY(e),d[t+2]=c.getZ(e),d[t+3]=p?.getX(e)??0,d[t+4]=p?.getY(e)??1,d[t+5]=p?.getZ(e)??0,d[t+6]=m?.getX(e)??0,d[t+7]=m?.getY(e)??0}return l!==i&&l.dispose(),i.dispose(),{texture:b(),meshVertices:d,meshColor:new e.Color(16777215),meshOpacity:1,localSpace:"local"===v.space,material:r??void 0}}const x=null!=v.texture?await f.getTexture(v.texture):b(),S="stretchedSprite"===v.type?"default":v.materialSource??("asset"===v.shaderGraph?.source?"shaderGraph":"default");let M="default"===S?null:await(w?.(v))??null;if(null==M&&"default"!==S)throw new Error(`${S} material requires a compatible GPU material resolver`);return M??(M=function(t,s){const p=l(s),f="sprite"===t.type&&!0===t.flipbook?.enabled?m(p,a.uv,t.flipbook.columns,t.flipbook.rows,u.time,t.flipbook.fps,t.flipbook.mode):p.sample(c.uv);let b=u.opacity;"red"===(t.opacityChannel??"red")?b=b.multiply(f.r):"alpha"===t.opacityChannel&&(b=b.multiply(f.a));if(t.softness>0){const e=h.subtract(d).divide(h);b=b.multiply(i(0,.2*t.softness,r(e,0,1e3)))}const g=new o({color:n(u.color.multiply(f.rgb),b),transparent:!0,lights:!1,fog:!1,alphaTest:1e-4});return g.blending=y[t.blendingMode]??e.NormalBlending,g.depthWrite=!1,g}(v,x)),M.transparent&&(M.depthWrite=!1),{texture:x,material:M,lockY:"sprite"===v.type&&!0===v.lockY,localSpace:"local"===v.space,stretchScale:"stretchedSprite"===v.type?0===v.scale?.001:v.scale:void 0}};return{renderClasses:await Promise.all(p.map(e=>v?.resolve(e.key,()=>x(e))??x(e))),unsupported:[]}}function w(t,a,r,s){if("sprite"!==t.output.type&&"mesh"!==t.output.type&&"decal"!==t.output.type&&"shape"!==t.output.type&&"trail"!==t.output.type&&"stretchedSprite"!==t.output.type)return null;const o="mesh"===t.output.type||"decal"===t.output.type||"shape"===t.output.type;let n=99999,i=99999,l=0,c=0;const p=new e.Vector4,u=new e.Vector4,m=new e.Vector3,d=new e.Vector3,h=new e.Vector3;let y=0,b=1;const g=new e.Vector3;let w=0,G=0,V=!1,C=0,P=!1;const I=new e.Vector3;let O,E=0,U=!1,A=!1,R=0,N=0,B=0,T=!1,z=[1,1],$=1,j=1,F=new e.Color("sprite"===t.output.type||"stretchedSprite"===t.output.type?t.output.color:"#ffffff"),Y=F.clone(),X=!1,Z=1,q=1,D=0,L=0;const Q=new e.Quaternion,J=new e.Vector3,W=new e.Vector3;let H=0;const K=new e.Vector3(0,1,0);let _=0,ee=0,te=!1;const ae=new e.Vector3;let re=0,se=0,oe=!1;const ne=new e.Vector3(0,1,0);let ie=0;const le=new e.Vector3,ce=new e.Vector3,pe=new e.Vector3(0,1,0);let ue=0,me=!1,de=0,he=0,ye=0,fe=!1;const be=new e.Vector4(0,0,0,0),ge=new e.Vector3(1,1,1),we=new e.Vector3(1,1,1),ve=new e.Vector3(1,1,1);let xe,Se,Me,ke,Ge,Ve="surface";for(const a of t.initializers.filter(e=>!1!==e.enabled))switch(a.type){case"lifetime":i=n=x(a.params.duration,1);break;case"randomLifetime":{const e=x(a.params.minDuration,1),t=x(a.params.maxDuration,2);i=Math.min(e,t),n=Math.max(e,t);break}case"velocity":{const e=M(a.params.velocity);m.copy(e),d.copy(e);break}case"randomVelocity":m.copy(M(a.params.min)),d.copy(M(a.params.max));break;case"randomDirection":{const e=x(a.params.speed,1);m.setScalar(-e),d.setScalar(e);break}case"radialVelocity":K.copy(M(a.params.direction)).normalize(),_=x(a.params.speed,1),ee=e.MathUtils.degToRad(x(a.params.spread,0)),te=!0;break;case"mass":b=Math.max(1e-6,x(a.params.min,1));break;case"positionPoint":p.copy(new e.Vector4(...M(a.params.position).toArray(),0));break;case"positionSphere":{l=x(a.params.radius,1);const e=M(a.params.position);c=1,p.set(e.x,e.y,e.z,!0===a.params.surface?.value?1:0);break}case"positionBox":{const e=M(a.params.position),t=M(a.params.dimensions);c=2,p.set(e.x,e.y,e.z,0),u.set(t.x,t.y,t.z,0);break}case"positionLine":{const e=M(a.params.a),t=M(a.params.b);c=3,p.set(e.x,e.y,e.z,0),u.set(t.x,t.y,t.z,0);break}case"positionCircle":case"positionRing":{const t=M(a.params.position),r=M(a.params.rotation).multiplyScalar(Math.PI/180);l=x(a.params.radius,1);const s="positionRing"===a.type?Math.max(x(a.params.thickness,.2),1e-4):0;c=4,p.set(t.x,t.y,t.z,s),u.set(r.x,r.y,r.z,e.MathUtils.degToRad(Math.max(0,Math.min(360,x(a.params.angle,360)))));break}case"positionMesh":{const r=a.params.mesh?.value,o=a.params.mesh?.binding;if("vfxInput"===o?.type&&(Se=o.inputId),("string"!=typeof r||0===r.length)&&null==Se){v(s,t,"error","mesh-sampler-source","GPU mesh sampling requires a selected fallback mesh asset");break}if(xe="string"==typeof r&&r.length>0?r:void 0,Ve="vertices"===a.params.sampling?.value?"vertices":"surface",Me=(new e.Matrix4).compose(M(a.params.position),(new e.Quaternion).setFromEuler((new e.Euler).setFromVector3(M(a.params.rotation).multiplyScalar(Math.PI/180))),null==a.params.scale?new e.Vector3(1,1,1):M(a.params.scale)),!0===a.params.alignNormal?.value){const t=a.params.alignmentAxis?.value;ke="+X"===t?new e.Vector3(1,0,0):"-X"===t?new e.Vector3(-1,0,0):"-Y"===t?new e.Vector3(0,-1,0):"+Z"===t?new e.Vector3(0,0,1):"-Z"===t?new e.Vector3(0,0,-1):new e.Vector3(0,1,0)}!0===a.params.normalVelocity?.value&&(Ge=new e.Vector4(x(a.params.normalVelocityMin,1),x(a.params.normalVelocityMax,1),e.MathUtils.degToRad(e.MathUtils.clamp(x(a.params.normalVelocitySpread,0),0,180)),1)),c=5;break}case"scale":{const e=x(a.params.scale,1);z=[e,e];break}case"scaleComponents":ge.copy(M(a.params.scale));break;case"randomScale":z=[x(a.params.min,1),x(a.params.max,1)];break;case"randomColor":F=k(a.params.a,F),Y=k(a.params.b,F),X=!0;break;case"rotation":{const t=M(a.params.rotation);D=L=e.MathUtils.degToRad(t.z),J.set(e.MathUtils.degToRad(t.x),e.MathUtils.degToRad(t.y),e.MathUtils.degToRad(t.z)),Q.setFromEuler(new e.Euler(J.x,J.y,J.z));break}case"randomRotation":{if(o){const e=a.params.axis?.value;H="X"===e?2:"Y"===e?3:"Z"===e?4:1;break}const e=a.params.axis?.value;"XYZ"!==e&&"Z"!==e&&null!=e||(L=2*Math.PI);break}case"alignRotation":{if(!o)break;const e=a.params.axis?.value;"+X"===e?ne.set(1,0,0):"-X"===e?ne.set(-1,0,0):"-Y"===e?ne.set(0,-1,0):"+Z"===e?ne.set(0,0,1):"-Z"===e?ne.set(0,0,-1):ne.set(0,1,0);const t=a.params.mode?.value;ie="TowardsCenter"===t?2:"AlongVelocity"===t?3:1,le.copy(M(a.params.center)),ce.copy(M(a.params.offset)).multiplyScalar(Math.PI/180);break}default:v(s,t,"error",`initializer:${a.type}`,`initializer ${a.type} is not supported on GPU`)}for(const e of t.behaviours.filter(e=>!1!==e.enabled))switch(e.type){case"force":h.add(M(e.params.force));break;case"gravity":h.y-=x(e.params.gravity,8);break;case"linearDamping":y+=x(e.params.factor,.1);break;case"randomDrift":g.copy(M(e.params.drift)),w=Math.max(0,x(e.params.delay,0)),G=S(e.params.ease?.value),V=!0;break;case"followParent":C=x(e.params.speed,0),P=!0;break;case"moveTo":I.copy(M(e.params.target)),E=S(e.params.ease?.value),U=!0;break;case"attraction":case"repulsion":if(oe){v(s,t,"error","multiple-attraction-behaviours","multiple attraction or repulsion behaviours are not supported in one GPU emitter");break}ae.copy(M(e.params.target)),re=x(e.params.force,1)*("repulsion"===e.type?-1:1),se=Math.max(0,x(e.params.radius,1)),oe=!0;break;case"vortex":if(me){v(s,t,"error","multiple-vortex-behaviours","multiple vortex behaviours are not supported in one GPU emitter");break}pe.copy(M(e.params.axis)),ue=x(e.params.amount,1),me=!0;break;case"disperse":{if(fe){v(s,t,"error","multiple-disperse-behaviours","multiple disperse behaviours are not supported in one GPU emitter");break}de=x(e.params.distance,1);const a=e.params.axis?.value;he="XY"===a?1:"XZ"===a?2:"YZ"===a?3:0,ye=S(e.params.ease?.value),fe=!0;break}case"worldCollision":if(e.params.method?.value===f.PhysicsRaycast){v(s,t,"requirement","physics-raycast-collision","Physics raycast world collision requests CPU particle simulation");break}A=!0,R=Math.max(0,x(e.params.bounce,0)),N=Math.max(0,Math.min(1,x(e.params.friction,0))),B=Math.max(0,x(e.params.lifeLoss,0)),T=!0===e.params.debug?.value;break;case"scale":$=x(e.params.a,1),j=x(e.params.b,1),be.x=S(e.params.ease?.value);break;case"scaleComponents":we.copy(ge).multiply(M(e.params.a)),ve.copy(ge).multiply(M(e.params.b)),be.w=S(e.params.ease?.value);break;case"changeColor":F=k(e.params.a,F),Y=k(e.params.b,Y),be.y=S(e.params.ease?.value),X=!1;break;case"changeOpacity":Z=x(e.params.a,1),q=x(e.params.b,0),be.z=S(e.params.ease?.value);break;case"rotate":case"rotateAdd":{const t=M(e.params.rotation);t.multiplyScalar(Math.PI/180*Math.PI/180),o?W.add(t):O=(O??0)+t.z;break}default:v(s,t,"error",`behaviour:${e.type}`,`behaviour ${e.type} is not supported on GPU`)}const Ce=Math.max(0,Math.floor(t.rate.count)),Pe="sprite"!==t.output.type&&"stretchedSprite"!==t.output.type||!Number.isFinite(t.output.intensity)?1:t.output.intensity;F.multiplyScalar(Pe),Y.multiplyScalar(Pe);const Ie="once"===t.rate.type?Ce:Math.max(Ce,Math.ceil(n/Math.max(t.rate.time,1e-4))*Ce),Oe=Math.min(25e4,Ie);return Oe!==Ie&&v(s,t,"warning","particle-capacity-clamped",`particle capacity ${Ie} exceeds the current GPU per-emitter limit of ${Oe}`),t.behaviours.some(e=>!1!==e.enabled&&"scaleComponents"===e.type)||(we.copy(ge),ve.copy(ge)),A&&"local"===t.output.space&&v(s,t,"error","world-collision-local-space","GPU screen-space world collision currently requires world-space output"),{position:(new e.Vector3).fromArray(t.position).add("local"===t.output.space?new e.Vector3:a),localSpace:"local"===t.output.space,capacity:Oe,rate:"once"===t.rate.type?{type:"once",count:Ce,delay:Math.max(0,t.rate.delay??0)}:{type:"continuous",count:Ce,interval:Math.max(t.rate.time,1e-4),delay:Math.max(0,t.rate.delay??0),duration:(t.rate.duration??0)>0?t.rate.duration:-1},life:n,lifeMin:i,positionRadius:l,spawnZoneType:c,spawnZoneA:p,spawnZoneB:u,meshSamplerAssetId:xe,meshSamplerInputId:Se,meshSamplerMode:Ve,meshSamplerTransform:Me,meshSamplerAlignAxis:ke,meshNormalVelocity:Ge,velocityMin:m,velocityMax:d,force:h,damping:y,mass:b,randomDrift:g,randomDriftDelay:w,randomDriftEasing:G,hasRandomDrift:V,followParentSpeed:C,hasFollowParent:P,moveToTarget:I,moveToEasing:E,hasMoveTo:U,hasWorldCollision:A,collisionBounce:R,collisionFriction:N,collisionLifeLoss:B,collisionDebug:T,orientAlongVelocity:!1,scaleStart:[z[0]*$,z[1]*$],scaleEnd:[z[0]*j,z[1]*j],colorStart:F,colorEnd:Y,randomColor:X,alphaStart:Z,alphaEnd:q,rotationMin:D,rotationMax:L,spriteRotationStep:O,meshRotation:Q,meshRotationEuler:J,meshRotationStep:W,randomMeshRotationAxis:H,radialVelocityDirection:K,radialVelocitySpeed:_,radialVelocitySpread:ee,hasRadialVelocity:te,attractionTarget:ae,attractionForce:re,attractionRadius:se,hasAttraction:oe,alignRotationAxis:ne,alignRotationMode:ie,alignRotationCenter:le,alignRotationOffset:ce,vortexAxis:pe,vortexAmount:ue,hasVortex:me,disperseDistance:de,dispersePlane:he,disperseEasing:ye,hasDisperse:fe,curveEasing:be,meshScaleStart:we,meshScaleEnd:ve,renderClass:r}}export function requiresCpuVfxBackend(e){const t=e=>e.behaviours.some(e=>!1!==e.enabled&&"worldCollision"===e.type&&e.params.method?.value===f.PhysicsRaycast)||(e.children??[]).some(t);return e.vfx.emitters.some(t)}function v(e,t,a,r,s){e.some(e=>e.emitter===t.name&&e.code===r)||e.push({severity:a,code:r,emitter:t.name||t.id,message:s})}function x(e,t){const a=e?.value;if("number"==typeof a)return Number.isFinite(a)?a:t;if("string"==typeof a&&""!==a.trim()){const e=Number(a);if(Number.isFinite(e))return e}return t}function S(e){switch(e){case"InQuad":return 1;case"OutQuad":return 2;case"InOutQuad":return 3;case"InCubic":return 4;case"OutCubic":return 5;case"InOutCubic":return 6;case"InQuart":return 7;case"OutQuart":return 8;case"InOutQuart":return 9;case"InSine":return 10;case"OutSine":return 11;case"InOutSine":return 12;case"InExpo":return 13;case"OutExpo":return 14;case"InOutExpo":return 15;case"InCirc":return 16;case"InBack":return 17;case"OutBack":return 18;case"Bump":return 19;case"BumpSharp":return 20;case"BumpFlat":return 21;case"SpikeFade":return 22;case"OutCirc":return 23;case"InOutCirc":return 24;case"InOutBack":return 25;case"BumpFade":return 26;case"BumpFall":return 27;default:return 0}}function M(t){const a=t?.value;return Array.isArray(a)?new e.Vector3(Number(a[0]),Number(a[1]),Number(a[2])):new e.Vector3}function k(t,a){const r=t?.value;if("string"==typeof r){if(null!=/^#([A-Fa-f0-9]{6})$/.exec(r))return new e.Color(r);const t=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/.exec(r);if(null!=t)return(new e.Color).setRGB(Math.min(255,Number.parseInt(t[1],10))/255,Math.min(255,Number.parseInt(t[2],10))/255,Math.min(255,Number.parseInt(t[3],10))/255,e.SRGBColorSpace)}if("number"==typeof r&&Number.isFinite(r))return new e.Color(Math.floor(r));if(null!=r&&"object"==typeof r&&"r"in r&&"g"in r&&"b"in r){const t=r;return(new e.Color).setRGB(t.r,t.g,t.b)}return a.clone()}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import*as s from"three";import{Service as r}from"typedi";import{inject as i}from"../../gameplay/inject.js";import{AssetLoader as n}from"../../gameplay/services/asset-loader.js";import{ViewController as a}from"../../gameplay/services/render.js";import{AssetResourceLoader as o}from"../../scene/asset-resource-loader.js";import{AssetsProvider as l}from"../../scene/assets-provider.js";import{ShaderProvider as h}from"../../gameplay/services/shader-provider.js";import{ensureWebGpuRuntimeBindings as u}from"../../rendering/webgpu-runtime-bridge.js";import{createGpuSpriteShaderGraphResolver as c}from"./vfx-materializer.js";import{GpuSpriteRenderClassCache as d,hasGpuUnsupportedVfxInputBindings as p}from"./gpu-sprite-compiler.js";import{addGpuSpriteRenderGraphPasses as m}from"./gpu-sprite-render-graph.js";import{GpuSpriteWorldRuntime as g}from"./gpu-sprite-world-runtime.js";import{buildGpuSpriteTemplate as f,GpuSpriteTemplateCache as y}from"./gpu-sprite-template.js";import{gpuVfxCapacityClass as v}from"./gpu-vfx-capacity.js";export class GpuVfxEffectHandle{constructor(e,t){this.epoch=e,this.instance=t,this.released=!1}setPosition(e){return!this.released&&this.epoch.runtime.setPosition(this.instance,e)}setTransform(e){return!this.released&&this.epoch.runtime.setTransform(this.instance,e)}pause(){return!this.released&&this.epoch.runtime.pause(this.instance)}play(){return!this.released&&this.epoch.runtime.play(this.instance)}restart(){return!this.released&&this.epoch.runtime.restart(this.instance)}stop(){return!this.released&&this.epoch.runtime.stop(this.instance)}expire(e){return!this.released&&this.epoch.runtime.stop(this.instance,Math.max(0,e))}kill(){return!this.released&&this.epoch.runtime.stop(this.instance,0)}setTimescale(e){return!this.released&&this.epoch.runtime.setTimescale(this.instance,e)}setInput(e,t){return!this.released&&this.epoch.runtime.setInput(this.instance,e,t)}release(){return!this.released&&(this.released=!0,this.epoch.runtime.destroy(this.instance))}get active(){return!this.released&&this.epoch.runtime.has(this.instance)}}export class PreparedGpuVfxEffect{constructor(e,t,s){this.entry=e,this.spawnEntry=t,this.releaseEntry=s,this.released=!1}spawn(e){return this.released?null:this.spawnEntry(this.entry,e)}release(){this.released||(this.released=!0,this.releaseEntry(this.entry))}}let w=class{constructor(){this.view=i(a),this.assetLoader=i(n),this.assetsProvider=i(l),this.assetResources=i(o),this.shaderProvider=i(h),this.templateCache=new y,this.renderClassCache=new d,this.entriesByAssetId=new Map,this.entries=new Set,this.epochs=new Set,this.reportedCpuFallbacks=new Set,this.cpuFallbackReasons=new Map,this.currentEpoch=null,this.nextGeneration=1,this.rebuildTail=Promise.resolve(!0),this.unregisterRenderGraph=null,this.estimatedWorldBytes=0,this.profilingEnabled=!1,this.view.onLateUpdate().subscribe(e=>this.update(e))}setProfilingEnabled(e){this.profilingEnabled=e}getStats(){const e=this.currentEpoch;return null==e?null:{particles:e.runtime.runtime.getStats(),scheduler:e.runtime.scheduler.getStats()}}beginPipelineWarmup(){const e=[],t=new s.Vector3;for(const s of this.epochs){for(const r of s.templateIndices.values()){const i=s.runtime.spawn(r,t);null!=i&&e.push({epoch:s,instance:i})}s.runtime.flushActivePages()}return()=>{for(const{epoch:t,instance:s}of e)t.runtime.destroy(s);for(const e of this.epochs)e.runtime.flushActivePages()}}async prepare(e,t,s){if(this.cpuFallbackReasons.delete(this.fallbackKey(e,t)),"webgpu"!==this.view.requestedBackend)return this.reportCpuFallback(e,t,[`GPU VFX requires the WebGPU renderer; the requested renderer is "${this.view.requestedBackend}".`]),null;if(await u(),p(e))return this.reportCpuFallback(e,t,["one or more authored VFX input bindings are not supported on GPU"]),null;let r=null==s||0===s.size?this.entriesByAssetId.get(e.id):void 0;if(null==r||r.asset!==e||r.revision!==t){const i=r;r={asset:e,revision:t,pending:(async()=>(null!=i&&await this.retireEntry(i.pending),this.createEntry(e,t,s)))()},null!=s&&0!==s.size||this.entriesByAssetId.set(e.id,r)}const i=await r.pending;if(null==i)return this.reportCpuFallback(e,t,["GPU template preparation rejected this asset without a diagnostic"]),null;i.references+=1;const n=v(i.references),a=this.currentEpoch?.reservations.get(i)??0,o=i.reservedInstances;return n>i.reservedInstances&&(i.reservedInstances=n),a<n&&!await this.queueRebuild()?(i.references-=1,i.reservedInstances=o,this.reportCpuFallback(e,t,["the shared GPU VFX world could not grow within its memory budget or WebGPU device limits"]),null):new PreparedGpuVfxEffect(i,(e,t)=>this.spawn(e,t),e=>this.releaseEntry(e))}getFallbackReasons(e,t){return this.cpuFallbackReasons.get(this.fallbackKey(e,t))??[]}async createEntry(e,t,s){const r={assets:this.assets,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,revision:t,meshInputs:s},i=null==s||0===s.size?await this.templateCache.resolve(e,r):await f(e,r);if(null==i.template){const s=i.compatibility.issues.filter(e=>"error"===e.severity).map(e=>`${e.emitter}: ${e.message}`);return this.reportCpuFallback(e,t,s.length>0?s:i.reasons),null}const n={asset:e,revision:t,references:0,reservedInstances:1,retired:!1,runtimeMeshInput:null!=s&&s.size>0,template:i.template};return this.entries.add(n),n}spawn(e,t){let s=this.currentEpoch,r=s?.templateIndices.get(e);if(null==r&&e.retired)for(const t of this.epochs){const i=t.templateIndices.get(e);t.disposalQueued||null==i||(s=t,r=i)}if(null==s||null==r)return null;const i=s.runtime.spawn(r,t);return null==i?null:new GpuVfxEffectHandle(s,i)}releaseEntry(e){e.references=Math.max(0,e.references-1),!e.runtimeMeshInput||e.references>0||e.retired||(e.retired=!0,this.entries.delete(e),this.queueRebuild())}async retireEntry(e){const t=await e;null!=t&&(t.retired=!0,this.entries.delete(t))}queueRebuild(){const e=this.rebuildTail.then(()=>this.rebuildWorld()).catch(e=>(console.error("[Hology GPU VFX] Failed to rebuild the shared world generation.",e),!1));return this.rebuildTail=e,e}async rebuildWorld(){const e=[...this.entries].filter(e=>!e.retired);if(0===e.length)return null!=this.currentEpoch&&(this.currentEpoch.retired=!0,this.currentEpoch=null,this.disposeRetiredEpochs()),!0;if(null!=this.currentEpoch&&this.currentEpoch.templateIndices.size===e.length&&e.every(e=>(this.currentEpoch.reservations.get(e)??0)>=e.reservedInstances))return!0;const t=[...this.epochs].reduce((e,t)=>t===this.currentEpoch&&0===t.runtime.scheduler.getStats().activeInstances?e:e+t.estimatedBytes,0),s=Math.max(0,this.view.webgpuVfxWorldMemoryBudgetBytes-t),r=await g.create({templates:e.map(e=>({asset:e.asset,revision:e.revision,maximumInstances:e.reservedInstances,preparedTemplate:e.template})),assets:this.assets,templateCache:this.templateCache,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,particlePageSize:256,aliveCountReadback:this.profilingEnabled,device:this.view.experimentalWebGpuDevice??void 0,maximumStorageBytes:s});if(null==r)return!1;const i=r.runtime.getStats().storageBytes;if(i>this.view.webgpuVfxWorldMemoryBudgetBytes||t+i>this.view.webgpuVfxWorldMemoryBudgetBytes)return r.dispose(),console.warn(`[Hology GPU VFX] Refusing shared world growth: retained storage would become ${b(t+i)} MiB, exceeding the ${b(this.view.webgpuVfxWorldMemoryBudgetBytes)} MiB budget.`),!1;const n={generation:this.nextGeneration++,runtime:r,templateIndices:new Map(e.map((e,t)=>[e,t])),reservations:new Map(e.map(e=>[e,e.reservedInstances])),estimatedBytes:i,retired:!1,disposalQueued:!1};return null!=this.currentEpoch&&(this.currentEpoch.retired=!0),this.currentEpoch=n,this.epochs.add(n),this.estimatedWorldBytes+=i,this.ensureRenderGraph(),console.info(`[Hology GPU VFX] Shared world generation ${n.generation}: ${e.length} template(s), ${e.reduce((e,t)=>e+t.reservedInstances,0)} reserved instance(s), ${r.runtime.emitters.length} emitter slots, ${r.runtime.getStats().capacity.toLocaleString()} particle slots, ${b(i)} MiB estimated storage.`),this.disposeRetiredEpochs(),!0}ensureRenderGraph(){if(null!=this.unregisterRenderGraph)return;const e=(e,t)=>m(e,this,t,"WorldGpuVfx");e.getSceneTextureReads=()=>this.getSceneTextureReads(),this.unregisterRenderGraph=this.view.registerExperimentalWebGpuRenderGraphExtension(e)}update(e){for(const t of this.epochs)t.runtime.update(e);this.disposeRetiredEpochs()}disposeRetiredEpochs(){for(const e of this.epochs){if(!e.retired||e.disposalQueued||0!==e.runtime.scheduler.getStats().activeInstances||[...e.templateIndices.keys()].some(e=>e.retired&&e.references>0))continue;e.disposalQueued=!0,this.epochs.delete(e),this.estimatedWorldBytes=Math.max(0,this.estimatedWorldBytes-e.estimatedBytes);const t=()=>{e.runtime.dispose(),console.info(`[Hology GPU VFX] Retired shared world generation ${e.generation}, releasing ${b(e.estimatedBytes)} MiB estimated storage.`)},s=this.view.experimentalWebGpuDevice;null==s?t():s.queue.onSubmittedWorkDone().then(t,t)}}reportCpuFallback(e,t,s){const r=this.fallbackKey(e,t);this.cpuFallbackReasons.set(r,[...s]),this.reportedCpuFallbacks.has(r)||(this.reportedCpuFallbacks.add(r),console.warn(`[Hology GPU VFX] Falling back to CPU for "${e.name}".`,s))}fallbackKey(e,t){return`${e.id}:${t??""}`}executeCompute(e){for(const t of this.epochs)t.runtime.runtime.executeCompute(e)}executeRender(e,t){for(const s of this.epochs)s.runtime.runtime.executeRender(e,t)}getSceneTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getSceneTextureReads())e.add(s);return[...e]}getComputeTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getComputeTextureReads())e.add(s);return[...e]}get assets(){return{getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMesh:async e=>(await this.assetResources.getMesh(await this.assetsProvider.getAsset(e),{applyMaterials:!0,rescale:!0})).scene}}get resolveCustomMaterial(){return c(this.assetsProvider,this.assetResources,this.shaderProvider,{getAsset:e=>this.assetLoader.getAsset(e),getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMaterial:e=>this.assetLoader.getMaterialByAssetId(e),getMesh:e=>this.assetLoader.getModelByAssetId(e).then(e=>e.scene)})}};w=e([r(),t("design:paramtypes",[])],w);export{w as GpuVfxWorldService};function b(e){return(e/1048576).toFixed(1)}/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import*as s from"three";import{Service as r}from"typedi";import{inject as i}from"../../gameplay/inject.js";import{AssetLoader as n}from"../../gameplay/services/asset-loader.js";import{ViewController as a}from"../../gameplay/services/render.js";import{AssetResourceLoader as o}from"../../scene/asset-resource-loader.js";import{AssetsProvider as l}from"../../scene/assets-provider.js";import{ShaderProvider as h}from"../../gameplay/services/shader-provider.js";import{ensureWebGpuRuntimeBindings as u}from"../../rendering/webgpu-runtime-bridge.js";import{createGpuSpriteShaderGraphResolver as c}from"./vfx-materializer.js";import{GpuSpriteRenderClassCache as d,hasGpuUnsupportedVfxInputBindings as p}from"./gpu-sprite-compiler.js";import{addGpuSpriteRenderGraphPasses as m}from"./gpu-sprite-render-graph.js";import{GpuSpriteWorldRuntime as g}from"./gpu-sprite-world-runtime.js";import{buildGpuSpriteTemplate as f,GpuSpriteTemplateCache as y}from"./gpu-sprite-template.js";import{gpuVfxCapacityClass as v}from"./gpu-vfx-capacity.js";export class GpuVfxEffectHandle{constructor(e,t){this.epoch=e,this.instance=t,this.released=!1}setPosition(e){return!this.released&&this.epoch.runtime.setPosition(this.instance,e)}setTransform(e){return!this.released&&this.epoch.runtime.setTransform(this.instance,e)}pause(){return!this.released&&this.epoch.runtime.pause(this.instance)}play(){return!this.released&&this.epoch.runtime.play(this.instance)}restart(){return!this.released&&this.epoch.runtime.restart(this.instance)}stop(){return!this.released&&this.epoch.runtime.stop(this.instance)}expire(e){return!this.released&&this.epoch.runtime.stop(this.instance,Math.max(0,e))}kill(){return!this.released&&this.epoch.runtime.stop(this.instance,0)}setTimescale(e){return!this.released&&this.epoch.runtime.setTimescale(this.instance,e)}setInput(e,t){return!this.released&&this.epoch.runtime.setInput(this.instance,e,t)}release(){return!this.released&&(this.released=!0,this.epoch.runtime.destroy(this.instance))}get active(){return!this.released&&this.epoch.runtime.has(this.instance)}}export class PreparedGpuVfxEffect{constructor(e,t,s){this.entry=e,this.spawnEntry=t,this.releaseEntry=s,this.released=!1}spawn(e){return this.released?null:this.spawnEntry(this.entry,e)}release(){this.released||(this.released=!0,this.releaseEntry(this.entry))}}let w=class{constructor(){this.view=i(a),this.assetLoader=i(n),this.assetsProvider=i(l),this.assetResources=i(o),this.shaderProvider=i(h),this.templateCache=new y,this.renderClassCache=new d,this.entriesByAssetId=new Map,this.entries=new Set,this.epochs=new Set,this.reportedCpuFallbacks=new Set,this.cpuFallbackReasons=new Map,this.currentEpoch=null,this.nextGeneration=1,this.rebuildTail=Promise.resolve(!0),this.unregisterRenderGraph=null,this.estimatedWorldBytes=0,this.profilingEnabled=!1,this.view.onLateUpdate().subscribe(e=>this.update(e))}setProfilingEnabled(e){this.profilingEnabled=e}getStats(){const e=this.currentEpoch;return null==e?null:{particles:e.runtime.runtime.getStats(),scheduler:e.runtime.scheduler.getStats()}}beginPipelineWarmup(){const e=[],t=new s.Vector3;for(const s of this.epochs){for(const r of s.templateIndices.values()){const i=s.runtime.spawn(r,t);null!=i&&e.push({epoch:s,instance:i})}s.runtime.flushActivePages()}return()=>{for(const{epoch:t,instance:s}of e)t.runtime.destroy(s);for(const e of this.epochs)e.runtime.flushActivePages()}}async prepare(e,t,s){if(this.cpuFallbackReasons.delete(this.fallbackKey(e,t)),"webgpu"!==this.view.requestedBackend)return this.reportCpuFallback(e,t,[`GPU VFX requires the WebGPU renderer; the requested renderer is "${this.view.requestedBackend}".`]),null;if(await u(),p(e))return this.reportCpuFallback(e,t,["one or more authored VFX input bindings are not supported on GPU"]),null;let r=null==s||0===s.size?this.entriesByAssetId.get(e.id):void 0;if(null==r||r.asset!==e||r.revision!==t){const i=r;r={asset:e,revision:t,pending:(async()=>(null!=i&&await this.retireEntry(i.pending),this.createEntry(e,t,s)))()},null!=s&&0!==s.size||this.entriesByAssetId.set(e.id,r)}const i=await r.pending;if(null==i)return this.reportCpuFallback(e,t,["GPU template preparation rejected this asset without a diagnostic"]),null;i.references+=1;const n=v(i.references),a=this.currentEpoch?.reservations.get(i)??0,o=i.reservedInstances;return n>i.reservedInstances&&(i.reservedInstances=n),a<n&&!await this.queueRebuild()?(i.references-=1,i.reservedInstances=o,this.reportCpuFallback(e,t,["the shared GPU VFX world could not grow within its memory budget or WebGPU device limits"]),null):new PreparedGpuVfxEffect(i,(e,t)=>this.spawn(e,t),e=>this.releaseEntry(e))}getFallbackReasons(e,t){return this.cpuFallbackReasons.get(this.fallbackKey(e,t))??[]}async createEntry(e,t,s){const r={assets:this.assets,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,revision:t,meshInputs:s},i=null==s||0===s.size?await this.templateCache.resolve(e,r):await f(e,r);if(null==i.template){const s=i.compatibility.issues.filter(e=>"warning"!==e.severity).map(e=>`${e.emitter}: ${e.message}`);return this.reportCpuFallback(e,t,s.length>0?s:i.reasons),null}const n={asset:e,revision:t,references:0,reservedInstances:1,retired:!1,runtimeMeshInput:null!=s&&s.size>0,template:i.template};return this.entries.add(n),n}spawn(e,t){let s=this.currentEpoch,r=s?.templateIndices.get(e);if(null==r&&e.retired)for(const t of this.epochs){const i=t.templateIndices.get(e);t.disposalQueued||null==i||(s=t,r=i)}if(null==s||null==r)return null;const i=s.runtime.spawn(r,t);return null==i?null:new GpuVfxEffectHandle(s,i)}releaseEntry(e){e.references=Math.max(0,e.references-1),!e.runtimeMeshInput||e.references>0||e.retired||(e.retired=!0,this.entries.delete(e),this.queueRebuild())}async retireEntry(e){const t=await e;null!=t&&(t.retired=!0,this.entries.delete(t))}queueRebuild(){const e=this.rebuildTail.then(()=>this.rebuildWorld()).catch(e=>(console.error("[Hology GPU VFX] Failed to rebuild the shared world generation.",e),!1));return this.rebuildTail=e,e}async rebuildWorld(){const e=[...this.entries].filter(e=>!e.retired);if(0===e.length)return null!=this.currentEpoch&&(this.currentEpoch.retired=!0,this.currentEpoch=null,this.disposeRetiredEpochs()),!0;if(null!=this.currentEpoch&&this.currentEpoch.templateIndices.size===e.length&&e.every(e=>(this.currentEpoch.reservations.get(e)??0)>=e.reservedInstances))return!0;const t=[...this.epochs].reduce((e,t)=>t===this.currentEpoch&&0===t.runtime.scheduler.getStats().activeInstances?e:e+t.estimatedBytes,0),s=Math.max(0,this.view.webgpuVfxWorldMemoryBudgetBytes-t),r=await g.create({templates:e.map(e=>({asset:e.asset,revision:e.revision,maximumInstances:e.reservedInstances,preparedTemplate:e.template})),assets:this.assets,templateCache:this.templateCache,renderClassCache:this.renderClassCache,resolveCustomMaterial:this.resolveCustomMaterial,particlePageSize:256,aliveCountReadback:this.profilingEnabled,device:this.view.experimentalWebGpuDevice??void 0,maximumStorageBytes:s});if(null==r)return!1;const i=r.runtime.getStats().storageBytes;if(i>this.view.webgpuVfxWorldMemoryBudgetBytes||t+i>this.view.webgpuVfxWorldMemoryBudgetBytes)return r.dispose(),console.warn(`[Hology GPU VFX] Refusing shared world growth: retained storage would become ${b(t+i)} MiB, exceeding the ${b(this.view.webgpuVfxWorldMemoryBudgetBytes)} MiB budget.`),!1;const n={generation:this.nextGeneration++,runtime:r,templateIndices:new Map(e.map((e,t)=>[e,t])),reservations:new Map(e.map(e=>[e,e.reservedInstances])),estimatedBytes:i,retired:!1,disposalQueued:!1};return null!=this.currentEpoch&&(this.currentEpoch.retired=!0),this.currentEpoch=n,this.epochs.add(n),this.estimatedWorldBytes+=i,this.ensureRenderGraph(),console.info(`[Hology GPU VFX] Shared world generation ${n.generation}: ${e.length} template(s), ${e.reduce((e,t)=>e+t.reservedInstances,0)} reserved instance(s), ${r.runtime.emitters.length} emitter slots, ${r.runtime.getStats().capacity.toLocaleString()} particle slots, ${b(i)} MiB estimated storage.`),this.disposeRetiredEpochs(),!0}ensureRenderGraph(){if(null!=this.unregisterRenderGraph)return;const e=(e,t)=>m(e,this,t,"WorldGpuVfx");e.getSceneTextureReads=()=>this.getSceneTextureReads(),this.unregisterRenderGraph=this.view.registerExperimentalWebGpuRenderGraphExtension(e)}update(e){for(const t of this.epochs)t.runtime.update(e);this.disposeRetiredEpochs()}disposeRetiredEpochs(){for(const e of this.epochs){if(!e.retired||e.disposalQueued||0!==e.runtime.scheduler.getStats().activeInstances||[...e.templateIndices.keys()].some(e=>e.retired&&e.references>0))continue;e.disposalQueued=!0,this.epochs.delete(e),this.estimatedWorldBytes=Math.max(0,this.estimatedWorldBytes-e.estimatedBytes);const t=()=>{e.runtime.dispose(),console.info(`[Hology GPU VFX] Retired shared world generation ${e.generation}, releasing ${b(e.estimatedBytes)} MiB estimated storage.`)},s=this.view.experimentalWebGpuDevice;null==s?t():s.queue.onSubmittedWorkDone().then(t,t)}}reportCpuFallback(e,t,s){const r=this.fallbackKey(e,t);this.cpuFallbackReasons.set(r,[...s]),this.reportedCpuFallbacks.has(r)||(this.reportedCpuFallbacks.add(r),console.warn(`[Hology GPU VFX] Falling back to CPU for "${e.name}".`,s))}fallbackKey(e,t){return`${e.id}:${t??""}`}executeCompute(e){for(const t of this.epochs)t.runtime.runtime.executeCompute(e)}executeRender(e,t){for(const s of this.epochs)s.runtime.runtime.executeRender(e,t)}getSceneTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getSceneTextureReads())e.add(s);return[...e]}getComputeTextureReads(){const e=new Set;for(const t of this.epochs)if(t.runtime.runtime.hasActiveParticles)for(const s of t.runtime.runtime.getComputeTextureReads())e.add(s);return[...e]}get assets(){return{getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMesh:async e=>(await this.assetResources.getMesh(await this.assetsProvider.getAsset(e),{applyMaterials:!0,rescale:!0})).scene}}get resolveCustomMaterial(){return c(this.assetsProvider,this.assetResources,this.shaderProvider,{getAsset:e=>this.assetLoader.getAsset(e),getTexture:e=>this.assetLoader.getTextureByAssetId(e),getMaterial:e=>this.assetLoader.getMaterialByAssetId(e),getMesh:e=>this.assetLoader.getModelByAssetId(e).then(e=>e.scene)})}};w=e([r(),t("design:paramtypes",[])],w);export{w as GpuVfxWorldService};function b(e){return(e/1048576).toFixed(1)}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -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}from"./gpu-sprite-compiler.js";import{withSeededRandom as j}from"./seeded-random.js";let E=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;if("cpu"===a&&(this.backendFallbackReasons=["GPU VFX was not requested; the selected VFX backend preference is CPU."]),"cpu"!==a){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=>"error"===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:n,dispose:o,container:l}=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=n,this.disposeSystem=o,this.particleSystemContainer=l,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(),j(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)],E.prototype,"play",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"pause",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"stop",null),t([v({parameters:[],returns:b}),e("design:type",Function),e("design:paramtypes",[]),e("design:returntype",void 0)],E.prototype,"restart",null),E=t([r({typeId:w})],E);export{E 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 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};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -32,6 +32,10 @@ export interface BehaviourData {
32
32
  params: Record<string, CustomParamValue>;
33
33
  }
34
34
  export type Vector3Data = [number, number, number];
35
+ export declare enum WorldCollisionMethod {
36
+ ScreenSpace = "screenSpace",
37
+ PhysicsRaycast = "physicsRaycast"
38
+ }
35
39
  export declare const BlendingModes: readonly ["additive", "subtractive", "multiply", "normal"];
36
40
  export type BlendingMode = (typeof BlendingModes)[number];
37
41
  export declare const ThreeBlendingMode: {
@@ -1,4 +1,4 @@
1
- import{SerializedParamType as e}from"../../scene/model.js";import*as t from"three";import{randomString as n}from"../../utils/math.js";export const BlendingModes=["additive","subtractive","multiply","normal"];export const ThreeBlendingMode={normal:t.NormalBlending,additive:t.AdditiveBlending,subtractive:t.SubtractiveBlending,multiply:t.MultiplyBlending};export const FlipbookModes=["clamp","loop"];export const VfxEffectInputTypes=["number","vec3","color","mesh"];export const ParticleChildSpawnEvents=["collision","start"];export function defaultVfxEffectInputValue(e){switch(e){case"number":return 0;case"vec3":return[0,0,0];case"color":return"#ffffff";case"mesh":return null}}export function createVfxEffectInputDefinition(e="input",t="number"){return{id:n(),name:e,type:t,defaultValue:defaultVfxEffectInputValue(t)}}export function EmitterDataConstructor(){return{id:n(),name:"Emitter",rate:{type:"continuous",count:1,time:.5,delay:0},position:[0,0,0],rotation:[0,0,0],initializers:[{id:n(),enabled:!0,type:"lifetime",params:{duration:{type:e.Number,value:1}}}],behaviours:[],children:[],output:{type:"sprite",texture:null,opacityChannel:"alpha",color:"#ffffff",blendingMode:"normal",space:"world",renderOrder:0,softness:0,intensity:1,bloom:!1}}}/*
1
+ import{SerializedParamType as e}from"../../scene/model.js";import*as t from"three";import{randomString as n}from"../../utils/math.js";export var WorldCollisionMethod;!function(e){e.ScreenSpace="screenSpace",e.PhysicsRaycast="physicsRaycast"}(WorldCollisionMethod||(WorldCollisionMethod={}));export const BlendingModes=["additive","subtractive","multiply","normal"];export const ThreeBlendingMode={normal:t.NormalBlending,additive:t.AdditiveBlending,subtractive:t.SubtractiveBlending,multiply:t.MultiplyBlending};export const FlipbookModes=["clamp","loop"];export const VfxEffectInputTypes=["number","vec3","color","mesh"];export const ParticleChildSpawnEvents=["collision","start"];export function defaultVfxEffectInputValue(e){switch(e){case"number":return 0;case"vec3":return[0,0,0];case"color":return"#ffffff";case"mesh":return null}}export function createVfxEffectInputDefinition(e="input",t="number"){return{id:n(),name:e,type:t,defaultValue:defaultVfxEffectInputValue(t)}}export function EmitterDataConstructor(){return{id:n(),name:"Emitter",rate:{type:"continuous",count:1,time:.5,delay:0},position:[0,0,0],rotation:[0,0,0],initializers:[{id:n(),enabled:!0,type:"lifetime",params:{duration:{type:e.Number,value:1}}}],behaviours:[],children:[],output:{type:"sprite",texture:null,opacityChannel:"alpha",color:"#ffffff",blendingMode:"normal",space:"world",renderOrder:0,softness:0,intensity:1,bloom:!1}}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -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 m=d.copy(o.old.velocity).normalize(),p=o.old.rayFrom,u=o.old.hitDistance,f=o.old.hitNormal,v=o.old.rayLength;if(m.dot(a)>.99&&o.position.distanceTo(p)+r<v)u>0?(e.hasHit=!0,e.distance=u-p.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&&setTimeout(()=>{o.life-=this.lifeLoss+30},30))}}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){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());/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -21,6 +21,7 @@ type FloatParameterDef = ShapeParameterDef<number> & {
21
21
  export type SelectParameterDef<T> = ShapeParameterDef<T> & {
22
22
  type: 'select';
23
23
  opts: Readonly<T[]>;
24
+ optionNames?: Readonly<Partial<Record<string, string>>>;
24
25
  };
25
26
  interface InitializerDefinition extends VfxBoundInitializerDefinition<Initializer> {
26
27
  build(params?: any): Initializer;
@@ -398,6 +399,7 @@ declare class LinearDampingDef extends BaseBevDef<LinearDampingDef> {
398
399
  }
399
400
  declare class WorldCollisionDef extends BaseBevDef<WorldCollisionDef> {
400
401
  parameters: {
402
+ method: SelectParameterDef<string>;
401
403
  friction: FloatParameterDef;
402
404
  bounce: FloatParameterDef;
403
405
  lifeLoss: FloatParameterDef;
@@ -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 V,FollowParent as L,LinearDamping as D,MoveOverLife as S,OrientAlongVelocity as C,RotatePosition as j,Scale as T,ScaleComponents as M}from"./behaviours.js";import{AdditiveVelocity as Y,AlignRotation as B,alignRotationAxes as O,alignRotationModes as F,InitialScale as P,InitialScaleComponents as X,MeshPositionInitializer as Z,RandomColor as q,RandomDirection as I,RandomRotation as K,randomRotationAxis as N,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";class ee{build(e={}){const t=de(e,this.parameters);return this.make(t)}}class te{build(e={}){const t=de(e,this.parameters);return this.make(t)}}function ne(e,t,n){return{type:"number",default:e,float:!0,min:t,max:n}}function se(e,t,n,s){return{...ne(e,n,s),bindable:t}}function re(e){return{type:"boolean",default:e}}function ae(e){return{type:"vec3",default:(new a).fromArray(e)}}function ie(e,t){return{...ae(e),bindable:t}}function oe(e){return{type:"color",default:e}}function ce(e,t){return{...oe(e),bindable:t}}function pe(e,t){return{type:"select",opts:e,default:t}}function ue(){return{type:"curve",default:U.linear()}}function de(e,t){const n={};for(let s in t)null==e[s]?n[s]=t[s].default:n[s]=e[s];return n}function le(e){return new k(e.x,e.y,e.z)}function me(e){return new a(s.degToRad(e.x),s.degToRad(e.y),s.degToRad(e.z))}function we(e){const{x:t,y:n,z:s}=e;return new H(t,n,s)}function fe(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 he(e,t,n=!1){const{x:s,y:r,z:a}=e;return new J(s,r,a,t,n)}function xe(e,t){return new f(e.x,e.y,e.z,t.x,t.y,t.z)}function ge(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 be(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 ye(e){return t=>e.getY(t)}const ve={lifetime:new class extends te{constructor(){super(...arguments),this.parameters={duration:se(1,"spawn",0,1e5)},this.bindingAdapter=_((e,t)=>{e.resetLife(t.duration)})}make(e={}){return new w(e.duration)}},randomLifetime:new class extends te{constructor(){super(...arguments),this.parameters={minDuration:se(1,"spawn",0,1e5),maxDuration:se(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 te{constructor(){super(...arguments),this.parameters={position:ie([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(we(t.position))})}make(e={}){return new x(we(e.position))}},positionBox:new class extends te{constructor(){super(...arguments),this.parameters={position:ie([0,0,0],"spawn"),dimensions:ie([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(fe(t.position,t.dimensions))})}make(e={}){return new x(fe(e.position,e.dimensions))}},positionSphere:new class extends te{constructor(){super(...arguments),this.parameters={position:ie([0,0,0],"spawn"),radius:se(1,"spawn"),surface:re(!1)},this.bindingAdapter=_((e,t)=>{e.reset(he(t.position,t.radius,t.surface))})}make(e={}){return new x(he(e.position,e.radius,e.surface))}},positionLine:new class extends te{constructor(){super(...arguments),this.parameters={a:ie([0,0,0],"spawn"),b:ie([0,0,1],"spawn")},this.bindingAdapter=_((e,t)=>{e.reset(xe(t.a,t.b))})}make(e={}){return new x(xe(e.a,e.b))}},positionCircle:new class extends te{constructor(){super(...arguments),this.parameters={position:ie([0,0,0],"spawn"),rotation:ie([0,0,0],"spawn"),radius:se(1,"spawn",0,1e4),angle:se(360,"spawn",0,360)},this.bindingAdapter=_((e,t)=>{e.reset(ge(t.position,t.rotation,t.radius,0,t.angle))})}make(e={}){return new x(ge(e.position,e.rotation,e.radius,0,e.angle))}},positionRing:new class extends te{constructor(){super(...arguments),this.parameters={position:ie([0,0,0],"spawn"),rotation:ie([0,0,0],"spawn"),radius:se(1,"spawn",0,1e4),thickness:se(.2,"spawn",0,1e4),angle:se(360,"spawn",0,360)},this.bindingAdapter=_((e,t)=>{e.reset(ge(t.position,t.rotation,t.radius,Math.max(t.thickness,1e-4),t.angle))})}make(e={}){return new x(ge(e.position,e.rotation,e.radius,Math.max(e.thickness,1e-4),e.angle))}},positionMesh:new class extends te{constructor(){var e;super(...arguments),this.parameters={mesh:(e="spawn",{type:"mesh",default:null,bindable:e}),sampling:pe(["surface","vertices"],"surface"),position:ae([0,0,0]),rotation:ae([0,0,0]),scale:ae([1,1,1]),alignNormal:re(!1),alignmentAxis:pe(O,"+Y"),normalVelocity:re(!1),normalVelocityMin:{...ne(1),requires:{normalVelocity:!0}},normalVelocityMax:{...ne(1),requires:{normalVelocity:!0}},normalVelocitySpread:{...ne(0,0,180),requires:{normalVelocity:!0}}},this.bindingAdapter={buildBound:e=>be(e.resolveAll())}}make(e={}){return be(e)}},rotation:new class extends te{constructor(){super(...arguments),this.parameters={rotation:ie([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{e.setRotation(me(t.rotation))})}make(e={}){return new E(me(e.rotation))}},randomRotation:new class extends te{constructor(){super(...arguments),this.parameters={axis:pe(N,"XYZ")}}make(e={}){return new K(e.axis)}},scale:new class extends te{constructor(){super(...arguments),this.parameters={scale:se(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setScale(t.scale)})}make(e={}){return new P(e.scale)}},scaleComponents:new class extends te{constructor(){super(...arguments),this.parameters={scale:ie([1,1,1],"spawn")},this.bindingAdapter=_((e,t)=>{e.setScaleComponents(t.scale)})}make(e={}){return new X(e.scale)}},randomScale:new class extends te{constructor(){super(...arguments),this.parameters={min:se(1,"spawn"),max:se(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 te{constructor(){super(...arguments),this.parameters={a:ce("#ffffff","spawn"),b:ce("#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 te{constructor(){super(...arguments),this.parameters={min:se(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.resetMass(t.min)})}make(e={}){return new h(e.min)}},velocity:new class extends te{constructor(){super(...arguments),this.parameters={velocity:ie([0,0,0],"spawn")},this.bindingAdapter={buildBound:e=>new Y(()=>e.get("velocity"))}}make(e={}){const{x:t,y:n,z:s}=e.velocity;return new Y(new a(t,n,s))}},randomVelocity:new class extends te{constructor(){super(...arguments),this.parameters={min:ie([0,0,0],"spawn"),max:ie([0,0,0],"spawn")},this.bindingAdapter={buildBound:e=>new Y(()=>e.get("min"),()=>e.get("max"))}}make(e={}){return new Y(e.min,e.max)}},radialVelocity:new class extends te{constructor(){super(...arguments),this.parameters={speed:se(1,"spawn"),direction:ie([0,1,0],"spawn"),spread:se(0,"spawn")},this.bindingAdapter=_((e,t)=>{e.resetRadialVelocity(t.speed,le(t.direction),t.spread)})}make(e={}){return new g(e.speed,le(e.direction),e.spread)}},randomDirection:new class extends te{constructor(){super(...arguments),this.parameters={speed:se(1,"spawn")},this.bindingAdapter=_((e,t)=>{e.setSpeed(t.speed)})}make(e={}){return new I(e.speed)}},alignRotation:new class extends te{constructor(){super(...arguments),this.parameters={mode:pe(F,"AwayFromCenter"),axis:pe(O,"+Y"),offset:ae([0,0,0]),center:ae([0,0,0])}}make(e={}){return new B(e.axis,e.mode,me(e.offset),e.center)}}},ke={force:new class extends ee{constructor(){super(...arguments),this.parameters={force:ie([0,0,0],"live"),ease:ue()},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,ye(e.ease))}},gravity:new class extends ee{constructor(){super(...arguments),this.parameters={gravity:se(8,"live"),easing:ue()},this.bindingAdapter=$((e,t)=>{e.setForce(0,-t.gravity,0)})}make(e={}){return new m(e.gravity,void 0,ye(e.easing))}},repulsion:new class extends ee{constructor(){super(...arguments),this.parameters={target:ie([0,0,0],"live"),force:se(1,"live"),radius:se(1,"live"),easing:ue()},this.bindingAdapter=$((e,t)=>{e.resetAttraction(le(t.target),t.force,t.radius)})}make(e={}){const t=le(e.target);return new y(t,e.force,e.radius,void 0,ye(e.easing))}},attraction:new class extends ee{constructor(){super(...arguments),this.parameters={target:ie([0,0,0],"live"),force:se(1,"live"),radius:se(1,"live"),easing:ue()},this.bindingAdapter=$((e,t)=>{e.resetAttraction(le(t.target),t.force,t.radius)})}make(e={}){const t=le(e.target);return new o(t,e.force,e.radius,void 0,ye(e.easing))}},scale:new class extends ee{constructor(){super(...arguments),this.parameters={a:se(1,"spawn"),b:se(1,"spawn"),ease:ue()},this.bindingAdapter=_((e,t)=>{e.setScaleRange(t.a,t.b)})}make(e={}){return new T(e.a,e.b,ye(e.ease))}},scaleComponents:new class extends ee{constructor(){super(...arguments),this.parameters={a:ie([1,1,1],"spawn"),b:ie([1,1,1],"spawn"),ease:ue()},this.bindingAdapter=_((e,t)=>{e.setScaleRange(t.a,t.b)})}make(e={}){return new M(e.a,e.b,ye(e.ease))}},randomDrift:new class extends ee{constructor(){super(...arguments),this.parameters={drift:ie([1,1,1],"live"),delay:se(0,"live"),ease:ue()},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,ye(e.ease))}},disperse:new class extends ee{constructor(){super(...arguments),this.parameters={distance:se(1,"spawn"),axis:pe(["XYZ","XZ","XY","YZ"],"XYZ"),ease:ue()},this.bindingAdapter=_((e,t)=>{e.setDistance(t.distance)})}make(e={}){return new V(e.distance,R[e.axis.toLowerCase()],ye(e.ease))}},rotate:new class extends ee{constructor(){super(...arguments),this.parameters={rotation:ie([0,0,0],"spawn"),ease:ue()},this.bindingAdapter=_((e,t)=>{const n=me(t.rotation);e.resetRotation(n.x,n.y,n.z)})}make(e={}){const t=me(e.rotation);return new v(t.x,t.y,t.z,void 0,ye(e.ease))}},rotateAdd:new class extends ee{constructor(){super(...arguments),this.parameters={rotation:ie([0,0,0],"spawn")},this.bindingAdapter=_((e,t)=>{const n=me(t.rotation);e.resetRotation(n.x,n.y,n.z)})}make(e={}){const t=me(e.rotation),n=new v(t.x,t.y,t.z,void 0);return n.rotationType="add",n}},changeColor:new class extends ee{constructor(){super(...arguments),this.parameters={a:ce("#ffffff","spawn"),b:ce("#ffffff","spawn"),ease:ue()},this.bindingAdapter=_((e,t)=>{e.resetColor(t.a,t.b)})}make(e={}){return new u(e.a,e.b,void 0,ye(e.ease))}},changeOpacity:new class extends ee{constructor(){super(...arguments),this.parameters={a:se(1,"spawn",0,1),b:se(0,"spawn",0,1),ease:ue()},this.bindingAdapter=_((e,t)=>{e.resetAlpha(t.a,t.b)})}make(e={}){return new i(e.a,e.b,void 0,ye(e.ease))}},vortex:new class extends ee{constructor(){super(...arguments),this.parameters={axis:ie([0,1,0],"live"),amount:se(1,"live")},this.bindingAdapter=$((e,t)=>{e.setAxisAngle(t.axis,t.amount)})}make(e={}){return new j(e.axis,e.amount)}},moveTo:new class extends ee{constructor(){super(...arguments),this.parameters={target:ie([0,1,0],"live"),ease:ue()},this.bindingAdapter=$((e,t)=>{const n=t.target;e.setTarget(n.x,n.y,n.z)})}make(e={}){return new S(e.target.x,e.target.y,e.target.z,ye(e.ease))}},linearDamping:new class extends ee{constructor(){super(...arguments),this.parameters={factor:se(.1,"live",0,1e3)},this.bindingAdapter=$((e,t)=>{e.setFactor(t.factor)})}make(e={}){return new D(e.factor)}},followParent:new class extends ee{constructor(){super(...arguments),this.parameters={speed:se(0,"live")},this.bindingAdapter=$((e,t)=>{e.setSpeed(t.speed)})}make(e={}){return new L(e.speed)}},worldCollision:new class extends ee{constructor(){super(...arguments),this.parameters={friction:ne(1,0,1),bounce:ne(1,0,1),lifeLoss:ne(0,0)}}make(e={}){return new Q(null,e.bounce,e.friction,e.lifeLoss)}},animation:new class extends ee{constructor(){super(...arguments),this.parameters={clip:{type:"animationclip",default:null},timeScale:ne(1,0,10),weight:ne(1,0,1),loop:pe(["Once","Repeat","PingPong"],"Once"),clampWhenFinished:{...re(!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=ve;export const VfxInitializserLibraryKeys=Object.keys(VfxInitializserLibrary);export const VfxBehaviourLibrary=ke;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 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);/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -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 U}from"../../scene/model.js";import{ShapeLibrary as Q}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as H,linearEyeDepth as N}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=N.subtract(H).divide(N);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=N.subtract(H).divide(E(N)),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=Q[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!==U.Curve&&(r.type=U.Curve);const a=await W(e.params??{},r,s);return ue(t,e.params??{},a,T)}).sort((e,t)=>e instanceof ie?1:0));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 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}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */