@codexo/exojs 0.7.12 → 0.8.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/CHANGELOG.md +737 -0
- package/dist/esm/core/Application.d.ts +3 -1
- package/dist/esm/core/Application.js +7 -6
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/core/Scene.d.ts +30 -0
- package/dist/esm/core/Scene.js +56 -0
- package/dist/esm/core/Scene.js.map +1 -1
- package/dist/esm/core/SceneManager.js +2 -2
- package/dist/esm/core/SceneManager.js.map +1 -1
- package/dist/esm/debug/DebugOverlay.js +2 -2
- package/dist/esm/debug/DebugOverlay.js.map +1 -1
- package/dist/esm/debug/PointerStackLayer.js +1 -1
- package/dist/esm/debug/PointerStackLayer.js.map +1 -1
- package/dist/esm/index.js +32 -10
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input/ArcadeStickGamepadMapping.js +18 -19
- package/dist/esm/input/ArcadeStickGamepadMapping.js.map +1 -1
- package/dist/esm/input/Gamepad.d.ts +164 -62
- package/dist/esm/input/Gamepad.js +290 -134
- package/dist/esm/input/Gamepad.js.map +1 -1
- package/dist/esm/input/GamepadAxis.d.ts +120 -0
- package/dist/esm/input/GamepadAxis.js +106 -0
- package/dist/esm/input/GamepadAxis.js.map +1 -0
- package/dist/esm/input/GamepadButton.d.ts +110 -0
- package/dist/esm/input/GamepadButton.js +99 -0
- package/dist/esm/input/GamepadButton.js.map +1 -0
- package/dist/esm/input/GamepadDefinitions.js +4 -0
- package/dist/esm/input/GamepadDefinitions.js.map +1 -1
- package/dist/esm/input/GamepadMapping.d.ts +28 -24
- package/dist/esm/input/GamepadMapping.js +33 -16
- package/dist/esm/input/GamepadMapping.js.map +1 -1
- package/dist/esm/input/GamepadPromptLayouts.d.ts +10 -8
- package/dist/esm/input/GamepadPromptLayouts.js +21 -20
- package/dist/esm/input/GamepadPromptLayouts.js.map +1 -1
- package/dist/esm/input/GenericDualAnalogGamepadMapping.d.ts +6 -3
- package/dist/esm/input/GenericDualAnalogGamepadMapping.js +55 -46
- package/dist/esm/input/GenericDualAnalogGamepadMapping.js.map +1 -1
- package/dist/esm/input/InputBinding.d.ts +74 -0
- package/dist/esm/input/InputBinding.js +100 -0
- package/dist/esm/input/InputBinding.js.map +1 -0
- package/dist/esm/input/InputManager.d.ts +79 -33
- package/dist/esm/input/InputManager.js +229 -104
- package/dist/esm/input/InputManager.js.map +1 -1
- package/dist/esm/input/InteractionManager.d.ts +1 -1
- package/dist/esm/input/InteractionManager.js +13 -13
- package/dist/esm/input/InteractionManager.js.map +1 -1
- package/dist/esm/input/JoyConLeftGamepadMapping.d.ts +14 -9
- package/dist/esm/input/JoyConLeftGamepadMapping.js +39 -9
- package/dist/esm/input/JoyConLeftGamepadMapping.js.map +1 -1
- package/dist/esm/input/JoyConRightGamepadMapping.d.ts +14 -9
- package/dist/esm/input/JoyConRightGamepadMapping.js +35 -9
- package/dist/esm/input/JoyConRightGamepadMapping.js.map +1 -1
- package/dist/esm/input/Pointer.d.ts +84 -71
- package/dist/esm/input/Pointer.js +71 -71
- package/dist/esm/input/Pointer.js.map +1 -1
- package/dist/esm/input/SteamDeckGamepadMapping.d.ts +18 -0
- package/dist/esm/input/SteamDeckGamepadMapping.js +76 -0
- package/dist/esm/input/SteamDeckGamepadMapping.js.map +1 -0
- package/dist/esm/input/index.d.ts +7 -4
- package/dist/esm/input/types.d.ts +0 -76
- package/dist/esm/input/types.js +1 -80
- package/dist/esm/input/types.js.map +1 -1
- package/dist/esm/particles/ParticleSystem.d.ts +180 -83
- package/dist/esm/particles/ParticleSystem.js +446 -133
- package/dist/esm/particles/ParticleSystem.js.map +1 -1
- package/dist/esm/particles/distributions/BoxArea.d.ts +17 -0
- package/dist/esm/particles/distributions/BoxArea.js +48 -0
- package/dist/esm/particles/distributions/BoxArea.js.map +1 -0
- package/dist/esm/particles/distributions/CircleArea.d.ts +19 -0
- package/dist/esm/particles/distributions/CircleArea.js +33 -0
- package/dist/esm/particles/distributions/CircleArea.js.map +1 -0
- package/dist/esm/particles/distributions/ConeDirection.d.ts +28 -0
- package/dist/esm/particles/distributions/ConeDirection.js +44 -0
- package/dist/esm/particles/distributions/ConeDirection.js.map +1 -0
- package/dist/esm/particles/distributions/Constant.d.ts +17 -0
- package/dist/esm/particles/distributions/Constant.js +35 -0
- package/dist/esm/particles/distributions/Constant.js.map +1 -0
- package/dist/esm/particles/distributions/Curve.d.ts +30 -0
- package/dist/esm/particles/distributions/Curve.js +53 -0
- package/dist/esm/particles/distributions/Curve.js.map +1 -0
- package/dist/esm/particles/distributions/Distribution.d.ts +45 -0
- package/dist/esm/particles/distributions/Gradient.d.ts +40 -0
- package/dist/esm/particles/distributions/Gradient.js +72 -0
- package/dist/esm/particles/distributions/Gradient.js.map +1 -0
- package/dist/esm/particles/distributions/LineSegment.d.ts +15 -0
- package/dist/esm/particles/distributions/LineSegment.js +27 -0
- package/dist/esm/particles/distributions/LineSegment.js.map +1 -0
- package/dist/esm/particles/distributions/Range.d.ts +12 -0
- package/dist/esm/particles/distributions/Range.js +19 -0
- package/dist/esm/particles/distributions/Range.js.map +1 -0
- package/dist/esm/particles/distributions/VectorRange.d.ts +20 -0
- package/dist/esm/particles/distributions/VectorRange.js +31 -0
- package/dist/esm/particles/distributions/VectorRange.js.map +1 -0
- package/dist/esm/particles/distributions/index.d.ts +12 -0
- package/dist/esm/particles/gpu/ParticleGpuState.d.ts +57 -0
- package/dist/esm/particles/gpu/ParticleGpuState.js +508 -0
- package/dist/esm/particles/gpu/ParticleGpuState.js.map +1 -0
- package/dist/esm/particles/index.d.ts +2 -10
- package/dist/esm/particles/modules/AlphaFadeOverLifetime.d.ts +24 -0
- package/dist/esm/particles/modules/AlphaFadeOverLifetime.js +60 -0
- package/dist/esm/particles/modules/AlphaFadeOverLifetime.js.map +1 -0
- package/dist/esm/particles/modules/ApplyForce.d.ts +20 -0
- package/dist/esm/particles/modules/ApplyForce.js +48 -0
- package/dist/esm/particles/modules/ApplyForce.js.map +1 -0
- package/dist/esm/particles/modules/AttractToPoint.d.ts +27 -0
- package/dist/esm/particles/modules/AttractToPoint.js +73 -0
- package/dist/esm/particles/modules/AttractToPoint.js.map +1 -0
- package/dist/esm/particles/modules/BurstSpawn.d.ts +53 -0
- package/dist/esm/particles/modules/BurstSpawn.js +94 -0
- package/dist/esm/particles/modules/BurstSpawn.js.map +1 -0
- package/dist/esm/particles/modules/ColorOverLifetime.d.ts +22 -0
- package/dist/esm/particles/modules/ColorOverLifetime.js +65 -0
- package/dist/esm/particles/modules/ColorOverLifetime.js.map +1 -0
- package/dist/esm/particles/modules/ColorOverSpeed.d.ts +27 -0
- package/dist/esm/particles/modules/ColorOverSpeed.js +86 -0
- package/dist/esm/particles/modules/ColorOverSpeed.js.map +1 -0
- package/dist/esm/particles/modules/DeathModule.d.ts +24 -0
- package/dist/esm/particles/modules/DeathModule.js +25 -0
- package/dist/esm/particles/modules/DeathModule.js.map +1 -0
- package/dist/esm/particles/modules/Drag.d.ts +20 -0
- package/dist/esm/particles/modules/Drag.js +45 -0
- package/dist/esm/particles/modules/Drag.js.map +1 -0
- package/dist/esm/particles/modules/OrbitalForce.d.ts +28 -0
- package/dist/esm/particles/modules/OrbitalForce.js +65 -0
- package/dist/esm/particles/modules/OrbitalForce.js.map +1 -0
- package/dist/esm/particles/modules/RateSpawn.d.ts +41 -0
- package/dist/esm/particles/modules/RateSpawn.js +76 -0
- package/dist/esm/particles/modules/RateSpawn.js.map +1 -0
- package/dist/esm/particles/modules/RepelFromPoint.d.ts +24 -0
- package/dist/esm/particles/modules/RepelFromPoint.js +76 -0
- package/dist/esm/particles/modules/RepelFromPoint.js.map +1 -0
- package/dist/esm/particles/modules/RotateOverLifetime.d.ts +20 -0
- package/dist/esm/particles/modules/RotateOverLifetime.js +43 -0
- package/dist/esm/particles/modules/RotateOverLifetime.js.map +1 -0
- package/dist/esm/particles/modules/ScaleOverLifetime.d.ts +26 -0
- package/dist/esm/particles/modules/ScaleOverLifetime.js +59 -0
- package/dist/esm/particles/modules/ScaleOverLifetime.js.map +1 -0
- package/dist/esm/particles/modules/SpawnModule.d.ts +30 -0
- package/dist/esm/particles/modules/SpawnModule.js +31 -0
- package/dist/esm/particles/modules/SpawnModule.js.map +1 -0
- package/dist/esm/particles/modules/SpawnOnDeath.d.ts +24 -0
- package/dist/esm/particles/modules/SpawnOnDeath.js +47 -0
- package/dist/esm/particles/modules/SpawnOnDeath.js.map +1 -0
- package/dist/esm/particles/modules/Turbulence.d.ts +30 -0
- package/dist/esm/particles/modules/Turbulence.js +122 -0
- package/dist/esm/particles/modules/Turbulence.js.map +1 -0
- package/dist/esm/particles/modules/UpdateModule.d.ts +95 -0
- package/dist/esm/particles/modules/UpdateModule.js +66 -0
- package/dist/esm/particles/modules/UpdateModule.js.map +1 -0
- package/dist/esm/particles/modules/VelocityOverLifetime.d.ts +30 -0
- package/dist/esm/particles/modules/VelocityOverLifetime.js +84 -0
- package/dist/esm/particles/modules/VelocityOverLifetime.js.map +1 -0
- package/dist/esm/particles/modules/WgslContribution.d.ts +81 -0
- package/dist/esm/particles/modules/WgslContribution.js +34 -0
- package/dist/esm/particles/modules/WgslContribution.js.map +1 -0
- package/dist/esm/particles/modules/index.d.ts +22 -0
- package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.d.ts +9 -14
- package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js +90 -61
- package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js.map +1 -1
- package/dist/esm/rendering/webgl2/glsl/particle.vert.js +1 -1
- package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.d.ts +9 -0
- package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js +107 -23
- package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js.map +1 -1
- package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.d.ts +52 -0
- package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.d.ts +29 -0
- package/dist/esm/rendering/webgpu/compute/index.d.ts +3 -0
- package/dist/esm/resources/CacheFirstStrategy.d.ts +7 -4
- package/dist/esm/resources/CacheFirstStrategy.js +11 -8
- package/dist/esm/resources/CacheFirstStrategy.js.map +1 -1
- package/dist/esm/resources/CacheStrategy.d.ts +14 -6
- package/dist/esm/resources/Loader.d.ts +8 -3
- package/dist/esm/resources/Loader.js +19 -37
- package/dist/esm/resources/Loader.js.map +1 -1
- package/dist/esm/resources/NetworkOnlyStrategy.d.ts +3 -0
- package/dist/esm/resources/NetworkOnlyStrategy.js +8 -3
- package/dist/esm/resources/NetworkOnlyStrategy.js.map +1 -1
- package/dist/esm/resources/factories/ImageFactory.d.ts +2 -2
- package/dist/esm/resources/factories/ImageFactory.js.map +1 -1
- package/dist/esm/resources/factories/TextureFactory.d.ts +2 -2
- package/dist/esm/resources/factories/TextureFactory.js.map +1 -1
- package/dist/esm/resources/factories/VttFactory.d.ts +3 -3
- package/dist/esm/resources/factories/VttFactory.js +83 -6
- package/dist/esm/resources/factories/VttFactory.js.map +1 -1
- package/dist/exo.esm.js +4028 -1518
- package/dist/exo.esm.js.map +1 -1
- package/package.json +2 -1
- package/dist/esm/input/GamepadChannels.d.ts +0 -47
- package/dist/esm/input/GamepadChannels.js +0 -53
- package/dist/esm/input/GamepadChannels.js.map +0 -1
- package/dist/esm/input/GamepadControl.d.ts +0 -33
- package/dist/esm/input/GamepadControl.js +0 -42
- package/dist/esm/input/GamepadControl.js.map +0 -1
- package/dist/esm/input/Input.d.ts +0 -52
- package/dist/esm/input/Input.js +0 -90
- package/dist/esm/input/Input.js.map +0 -1
- package/dist/esm/particles/Particle.d.ts +0 -77
- package/dist/esm/particles/Particle.js +0 -143
- package/dist/esm/particles/Particle.js.map +0 -1
- package/dist/esm/particles/ParticleProperties.d.ts +0 -29
- package/dist/esm/particles/affectors/ColorAffector.d.ts +0 -30
- package/dist/esm/particles/affectors/ColorAffector.js +0 -55
- package/dist/esm/particles/affectors/ColorAffector.js.map +0 -1
- package/dist/esm/particles/affectors/ForceAffector.d.ts +0 -24
- package/dist/esm/particles/affectors/ForceAffector.js +0 -39
- package/dist/esm/particles/affectors/ForceAffector.js.map +0 -1
- package/dist/esm/particles/affectors/ParticleAffector.d.ts +0 -19
- package/dist/esm/particles/affectors/ScaleAffector.d.ts +0 -23
- package/dist/esm/particles/affectors/ScaleAffector.js +0 -38
- package/dist/esm/particles/affectors/ScaleAffector.js.map +0 -1
- package/dist/esm/particles/affectors/TorqueAffector.d.ts +0 -23
- package/dist/esm/particles/affectors/TorqueAffector.js +0 -37
- package/dist/esm/particles/affectors/TorqueAffector.js.map +0 -1
- package/dist/esm/particles/emitters/ParticleEmitter.d.ts +0 -19
- package/dist/esm/particles/emitters/ParticleOptions.d.ts +0 -62
- package/dist/esm/particles/emitters/ParticleOptions.js +0 -120
- package/dist/esm/particles/emitters/ParticleOptions.js.map +0 -1
- package/dist/esm/particles/emitters/UniversalEmitter.d.ts +0 -40
- package/dist/esm/particles/emitters/UniversalEmitter.js +0 -68
- package/dist/esm/particles/emitters/UniversalEmitter.js.map +0 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule.js';
|
|
2
|
+
import { Color } from '../../core/Color.js';
|
|
3
|
+
|
|
4
|
+
/// <reference types="@webgpu/types" />
|
|
5
|
+
const lookupSize = 256;
|
|
6
|
+
/**
|
|
7
|
+
* Per-frame, per-particle color sampler driven by velocity magnitude rather
|
|
8
|
+
* than lifetime ratio. Each live particle's tint is set to the gradient
|
|
9
|
+
* evaluated at `clamp((|velocity| - minSpeed) / (maxSpeed - minSpeed), 0, 1)`.
|
|
10
|
+
*
|
|
11
|
+
* Use cases: heat-mapping (slow=blue, fast=red), velocity-tinted trails,
|
|
12
|
+
* speed-gated highlights.
|
|
13
|
+
*
|
|
14
|
+
* GPU-eligible: gradient uploaded as a 256-tap 1D RGBA8 texture, sampled
|
|
15
|
+
* with linear filtering. Replaces the full color word — pair with a
|
|
16
|
+
* separate {@link AlphaFadeOverLifetime} after this module if you want to
|
|
17
|
+
* keep alpha controlled by lifetime.
|
|
18
|
+
*/
|
|
19
|
+
class ColorOverSpeed extends UpdateModule {
|
|
20
|
+
gradient;
|
|
21
|
+
minSpeed;
|
|
22
|
+
maxSpeed;
|
|
23
|
+
constructor(gradient, minSpeed, maxSpeed) {
|
|
24
|
+
super();
|
|
25
|
+
this.gradient = gradient;
|
|
26
|
+
this.minSpeed = minSpeed;
|
|
27
|
+
this.maxSpeed = maxSpeed;
|
|
28
|
+
}
|
|
29
|
+
apply(system, _dt) {
|
|
30
|
+
const { velX, velY, color, liveCount } = system;
|
|
31
|
+
const gradient = this.gradient;
|
|
32
|
+
const min = this.minSpeed;
|
|
33
|
+
const span = Math.max(1e-5, this.maxSpeed - this.minSpeed);
|
|
34
|
+
for (let i = 0; i < liveCount; i++) {
|
|
35
|
+
const speed = Math.sqrt(velX[i] * velX[i] + velY[i] * velY[i]);
|
|
36
|
+
const t = Math.max(0, Math.min(1, (speed - min) / span));
|
|
37
|
+
color[i] = gradient.evaluateRgba(t);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
wgsl() {
|
|
41
|
+
return {
|
|
42
|
+
key: 'ColorOverSpeed',
|
|
43
|
+
uniforms: [
|
|
44
|
+
{ name: 'minSpeed', type: 'f32' },
|
|
45
|
+
{ name: 'invSpan', type: 'f32' },
|
|
46
|
+
],
|
|
47
|
+
textures: [{ name: 'gradient', format: 'rgba8unorm' }],
|
|
48
|
+
body: `
|
|
49
|
+
let speedMag = length(velocities[idx]);
|
|
50
|
+
let speedT = clamp((speedMag - modules.u_ColorOverSpeed.minSpeed) * modules.u_ColorOverSpeed.invSpan, 0.0, 1.0);
|
|
51
|
+
let speedSample = textureSampleLevel(u_ColorOverSpeed_gradient, u_ColorOverSpeed_gradient_sampler, speedT, 0.0);
|
|
52
|
+
let speedR = u32(speedSample.r * 255.0) & 255u;
|
|
53
|
+
let speedG = u32(speedSample.g * 255.0) & 255u;
|
|
54
|
+
let speedB = u32(speedSample.b * 255.0) & 255u;
|
|
55
|
+
let speedA = u32(speedSample.a * 255.0) & 255u;
|
|
56
|
+
color[idx] = (speedA << 24u) | (speedB << 16u) | (speedG << 8u) | speedR;
|
|
57
|
+
`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
writeUniforms(view, offset) {
|
|
61
|
+
const span = Math.max(1e-5, this.maxSpeed - this.minSpeed);
|
|
62
|
+
view.setFloat32(offset + 0, this.minSpeed, true);
|
|
63
|
+
view.setFloat32(offset + 4, 1 / span, true);
|
|
64
|
+
}
|
|
65
|
+
uploadTextures(device, textures) {
|
|
66
|
+
const texture = textures.get('gradient');
|
|
67
|
+
if (texture === undefined) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const data = new Uint8Array(lookupSize * 4);
|
|
71
|
+
const scratch = new Color();
|
|
72
|
+
for (let i = 0; i < lookupSize; i++) {
|
|
73
|
+
const t = i / (lookupSize - 1);
|
|
74
|
+
this.gradient.evaluate(t, scratch);
|
|
75
|
+
const o = i * 4;
|
|
76
|
+
data[o + 0] = scratch.r & 255;
|
|
77
|
+
data[o + 1] = scratch.g & 255;
|
|
78
|
+
data[o + 2] = scratch.b & 255;
|
|
79
|
+
data[o + 3] = ((scratch.a * 255) | 0) & 255;
|
|
80
|
+
}
|
|
81
|
+
device.queue.writeTexture({ texture }, data.buffer, { offset: 0, bytesPerRow: lookupSize * 4, rowsPerImage: 1 }, { width: lookupSize, height: 1, depthOrArrayLayers: 1 });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { ColorOverSpeed };
|
|
86
|
+
//# sourceMappingURL=ColorOverSpeed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorOverSpeed.js","sources":["../../../../../src/particles/modules/ColorOverSpeed.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
2
|
+
/**
|
|
3
|
+
* Per-particle hook invoked exactly once when a particle expires, before
|
|
4
|
+
* its slot is recycled by the compaction pass. The dying particle's data
|
|
5
|
+
* is still readable at `system.posX[slot]` etc.
|
|
6
|
+
*
|
|
7
|
+
* Use for sub-emitters (spawn child particles where this one died), event
|
|
8
|
+
* dispatch (trigger an audio cue, score event), or trail termination.
|
|
9
|
+
*
|
|
10
|
+
* Implementation pattern:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* onDeath(system, slot) {
|
|
14
|
+
* const x = system.posX[slot];
|
|
15
|
+
* const y = system.posY[slot];
|
|
16
|
+
* this._childSystem.spawnBurstAt(x, y, 8);
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare abstract class DeathModule {
|
|
21
|
+
abstract onDeath(system: ParticleSystem, slot: number): void;
|
|
22
|
+
/** Optional cleanup hook called from `ParticleSystem.destroy`. */
|
|
23
|
+
destroy(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-particle hook invoked exactly once when a particle expires, before
|
|
3
|
+
* its slot is recycled by the compaction pass. The dying particle's data
|
|
4
|
+
* is still readable at `system.posX[slot]` etc.
|
|
5
|
+
*
|
|
6
|
+
* Use for sub-emitters (spawn child particles where this one died), event
|
|
7
|
+
* dispatch (trigger an audio cue, score event), or trail termination.
|
|
8
|
+
*
|
|
9
|
+
* Implementation pattern:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* onDeath(system, slot) {
|
|
13
|
+
* const x = system.posX[slot];
|
|
14
|
+
* const y = system.posY[slot];
|
|
15
|
+
* this._childSystem.spawnBurstAt(x, y, 8);
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
class DeathModule {
|
|
20
|
+
/** Optional cleanup hook called from `ParticleSystem.destroy`. */
|
|
21
|
+
destroy() { }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { DeathModule };
|
|
25
|
+
//# sourceMappingURL=DeathModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeathModule.js","sources":["../../../../../src/particles/modules/DeathModule.ts"],"sourcesContent":[null],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;AAiBG;MACmB,WAAW,CAAA;;AAGtB,IAAA,OAAO,KAAU;AAC3B;;;;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule';
|
|
2
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
3
|
+
import type { WgslContribution } from './WgslContribution';
|
|
4
|
+
/**
|
|
5
|
+
* Exponential velocity damping. Each frame multiplies every live particle's
|
|
6
|
+
* velocity by `(1 - drag * dt)`, simulating linear air resistance.
|
|
7
|
+
*
|
|
8
|
+
* `drag = 0` is no damping; `drag = 1` halves velocity in ~1 second; higher
|
|
9
|
+
* values slow particles faster. Negative values accelerate (don't do that
|
|
10
|
+
* unless you mean it).
|
|
11
|
+
*
|
|
12
|
+
* GPU-eligible.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Drag extends UpdateModule {
|
|
15
|
+
drag: number;
|
|
16
|
+
constructor(drag: number);
|
|
17
|
+
apply(system: ParticleSystem, dt: number): void;
|
|
18
|
+
wgsl(): WgslContribution;
|
|
19
|
+
writeUniforms(view: DataView, offset: number): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Exponential velocity damping. Each frame multiplies every live particle's
|
|
5
|
+
* velocity by `(1 - drag * dt)`, simulating linear air resistance.
|
|
6
|
+
*
|
|
7
|
+
* `drag = 0` is no damping; `drag = 1` halves velocity in ~1 second; higher
|
|
8
|
+
* values slow particles faster. Negative values accelerate (don't do that
|
|
9
|
+
* unless you mean it).
|
|
10
|
+
*
|
|
11
|
+
* GPU-eligible.
|
|
12
|
+
*/
|
|
13
|
+
class Drag extends UpdateModule {
|
|
14
|
+
drag;
|
|
15
|
+
constructor(drag) {
|
|
16
|
+
super();
|
|
17
|
+
this.drag = drag;
|
|
18
|
+
}
|
|
19
|
+
apply(system, dt) {
|
|
20
|
+
const { velX, velY, liveCount } = system;
|
|
21
|
+
const factor = 1 - this.drag * dt;
|
|
22
|
+
for (let i = 0; i < liveCount; i++) {
|
|
23
|
+
velX[i] *= factor;
|
|
24
|
+
velY[i] *= factor;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
wgsl() {
|
|
28
|
+
return {
|
|
29
|
+
key: 'Drag',
|
|
30
|
+
uniforms: [
|
|
31
|
+
{ name: 'drag', type: 'f32' },
|
|
32
|
+
],
|
|
33
|
+
body: `
|
|
34
|
+
let dragFactor = 1.0 - modules.u_Drag.drag * dt;
|
|
35
|
+
velocities[idx] = velocities[idx] * dragFactor;
|
|
36
|
+
`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
writeUniforms(view, offset) {
|
|
40
|
+
view.setFloat32(offset + 0, this.drag, true);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { Drag };
|
|
45
|
+
//# sourceMappingURL=Drag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Drag.js","sources":["../../../../../src/particles/modules/Drag.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;;;;;;;;;AASG;AACG,MAAO,IAAK,SAAQ,YAAY,CAAA;AAC3B,IAAA,IAAI;AAEX,IAAA,WAAA,CAAmB,IAAY,EAAA;AAC3B,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;IACpB;IAEgB,KAAK,CAAC,MAAsB,EAAE,EAAU,EAAA;QACpD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM;QACxC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,EAAE;AAEjC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;AAChC,YAAA,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM;AACjB,YAAA,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM;QACrB;IACJ;IAEgB,IAAI,GAAA;QAChB,OAAO;AACH,YAAA,GAAG,EAAE,MAAM;AACX,YAAA,QAAQ,EAAE;AACN,gBAAA,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE;AAChC,aAAA;AACD,YAAA,IAAI,EAAE;;;AAGL,YAAA,CAAA;SACJ;IACL;IAEgB,aAAa,CAAC,IAAc,EAAE,MAAc,EAAA;AACxD,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;IAChD;AACH;;;;"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule';
|
|
2
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
3
|
+
import type { WgslContribution } from './WgslContribution';
|
|
4
|
+
/**
|
|
5
|
+
* Applies a tangential acceleration around a center point — perpendicular
|
|
6
|
+
* to the radial vector `(particle − center)`. Combined with an attract /
|
|
7
|
+
* repel module that controls the radial distance, this produces orbital,
|
|
8
|
+
* spiral, or vortex motion.
|
|
9
|
+
*
|
|
10
|
+
* `angularSpeed` is the target angular velocity in radians/second. The
|
|
11
|
+
* effective tangential acceleration scales with `radius * angularSpeed`,
|
|
12
|
+
* so distant particles get pushed harder (matching uniform circular
|
|
13
|
+
* motion). Positive values orbit counter-clockwise, negative clockwise.
|
|
14
|
+
*
|
|
15
|
+
* Use cases: galactic spirals, smoke vortices around an attractor, wind
|
|
16
|
+
* eddies. Layer with {@link AttractToPoint} for stable orbits.
|
|
17
|
+
*
|
|
18
|
+
* GPU-eligible.
|
|
19
|
+
*/
|
|
20
|
+
export declare class OrbitalForce extends UpdateModule {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
angularSpeed: number;
|
|
24
|
+
constructor(x: number, y: number, angularSpeed: number);
|
|
25
|
+
apply(system: ParticleSystem, dt: number): void;
|
|
26
|
+
wgsl(): WgslContribution;
|
|
27
|
+
writeUniforms(view: DataView, offset: number): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Applies a tangential acceleration around a center point — perpendicular
|
|
5
|
+
* to the radial vector `(particle − center)`. Combined with an attract /
|
|
6
|
+
* repel module that controls the radial distance, this produces orbital,
|
|
7
|
+
* spiral, or vortex motion.
|
|
8
|
+
*
|
|
9
|
+
* `angularSpeed` is the target angular velocity in radians/second. The
|
|
10
|
+
* effective tangential acceleration scales with `radius * angularSpeed`,
|
|
11
|
+
* so distant particles get pushed harder (matching uniform circular
|
|
12
|
+
* motion). Positive values orbit counter-clockwise, negative clockwise.
|
|
13
|
+
*
|
|
14
|
+
* Use cases: galactic spirals, smoke vortices around an attractor, wind
|
|
15
|
+
* eddies. Layer with {@link AttractToPoint} for stable orbits.
|
|
16
|
+
*
|
|
17
|
+
* GPU-eligible.
|
|
18
|
+
*/
|
|
19
|
+
class OrbitalForce extends UpdateModule {
|
|
20
|
+
x;
|
|
21
|
+
y;
|
|
22
|
+
angularSpeed;
|
|
23
|
+
constructor(x, y, angularSpeed) {
|
|
24
|
+
super();
|
|
25
|
+
this.x = x;
|
|
26
|
+
this.y = y;
|
|
27
|
+
this.angularSpeed = angularSpeed;
|
|
28
|
+
}
|
|
29
|
+
apply(system, dt) {
|
|
30
|
+
const { posX, posY, velX, velY, liveCount } = system;
|
|
31
|
+
const { x, y, angularSpeed } = this;
|
|
32
|
+
const omega = angularSpeed * dt;
|
|
33
|
+
for (let i = 0; i < liveCount; i++) {
|
|
34
|
+
const dx = posX[i] - x;
|
|
35
|
+
const dy = posY[i] - y;
|
|
36
|
+
// Perpendicular vector: (-dy, dx) for counter-clockwise.
|
|
37
|
+
velX[i] += -dy * omega;
|
|
38
|
+
velY[i] += dx * omega;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
wgsl() {
|
|
42
|
+
return {
|
|
43
|
+
key: 'OrbitalForce',
|
|
44
|
+
uniforms: [
|
|
45
|
+
{ name: 'center', type: 'vec2<f32>' },
|
|
46
|
+
{ name: 'angularSpeed', type: 'f32' },
|
|
47
|
+
{ name: '_pad0', type: 'f32' },
|
|
48
|
+
],
|
|
49
|
+
body: `
|
|
50
|
+
let orbitDelta = positions[idx] - modules.u_OrbitalForce.center;
|
|
51
|
+
let orbitOmega = modules.u_OrbitalForce.angularSpeed * dt;
|
|
52
|
+
velocities[idx] = velocities[idx] + vec2<f32>(-orbitDelta.y, orbitDelta.x) * orbitOmega;
|
|
53
|
+
`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
writeUniforms(view, offset) {
|
|
57
|
+
view.setFloat32(offset + 0, this.x, true);
|
|
58
|
+
view.setFloat32(offset + 4, this.y, true);
|
|
59
|
+
view.setFloat32(offset + 8, this.angularSpeed, true);
|
|
60
|
+
view.setFloat32(offset + 12, 0, true);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { OrbitalForce };
|
|
65
|
+
//# sourceMappingURL=OrbitalForce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OrbitalForce.js","sources":["../../../../../src/particles/modules/OrbitalForce.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;;;;;;;;;;;;;;;AAeG;AACG,MAAO,YAAa,SAAQ,YAAY,CAAA;AACnC,IAAA,CAAC;AACD,IAAA,CAAC;AACD,IAAA,YAAY;AAEnB,IAAA,WAAA,CAAmB,CAAS,EAAE,CAAS,EAAE,YAAoB,EAAA;AACzD,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,CAAC,GAAG,CAAC;AACV,QAAA,IAAI,CAAC,CAAC,GAAG,CAAC;AACV,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;IACpC;IAEgB,KAAK,CAAC,MAAsB,EAAE,EAAU,EAAA;AACpD,QAAA,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM;QACpD,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI;AACnC,QAAA,MAAM,KAAK,GAAG,YAAY,GAAG,EAAE;AAE/B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;YAChC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YACtB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;;YAEtB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK;AACtB,YAAA,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,KAAK;QACzB;IACJ;IAEgB,IAAI,GAAA;QAChB,OAAO;AACH,YAAA,GAAG,EAAE,cAAc;AACnB,YAAA,QAAQ,EAAE;AACN,gBAAA,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE;AACrC,gBAAA,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE;AACrC,gBAAA,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE;AACjC,aAAA;AACD,YAAA,IAAI,EAAE;;;;AAIL,YAAA,CAAA;SACJ;IACL;IAEgB,aAAa,CAAC,IAAc,EAAE,MAAc,EAAA;AACxD,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;AACzC,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;AACzC,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC;QACpD,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC;IACzC;AACH;;;;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Vector } from '@/math/Vector';
|
|
2
|
+
import { Color } from '@/core/Color';
|
|
3
|
+
import { SpawnModule } from './SpawnModule';
|
|
4
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
5
|
+
import type { Distribution } from '@/particles/distributions/Distribution';
|
|
6
|
+
/**
|
|
7
|
+
* Per-property spawn configuration. Every entry is a {@link Distribution}
|
|
8
|
+
* sampled once per spawned particle. Omitting an entry leaves the slot's
|
|
9
|
+
* field at its zero/default value (zero position/velocity/rotation, unit
|
|
10
|
+
* scale, opaque white, lifetime 1 s).
|
|
11
|
+
*/
|
|
12
|
+
export interface RateSpawnConfig {
|
|
13
|
+
/** Particles emitted per second. Sampled each frame. */
|
|
14
|
+
rate: Distribution<number>;
|
|
15
|
+
/** Total lifetime in seconds. Required — drives expiry. Default 1. */
|
|
16
|
+
lifetime?: Distribution<number>;
|
|
17
|
+
position?: Distribution<Vector>;
|
|
18
|
+
velocity?: Distribution<Vector>;
|
|
19
|
+
scale?: Distribution<Vector>;
|
|
20
|
+
rotation?: Distribution<number>;
|
|
21
|
+
rotationSpeed?: Distribution<number>;
|
|
22
|
+
/** Initial tint at spawn. For per-frame fade use a `ColorOverLifetime` update module. */
|
|
23
|
+
tint?: Distribution<Color>;
|
|
24
|
+
textureIndex?: Distribution<number>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Continuous, rate-based spawner. Emits a {@link RateSpawnConfig.rate}
|
|
28
|
+
* sample per second; sub-frame fractions accumulate so low rates (e.g.
|
|
29
|
+
* 0.5 particles/s) remain accurate over time.
|
|
30
|
+
*
|
|
31
|
+
* Each property is independently randomised via its {@link Distribution}.
|
|
32
|
+
* Every spawned particle gets a fresh sample for every configured field.
|
|
33
|
+
*/
|
|
34
|
+
export declare class RateSpawn extends SpawnModule {
|
|
35
|
+
config: RateSpawnConfig;
|
|
36
|
+
private _accumulator;
|
|
37
|
+
private readonly _vec;
|
|
38
|
+
private readonly _color;
|
|
39
|
+
constructor(config: RateSpawnConfig);
|
|
40
|
+
apply(system: ParticleSystem, dt: number): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Vector } from '../../math/Vector.js';
|
|
2
|
+
import { Color } from '../../core/Color.js';
|
|
3
|
+
import { SpawnModule } from './SpawnModule.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Continuous, rate-based spawner. Emits a {@link RateSpawnConfig.rate}
|
|
7
|
+
* sample per second; sub-frame fractions accumulate so low rates (e.g.
|
|
8
|
+
* 0.5 particles/s) remain accurate over time.
|
|
9
|
+
*
|
|
10
|
+
* Each property is independently randomised via its {@link Distribution}.
|
|
11
|
+
* Every spawned particle gets a fresh sample for every configured field.
|
|
12
|
+
*/
|
|
13
|
+
class RateSpawn extends SpawnModule {
|
|
14
|
+
config;
|
|
15
|
+
_accumulator = 0;
|
|
16
|
+
_vec = new Vector();
|
|
17
|
+
_color = new Color();
|
|
18
|
+
constructor(config) {
|
|
19
|
+
super();
|
|
20
|
+
this.config = config;
|
|
21
|
+
}
|
|
22
|
+
apply(system, dt) {
|
|
23
|
+
const cfg = this.config;
|
|
24
|
+
const rate = cfg.rate.sample();
|
|
25
|
+
this._accumulator += rate * dt;
|
|
26
|
+
const count = this._accumulator | 0;
|
|
27
|
+
if (count <= 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this._accumulator -= count;
|
|
31
|
+
const v = this._vec;
|
|
32
|
+
const c = this._color;
|
|
33
|
+
for (let i = 0; i < count; i++) {
|
|
34
|
+
const slot = system.spawn();
|
|
35
|
+
if (slot < 0) {
|
|
36
|
+
this._accumulator = 0;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
system.lifetime[slot] = cfg.lifetime ? cfg.lifetime.sample() : 1;
|
|
40
|
+
if (cfg.position) {
|
|
41
|
+
cfg.position.sample(v);
|
|
42
|
+
system.posX[slot] = v.x;
|
|
43
|
+
system.posY[slot] = v.y;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
system.posX[slot] = 0;
|
|
47
|
+
system.posY[slot] = 0;
|
|
48
|
+
}
|
|
49
|
+
if (cfg.velocity) {
|
|
50
|
+
cfg.velocity.sample(v);
|
|
51
|
+
system.velX[slot] = v.x;
|
|
52
|
+
system.velY[slot] = v.y;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
system.velX[slot] = 0;
|
|
56
|
+
system.velY[slot] = 0;
|
|
57
|
+
}
|
|
58
|
+
if (cfg.scale) {
|
|
59
|
+
cfg.scale.sample(v);
|
|
60
|
+
system.scaleX[slot] = v.x;
|
|
61
|
+
system.scaleY[slot] = v.y;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
system.scaleX[slot] = 1;
|
|
65
|
+
system.scaleY[slot] = 1;
|
|
66
|
+
}
|
|
67
|
+
system.rotations[slot] = cfg.rotation ? cfg.rotation.sample() : 0;
|
|
68
|
+
system.rotationSpeeds[slot] = cfg.rotationSpeed ? cfg.rotationSpeed.sample() : 0;
|
|
69
|
+
system.color[slot] = cfg.tint ? cfg.tint.sample(c).toRgba() : 0xffffffff;
|
|
70
|
+
system.textureIndex[slot] = cfg.textureIndex ? (cfg.textureIndex.sample() | 0) : 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { RateSpawn };
|
|
76
|
+
//# sourceMappingURL=RateSpawn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateSpawn.js","sources":["../../../../../src/particles/modules/RateSpawn.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule';
|
|
2
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
3
|
+
import type { WgslContribution } from './WgslContribution';
|
|
4
|
+
/**
|
|
5
|
+
* Pushes every live particle away from a fixed point in the system's local
|
|
6
|
+
* coordinate space. Acceleration magnitude is `strength` (units / s²)
|
|
7
|
+
* along the direction `(particle − point)`. The optional `radius` controls
|
|
8
|
+
* the influence range — particles farther than `radius` are unaffected.
|
|
9
|
+
* Setting `radius = 0` (default) means infinite range with no falloff.
|
|
10
|
+
*
|
|
11
|
+
* Use cases: shockwaves, explosion blast, mouse-cursor repel field.
|
|
12
|
+
*
|
|
13
|
+
* GPU-eligible.
|
|
14
|
+
*/
|
|
15
|
+
export declare class RepelFromPoint extends UpdateModule {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
strength: number;
|
|
19
|
+
radius: number;
|
|
20
|
+
constructor(x: number, y: number, strength: number, radius?: number);
|
|
21
|
+
apply(system: ParticleSystem, dt: number): void;
|
|
22
|
+
wgsl(): WgslContribution;
|
|
23
|
+
writeUniforms(view: DataView, offset: number): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pushes every live particle away from a fixed point in the system's local
|
|
5
|
+
* coordinate space. Acceleration magnitude is `strength` (units / s²)
|
|
6
|
+
* along the direction `(particle − point)`. The optional `radius` controls
|
|
7
|
+
* the influence range — particles farther than `radius` are unaffected.
|
|
8
|
+
* Setting `radius = 0` (default) means infinite range with no falloff.
|
|
9
|
+
*
|
|
10
|
+
* Use cases: shockwaves, explosion blast, mouse-cursor repel field.
|
|
11
|
+
*
|
|
12
|
+
* GPU-eligible.
|
|
13
|
+
*/
|
|
14
|
+
class RepelFromPoint extends UpdateModule {
|
|
15
|
+
x;
|
|
16
|
+
y;
|
|
17
|
+
strength;
|
|
18
|
+
radius;
|
|
19
|
+
constructor(x, y, strength, radius = 0) {
|
|
20
|
+
super();
|
|
21
|
+
this.x = x;
|
|
22
|
+
this.y = y;
|
|
23
|
+
this.strength = strength;
|
|
24
|
+
this.radius = radius;
|
|
25
|
+
}
|
|
26
|
+
apply(system, dt) {
|
|
27
|
+
const { posX, posY, velX, velY, liveCount } = system;
|
|
28
|
+
const { x, y, strength, radius } = this;
|
|
29
|
+
const radiusSq = radius * radius;
|
|
30
|
+
for (let i = 0; i < liveCount; i++) {
|
|
31
|
+
const dx = posX[i] - x;
|
|
32
|
+
const dy = posY[i] - y;
|
|
33
|
+
const distSq = dx * dx + dy * dy;
|
|
34
|
+
if (distSq < 1e-10)
|
|
35
|
+
continue;
|
|
36
|
+
if (radius > 0 && distSq > radiusSq)
|
|
37
|
+
continue;
|
|
38
|
+
const dist = Math.sqrt(distSq);
|
|
39
|
+
const falloff = radius > 0 ? 1 - dist / radius : 1;
|
|
40
|
+
const a = (strength * falloff * dt) / dist;
|
|
41
|
+
velX[i] += dx * a;
|
|
42
|
+
velY[i] += dy * a;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
wgsl() {
|
|
46
|
+
return {
|
|
47
|
+
key: 'RepelFromPoint',
|
|
48
|
+
uniforms: [
|
|
49
|
+
{ name: 'point', type: 'vec2<f32>' },
|
|
50
|
+
{ name: 'strength', type: 'f32' },
|
|
51
|
+
{ name: 'radius', type: 'f32' },
|
|
52
|
+
],
|
|
53
|
+
body: `
|
|
54
|
+
let repelDelta = positions[idx] - modules.u_RepelFromPoint.point;
|
|
55
|
+
let repelDistSq = dot(repelDelta, repelDelta);
|
|
56
|
+
let repelRadius = modules.u_RepelFromPoint.radius;
|
|
57
|
+
let repelInRange = (repelRadius <= 0.0) || (repelDistSq <= repelRadius * repelRadius);
|
|
58
|
+
if (repelDistSq > 0.0000001 && repelInRange) {
|
|
59
|
+
let repelDist = sqrt(repelDistSq);
|
|
60
|
+
let repelFalloff = select(1.0, 1.0 - repelDist / max(repelRadius, 0.000001), repelRadius > 0.0);
|
|
61
|
+
let repelAccel = (modules.u_RepelFromPoint.strength * repelFalloff * dt) / repelDist;
|
|
62
|
+
velocities[idx] = velocities[idx] + repelDelta * repelAccel;
|
|
63
|
+
}
|
|
64
|
+
`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
writeUniforms(view, offset) {
|
|
68
|
+
view.setFloat32(offset + 0, this.x, true);
|
|
69
|
+
view.setFloat32(offset + 4, this.y, true);
|
|
70
|
+
view.setFloat32(offset + 8, this.strength, true);
|
|
71
|
+
view.setFloat32(offset + 12, this.radius, true);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { RepelFromPoint };
|
|
76
|
+
//# sourceMappingURL=RepelFromPoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RepelFromPoint.js","sources":["../../../../../src/particles/modules/RepelFromPoint.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;;;;;;;;;;AAUG;AACG,MAAO,cAAe,SAAQ,YAAY,CAAA;AACrC,IAAA,CAAC;AACD,IAAA,CAAC;AACD,IAAA,QAAQ;AACR,IAAA,MAAM;IAEb,WAAA,CAAmB,CAAS,EAAE,CAAS,EAAE,QAAgB,EAAE,MAAM,GAAG,CAAC,EAAA;AACjE,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,CAAC,GAAG,CAAC;AACV,QAAA,IAAI,CAAC,CAAC,GAAG,CAAC;AACV,QAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACxB,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;IACxB;IAEgB,KAAK,CAAC,MAAsB,EAAE,EAAU,EAAA;AACpD,QAAA,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM;QACpD,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI;AACvC,QAAA,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM;AAEhC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;YAChC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YACtB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YACtB,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;YAEhC,IAAI,MAAM,GAAG,KAAK;gBAAE;AACpB,YAAA,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,QAAQ;gBAAE;YAErC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9B,YAAA,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,MAAM,GAAG,CAAC;YAClD,MAAM,CAAC,GAAG,CAAC,QAAQ,GAAG,OAAO,GAAG,EAAE,IAAI,IAAI;AAE1C,YAAA,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC;AACjB,YAAA,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC;QACrB;IACJ;IAEgB,IAAI,GAAA;QAChB,OAAO;AACH,YAAA,GAAG,EAAE,gBAAgB;AACrB,YAAA,QAAQ,EAAE;AACN,gBAAA,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE;AACpC,gBAAA,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE;AACjC,gBAAA,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE;AAClC,aAAA;AACD,YAAA,IAAI,EAAE;;;;;;;;;;;AAWL,YAAA,CAAA;SACJ;IACL;IAEgB,aAAa,CAAC,IAAc,EAAE,MAAc,EAAA;AACxD,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;AACzC,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;AACzC,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC;AAChD,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;IACnD;AACH;;;;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule';
|
|
2
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
3
|
+
import type { WgslContribution } from './WgslContribution';
|
|
4
|
+
/**
|
|
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
|
+
export declare class RotateOverLifetime extends UpdateModule {
|
|
15
|
+
angularAcceleration: number;
|
|
16
|
+
constructor(angularAcceleration: number);
|
|
17
|
+
apply(system: ParticleSystem, dt: number): void;
|
|
18
|
+
wgsl(): WgslContribution;
|
|
19
|
+
writeUniforms(view: DataView, offset: number): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adds a constant angular acceleration to every live particle each frame
|
|
5
|
+
* (analogous to the legacy `TorqueAffector`). The system's integrate pass
|
|
6
|
+
* advances `rotation` from `rotationSpeed`; this module increments
|
|
7
|
+
* `rotationSpeed` itself.
|
|
8
|
+
*
|
|
9
|
+
* Units: degrees per second². Negative values decelerate spin.
|
|
10
|
+
*
|
|
11
|
+
* GPU-eligible.
|
|
12
|
+
*/
|
|
13
|
+
class RotateOverLifetime extends UpdateModule {
|
|
14
|
+
angularAcceleration;
|
|
15
|
+
constructor(angularAcceleration) {
|
|
16
|
+
super();
|
|
17
|
+
this.angularAcceleration = angularAcceleration;
|
|
18
|
+
}
|
|
19
|
+
apply(system, dt) {
|
|
20
|
+
const { rotationSpeeds, liveCount } = system;
|
|
21
|
+
const delta = this.angularAcceleration * dt;
|
|
22
|
+
for (let i = 0; i < liveCount; i++) {
|
|
23
|
+
rotationSpeeds[i] += delta;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
wgsl() {
|
|
27
|
+
return {
|
|
28
|
+
key: 'RotateOverLifetime',
|
|
29
|
+
uniforms: [
|
|
30
|
+
{ name: 'angularAcceleration', type: 'f32' },
|
|
31
|
+
],
|
|
32
|
+
body: `
|
|
33
|
+
rotInfo[idx].y = rotInfo[idx].y + modules.u_RotateOverLifetime.angularAcceleration * dt;
|
|
34
|
+
`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
writeUniforms(view, offset) {
|
|
38
|
+
view.setFloat32(offset + 0, this.angularAcceleration, true);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { RotateOverLifetime };
|
|
43
|
+
//# sourceMappingURL=RotateOverLifetime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RotateOverLifetime.js","sources":["../../../../../src/particles/modules/RotateOverLifetime.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;;;;;;;;;AASG;AACG,MAAO,kBAAmB,SAAQ,YAAY,CAAA;AACzC,IAAA,mBAAmB;AAE1B,IAAA,WAAA,CAAmB,mBAA2B,EAAA;AAC1C,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,mBAAmB,GAAG,mBAAmB;IAClD;IAEgB,KAAK,CAAC,MAAsB,EAAE,EAAU,EAAA;AACpD,QAAA,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,MAAM;AAC5C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,GAAG,EAAE;AAE3C,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;AAChC,YAAA,cAAc,CAAC,CAAC,CAAC,IAAI,KAAK;QAC9B;IACJ;IAEgB,IAAI,GAAA;QAChB,OAAO;AACH,YAAA,GAAG,EAAE,oBAAoB;AACzB,YAAA,QAAQ,EAAE;AACN,gBAAA,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,KAAK,EAAE;AAC/C,aAAA;AACD,YAAA,IAAI,EAAE;;AAEL,YAAA,CAAA;SACJ;IACL;IAEgB,aAAa,CAAC,IAAc,EAAE,MAAc,EAAA;AACxD,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC;IAC/D;AACH;;;;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { UpdateModule } from './UpdateModule';
|
|
2
|
+
import type { ParticleSystem } from '@/particles/ParticleSystem';
|
|
3
|
+
import type { Curve } from '@/particles/distributions/Curve';
|
|
4
|
+
import type { WgslContribution } from './WgslContribution';
|
|
5
|
+
/**
|
|
6
|
+
* Sets every live particle's scale to a curve sampled at the particle's
|
|
7
|
+
* current lifetime ratio. Both axes share one curve — for non-uniform
|
|
8
|
+
* scaling layer two ScaleOverLifetime modules with separate `axis` filters
|
|
9
|
+
* (or extend with a per-axis variant).
|
|
10
|
+
*
|
|
11
|
+
* Common patterns: shrink-to-zero (start at 1, end at 0), pulse (sine-like
|
|
12
|
+
* curve up to peak then down), slow-grow (linear ramp).
|
|
13
|
+
*
|
|
14
|
+
* GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and
|
|
15
|
+
* sampled with linear filtering on the GPU — no curve evaluation cost in
|
|
16
|
+
* the inner loop.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ScaleOverLifetime extends UpdateModule {
|
|
19
|
+
curve: Curve;
|
|
20
|
+
constructor(curve: Curve);
|
|
21
|
+
apply(system: ParticleSystem, _dt: number): void;
|
|
22
|
+
wgsl(): WgslContribution;
|
|
23
|
+
uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void;
|
|
24
|
+
}
|
|
25
|
+
/** Texture width for the curve lookup table. Exposed for ParticleGpuState. */
|
|
26
|
+
export declare const scaleLookupSize = 256;
|