@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,63 +1,60 @@
|
|
|
1
|
-
import { UpdateModule } from
|
|
1
|
+
import { UpdateModule } from "./UpdateModule.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
//#region src/modules/VelocityOverLifetime.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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
key: 'VelocityOverLifetime',
|
|
59
|
-
textures: [{ name: 'curve', format: 'r32float' }],
|
|
60
|
-
body: `
|
|
6
|
+
* Multiplies every live particle's velocity by a curve sampled at the
|
|
7
|
+
* particle's current `elapsed / lifetime` ratio. The same scalar is applied
|
|
8
|
+
* to both axes - the direction is preserved, only the magnitude scales.
|
|
9
|
+
*
|
|
10
|
+
* Common patterns:
|
|
11
|
+
* - **Snappy spawn, slow drift:** `[0,1]→[1,0.1]` - fast initial motion
|
|
12
|
+
* that decays over lifetime.
|
|
13
|
+
* - **Late acceleration:** `[0,0.2]→[1,1]` - particles ease in.
|
|
14
|
+
* - **Pulse:** sine-shaped curve for breathing-style motion.
|
|
15
|
+
*
|
|
16
|
+
* Note: the curve **replaces** velocity each frame relative to the previous
|
|
17
|
+
* frame's velocity, so the effect is multiplicative. Pair with `ApplyForce`
|
|
18
|
+
* if you want a constant external acceleration on top.
|
|
19
|
+
*
|
|
20
|
+
* GPU-eligible: uploads the curve as a 256-tap 1D R32F texture; sampled
|
|
21
|
+
* once per particle per frame.
|
|
22
|
+
*/
|
|
23
|
+
var VelocityOverLifetime = class extends UpdateModule {
|
|
24
|
+
curve;
|
|
25
|
+
_prevSample = /* @__PURE__ */ new Float32Array(0);
|
|
26
|
+
constructor(curve) {
|
|
27
|
+
super();
|
|
28
|
+
this.curve = curve;
|
|
29
|
+
}
|
|
30
|
+
apply(particles, _dt) {
|
|
31
|
+
const { x: velX, y: velY } = particles.velocity;
|
|
32
|
+
const { elapsed, lifetime } = particles.timing;
|
|
33
|
+
const liveCount = particles.count;
|
|
34
|
+
const curve = this.curve;
|
|
35
|
+
if (this._prevSample.length < particles.capacity) {
|
|
36
|
+
this._prevSample = new Float32Array(particles.capacity);
|
|
37
|
+
this._prevSample.fill(1);
|
|
38
|
+
}
|
|
39
|
+
const prev = this._prevSample;
|
|
40
|
+
for (let i = 0; i < liveCount; i++) {
|
|
41
|
+
const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);
|
|
42
|
+
const sample = curve.evaluate(t);
|
|
43
|
+
const prevSample = prev[i] ?? 1;
|
|
44
|
+
const delta = sample / (prevSample === 0 ? 1 : prevSample);
|
|
45
|
+
velX[i] = (velX[i] ?? 0) * delta;
|
|
46
|
+
velY[i] = (velY[i] ?? 0) * delta;
|
|
47
|
+
prev[i] = sample === 0 ? 1e-6 : sample;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
wgsl() {
|
|
51
|
+
return {
|
|
52
|
+
key: "VelocityOverLifetime",
|
|
53
|
+
textures: [{
|
|
54
|
+
name: "curve",
|
|
55
|
+
format: "r32float"
|
|
56
|
+
}],
|
|
57
|
+
body: `
|
|
61
58
|
let velLifetime = max(timing[idx].y, 0.000001);
|
|
62
59
|
let velTNow = clamp(timing[idx].x / velLifetime, 0.0, 1.0);
|
|
63
60
|
let velTPrev = clamp((timing[idx].x - dt) / velLifetime, 0.0, 1.0);
|
|
@@ -65,21 +62,26 @@ class VelocityOverLifetime extends UpdateModule {
|
|
|
65
62
|
let velSamplePrev = textureSampleLevel(u_VelocityOverLifetime_curve, u_VelocityOverLifetime_curve_sampler, velTPrev, 0.0).r;
|
|
66
63
|
let velRatio = velSampleNow / max(velSamplePrev, 0.000001);
|
|
67
64
|
velocities[idx] = velocities[idx] * velRatio;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
65
|
+
`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
uploadTextures(device, textures) {
|
|
69
|
+
const texture = textures.get("curve");
|
|
70
|
+
if (texture === void 0) return;
|
|
71
|
+
const data = new Float32Array(lookupSize);
|
|
72
|
+
for (let i = 0; i < lookupSize; i++) data[i] = this.curve.evaluate(i / 255);
|
|
73
|
+
device.queue.writeTexture({ texture }, data.buffer, {
|
|
74
|
+
offset: 0,
|
|
75
|
+
bytesPerRow: lookupSize * 4,
|
|
76
|
+
rowsPerImage: 1
|
|
77
|
+
}, {
|
|
78
|
+
width: lookupSize,
|
|
79
|
+
height: 1,
|
|
80
|
+
depthOrArrayLayers: 1
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
};
|
|
83
84
|
|
|
85
|
+
//#endregion
|
|
84
86
|
export { VelocityOverLifetime };
|
|
85
|
-
//# sourceMappingURL=VelocityOverLifetime.js.map
|
|
87
|
+
//# sourceMappingURL=VelocityOverLifetime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VelocityOverLifetime.js","sources":["
|
|
1
|
+
{"version":3,"file":"VelocityOverLifetime.js","names":[],"sources":["../../../src/modules/VelocityOverLifetime.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 * Multiplies every live particle's velocity by a curve sampled at the\n * particle's current `elapsed / lifetime` ratio. The same scalar is applied\n * to both axes - the direction is preserved, only the magnitude scales.\n *\n * Common patterns:\n * - **Snappy spawn, slow drift:** `[0,1]→[1,0.1]` - fast initial motion\n * that decays over lifetime.\n * - **Late acceleration:** `[0,0.2]→[1,1]` - particles ease in.\n * - **Pulse:** sine-shaped curve for breathing-style motion.\n *\n * Note: the curve **replaces** velocity each frame relative to the previous\n * frame's velocity, so the effect is multiplicative. Pair with `ApplyForce`\n * if you want a constant external acceleration on top.\n *\n * GPU-eligible: uploads the curve as a 256-tap 1D R32F texture; sampled\n * once per particle per frame.\n */\nexport class VelocityOverLifetime extends UpdateModule {\n public curve: Curve;\n\n private _prevSample = new Float32Array(0);\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: velX, y: velY } = particles.velocity;\n const { elapsed, lifetime } = particles.timing;\n const liveCount = particles.count;\n const curve = this.curve;\n\n // Resize per-particle previous-sample cache once.\n if (this._prevSample.length < particles.capacity) {\n this._prevSample = new Float32Array(particles.capacity);\n this._prevSample.fill(1);\n }\n\n const prev = this._prevSample;\n\n for (let i = 0; i < liveCount; i++) {\n const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);\n const sample = curve.evaluate(t);\n const prevSample = prev[i] ?? 1;\n const last = prevSample === 0 ? 1 : prevSample;\n const delta = sample / last;\n\n velX[i] = (velX[i] ?? 0) * delta;\n velY[i] = (velY[i] ?? 0) * delta;\n prev[i] = sample === 0 ? 1e-6 : sample;\n }\n }\n\n public override wgsl(): WgslContribution {\n // GPU path uses a different formulation: re-derive velocity from\n // initial speed at t=0 by storing nothing - instead, scale relative\n // to the previous sample stored in scales[idx] alpha? No - keep it\n // simple and stateless: scale the integrated velocity by the\n // *ratio* of (current sample) / (sample at previous frame's t).\n // We approximate the previous t with `(elapsed - dt) / lifetime`.\n return {\n key: 'VelocityOverLifetime',\n textures: [{ name: 'curve', format: 'r32float' }],\n body: `\n let velLifetime = max(timing[idx].y, 0.000001);\n let velTNow = clamp(timing[idx].x / velLifetime, 0.0, 1.0);\n let velTPrev = clamp((timing[idx].x - dt) / velLifetime, 0.0, 1.0);\n let velSampleNow = textureSampleLevel(u_VelocityOverLifetime_curve, u_VelocityOverLifetime_curve_sampler, velTNow, 0.0).r;\n let velSamplePrev = textureSampleLevel(u_VelocityOverLifetime_curve, u_VelocityOverLifetime_curve_sampler, velTPrev, 0.0).r;\n let velRatio = velSampleNow / max(velSamplePrev, 0.000001);\n velocities[idx] = velocities[idx] * velRatio;\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"],"mappings":";;;AAQA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;AAoBnB,IAAa,uBAAb,cAA0C,aAAa;CACrD,AAAO;CAEP,AAAQ,8BAAc,IAAI,aAAa,CAAC;CAExC,AAAO,YAAY,OAAc;EAC/B,MAAM;EACN,KAAK,QAAQ;CACf;CAEA,AAAgB,MAAM,WAA0B,KAAmB;EACjE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,UAAU;EACvC,MAAM,EAAE,SAAS,aAAa,UAAU;EACxC,MAAM,YAAY,UAAU;EAC5B,MAAM,QAAQ,KAAK;EAGnB,IAAI,KAAK,YAAY,SAAS,UAAU,UAAU;GAChD,KAAK,cAAc,IAAI,aAAa,UAAU,QAAQ;GACtD,KAAK,YAAY,KAAK,CAAC;EACzB;EAEA,MAAM,OAAO,KAAK;EAElB,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;GAClC,MAAM,KAAK,QAAQ,MAAM,MAAM,SAAS,MAAM;GAC9C,MAAM,SAAS,MAAM,SAAS,CAAC;GAC/B,MAAM,aAAa,KAAK,MAAM;GAE9B,MAAM,QAAQ,UADD,eAAe,IAAI,IAAI;GAGpC,KAAK,MAAM,KAAK,MAAM,KAAK;GAC3B,KAAK,MAAM,KAAK,MAAM,KAAK;GAC3B,KAAK,KAAK,WAAW,IAAI,OAAO;EAClC;CACF;CAEA,AAAgB,OAAyB;EAOvC,OAAO;GACL,KAAK;GACL,UAAU,CAAC;IAAE,MAAM;IAAS,QAAQ;GAAW,CAAC;GAChD,MAAM;;;;;;;;;EASR;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"}
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
* more types here as new modules require them.
|
|
13
13
|
*/
|
|
14
14
|
export type WgslPrimitive = 'f32' | 'i32' | 'u32' | 'vec2<f32>' | 'vec4<f32>';
|
|
15
|
-
/** A named uniform field within a module's struct. Order matters
|
|
15
|
+
/** A named uniform field within a module's struct. Order matters - defines memory layout. */
|
|
16
16
|
export interface WgslUniformField {
|
|
17
17
|
name: string;
|
|
18
18
|
type: WgslPrimitive;
|
|
19
19
|
}
|
|
20
20
|
/** A 1D texture binding (used by Curve / ColorGradient lookups). */
|
|
21
21
|
export interface WgslTextureBinding {
|
|
22
|
-
/** Field name within the module
|
|
22
|
+
/** Field name within the module - referenced in WGSL as `u_${moduleKey}_${name}`. */
|
|
23
23
|
name: string;
|
|
24
24
|
/** WGSL texture format. `r32float` for Curve, `rgba8unorm` for ColorGradient. */
|
|
25
25
|
format: 'r32float' | 'rgba8unorm';
|
|
@@ -29,29 +29,29 @@ export interface WgslTextureBinding {
|
|
|
29
29
|
* shader. `body` runs once per particle in the inner main function, with
|
|
30
30
|
* these locals in scope:
|
|
31
31
|
*
|
|
32
|
-
* - `idx: u32`
|
|
32
|
+
* - `idx: u32` - the particle slot index (already gated on `< sim.liveCount`
|
|
33
33
|
* and skip-on-dead via `timing[idx].y < 0.0`).
|
|
34
|
-
* - `dt: f32`
|
|
35
|
-
* - **Packed SoA bindings** (see body of doc)
|
|
34
|
+
* - `dt: f32` - frame delta in seconds (mirrors `sim.dt`).
|
|
35
|
+
* - **Packed SoA bindings** (see body of doc) - channels are packed into
|
|
36
36
|
* `vec2<f32>`-typed storage buffers to fit within WebGPU's default 8-buffer
|
|
37
37
|
* limit. Access x/y components for the per-axis values:
|
|
38
38
|
* - `positions[idx].x` / `.y` (was posX/posY)
|
|
39
39
|
* - `velocities[idx].x` / `.y` (was velX/velY)
|
|
40
40
|
* - `scales[idx].x` / `.y` (was scaleX/scaleY)
|
|
41
41
|
* - `rotInfo[idx].x` / `.y` (rotation, rotationSpeed)
|
|
42
|
-
* - `timing[idx].x` / `.y` (elapsed, lifetime
|
|
43
|
-
* - `color[idx]`
|
|
44
|
-
* - `sim: SimUniforms`
|
|
45
|
-
* - `modules.u_${key}: ${Key}Uniforms`
|
|
46
|
-
* - `u_${key}_${textureName}` and `u_${key}_${textureName}_sampler`
|
|
42
|
+
* - `timing[idx].x` / `.y` (elapsed, lifetime - y is set to -1 when expired)
|
|
43
|
+
* - `color[idx]` - packed RGBA u32, single channel (no .x/.y)
|
|
44
|
+
* - `sim: SimUniforms` - `{ dt: f32, liveCount: u32 }`.
|
|
45
|
+
* - `modules.u_${key}: ${Key}Uniforms` - your module's uniform struct (if declared).
|
|
46
|
+
* - `u_${key}_${textureName}` and `u_${key}_${textureName}_sampler` - texture bindings (if any).
|
|
47
47
|
*
|
|
48
48
|
* The body should not declare new functions or top-level statements; it
|
|
49
49
|
* runs inline in the main function. Use comments and parentheses generously
|
|
50
|
-
*
|
|
50
|
+
* - composition concatenates several module bodies and any syntax mistake
|
|
51
51
|
* surfaces only at pipeline-creation time.
|
|
52
52
|
*/
|
|
53
53
|
export interface WgslContribution {
|
|
54
|
-
/** Unique key per module *class* (e.g. `'ApplyForce'`). Two ApplyForce instances on one system aren't supported
|
|
54
|
+
/** Unique key per module *class* (e.g. `'ApplyForce'`). Two ApplyForce instances on one system aren't supported - combine into one. */
|
|
55
55
|
key: string;
|
|
56
56
|
uniforms?: readonly WgslUniformField[];
|
|
57
57
|
textures?: readonly WgslTextureBinding[];
|
|
@@ -60,7 +60,7 @@ export interface WgslContribution {
|
|
|
60
60
|
* scope before `main()`. Use this for noise/hash helpers or any
|
|
61
61
|
* supporting function the {@link body} calls. Multiple modules can
|
|
62
62
|
* declare preludes; they're concatenated in registration order. Naming
|
|
63
|
-
* collisions across modules are the author's problem
|
|
63
|
+
* collisions across modules are the author's problem - prefix helpers
|
|
64
64
|
* with the module key (e.g. `myModule_hash`) to avoid clashes.
|
|
65
65
|
*/
|
|
66
66
|
prelude?: string;
|
|
@@ -73,9 +73,10 @@ export interface WgslContribution {
|
|
|
73
73
|
*
|
|
74
74
|
* Used by the codegen to size the system's combined uniform buffer.
|
|
75
75
|
*/
|
|
76
|
-
export declare const
|
|
76
|
+
export declare const getWgslUniformByteSize: (fields: readonly WgslUniformField[]) => number;
|
|
77
77
|
/** Per-WGSL-primitive size and alignment in bytes. */
|
|
78
|
-
export declare const
|
|
78
|
+
export declare const getWgslFieldLayout: (type: WgslPrimitive) => {
|
|
79
79
|
size: number;
|
|
80
80
|
align: number;
|
|
81
81
|
};
|
|
82
|
+
//# sourceMappingURL=WgslContribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WgslContribution.d.ts","sourceRoot":"","sources":["../../../src/modules/WgslContribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,CAAC;AAE9E,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,oEAAoE;AACpE,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,MAAM,EAAE,UAAU,GAAG,YAAY,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uIAAuI;IACvI,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACzC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,SAAS,gBAAgB,EAAE,KAAG,MAa5E,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,kBAAkB,GAAI,MAAM,aAAa,KAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAWrF,CAAC"}
|
|
@@ -1,34 +1,42 @@
|
|
|
1
|
+
//#region src/modules/WgslContribution.ts
|
|
1
2
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
* Compute the byte size of a uniform struct from its declared fields,
|
|
4
|
+
* respecting WGSL std140-like alignment rules. Each field aligns to its
|
|
5
|
+
* natural alignment; the struct itself rounds to its largest alignment.
|
|
6
|
+
*
|
|
7
|
+
* Used by the codegen to size the system's combined uniform buffer.
|
|
8
|
+
*/
|
|
9
|
+
const getWgslUniformByteSize = (fields) => {
|
|
10
|
+
let offset = 0;
|
|
11
|
+
let maxAlign = 4;
|
|
12
|
+
for (const field of fields) {
|
|
13
|
+
const { size, align } = getWgslFieldLayout(field.type);
|
|
14
|
+
offset = Math.ceil(offset / align) * align;
|
|
15
|
+
offset += size;
|
|
16
|
+
maxAlign = Math.max(maxAlign, align);
|
|
17
|
+
}
|
|
18
|
+
return Math.ceil(offset / maxAlign) * maxAlign;
|
|
18
19
|
};
|
|
19
20
|
/** Per-WGSL-primitive size and alignment in bytes. */
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
const getWgslFieldLayout = (type) => {
|
|
22
|
+
switch (type) {
|
|
23
|
+
case "f32":
|
|
24
|
+
case "i32":
|
|
25
|
+
case "u32": return {
|
|
26
|
+
size: 4,
|
|
27
|
+
align: 4
|
|
28
|
+
};
|
|
29
|
+
case "vec2<f32>": return {
|
|
30
|
+
size: 8,
|
|
31
|
+
align: 8
|
|
32
|
+
};
|
|
33
|
+
case "vec4<f32>": return {
|
|
34
|
+
size: 16,
|
|
35
|
+
align: 16
|
|
36
|
+
};
|
|
37
|
+
}
|
|
31
38
|
};
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
//#endregion
|
|
41
|
+
export { getWgslFieldLayout, getWgslUniformByteSize };
|
|
42
|
+
//# sourceMappingURL=WgslContribution.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WgslContribution.js","sources":["
|
|
1
|
+
{"version":3,"file":"WgslContribution.js","names":[],"sources":["../../../src/modules/WgslContribution.ts"],"sourcesContent":["/**\n * WGSL primitive types accepted in {@link WgslUniformField} declarations.\n * The codegen emits matching WGSL field declarations; the writeUniforms\n * implementation must produce bytes in the layout WGSL expects (see\n * https://www.w3.org/TR/WGSL/#alignment-and-size).\n *\n * Common pitfalls:\n * - `vec2<f32>` aligns to 8 bytes; pad with `f32` or use `vec4<f32>`.\n * - `vec3<f32>` aligns to 16 bytes (so does `vec4<f32>`); avoid `vec3` for tight packing.\n *\n * For now the supported subset covers what the built-in modules need. Add\n * more types here as new modules require them.\n */\nexport type WgslPrimitive = 'f32' | 'i32' | 'u32' | 'vec2<f32>' | 'vec4<f32>';\n\n/** A named uniform field within a module's struct. Order matters - defines memory layout. */\nexport interface WgslUniformField {\n name: string;\n type: WgslPrimitive;\n}\n\n/** A 1D texture binding (used by Curve / ColorGradient lookups). */\nexport interface WgslTextureBinding {\n /** Field name within the module - referenced in WGSL as `u_${moduleKey}_${name}`. */\n name: string;\n /** WGSL texture format. `r32float` for Curve, `rgba8unorm` for ColorGradient. */\n format: 'r32float' | 'rgba8unorm';\n}\n\n/**\n * What an {@link UpdateModule} contributes to the system's composite compute\n * shader. `body` runs once per particle in the inner main function, with\n * these locals in scope:\n *\n * - `idx: u32` - the particle slot index (already gated on `< sim.liveCount`\n * and skip-on-dead via `timing[idx].y < 0.0`).\n * - `dt: f32` - frame delta in seconds (mirrors `sim.dt`).\n * - **Packed SoA bindings** (see body of doc) - channels are packed into\n * `vec2<f32>`-typed storage buffers to fit within WebGPU's default 8-buffer\n * limit. Access x/y components for the per-axis values:\n * - `positions[idx].x` / `.y` (was posX/posY)\n * - `velocities[idx].x` / `.y` (was velX/velY)\n * - `scales[idx].x` / `.y` (was scaleX/scaleY)\n * - `rotInfo[idx].x` / `.y` (rotation, rotationSpeed)\n * - `timing[idx].x` / `.y` (elapsed, lifetime - y is set to -1 when expired)\n * - `color[idx]` - packed RGBA u32, single channel (no .x/.y)\n * - `sim: SimUniforms` - `{ dt: f32, liveCount: u32 }`.\n * - `modules.u_${key}: ${Key}Uniforms` - your module's uniform struct (if declared).\n * - `u_${key}_${textureName}` and `u_${key}_${textureName}_sampler` - texture bindings (if any).\n *\n * The body should not declare new functions or top-level statements; it\n * runs inline in the main function. Use comments and parentheses generously\n * - composition concatenates several module bodies and any syntax mistake\n * surfaces only at pipeline-creation time.\n */\nexport interface WgslContribution {\n /** Unique key per module *class* (e.g. `'ApplyForce'`). Two ApplyForce instances on one system aren't supported - combine into one. */\n key: string;\n uniforms?: readonly WgslUniformField[];\n textures?: readonly WgslTextureBinding[];\n /**\n * Optional WGSL declarations (functions, constants) emitted at module\n * scope before `main()`. Use this for noise/hash helpers or any\n * supporting function the {@link body} calls. Multiple modules can\n * declare preludes; they're concatenated in registration order. Naming\n * collisions across modules are the author's problem - prefix helpers\n * with the module key (e.g. `myModule_hash`) to avoid clashes.\n */\n prelude?: string;\n body: string;\n}\n\n/**\n * Compute the byte size of a uniform struct from its declared fields,\n * respecting WGSL std140-like alignment rules. Each field aligns to its\n * natural alignment; the struct itself rounds to its largest alignment.\n *\n * Used by the codegen to size the system's combined uniform buffer.\n */\nexport const getWgslUniformByteSize = (fields: readonly WgslUniformField[]): number => {\n let offset = 0;\n let maxAlign = 4;\n\n for (const field of fields) {\n const { size, align } = getWgslFieldLayout(field.type);\n\n offset = Math.ceil(offset / align) * align;\n offset += size;\n maxAlign = Math.max(maxAlign, align);\n }\n\n return Math.ceil(offset / maxAlign) * maxAlign;\n};\n\n/** Per-WGSL-primitive size and alignment in bytes. */\nexport const getWgslFieldLayout = (type: WgslPrimitive): { size: number; align: number } => {\n switch (type) {\n case 'f32':\n case 'i32':\n case 'u32':\n return { size: 4, align: 4 };\n case 'vec2<f32>':\n return { size: 8, align: 8 };\n case 'vec4<f32>':\n return { size: 16, align: 16 };\n }\n};\n"],"mappings":";;;;;;;;AA+EA,MAAa,0BAA0B,WAAgD;CACrF,IAAI,SAAS;CACb,IAAI,WAAW;CAEf,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,EAAE,MAAM,UAAU,mBAAmB,MAAM,IAAI;EAErD,SAAS,KAAK,KAAK,SAAS,KAAK,IAAI;EACrC,UAAU;EACV,WAAW,KAAK,IAAI,UAAU,KAAK;CACrC;CAEA,OAAO,KAAK,KAAK,SAAS,QAAQ,IAAI;AACxC;;AAGA,MAAa,sBAAsB,SAAyD;CAC1F,QAAQ,MAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK,OACH,OAAO;GAAE,MAAM;GAAG,OAAO;EAAE;EAC7B,KAAK,aACH,OAAO;GAAE,MAAM;GAAG,OAAO;EAAE;EAC7B,KAAK,aACH,OAAO;GAAE,MAAM;GAAI,OAAO;EAAG;CACjC;AACF"}
|
|
@@ -13,10 +13,12 @@ export { RateSpawn } from './RateSpawn';
|
|
|
13
13
|
export { RepelFromPoint } from './RepelFromPoint';
|
|
14
14
|
export { RotateOverLifetime } from './RotateOverLifetime';
|
|
15
15
|
export { ScaleOverLifetime } from './ScaleOverLifetime';
|
|
16
|
+
export type { ParticleSpawnFields } from './spawnFields';
|
|
16
17
|
export { SpawnModule } from './SpawnModule';
|
|
17
18
|
export { SpawnOnDeath } from './SpawnOnDeath';
|
|
18
19
|
export { Turbulence } from './Turbulence';
|
|
19
20
|
export { UpdateModule } from './UpdateModule';
|
|
20
21
|
export { VelocityOverLifetime } from './VelocityOverLifetime';
|
|
21
22
|
export type { WgslContribution, WgslPrimitive, WgslTextureBinding, WgslUniformField } from './WgslContribution';
|
|
22
|
-
export {
|
|
23
|
+
export { getWgslFieldLayout, getWgslUniformByteSize } from './WgslContribution';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAChH,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Color, Vector } from '@codexo/exojs';
|
|
2
|
+
import type { Distribution } from '#distributions/Distribution';
|
|
3
|
+
import type { ParticleWriter } from '#ParticleStorage';
|
|
4
|
+
/**
|
|
5
|
+
* Per-property spawn configuration shared by the built-in spawners.
|
|
6
|
+
*
|
|
7
|
+
* Every entry is a {@link Distribution} sampled once per emitted particle.
|
|
8
|
+
* Omitting an entry leaves that property at its spawn default: origin, no
|
|
9
|
+
* velocity, unit scale, no rotation, opaque white, frame 0, one second of life.
|
|
10
|
+
*/
|
|
11
|
+
export interface ParticleSpawnFields {
|
|
12
|
+
/** Total lifetime in seconds. Drives expiry. */
|
|
13
|
+
lifetime?: Distribution<number>;
|
|
14
|
+
position?: Distribution<Vector>;
|
|
15
|
+
velocity?: Distribution<Vector>;
|
|
16
|
+
scale?: Distribution<Vector>;
|
|
17
|
+
rotation?: Distribution<number>;
|
|
18
|
+
rotationSpeed?: Distribution<number>;
|
|
19
|
+
/** Initial tint. For a per-frame fade use a `ColorOverLifetime` update module. */
|
|
20
|
+
tint?: Distribution<Color>;
|
|
21
|
+
/** Atlas frame index. Ignored by a system that declares no frames. */
|
|
22
|
+
textureIndex?: Distribution<number>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Samples every configured field of `fields` into one emitted particle.
|
|
26
|
+
*
|
|
27
|
+
* `vector` and `color` are scratch instances the caller owns, so a spawner
|
|
28
|
+
* allocates nothing per particle.
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export declare const fillParticle: (particle: ParticleWriter, fields: ParticleSpawnFields, vector: Vector, color: Color) => void;
|
|
32
|
+
//# sourceMappingURL=spawnFields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawnFields.d.ts","sourceRoot":"","sources":["../../../src/modules/spawnFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,QAAQ,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACrC,kFAAkF;IAClF,IAAI,CAAC,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IAC3B,sEAAsE;IACtE,YAAY,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;CACrC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,cAAc,EAAE,QAAQ,mBAAmB,EAAE,QAAQ,MAAM,EAAE,OAAO,KAAK,KAAG,IAmClH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/modules/spawnFields.ts
|
|
2
|
+
/**
|
|
3
|
+
* Samples every configured field of `fields` into one emitted particle.
|
|
4
|
+
*
|
|
5
|
+
* `vector` and `color` are scratch instances the caller owns, so a spawner
|
|
6
|
+
* allocates nothing per particle.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
const fillParticle = (particle, fields, vector, color) => {
|
|
10
|
+
if (fields.lifetime) particle.lifetime = fields.lifetime.sample();
|
|
11
|
+
if (fields.position) {
|
|
12
|
+
fields.position.sample(vector);
|
|
13
|
+
particle.position.set(vector.x, vector.y);
|
|
14
|
+
}
|
|
15
|
+
if (fields.velocity) {
|
|
16
|
+
fields.velocity.sample(vector);
|
|
17
|
+
particle.velocity.set(vector.x, vector.y);
|
|
18
|
+
}
|
|
19
|
+
if (fields.scale) {
|
|
20
|
+
fields.scale.sample(vector);
|
|
21
|
+
particle.scale.set(vector.x, vector.y);
|
|
22
|
+
}
|
|
23
|
+
if (fields.rotation) particle.rotation = fields.rotation.sample();
|
|
24
|
+
if (fields.rotationSpeed) particle.rotationSpeed = fields.rotationSpeed.sample();
|
|
25
|
+
if (fields.tint) particle.color = fields.tint.sample(color).toRgba8();
|
|
26
|
+
if (fields.textureIndex) particle.frame = fields.textureIndex.sample();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { fillParticle };
|
|
31
|
+
//# sourceMappingURL=spawnFields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawnFields.js","names":[],"sources":["../../../src/modules/spawnFields.ts"],"sourcesContent":["import type { Color, Vector } from '@codexo/exojs';\n\nimport type { Distribution } from '#distributions/Distribution';\nimport type { ParticleWriter } from '#ParticleStorage';\n\n/**\n * Per-property spawn configuration shared by the built-in spawners.\n *\n * Every entry is a {@link Distribution} sampled once per emitted particle.\n * Omitting an entry leaves that property at its spawn default: origin, no\n * velocity, unit scale, no rotation, opaque white, frame 0, one second of life.\n */\nexport interface ParticleSpawnFields {\n /** Total lifetime in seconds. Drives expiry. */\n lifetime?: Distribution<number>;\n position?: Distribution<Vector>;\n velocity?: Distribution<Vector>;\n scale?: Distribution<Vector>;\n rotation?: Distribution<number>;\n rotationSpeed?: Distribution<number>;\n /** Initial tint. For a per-frame fade use a `ColorOverLifetime` update module. */\n tint?: Distribution<Color>;\n /** Atlas frame index. Ignored by a system that declares no frames. */\n textureIndex?: Distribution<number>;\n}\n\n/**\n * Samples every configured field of `fields` into one emitted particle.\n *\n * `vector` and `color` are scratch instances the caller owns, so a spawner\n * allocates nothing per particle.\n * @internal\n */\nexport const fillParticle = (particle: ParticleWriter, fields: ParticleSpawnFields, vector: Vector, color: Color): void => {\n if (fields.lifetime) {\n particle.lifetime = fields.lifetime.sample();\n }\n\n if (fields.position) {\n fields.position.sample(vector);\n particle.position.set(vector.x, vector.y);\n }\n\n if (fields.velocity) {\n fields.velocity.sample(vector);\n particle.velocity.set(vector.x, vector.y);\n }\n\n if (fields.scale) {\n fields.scale.sample(vector);\n particle.scale.set(vector.x, vector.y);\n }\n\n if (fields.rotation) {\n particle.rotation = fields.rotation.sample();\n }\n\n if (fields.rotationSpeed) {\n particle.rotationSpeed = fields.rotationSpeed.sample();\n }\n\n if (fields.tint) {\n particle.color = fields.tint.sample(color).toRgba8();\n }\n\n if (fields.textureIndex) {\n particle.frame = fields.textureIndex.sample();\n }\n};\n"],"mappings":";;;;;;;;AAiCA,MAAa,gBAAgB,UAA0B,QAA6B,QAAgB,UAAuB;CACzH,IAAI,OAAO,UACT,SAAS,WAAW,OAAO,SAAS,OAAO;CAG7C,IAAI,OAAO,UAAU;EACnB,OAAO,SAAS,OAAO,MAAM;EAC7B,SAAS,SAAS,IAAI,OAAO,GAAG,OAAO,CAAC;CAC1C;CAEA,IAAI,OAAO,UAAU;EACnB,OAAO,SAAS,OAAO,MAAM;EAC7B,SAAS,SAAS,IAAI,OAAO,GAAG,OAAO,CAAC;CAC1C;CAEA,IAAI,OAAO,OAAO;EAChB,OAAO,MAAM,OAAO,MAAM;EAC1B,SAAS,MAAM,IAAI,OAAO,GAAG,OAAO,CAAC;CACvC;CAEA,IAAI,OAAO,UACT,SAAS,WAAW,OAAO,SAAS,OAAO;CAG7C,IAAI,OAAO,eACT,SAAS,gBAAgB,OAAO,cAAc,OAAO;CAGvD,IAAI,OAAO,MACT,SAAS,QAAQ,OAAO,KAAK,OAAO,KAAK,CAAC,CAAC,QAAQ;CAGrD,IAAI,OAAO,cACT,SAAS,QAAQ,OAAO,aAAa,OAAO;AAEhD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"particlesBuildInfo.d.ts","sourceRoot":"","sources":["../../src/particlesBuildInfo.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,eAAO,MAAM,kBAAkB,EAAE,kBAI/B,CAAC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
//#region src/particlesBuildInfo.ts
|
|
1
2
|
const particlesBuildInfo = Object.freeze({
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
version: "0.16.0",
|
|
4
|
+
revision: "3a59179",
|
|
5
|
+
development: false
|
|
5
6
|
});
|
|
6
7
|
|
|
8
|
+
//#endregion
|
|
7
9
|
export { particlesBuildInfo };
|
|
8
|
-
//# sourceMappingURL=particlesBuildInfo.js.map
|
|
10
|
+
//# sourceMappingURL=particlesBuildInfo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particlesBuildInfo.js","sources":["
|
|
1
|
+
{"version":3,"file":"particlesBuildInfo.js","names":[],"sources":["../../src/particlesBuildInfo.ts"],"sourcesContent":["/**\n * Immutable compile-time build metadata for `@codexo/exojs-particles`.\n *\n * `development` mirrors the `__DEV__` compile-time constant and is statically\n * replaced before tree shaking. `version` is the exact `package.json` version\n * of the Particles package at build time. `revision` is the short\n * source-control revision (appended with `-dirty` when uncommitted changes are\n * present) or `\"unknown\"` when no revision information is available.\n */\nexport interface ParticlesBuildInfo {\n readonly version: string;\n readonly revision: string;\n readonly development: boolean;\n}\n\nexport const particlesBuildInfo: ParticlesBuildInfo = Object.freeze({\n version: __VERSION__,\n revision: __REVISION__,\n development: __DEV__,\n});\n"],"mappings":";AAeA,MAAa,qBAAyC,OAAO,OAAO;CAClE;CACA;CACA;AACF,CAAC"}
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import type { Extension } from '@codexo/exojs/extensions';
|
|
2
2
|
/** Options for {@link createParticlesExtension}. */
|
|
3
3
|
export interface ParticlesExtensionOptions {
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Particles the WebGL2 renderer's instance buffer is pre-sized for.
|
|
6
|
+
* Defaults to 8192.
|
|
7
|
+
*
|
|
8
|
+
* This is a starting allocation, not a limit: a system with more live
|
|
9
|
+
* particles grows the buffer instead of dropping the surplus, so raise it
|
|
10
|
+
* only to avoid the initial growth steps for a known-large system.
|
|
11
|
+
*/
|
|
5
12
|
readonly batchSize?: number;
|
|
6
13
|
}
|
|
7
14
|
/**
|
|
8
15
|
* Default immutable Particles extension descriptor.
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
16
|
+
* Pass it to the application that should have it via
|
|
17
|
+
* `ApplicationOptions.extensions`.
|
|
11
18
|
*/
|
|
12
19
|
export declare const particlesExtension: Extension;
|
|
13
20
|
/**
|
|
14
21
|
* Create a Particles extension with custom configuration.
|
|
15
|
-
* Returns an application-local descriptor
|
|
22
|
+
* Returns an application-local descriptor - safe to pass to one
|
|
16
23
|
* `Application` only. For shared use, prefer {@link particlesExtension}.
|
|
17
24
|
*
|
|
18
25
|
* @example
|
|
@@ -21,4 +28,5 @@ export declare const particlesExtension: Extension;
|
|
|
21
28
|
* const app = new Application({ extensions: [ext] });
|
|
22
29
|
* ```
|
|
23
30
|
*/
|
|
24
|
-
export declare
|
|
31
|
+
export declare const createParticlesExtension: (options?: ParticlesExtensionOptions) => Extension;
|
|
32
|
+
//# sourceMappingURL=particlesExtension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"particlesExtension.d.ts","sourceRoot":"","sources":["../../src/particlesExtension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,0BAA0B,CAAC;AAS3E,oDAAoD;AACpD,MAAM,WAAW,yBAAyB;IACxC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAiBD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAG/B,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,UAAS,yBAA8B,KAAG,SAOlF,CAAC"}
|