@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.
Files changed (219) hide show
  1. package/CHANGELOG.md +737 -0
  2. package/dist/esm/core/Application.d.ts +3 -1
  3. package/dist/esm/core/Application.js +7 -6
  4. package/dist/esm/core/Application.js.map +1 -1
  5. package/dist/esm/core/Scene.d.ts +30 -0
  6. package/dist/esm/core/Scene.js +56 -0
  7. package/dist/esm/core/Scene.js.map +1 -1
  8. package/dist/esm/core/SceneManager.js +2 -2
  9. package/dist/esm/core/SceneManager.js.map +1 -1
  10. package/dist/esm/debug/DebugOverlay.js +2 -2
  11. package/dist/esm/debug/DebugOverlay.js.map +1 -1
  12. package/dist/esm/debug/PointerStackLayer.js +1 -1
  13. package/dist/esm/debug/PointerStackLayer.js.map +1 -1
  14. package/dist/esm/index.js +32 -10
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/input/ArcadeStickGamepadMapping.js +18 -19
  17. package/dist/esm/input/ArcadeStickGamepadMapping.js.map +1 -1
  18. package/dist/esm/input/Gamepad.d.ts +164 -62
  19. package/dist/esm/input/Gamepad.js +290 -134
  20. package/dist/esm/input/Gamepad.js.map +1 -1
  21. package/dist/esm/input/GamepadAxis.d.ts +120 -0
  22. package/dist/esm/input/GamepadAxis.js +106 -0
  23. package/dist/esm/input/GamepadAxis.js.map +1 -0
  24. package/dist/esm/input/GamepadButton.d.ts +110 -0
  25. package/dist/esm/input/GamepadButton.js +99 -0
  26. package/dist/esm/input/GamepadButton.js.map +1 -0
  27. package/dist/esm/input/GamepadDefinitions.js +4 -0
  28. package/dist/esm/input/GamepadDefinitions.js.map +1 -1
  29. package/dist/esm/input/GamepadMapping.d.ts +28 -24
  30. package/dist/esm/input/GamepadMapping.js +33 -16
  31. package/dist/esm/input/GamepadMapping.js.map +1 -1
  32. package/dist/esm/input/GamepadPromptLayouts.d.ts +10 -8
  33. package/dist/esm/input/GamepadPromptLayouts.js +21 -20
  34. package/dist/esm/input/GamepadPromptLayouts.js.map +1 -1
  35. package/dist/esm/input/GenericDualAnalogGamepadMapping.d.ts +6 -3
  36. package/dist/esm/input/GenericDualAnalogGamepadMapping.js +55 -46
  37. package/dist/esm/input/GenericDualAnalogGamepadMapping.js.map +1 -1
  38. package/dist/esm/input/InputBinding.d.ts +74 -0
  39. package/dist/esm/input/InputBinding.js +100 -0
  40. package/dist/esm/input/InputBinding.js.map +1 -0
  41. package/dist/esm/input/InputManager.d.ts +79 -33
  42. package/dist/esm/input/InputManager.js +229 -104
  43. package/dist/esm/input/InputManager.js.map +1 -1
  44. package/dist/esm/input/InteractionManager.d.ts +1 -1
  45. package/dist/esm/input/InteractionManager.js +13 -13
  46. package/dist/esm/input/InteractionManager.js.map +1 -1
  47. package/dist/esm/input/JoyConLeftGamepadMapping.d.ts +14 -9
  48. package/dist/esm/input/JoyConLeftGamepadMapping.js +39 -9
  49. package/dist/esm/input/JoyConLeftGamepadMapping.js.map +1 -1
  50. package/dist/esm/input/JoyConRightGamepadMapping.d.ts +14 -9
  51. package/dist/esm/input/JoyConRightGamepadMapping.js +35 -9
  52. package/dist/esm/input/JoyConRightGamepadMapping.js.map +1 -1
  53. package/dist/esm/input/Pointer.d.ts +84 -71
  54. package/dist/esm/input/Pointer.js +71 -71
  55. package/dist/esm/input/Pointer.js.map +1 -1
  56. package/dist/esm/input/SteamDeckGamepadMapping.d.ts +18 -0
  57. package/dist/esm/input/SteamDeckGamepadMapping.js +76 -0
  58. package/dist/esm/input/SteamDeckGamepadMapping.js.map +1 -0
  59. package/dist/esm/input/index.d.ts +7 -4
  60. package/dist/esm/input/types.d.ts +0 -76
  61. package/dist/esm/input/types.js +1 -80
  62. package/dist/esm/input/types.js.map +1 -1
  63. package/dist/esm/particles/ParticleSystem.d.ts +180 -83
  64. package/dist/esm/particles/ParticleSystem.js +446 -133
  65. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  66. package/dist/esm/particles/distributions/BoxArea.d.ts +17 -0
  67. package/dist/esm/particles/distributions/BoxArea.js +48 -0
  68. package/dist/esm/particles/distributions/BoxArea.js.map +1 -0
  69. package/dist/esm/particles/distributions/CircleArea.d.ts +19 -0
  70. package/dist/esm/particles/distributions/CircleArea.js +33 -0
  71. package/dist/esm/particles/distributions/CircleArea.js.map +1 -0
  72. package/dist/esm/particles/distributions/ConeDirection.d.ts +28 -0
  73. package/dist/esm/particles/distributions/ConeDirection.js +44 -0
  74. package/dist/esm/particles/distributions/ConeDirection.js.map +1 -0
  75. package/dist/esm/particles/distributions/Constant.d.ts +17 -0
  76. package/dist/esm/particles/distributions/Constant.js +35 -0
  77. package/dist/esm/particles/distributions/Constant.js.map +1 -0
  78. package/dist/esm/particles/distributions/Curve.d.ts +30 -0
  79. package/dist/esm/particles/distributions/Curve.js +53 -0
  80. package/dist/esm/particles/distributions/Curve.js.map +1 -0
  81. package/dist/esm/particles/distributions/Distribution.d.ts +45 -0
  82. package/dist/esm/particles/distributions/Gradient.d.ts +40 -0
  83. package/dist/esm/particles/distributions/Gradient.js +72 -0
  84. package/dist/esm/particles/distributions/Gradient.js.map +1 -0
  85. package/dist/esm/particles/distributions/LineSegment.d.ts +15 -0
  86. package/dist/esm/particles/distributions/LineSegment.js +27 -0
  87. package/dist/esm/particles/distributions/LineSegment.js.map +1 -0
  88. package/dist/esm/particles/distributions/Range.d.ts +12 -0
  89. package/dist/esm/particles/distributions/Range.js +19 -0
  90. package/dist/esm/particles/distributions/Range.js.map +1 -0
  91. package/dist/esm/particles/distributions/VectorRange.d.ts +20 -0
  92. package/dist/esm/particles/distributions/VectorRange.js +31 -0
  93. package/dist/esm/particles/distributions/VectorRange.js.map +1 -0
  94. package/dist/esm/particles/distributions/index.d.ts +12 -0
  95. package/dist/esm/particles/gpu/ParticleGpuState.d.ts +57 -0
  96. package/dist/esm/particles/gpu/ParticleGpuState.js +508 -0
  97. package/dist/esm/particles/gpu/ParticleGpuState.js.map +1 -0
  98. package/dist/esm/particles/index.d.ts +2 -10
  99. package/dist/esm/particles/modules/AlphaFadeOverLifetime.d.ts +24 -0
  100. package/dist/esm/particles/modules/AlphaFadeOverLifetime.js +60 -0
  101. package/dist/esm/particles/modules/AlphaFadeOverLifetime.js.map +1 -0
  102. package/dist/esm/particles/modules/ApplyForce.d.ts +20 -0
  103. package/dist/esm/particles/modules/ApplyForce.js +48 -0
  104. package/dist/esm/particles/modules/ApplyForce.js.map +1 -0
  105. package/dist/esm/particles/modules/AttractToPoint.d.ts +27 -0
  106. package/dist/esm/particles/modules/AttractToPoint.js +73 -0
  107. package/dist/esm/particles/modules/AttractToPoint.js.map +1 -0
  108. package/dist/esm/particles/modules/BurstSpawn.d.ts +53 -0
  109. package/dist/esm/particles/modules/BurstSpawn.js +94 -0
  110. package/dist/esm/particles/modules/BurstSpawn.js.map +1 -0
  111. package/dist/esm/particles/modules/ColorOverLifetime.d.ts +22 -0
  112. package/dist/esm/particles/modules/ColorOverLifetime.js +65 -0
  113. package/dist/esm/particles/modules/ColorOverLifetime.js.map +1 -0
  114. package/dist/esm/particles/modules/ColorOverSpeed.d.ts +27 -0
  115. package/dist/esm/particles/modules/ColorOverSpeed.js +86 -0
  116. package/dist/esm/particles/modules/ColorOverSpeed.js.map +1 -0
  117. package/dist/esm/particles/modules/DeathModule.d.ts +24 -0
  118. package/dist/esm/particles/modules/DeathModule.js +25 -0
  119. package/dist/esm/particles/modules/DeathModule.js.map +1 -0
  120. package/dist/esm/particles/modules/Drag.d.ts +20 -0
  121. package/dist/esm/particles/modules/Drag.js +45 -0
  122. package/dist/esm/particles/modules/Drag.js.map +1 -0
  123. package/dist/esm/particles/modules/OrbitalForce.d.ts +28 -0
  124. package/dist/esm/particles/modules/OrbitalForce.js +65 -0
  125. package/dist/esm/particles/modules/OrbitalForce.js.map +1 -0
  126. package/dist/esm/particles/modules/RateSpawn.d.ts +41 -0
  127. package/dist/esm/particles/modules/RateSpawn.js +76 -0
  128. package/dist/esm/particles/modules/RateSpawn.js.map +1 -0
  129. package/dist/esm/particles/modules/RepelFromPoint.d.ts +24 -0
  130. package/dist/esm/particles/modules/RepelFromPoint.js +76 -0
  131. package/dist/esm/particles/modules/RepelFromPoint.js.map +1 -0
  132. package/dist/esm/particles/modules/RotateOverLifetime.d.ts +20 -0
  133. package/dist/esm/particles/modules/RotateOverLifetime.js +43 -0
  134. package/dist/esm/particles/modules/RotateOverLifetime.js.map +1 -0
  135. package/dist/esm/particles/modules/ScaleOverLifetime.d.ts +26 -0
  136. package/dist/esm/particles/modules/ScaleOverLifetime.js +59 -0
  137. package/dist/esm/particles/modules/ScaleOverLifetime.js.map +1 -0
  138. package/dist/esm/particles/modules/SpawnModule.d.ts +30 -0
  139. package/dist/esm/particles/modules/SpawnModule.js +31 -0
  140. package/dist/esm/particles/modules/SpawnModule.js.map +1 -0
  141. package/dist/esm/particles/modules/SpawnOnDeath.d.ts +24 -0
  142. package/dist/esm/particles/modules/SpawnOnDeath.js +47 -0
  143. package/dist/esm/particles/modules/SpawnOnDeath.js.map +1 -0
  144. package/dist/esm/particles/modules/Turbulence.d.ts +30 -0
  145. package/dist/esm/particles/modules/Turbulence.js +122 -0
  146. package/dist/esm/particles/modules/Turbulence.js.map +1 -0
  147. package/dist/esm/particles/modules/UpdateModule.d.ts +95 -0
  148. package/dist/esm/particles/modules/UpdateModule.js +66 -0
  149. package/dist/esm/particles/modules/UpdateModule.js.map +1 -0
  150. package/dist/esm/particles/modules/VelocityOverLifetime.d.ts +30 -0
  151. package/dist/esm/particles/modules/VelocityOverLifetime.js +84 -0
  152. package/dist/esm/particles/modules/VelocityOverLifetime.js.map +1 -0
  153. package/dist/esm/particles/modules/WgslContribution.d.ts +81 -0
  154. package/dist/esm/particles/modules/WgslContribution.js +34 -0
  155. package/dist/esm/particles/modules/WgslContribution.js.map +1 -0
  156. package/dist/esm/particles/modules/index.d.ts +22 -0
  157. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.d.ts +9 -14
  158. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js +90 -61
  159. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js.map +1 -1
  160. package/dist/esm/rendering/webgl2/glsl/particle.vert.js +1 -1
  161. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.d.ts +9 -0
  162. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js +107 -23
  163. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js.map +1 -1
  164. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.d.ts +52 -0
  165. package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.d.ts +29 -0
  166. package/dist/esm/rendering/webgpu/compute/index.d.ts +3 -0
  167. package/dist/esm/resources/CacheFirstStrategy.d.ts +7 -4
  168. package/dist/esm/resources/CacheFirstStrategy.js +11 -8
  169. package/dist/esm/resources/CacheFirstStrategy.js.map +1 -1
  170. package/dist/esm/resources/CacheStrategy.d.ts +14 -6
  171. package/dist/esm/resources/Loader.d.ts +8 -3
  172. package/dist/esm/resources/Loader.js +19 -37
  173. package/dist/esm/resources/Loader.js.map +1 -1
  174. package/dist/esm/resources/NetworkOnlyStrategy.d.ts +3 -0
  175. package/dist/esm/resources/NetworkOnlyStrategy.js +8 -3
  176. package/dist/esm/resources/NetworkOnlyStrategy.js.map +1 -1
  177. package/dist/esm/resources/factories/ImageFactory.d.ts +2 -2
  178. package/dist/esm/resources/factories/ImageFactory.js.map +1 -1
  179. package/dist/esm/resources/factories/TextureFactory.d.ts +2 -2
  180. package/dist/esm/resources/factories/TextureFactory.js.map +1 -1
  181. package/dist/esm/resources/factories/VttFactory.d.ts +3 -3
  182. package/dist/esm/resources/factories/VttFactory.js +83 -6
  183. package/dist/esm/resources/factories/VttFactory.js.map +1 -1
  184. package/dist/exo.esm.js +4028 -1518
  185. package/dist/exo.esm.js.map +1 -1
  186. package/package.json +2 -1
  187. package/dist/esm/input/GamepadChannels.d.ts +0 -47
  188. package/dist/esm/input/GamepadChannels.js +0 -53
  189. package/dist/esm/input/GamepadChannels.js.map +0 -1
  190. package/dist/esm/input/GamepadControl.d.ts +0 -33
  191. package/dist/esm/input/GamepadControl.js +0 -42
  192. package/dist/esm/input/GamepadControl.js.map +0 -1
  193. package/dist/esm/input/Input.d.ts +0 -52
  194. package/dist/esm/input/Input.js +0 -90
  195. package/dist/esm/input/Input.js.map +0 -1
  196. package/dist/esm/particles/Particle.d.ts +0 -77
  197. package/dist/esm/particles/Particle.js +0 -143
  198. package/dist/esm/particles/Particle.js.map +0 -1
  199. package/dist/esm/particles/ParticleProperties.d.ts +0 -29
  200. package/dist/esm/particles/affectors/ColorAffector.d.ts +0 -30
  201. package/dist/esm/particles/affectors/ColorAffector.js +0 -55
  202. package/dist/esm/particles/affectors/ColorAffector.js.map +0 -1
  203. package/dist/esm/particles/affectors/ForceAffector.d.ts +0 -24
  204. package/dist/esm/particles/affectors/ForceAffector.js +0 -39
  205. package/dist/esm/particles/affectors/ForceAffector.js.map +0 -1
  206. package/dist/esm/particles/affectors/ParticleAffector.d.ts +0 -19
  207. package/dist/esm/particles/affectors/ScaleAffector.d.ts +0 -23
  208. package/dist/esm/particles/affectors/ScaleAffector.js +0 -38
  209. package/dist/esm/particles/affectors/ScaleAffector.js.map +0 -1
  210. package/dist/esm/particles/affectors/TorqueAffector.d.ts +0 -23
  211. package/dist/esm/particles/affectors/TorqueAffector.js +0 -37
  212. package/dist/esm/particles/affectors/TorqueAffector.js.map +0 -1
  213. package/dist/esm/particles/emitters/ParticleEmitter.d.ts +0 -19
  214. package/dist/esm/particles/emitters/ParticleOptions.d.ts +0 -62
  215. package/dist/esm/particles/emitters/ParticleOptions.js +0 -120
  216. package/dist/esm/particles/emitters/ParticleOptions.js.map +0 -1
  217. package/dist/esm/particles/emitters/UniversalEmitter.d.ts +0 -40
  218. package/dist/esm/particles/emitters/UniversalEmitter.js +0 -68
  219. 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;