@codexo/exojs-particles 0.15.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -43
- package/dist/esm/ParticleStorage.d.ts +188 -0
- package/dist/esm/ParticleStorage.d.ts.map +1 -0
- package/dist/esm/ParticleStorage.js +208 -0
- package/dist/esm/ParticleStorage.js.map +1 -0
- package/dist/esm/ParticleSystem.d.ts +189 -60
- package/dist/esm/ParticleSystem.d.ts.map +1 -0
- package/dist/esm/ParticleSystem.js +660 -560
- package/dist/esm/ParticleSystem.js.map +1 -1
- package/dist/esm/distributions/BoxArea.d.ts +1 -0
- package/dist/esm/distributions/BoxArea.d.ts.map +1 -0
- package/dist/esm/distributions/BoxArea.js +38 -44
- package/dist/esm/distributions/BoxArea.js.map +1 -1
- package/dist/esm/distributions/CircleArea.d.ts +1 -0
- package/dist/esm/distributions/CircleArea.d.ts.map +1 -0
- package/dist/esm/distributions/CircleArea.js +30 -28
- package/dist/esm/distributions/CircleArea.js.map +1 -1
- package/dist/esm/distributions/ColorGradient.d.ts +3 -2
- package/dist/esm/distributions/ColorGradient.d.ts.map +1 -0
- package/dist/esm/distributions/ColorGradient.js +70 -75
- package/dist/esm/distributions/ColorGradient.js.map +1 -1
- package/dist/esm/distributions/ConeDirection.d.ts +2 -1
- package/dist/esm/distributions/ConeDirection.d.ts.map +1 -0
- package/dist/esm/distributions/ConeDirection.js +41 -39
- package/dist/esm/distributions/ConeDirection.js.map +1 -1
- package/dist/esm/distributions/Constant.d.ts +1 -0
- package/dist/esm/distributions/Constant.d.ts.map +1 -0
- package/dist/esm/distributions/Constant.js +32 -32
- package/dist/esm/distributions/Constant.js.map +1 -1
- package/dist/esm/distributions/Curve.d.ts +2 -1
- package/dist/esm/distributions/Curve.d.ts.map +1 -0
- package/dist/esm/distributions/Curve.js +46 -55
- package/dist/esm/distributions/Curve.js.map +1 -1
- package/dist/esm/distributions/Distribution.d.ts +4 -3
- package/dist/esm/distributions/Distribution.d.ts.map +1 -0
- package/dist/esm/distributions/LineSegment.d.ts +1 -0
- package/dist/esm/distributions/LineSegment.d.ts.map +1 -0
- package/dist/esm/distributions/LineSegment.js +25 -23
- package/dist/esm/distributions/LineSegment.js.map +1 -1
- package/dist/esm/distributions/Range.d.ts +1 -0
- package/dist/esm/distributions/Range.d.ts.map +1 -0
- package/dist/esm/distributions/Range.js +18 -16
- package/dist/esm/distributions/Range.js.map +1 -1
- package/dist/esm/distributions/VectorRange.d.ts +1 -0
- package/dist/esm/distributions/VectorRange.d.ts.map +1 -0
- package/dist/esm/distributions/VectorRange.js +29 -27
- package/dist/esm/distributions/VectorRange.js.map +1 -1
- package/dist/esm/distributions/index.d.ts +1 -0
- package/dist/esm/distributions/index.d.ts.map +1 -0
- package/dist/esm/gpu/ParticleGpuState.d.ts +143 -18
- package/dist/esm/gpu/ParticleGpuState.d.ts.map +1 -0
- package/dist/esm/gpu/ParticleGpuState.js +655 -497
- package/dist/esm/gpu/ParticleGpuState.js.map +1 -1
- package/dist/esm/gpu/shaders/particle-simulate.wgsl.js +6 -0
- package/dist/esm/gpu/shaders/particle-simulate.wgsl.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +39 -32
- package/dist/esm/modules/AlphaFadeOverLifetime.d.ts +4 -3
- package/dist/esm/modules/AlphaFadeOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/AlphaFadeOverLifetime.js +68 -55
- package/dist/esm/modules/AlphaFadeOverLifetime.js.map +1 -1
- package/dist/esm/modules/ApplyForce.d.ts +4 -3
- package/dist/esm/modules/ApplyForce.d.ts.map +1 -0
- package/dist/esm/modules/ApplyForce.js +49 -43
- package/dist/esm/modules/ApplyForce.js.map +1 -1
- package/dist/esm/modules/AttractToPoint.d.ts +4 -3
- package/dist/esm/modules/AttractToPoint.d.ts.map +1 -0
- package/dist/esm/modules/AttractToPoint.js +73 -62
- package/dist/esm/modules/AttractToPoint.js.map +1 -1
- package/dist/esm/modules/BurstSpawn.d.ts +6 -18
- package/dist/esm/modules/BurstSpawn.d.ts.map +1 -0
- package/dist/esm/modules/BurstSpawn.js +56 -91
- package/dist/esm/modules/BurstSpawn.js.map +1 -1
- package/dist/esm/modules/ColorOverLifetime.d.ts +4 -3
- package/dist/esm/modules/ColorOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/ColorOverLifetime.js +65 -53
- package/dist/esm/modules/ColorOverLifetime.js.map +1 -1
- package/dist/esm/modules/ColorOverSpeed.d.ts +5 -4
- package/dist/esm/modules/ColorOverSpeed.d.ts.map +1 -0
- package/dist/esm/modules/ColorOverSpeed.js +90 -75
- package/dist/esm/modules/ColorOverSpeed.js.map +1 -1
- package/dist/esm/modules/DeathModule.d.ts +26 -10
- package/dist/esm/modules/DeathModule.d.ts.map +1 -0
- package/dist/esm/modules/DeathModule.js +38 -22
- package/dist/esm/modules/DeathModule.js.map +1 -1
- package/dist/esm/modules/Drag.d.ts +3 -2
- package/dist/esm/modules/Drag.d.ts.map +1 -0
- package/dist/esm/modules/Drag.js +43 -37
- package/dist/esm/modules/Drag.js.map +1 -1
- package/dist/esm/modules/OrbitalForce.d.ts +4 -3
- package/dist/esm/modules/OrbitalForce.d.ts.map +1 -0
- package/dist/esm/modules/OrbitalForce.js +70 -58
- package/dist/esm/modules/OrbitalForce.js.map +1 -1
- package/dist/esm/modules/RateSpawn.d.ts +7 -22
- package/dist/esm/modules/RateSpawn.d.ts.map +1 -0
- package/dist/esm/modules/RateSpawn.js +39 -71
- package/dist/esm/modules/RateSpawn.js.map +1 -1
- package/dist/esm/modules/RepelFromPoint.d.ts +4 -3
- package/dist/esm/modules/RepelFromPoint.d.ts.map +1 -0
- package/dist/esm/modules/RepelFromPoint.js +72 -62
- package/dist/esm/modules/RepelFromPoint.js.map +1 -1
- package/dist/esm/modules/RotateOverLifetime.d.ts +3 -2
- package/dist/esm/modules/RotateOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/RotateOverLifetime.js +40 -36
- package/dist/esm/modules/RotateOverLifetime.js.map +1 -1
- package/dist/esm/modules/ScaleOverLifetime.d.ts +5 -4
- package/dist/esm/modules/ScaleOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/ScaleOverLifetime.js +60 -50
- package/dist/esm/modules/ScaleOverLifetime.js.map +1 -1
- package/dist/esm/modules/SpawnModule.d.ts +15 -12
- package/dist/esm/modules/SpawnModule.d.ts.map +1 -0
- package/dist/esm/modules/SpawnModule.js +32 -28
- package/dist/esm/modules/SpawnModule.js.map +1 -1
- package/dist/esm/modules/SpawnOnDeath.d.ts +13 -9
- package/dist/esm/modules/SpawnOnDeath.d.ts.map +1 -0
- package/dist/esm/modules/SpawnOnDeath.js +41 -43
- package/dist/esm/modules/SpawnOnDeath.js.map +1 -1
- package/dist/esm/modules/Turbulence.d.ts +4 -3
- package/dist/esm/modules/Turbulence.d.ts.map +1 -0
- package/dist/esm/modules/Turbulence.js +101 -89
- package/dist/esm/modules/Turbulence.js.map +1 -1
- package/dist/esm/modules/UpdateModule.d.ts +21 -13
- package/dist/esm/modules/UpdateModule.d.ts.map +1 -0
- package/dist/esm/modules/UpdateModule.js +65 -63
- package/dist/esm/modules/UpdateModule.js.map +1 -1
- package/dist/esm/modules/VelocityOverLifetime.d.ts +7 -6
- package/dist/esm/modules/VelocityOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/VelocityOverLifetime.js +75 -73
- package/dist/esm/modules/VelocityOverLifetime.js.map +1 -1
- package/dist/esm/modules/WgslContribution.d.ts +16 -15
- package/dist/esm/modules/WgslContribution.d.ts.map +1 -0
- package/dist/esm/modules/WgslContribution.js +37 -29
- package/dist/esm/modules/WgslContribution.js.map +1 -1
- package/dist/esm/modules/index.d.ts +3 -1
- package/dist/esm/modules/index.d.ts.map +1 -0
- package/dist/esm/modules/spawnFields.d.ts +32 -0
- package/dist/esm/modules/spawnFields.d.ts.map +1 -0
- package/dist/esm/modules/spawnFields.js +31 -0
- package/dist/esm/modules/spawnFields.js.map +1 -0
- package/dist/esm/particlesBuildInfo.d.ts +1 -0
- package/dist/esm/particlesBuildInfo.d.ts.map +1 -0
- package/dist/esm/particlesBuildInfo.js +6 -4
- package/dist/esm/particlesBuildInfo.js.map +1 -1
- package/dist/esm/particlesExtension.d.ts +13 -5
- package/dist/esm/particlesExtension.d.ts.map +1 -0
- package/dist/esm/particlesExtension.js +38 -42
- package/dist/esm/particlesExtension.js.map +1 -1
- package/dist/esm/public.d.ts +11 -0
- package/dist/esm/public.d.ts.map +1 -0
- package/dist/esm/renderModes/MeshParticles.d.ts +128 -0
- package/dist/esm/renderModes/MeshParticles.d.ts.map +1 -0
- package/dist/esm/renderModes/MeshParticles.js +263 -0
- package/dist/esm/renderModes/MeshParticles.js.map +1 -0
- package/dist/esm/renderModes/ParticleBufferLayout.d.ts +59 -0
- package/dist/esm/renderModes/ParticleBufferLayout.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleBufferLayout.js +99 -0
- package/dist/esm/renderModes/ParticleBufferLayout.js.map +1 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.d.ts +58 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.js +173 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.js.map +1 -0
- package/dist/esm/renderModes/ParticleMaterial.d.ts +18 -0
- package/dist/esm/renderModes/ParticleMaterial.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleMaterial.js +24 -0
- package/dist/esm/renderModes/ParticleMaterial.js.map +1 -0
- package/dist/esm/renderModes/ParticleRenderMode.d.ts +114 -0
- package/dist/esm/renderModes/ParticleRenderMode.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleRenderMode.js +99 -0
- package/dist/esm/renderModes/ParticleRenderMode.js.map +1 -0
- package/dist/esm/renderModes/QuadParticles.d.ts +55 -0
- package/dist/esm/renderModes/QuadParticles.d.ts.map +1 -0
- package/dist/esm/renderModes/QuadParticles.js +95 -0
- package/dist/esm/renderModes/QuadParticles.js.map +1 -0
- package/dist/esm/renderModes/RibbonParticles.d.ts +96 -0
- package/dist/esm/renderModes/RibbonParticles.d.ts.map +1 -0
- package/dist/esm/renderModes/RibbonParticles.js +202 -0
- package/dist/esm/renderModes/RibbonParticles.js.map +1 -0
- package/dist/esm/renderModes/shaders/mesh-particles.wgsl.js +6 -0
- package/dist/esm/renderModes/shaders/mesh-particles.wgsl.js.map +1 -0
- package/dist/esm/renderModes/shaders/mesh.vert.js +6 -0
- package/dist/esm/renderModes/shaders/mesh.vert.js.map +1 -0
- package/dist/esm/renderModes/shaders/quad-particles.wgsl.js +6 -0
- package/dist/esm/renderModes/shaders/quad-particles.wgsl.js.map +1 -0
- package/dist/esm/renderModes/shaders/ribbon-particles.wgsl.js +6 -0
- package/dist/esm/renderModes/shaders/ribbon-particles.wgsl.js.map +1 -0
- package/dist/esm/renderModes/shaders/ribbon.frag.js +6 -0
- package/dist/esm/renderModes/shaders/ribbon.frag.js.map +1 -0
- package/dist/esm/renderModes/shaders/ribbon.vert.js +6 -0
- package/dist/esm/renderModes/shaders/ribbon.vert.js.map +1 -0
- package/dist/esm/renderers/WebGl2ParticleRenderer.d.ts +48 -20
- package/dist/esm/renderers/WebGl2ParticleRenderer.d.ts.map +1 -0
- package/dist/esm/renderers/WebGl2ParticleRenderer.js +317 -321
- package/dist/esm/renderers/WebGl2ParticleRenderer.js.map +1 -1
- package/dist/esm/renderers/WebGpuParticleRenderer.d.ts +99 -18
- package/dist/esm/renderers/WebGpuParticleRenderer.d.ts.map +1 -0
- package/dist/esm/renderers/WebGpuParticleRenderer.js +542 -551
- package/dist/esm/renderers/WebGpuParticleRenderer.js.map +1 -1
- package/dist/esm/renderers/shaders/particle.frag.js +6 -0
- package/dist/esm/renderers/shaders/particle.frag.js.map +1 -0
- package/dist/esm/renderers/shaders/particle.vert.js +6 -0
- package/dist/esm/renderers/shaders/particle.vert.js.map +1 -0
- package/package.json +8 -15
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/register.d.ts +0 -1
- package/dist/esm/register.js +0 -43
- package/dist/esm/register.js.map +0 -1
- package/dist/esm/renderers/glsl/particle.frag.js +0 -4
- package/dist/esm/renderers/glsl/particle.frag.js.map +0 -1
- package/dist/esm/renderers/glsl/particle.vert.js +0 -4
- package/dist/esm/renderers/glsl/particle.vert.js.map +0 -1
|
@@ -1,41 +1,45 @@
|
|
|
1
|
-
import { UpdateModule } from
|
|
1
|
+
import { UpdateModule } from "./UpdateModule.js";
|
|
2
2
|
|
|
3
|
+
//#region src/modules/RotateOverLifetime.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
5
|
+
* Adds a constant angular acceleration to every live particle each frame
|
|
6
|
+
* (analogous to the legacy `TorqueAffector`). The system's integrate pass
|
|
7
|
+
* advances `rotation` from `rotationSpeed`; this module increments
|
|
8
|
+
* `rotationSpeed` itself.
|
|
9
|
+
*
|
|
10
|
+
* Units: degrees per second². Negative values decelerate spin.
|
|
11
|
+
*
|
|
12
|
+
* GPU-eligible.
|
|
13
|
+
*/
|
|
14
|
+
var RotateOverLifetime = class extends UpdateModule {
|
|
15
|
+
angularAcceleration;
|
|
16
|
+
constructor(angularAcceleration) {
|
|
17
|
+
super();
|
|
18
|
+
this.angularAcceleration = angularAcceleration;
|
|
19
|
+
}
|
|
20
|
+
apply(particles, dt) {
|
|
21
|
+
const { speed: rotationSpeeds } = particles.rotation;
|
|
22
|
+
const liveCount = particles.count;
|
|
23
|
+
const delta = this.angularAcceleration * dt;
|
|
24
|
+
for (let i = 0; i < liveCount; i++) rotationSpeeds[i] = (rotationSpeeds[i] ?? 0) + delta;
|
|
25
|
+
}
|
|
26
|
+
wgsl() {
|
|
27
|
+
return {
|
|
28
|
+
key: "RotateOverLifetime",
|
|
29
|
+
uniforms: [{
|
|
30
|
+
name: "angularAcceleration",
|
|
31
|
+
type: "f32"
|
|
32
|
+
}],
|
|
33
|
+
body: `
|
|
31
34
|
rotInfo[idx].y = rotInfo[idx].y + modules.u_RotateOverLifetime.angularAcceleration * dt;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
35
|
+
`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
writeUniforms(view, offset) {
|
|
39
|
+
view.setFloat32(offset + 0, this.angularAcceleration, true);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
39
42
|
|
|
43
|
+
//#endregion
|
|
40
44
|
export { RotateOverLifetime };
|
|
41
|
-
//# sourceMappingURL=RotateOverLifetime.js.map
|
|
45
|
+
//# sourceMappingURL=RotateOverLifetime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RotateOverLifetime.js","sources":["
|
|
1
|
+
{"version":3,"file":"RotateOverLifetime.js","names":[],"sources":["../../../src/modules/RotateOverLifetime.ts"],"sourcesContent":["import type { ParticleBatch } from '#ParticleStorage';\n\nimport { UpdateModule } from './UpdateModule';\nimport type { WgslContribution } from './WgslContribution';\n\n/**\n * Adds a constant angular acceleration to every live particle each frame\n * (analogous to the legacy `TorqueAffector`). The system's integrate pass\n * advances `rotation` from `rotationSpeed`; this module increments\n * `rotationSpeed` itself.\n *\n * Units: degrees per second². Negative values decelerate spin.\n *\n * GPU-eligible.\n */\nexport class RotateOverLifetime extends UpdateModule {\n public angularAcceleration: number;\n\n public constructor(angularAcceleration: number) {\n super();\n this.angularAcceleration = angularAcceleration;\n }\n\n public override apply(particles: ParticleBatch, dt: number): void {\n const { speed: rotationSpeeds } = particles.rotation;\n const liveCount = particles.count;\n const delta = this.angularAcceleration * dt;\n\n for (let i = 0; i < liveCount; i++) {\n rotationSpeeds[i] = (rotationSpeeds[i] ?? 0) + delta;\n }\n }\n\n public override wgsl(): WgslContribution {\n return {\n key: 'RotateOverLifetime',\n uniforms: [{ name: 'angularAcceleration', type: 'f32' }],\n body: `\n rotInfo[idx].y = rotInfo[idx].y + modules.u_RotateOverLifetime.angularAcceleration * dt;\n `,\n };\n }\n\n public override writeUniforms(view: DataView, offset: number): void {\n view.setFloat32(offset + 0, this.angularAcceleration, true);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAa,qBAAb,cAAwC,aAAa;CACnD,AAAO;CAEP,AAAO,YAAY,qBAA6B;EAC9C,MAAM;EACN,KAAK,sBAAsB;CAC7B;CAEA,AAAgB,MAAM,WAA0B,IAAkB;EAChE,MAAM,EAAE,OAAO,mBAAmB,UAAU;EAC5C,MAAM,YAAY,UAAU;EAC5B,MAAM,QAAQ,KAAK,sBAAsB;EAEzC,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAC7B,eAAe,MAAM,eAAe,MAAM,KAAK;CAEnD;CAEA,AAAgB,OAAyB;EACvC,OAAO;GACL,KAAK;GACL,UAAU,CAAC;IAAE,MAAM;IAAuB,MAAM;GAAM,CAAC;GACvD,MAAM;;;EAGR;CACF;CAEA,AAAgB,cAAc,MAAgB,QAAsB;EAClE,KAAK,WAAW,SAAS,GAAG,KAAK,qBAAqB,IAAI;CAC5D;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Curve } from
|
|
2
|
-
import type {
|
|
1
|
+
import type { Curve } from '#distributions/Curve';
|
|
2
|
+
import type { ParticleBatch } from '#ParticleStorage';
|
|
3
3
|
import { UpdateModule } from './UpdateModule';
|
|
4
4
|
import type { WgslContribution } from './WgslContribution';
|
|
5
5
|
/**
|
|
@@ -11,15 +11,16 @@ import type { WgslContribution } from './WgslContribution';
|
|
|
11
11
|
* curve up to peak then down), slow-grow (linear ramp).
|
|
12
12
|
*
|
|
13
13
|
* GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and
|
|
14
|
-
* sampled with linear filtering on the GPU
|
|
14
|
+
* sampled with linear filtering on the GPU - no curve evaluation cost in
|
|
15
15
|
* the inner loop.
|
|
16
16
|
*/
|
|
17
17
|
export declare class ScaleOverLifetime extends UpdateModule {
|
|
18
18
|
curve: Curve;
|
|
19
19
|
constructor(curve: Curve);
|
|
20
|
-
apply(
|
|
20
|
+
apply(particles: ParticleBatch, _dt: number): void;
|
|
21
21
|
wgsl(): WgslContribution;
|
|
22
22
|
uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void;
|
|
23
23
|
}
|
|
24
24
|
/** Texture width for the curve lookup table. Exposed for ParticleGpuState. */
|
|
25
25
|
export declare const scaleLookupSize = 256;
|
|
26
|
+
//# sourceMappingURL=ScaleOverLifetime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScaleOverLifetime.d.ts","sourceRoot":"","sources":["../../../src/modules/ScaleOverLifetime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IAC1C,KAAK,EAAE,KAAK,CAAC;gBAED,KAAK,EAAE,KAAK;IAKf,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAelD,IAAI,IAAI,gBAAgB;IAYxB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI;CAoBnG;AAED,8EAA8E;AAC9E,eAAO,MAAM,eAAe,MAAa,CAAC"}
|
|
@@ -1,58 +1,68 @@
|
|
|
1
|
-
import { UpdateModule } from
|
|
1
|
+
import { UpdateModule } from "./UpdateModule.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
//#region src/modules/ScaleOverLifetime.ts
|
|
4
4
|
const lookupSize = 256;
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
6
|
+
* Sets every live particle's scale to a curve sampled at the particle's
|
|
7
|
+
* current lifetime ratio. Both axes share one curve; non-uniform per-axis
|
|
8
|
+
* scaling isn't supported by this module.
|
|
9
|
+
*
|
|
10
|
+
* Common patterns: shrink-to-zero (start at 1, end at 0), pulse (sine-like
|
|
11
|
+
* curve up to peak then down), slow-grow (linear ramp).
|
|
12
|
+
*
|
|
13
|
+
* GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and
|
|
14
|
+
* sampled with linear filtering on the GPU - no curve evaluation cost in
|
|
15
|
+
* the inner loop.
|
|
16
|
+
*/
|
|
17
|
+
var ScaleOverLifetime = class extends UpdateModule {
|
|
18
|
+
curve;
|
|
19
|
+
constructor(curve) {
|
|
20
|
+
super();
|
|
21
|
+
this.curve = curve;
|
|
22
|
+
}
|
|
23
|
+
apply(particles, _dt) {
|
|
24
|
+
const { x: scaleX, y: scaleY } = particles.scale;
|
|
25
|
+
const { elapsed, lifetime } = particles.timing;
|
|
26
|
+
const liveCount = particles.count;
|
|
27
|
+
const curve = this.curve;
|
|
28
|
+
for (let i = 0; i < liveCount; i++) {
|
|
29
|
+
const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);
|
|
30
|
+
const s = curve.evaluate(t);
|
|
31
|
+
scaleX[i] = s;
|
|
32
|
+
scaleY[i] = s;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
wgsl() {
|
|
36
|
+
return {
|
|
37
|
+
key: "ScaleOverLifetime",
|
|
38
|
+
textures: [{
|
|
39
|
+
name: "curve",
|
|
40
|
+
format: "r32float"
|
|
41
|
+
}],
|
|
42
|
+
body: `
|
|
38
43
|
let scaleT = clamp(timing[idx].x / max(timing[idx].y, 0.000001), 0.0, 1.0);
|
|
39
44
|
let scaleSample = textureSampleLevel(u_ScaleOverLifetime_curve, u_ScaleOverLifetime_curve_sampler, scaleT, 0.0).r;
|
|
40
45
|
scales[idx] = vec2<f32>(scaleSample, scaleSample);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
`
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
uploadTextures(device, textures) {
|
|
50
|
+
const texture = textures.get("curve");
|
|
51
|
+
if (texture === void 0) return;
|
|
52
|
+
const data = new Float32Array(lookupSize);
|
|
53
|
+
for (let i = 0; i < lookupSize; i++) data[i] = this.curve.evaluate(i / 255);
|
|
54
|
+
device.queue.writeTexture({ texture }, data.buffer, {
|
|
55
|
+
offset: 0,
|
|
56
|
+
bytesPerRow: lookupSize * 4,
|
|
57
|
+
rowsPerImage: 1
|
|
58
|
+
}, {
|
|
59
|
+
width: lookupSize,
|
|
60
|
+
height: 1,
|
|
61
|
+
depthOrArrayLayers: 1
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
56
65
|
|
|
66
|
+
//#endregion
|
|
57
67
|
export { ScaleOverLifetime };
|
|
58
|
-
//# sourceMappingURL=ScaleOverLifetime.js.map
|
|
68
|
+
//# sourceMappingURL=ScaleOverLifetime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScaleOverLifetime.js","sources":["
|
|
1
|
+
{"version":3,"file":"ScaleOverLifetime.js","names":[],"sources":["../../../src/modules/ScaleOverLifetime.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n\nimport type { Curve } from '#distributions/Curve';\nimport type { ParticleBatch } from '#ParticleStorage';\n\nimport { UpdateModule } from './UpdateModule';\nimport type { WgslContribution } from './WgslContribution';\n\nconst lookupSize = 256;\n\n/**\n * Sets every live particle's scale to a curve sampled at the particle's\n * current lifetime ratio. Both axes share one curve; non-uniform per-axis\n * scaling isn't supported by this module.\n *\n * Common patterns: shrink-to-zero (start at 1, end at 0), pulse (sine-like\n * curve up to peak then down), slow-grow (linear ramp).\n *\n * GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and\n * sampled with linear filtering on the GPU - no curve evaluation cost in\n * the inner loop.\n */\nexport class ScaleOverLifetime extends UpdateModule {\n public curve: Curve;\n\n public constructor(curve: Curve) {\n super();\n this.curve = curve;\n }\n\n public override apply(particles: ParticleBatch, _dt: number): void {\n const { x: scaleX, y: scaleY } = particles.scale;\n const { elapsed, lifetime } = particles.timing;\n const liveCount = particles.count;\n const curve = this.curve;\n\n for (let i = 0; i < liveCount; i++) {\n const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);\n const s = curve.evaluate(t);\n\n scaleX[i] = s;\n scaleY[i] = s;\n }\n }\n\n public override wgsl(): WgslContribution {\n return {\n key: 'ScaleOverLifetime',\n textures: [{ name: 'curve', format: 'r32float' }],\n body: `\n let scaleT = clamp(timing[idx].x / max(timing[idx].y, 0.000001), 0.0, 1.0);\n let scaleSample = textureSampleLevel(u_ScaleOverLifetime_curve, u_ScaleOverLifetime_curve_sampler, scaleT, 0.0).r;\n scales[idx] = vec2<f32>(scaleSample, scaleSample);\n `,\n };\n }\n\n public override uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void {\n const texture = textures.get('curve');\n\n if (texture === undefined) {\n return;\n }\n\n const data = new Float32Array(lookupSize);\n\n for (let i = 0; i < lookupSize; i++) {\n data[i] = this.curve.evaluate(i / (lookupSize - 1));\n }\n\n device.queue.writeTexture(\n { texture },\n data.buffer,\n { offset: 0, bytesPerRow: lookupSize * 4, rowsPerImage: 1 },\n { width: lookupSize, height: 1, depthOrArrayLayers: 1 },\n );\n }\n}\n\n/** Texture width for the curve lookup table. Exposed for ParticleGpuState. */\nexport const scaleLookupSize = lookupSize;\n"],"mappings":";;;AAQA,MAAM,aAAa;;;;;;;;;;;;;AAcnB,IAAa,oBAAb,cAAuC,aAAa;CAClD,AAAO;CAEP,AAAO,YAAY,OAAc;EAC/B,MAAM;EACN,KAAK,QAAQ;CACf;CAEA,AAAgB,MAAM,WAA0B,KAAmB;EACjE,MAAM,EAAE,GAAG,QAAQ,GAAG,WAAW,UAAU;EAC3C,MAAM,EAAE,SAAS,aAAa,UAAU;EACxC,MAAM,YAAY,UAAU;EAC5B,MAAM,QAAQ,KAAK;EAEnB,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;GAClC,MAAM,KAAK,QAAQ,MAAM,MAAM,SAAS,MAAM;GAC9C,MAAM,IAAI,MAAM,SAAS,CAAC;GAE1B,OAAO,KAAK;GACZ,OAAO,KAAK;EACd;CACF;CAEA,AAAgB,OAAyB;EACvC,OAAO;GACL,KAAK;GACL,UAAU,CAAC;IAAE,MAAM;IAAS,QAAQ;GAAW,CAAC;GAChD,MAAM;;;;;EAKR;CACF;CAEA,AAAgB,eAAe,QAAmB,UAAiD;EACjG,MAAM,UAAU,SAAS,IAAI,OAAO;EAEpC,IAAI,YAAY,QACd;EAGF,MAAM,OAAO,IAAI,aAAa,UAAU;EAExC,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAC9B,KAAK,KAAK,KAAK,MAAM,SAAS,IAAK,GAAe;EAGpD,OAAO,MAAM,aACX,EAAE,QAAQ,GACV,KAAK,QACL;GAAE,QAAQ;GAAG,aAAa,aAAa;GAAG,cAAc;EAAE,GAC1D;GAAE,OAAO;GAAY,QAAQ;GAAG,oBAAoB;EAAE,CACxD;CACF;AACF"}
|
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ParticleEmitter } from '#ParticleStorage';
|
|
2
2
|
/**
|
|
3
|
-
* Per-frame particle spawner. Subclasses decide how many particles to emit
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Per-frame particle spawner. Subclasses decide how many particles to emit each
|
|
4
|
+
* tick (rate-based, burst, on-demand) and fill each emitted particle's initial
|
|
5
|
+
* values.
|
|
6
6
|
*
|
|
7
7
|
* Implementation pattern:
|
|
8
8
|
*
|
|
9
9
|
* ```ts
|
|
10
|
-
* apply(
|
|
10
|
+
* apply(emitter, dt) {
|
|
11
11
|
* const count = this.computeSpawnCount(dt);
|
|
12
12
|
* for (let i = 0; i < count; i++) {
|
|
13
|
-
* const
|
|
14
|
-
* if (
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* // ...etc
|
|
13
|
+
* const particle = emitter.emit();
|
|
14
|
+
* if (!particle) break; // capacity exhausted
|
|
15
|
+
* particle.position.set(x, y);
|
|
16
|
+
* particle.velocity.set(vx, vy);
|
|
17
|
+
* particle.lifetime = 2;
|
|
19
18
|
* }
|
|
20
19
|
* }
|
|
21
20
|
* ```
|
|
22
21
|
*
|
|
22
|
+
* A writer belongs to the emission that produced it: the next `emit()` rebinds
|
|
23
|
+
* it, so fill it before emitting again.
|
|
24
|
+
*
|
|
23
25
|
* Spawn modules run before integration each frame. Multiple modules can be
|
|
24
26
|
* registered on one system and execute in registration order.
|
|
25
27
|
*/
|
|
26
28
|
export declare abstract class SpawnModule {
|
|
27
|
-
abstract apply(
|
|
29
|
+
abstract apply(emitter: ParticleEmitter, dt: number): void;
|
|
28
30
|
/** Optional cleanup hook called from `ParticleSystem.destroy`. */
|
|
29
31
|
destroy(): void;
|
|
30
32
|
}
|
|
33
|
+
//# sourceMappingURL=SpawnModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnModule.d.ts","sourceRoot":"","sources":["../../../src/modules/SpawnModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,8BAAsB,WAAW;aACf,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IACjE,kEAAkE;IAC3D,OAAO,IAAI,IAAI;CACvB"}
|
|
@@ -1,31 +1,35 @@
|
|
|
1
|
+
//#region src/modules/SpawnModule.ts
|
|
1
2
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
3
|
+
* Per-frame particle spawner. Subclasses decide how many particles to emit each
|
|
4
|
+
* tick (rate-based, burst, on-demand) and fill each emitted particle's initial
|
|
5
|
+
* values.
|
|
6
|
+
*
|
|
7
|
+
* Implementation pattern:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* apply(emitter, dt) {
|
|
11
|
+
* const count = this.computeSpawnCount(dt);
|
|
12
|
+
* for (let i = 0; i < count; i++) {
|
|
13
|
+
* const particle = emitter.emit();
|
|
14
|
+
* if (!particle) break; // capacity exhausted
|
|
15
|
+
* particle.position.set(x, y);
|
|
16
|
+
* particle.velocity.set(vx, vy);
|
|
17
|
+
* particle.lifetime = 2;
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* A writer belongs to the emission that produced it: the next `emit()` rebinds
|
|
23
|
+
* it, so fill it before emitting again.
|
|
24
|
+
*
|
|
25
|
+
* Spawn modules run before integration each frame. Multiple modules can be
|
|
26
|
+
* registered on one system and execute in registration order.
|
|
27
|
+
*/
|
|
28
|
+
var SpawnModule = class {
|
|
29
|
+
/** Optional cleanup hook called from `ParticleSystem.destroy`. */
|
|
30
|
+
destroy() {}
|
|
31
|
+
};
|
|
29
32
|
|
|
33
|
+
//#endregion
|
|
30
34
|
export { SpawnModule };
|
|
31
|
-
//# sourceMappingURL=SpawnModule.js.map
|
|
35
|
+
//# sourceMappingURL=SpawnModule.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpawnModule.js","sources":["
|
|
1
|
+
{"version":3,"file":"SpawnModule.js","names":[],"sources":["../../../src/modules/SpawnModule.ts"],"sourcesContent":["import type { ParticleEmitter } from '#ParticleStorage';\n\n/**\n * Per-frame particle spawner. Subclasses decide how many particles to emit each\n * tick (rate-based, burst, on-demand) and fill each emitted particle's initial\n * values.\n *\n * Implementation pattern:\n *\n * ```ts\n * apply(emitter, dt) {\n * const count = this.computeSpawnCount(dt);\n * for (let i = 0; i < count; i++) {\n * const particle = emitter.emit();\n * if (!particle) break; // capacity exhausted\n * particle.position.set(x, y);\n * particle.velocity.set(vx, vy);\n * particle.lifetime = 2;\n * }\n * }\n * ```\n *\n * A writer belongs to the emission that produced it: the next `emit()` rebinds\n * it, so fill it before emitting again.\n *\n * Spawn modules run before integration each frame. Multiple modules can be\n * registered on one system and execute in registration order.\n */\nexport abstract class SpawnModule {\n public abstract apply(emitter: ParticleEmitter, dt: number): void;\n /** Optional cleanup hook called from `ParticleSystem.destroy`. */\n public destroy(): void {}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,IAAsB,cAAtB,MAAkC;;CAGhC,AAAO,UAAgB,CAAC;AAC1B"}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ParticleDeathContext } from '#ParticleStorage';
|
|
2
|
+
import type { ParticleSystem } from '#ParticleSystem';
|
|
2
3
|
import { DeathModule } from './DeathModule';
|
|
3
4
|
import type { SpawnModule } from './SpawnModule';
|
|
4
5
|
/**
|
|
5
|
-
* Sub-emitter: triggers a child {@link SpawnModule} on a target system at
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Sub-emitter: triggers a child {@link SpawnModule} on a target system at the
|
|
7
|
+
* dying particle's position. Use for explosion-on-impact, sparks at end of
|
|
8
|
+
* life, multi-stage VFX.
|
|
8
9
|
*
|
|
9
|
-
* The child module receives a synthesized `dt` of 0
|
|
10
|
+
* The child module receives a synthesized `dt` of 0 - it must spawn
|
|
10
11
|
* immediately rather than rely on rate accumulation. {@link BurstSpawn}
|
|
11
12
|
* works naturally; {@link RateSpawn} is the wrong fit here.
|
|
12
13
|
*
|
|
13
|
-
* Position is the only field
|
|
14
|
-
* everything else
|
|
15
|
-
*
|
|
14
|
+
* Position is the only field taken from the dying particle - child
|
|
15
|
+
* distributions decide everything else, and their sampled positions are treated
|
|
16
|
+
* as offsets from the death position. To keep child particles riding the
|
|
17
|
+
* parent's velocity, configure the child's velocity distribution to match, or
|
|
18
|
+
* read {@link ParticleDeathContext.velocityX} in a custom death module.
|
|
16
19
|
*/
|
|
17
20
|
export declare class SpawnOnDeath extends DeathModule {
|
|
18
21
|
targetSystem: ParticleSystem;
|
|
@@ -20,5 +23,6 @@ export declare class SpawnOnDeath extends DeathModule {
|
|
|
20
23
|
/** Number of times to invoke the spawner per dying particle. Default 1. */
|
|
21
24
|
count: number;
|
|
22
25
|
constructor(targetSystem: ParticleSystem, spawner: SpawnModule, count?: number);
|
|
23
|
-
onDeath(
|
|
26
|
+
onDeath(_system: ParticleSystem, death: ParticleDeathContext): void;
|
|
24
27
|
}
|
|
28
|
+
//# sourceMappingURL=SpawnOnDeath.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnOnDeath.d.ts","sourceRoot":"","sources":["../../../src/modules/SpawnOnDeath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,SAAQ,WAAW;IACpC,YAAY,EAAE,cAAc,CAAC;IAC7B,OAAO,EAAE,WAAW,CAAC;IAE5B,2EAA2E;IACpE,KAAK,EAAE,MAAM,CAAC;gBAEF,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,SAAI;IAOhE,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI;CAoBpF"}
|
|
@@ -1,47 +1,45 @@
|
|
|
1
|
-
import { DeathModule } from
|
|
1
|
+
import { DeathModule } from "./DeathModule.js";
|
|
2
2
|
|
|
3
|
+
//#region src/modules/SpawnOnDeath.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
target.posY[dst] = (target.posY[dst] ?? 0) + y;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
5
|
+
* Sub-emitter: triggers a child {@link SpawnModule} on a target system at the
|
|
6
|
+
* dying particle's position. Use for explosion-on-impact, sparks at end of
|
|
7
|
+
* life, multi-stage VFX.
|
|
8
|
+
*
|
|
9
|
+
* The child module receives a synthesized `dt` of 0 - it must spawn
|
|
10
|
+
* immediately rather than rely on rate accumulation. {@link BurstSpawn}
|
|
11
|
+
* works naturally; {@link RateSpawn} is the wrong fit here.
|
|
12
|
+
*
|
|
13
|
+
* Position is the only field taken from the dying particle - child
|
|
14
|
+
* distributions decide everything else, and their sampled positions are treated
|
|
15
|
+
* as offsets from the death position. To keep child particles riding the
|
|
16
|
+
* parent's velocity, configure the child's velocity distribution to match, or
|
|
17
|
+
* read {@link ParticleDeathContext.velocityX} in a custom death module.
|
|
18
|
+
*/
|
|
19
|
+
var SpawnOnDeath = class extends DeathModule {
|
|
20
|
+
targetSystem;
|
|
21
|
+
spawner;
|
|
22
|
+
/** Number of times to invoke the spawner per dying particle. Default 1. */
|
|
23
|
+
count;
|
|
24
|
+
constructor(targetSystem, spawner, count = 1) {
|
|
25
|
+
super();
|
|
26
|
+
this.targetSystem = targetSystem;
|
|
27
|
+
this.spawner = spawner;
|
|
28
|
+
this.count = count;
|
|
29
|
+
}
|
|
30
|
+
onDeath(_system, death) {
|
|
31
|
+
const target = this.targetSystem;
|
|
32
|
+
const previous = target._beginSpawnRecording();
|
|
33
|
+
let spawned;
|
|
34
|
+
try {
|
|
35
|
+
for (let n = 0; n < this.count; n++) this.spawner.apply(target, 0);
|
|
36
|
+
} finally {
|
|
37
|
+
spawned = target._endSpawnRecording(previous);
|
|
38
|
+
}
|
|
39
|
+
target._offsetSpawned(spawned, death.x, death.y);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
45
42
|
|
|
43
|
+
//#endregion
|
|
46
44
|
export { SpawnOnDeath };
|
|
47
|
-
//# sourceMappingURL=SpawnOnDeath.js.map
|
|
45
|
+
//# sourceMappingURL=SpawnOnDeath.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpawnOnDeath.js","sources":["
|
|
1
|
+
{"version":3,"file":"SpawnOnDeath.js","names":[],"sources":["../../../src/modules/SpawnOnDeath.ts"],"sourcesContent":["import type { ParticleDeathContext } from '#ParticleStorage';\nimport type { ParticleSystem } from '#ParticleSystem';\n\nimport { DeathModule } from './DeathModule';\nimport type { SpawnModule } from './SpawnModule';\n\n/**\n * Sub-emitter: triggers a child {@link SpawnModule} on a target system at the\n * dying particle's position. Use for explosion-on-impact, sparks at end of\n * life, multi-stage VFX.\n *\n * The child module receives a synthesized `dt` of 0 - it must spawn\n * immediately rather than rely on rate accumulation. {@link BurstSpawn}\n * works naturally; {@link RateSpawn} is the wrong fit here.\n *\n * Position is the only field taken from the dying particle - child\n * distributions decide everything else, and their sampled positions are treated\n * as offsets from the death position. To keep child particles riding the\n * parent's velocity, configure the child's velocity distribution to match, or\n * read {@link ParticleDeathContext.velocityX} in a custom death module.\n */\nexport class SpawnOnDeath extends DeathModule {\n public targetSystem: ParticleSystem;\n public spawner: SpawnModule;\n\n /** Number of times to invoke the spawner per dying particle. Default 1. */\n public count: number;\n\n public constructor(targetSystem: ParticleSystem, spawner: SpawnModule, count = 1) {\n super();\n this.targetSystem = targetSystem;\n this.spawner = spawner;\n this.count = count;\n }\n\n public override onDeath(_system: ParticleSystem, death: ParticleDeathContext): void {\n const target = this.targetSystem;\n\n // Which particles the spawner produced cannot be derived from the target's\n // live count: on the GPU path an emission recycles a dead slot below the\n // high-water mark, so the count can stay put while particles are added, and\n // the reused slots are scattered rather than contiguous.\n const previous = target._beginSpawnRecording();\n let spawned: readonly number[];\n\n try {\n for (let n = 0; n < this.count; n++) {\n this.spawner.apply(target, 0);\n }\n } finally {\n spawned = target._endSpawnRecording(previous);\n }\n\n target._offsetSpawned(spawned, death.x, death.y);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,IAAa,eAAb,cAAkC,YAAY;CAC5C,AAAO;CACP,AAAO;;CAGP,AAAO;CAEP,AAAO,YAAY,cAA8B,SAAsB,QAAQ,GAAG;EAChF,MAAM;EACN,KAAK,eAAe;EACpB,KAAK,UAAU;EACf,KAAK,QAAQ;CACf;CAEA,AAAgB,QAAQ,SAAyB,OAAmC;EAClF,MAAM,SAAS,KAAK;EAMpB,MAAM,WAAW,OAAO,qBAAqB;EAC7C,IAAI;EAEJ,IAAI;GACF,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,OAAO,KAC9B,KAAK,QAAQ,MAAM,QAAQ,CAAC;EAEhC,UAAU;GACR,UAAU,OAAO,mBAAmB,QAAQ;EAC9C;EAEA,OAAO,eAAe,SAAS,MAAM,GAAG,MAAM,CAAC;CACjD;AACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ParticleBatch } from '#ParticleStorage';
|
|
2
2
|
import { UpdateModule } from './UpdateModule';
|
|
3
3
|
import type { WgslContribution } from './WgslContribution';
|
|
4
4
|
/**
|
|
5
5
|
* Adds a smooth pseudo-random force field that animates over time.
|
|
6
|
-
* Implemented as 2D value noise with cubic Hermite smoothing
|
|
6
|
+
* Implemented as 2D value noise with cubic Hermite smoothing - sampled
|
|
7
7
|
* twice per particle (offset to decorrelate x and y components) and scaled
|
|
8
8
|
* by `strength`. The field evolves at `timeScale` units per second; lower
|
|
9
9
|
* values produce slow-moving currents, higher values produce buzzy chaos.
|
|
@@ -24,7 +24,8 @@ export declare class Turbulence extends UpdateModule {
|
|
|
24
24
|
timeScale: number;
|
|
25
25
|
private _time;
|
|
26
26
|
constructor(strength: number, frequency?: number, timeScale?: number);
|
|
27
|
-
apply(
|
|
27
|
+
apply(particles: ParticleBatch, dt: number): void;
|
|
28
28
|
wgsl(): WgslContribution;
|
|
29
29
|
writeUniforms(view: DataView, offset: number, dt: number): void;
|
|
30
30
|
}
|
|
31
|
+
//# sourceMappingURL=Turbulence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Turbulence.d.ts","sourceRoot":"","sources":["../../../src/modules/Turbulence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAW,SAAQ,YAAY;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,KAAK,CAAK;gBAEC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,SAAS,SAAI;IAOpD,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAqBjD,IAAI,IAAI,gBAAgB;IA4CxB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;CAWhF"}
|