@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.
Files changed (211) hide show
  1. package/README.md +21 -43
  2. package/dist/esm/ParticleStorage.d.ts +188 -0
  3. package/dist/esm/ParticleStorage.d.ts.map +1 -0
  4. package/dist/esm/ParticleStorage.js +208 -0
  5. package/dist/esm/ParticleStorage.js.map +1 -0
  6. package/dist/esm/ParticleSystem.d.ts +189 -60
  7. package/dist/esm/ParticleSystem.d.ts.map +1 -0
  8. package/dist/esm/ParticleSystem.js +660 -560
  9. package/dist/esm/ParticleSystem.js.map +1 -1
  10. package/dist/esm/distributions/BoxArea.d.ts +1 -0
  11. package/dist/esm/distributions/BoxArea.d.ts.map +1 -0
  12. package/dist/esm/distributions/BoxArea.js +38 -44
  13. package/dist/esm/distributions/BoxArea.js.map +1 -1
  14. package/dist/esm/distributions/CircleArea.d.ts +1 -0
  15. package/dist/esm/distributions/CircleArea.d.ts.map +1 -0
  16. package/dist/esm/distributions/CircleArea.js +30 -28
  17. package/dist/esm/distributions/CircleArea.js.map +1 -1
  18. package/dist/esm/distributions/ColorGradient.d.ts +3 -2
  19. package/dist/esm/distributions/ColorGradient.d.ts.map +1 -0
  20. package/dist/esm/distributions/ColorGradient.js +70 -75
  21. package/dist/esm/distributions/ColorGradient.js.map +1 -1
  22. package/dist/esm/distributions/ConeDirection.d.ts +2 -1
  23. package/dist/esm/distributions/ConeDirection.d.ts.map +1 -0
  24. package/dist/esm/distributions/ConeDirection.js +41 -39
  25. package/dist/esm/distributions/ConeDirection.js.map +1 -1
  26. package/dist/esm/distributions/Constant.d.ts +1 -0
  27. package/dist/esm/distributions/Constant.d.ts.map +1 -0
  28. package/dist/esm/distributions/Constant.js +32 -32
  29. package/dist/esm/distributions/Constant.js.map +1 -1
  30. package/dist/esm/distributions/Curve.d.ts +2 -1
  31. package/dist/esm/distributions/Curve.d.ts.map +1 -0
  32. package/dist/esm/distributions/Curve.js +46 -55
  33. package/dist/esm/distributions/Curve.js.map +1 -1
  34. package/dist/esm/distributions/Distribution.d.ts +4 -3
  35. package/dist/esm/distributions/Distribution.d.ts.map +1 -0
  36. package/dist/esm/distributions/LineSegment.d.ts +1 -0
  37. package/dist/esm/distributions/LineSegment.d.ts.map +1 -0
  38. package/dist/esm/distributions/LineSegment.js +25 -23
  39. package/dist/esm/distributions/LineSegment.js.map +1 -1
  40. package/dist/esm/distributions/Range.d.ts +1 -0
  41. package/dist/esm/distributions/Range.d.ts.map +1 -0
  42. package/dist/esm/distributions/Range.js +18 -16
  43. package/dist/esm/distributions/Range.js.map +1 -1
  44. package/dist/esm/distributions/VectorRange.d.ts +1 -0
  45. package/dist/esm/distributions/VectorRange.d.ts.map +1 -0
  46. package/dist/esm/distributions/VectorRange.js +29 -27
  47. package/dist/esm/distributions/VectorRange.js.map +1 -1
  48. package/dist/esm/distributions/index.d.ts +1 -0
  49. package/dist/esm/distributions/index.d.ts.map +1 -0
  50. package/dist/esm/gpu/ParticleGpuState.d.ts +143 -18
  51. package/dist/esm/gpu/ParticleGpuState.d.ts.map +1 -0
  52. package/dist/esm/gpu/ParticleGpuState.js +655 -497
  53. package/dist/esm/gpu/ParticleGpuState.js.map +1 -1
  54. package/dist/esm/gpu/shaders/particle-simulate.wgsl.js +6 -0
  55. package/dist/esm/gpu/shaders/particle-simulate.wgsl.js.map +1 -0
  56. package/dist/esm/index.d.ts +1 -0
  57. package/dist/esm/index.d.ts.map +1 -0
  58. package/dist/esm/index.js +39 -32
  59. package/dist/esm/modules/AlphaFadeOverLifetime.d.ts +4 -3
  60. package/dist/esm/modules/AlphaFadeOverLifetime.d.ts.map +1 -0
  61. package/dist/esm/modules/AlphaFadeOverLifetime.js +68 -55
  62. package/dist/esm/modules/AlphaFadeOverLifetime.js.map +1 -1
  63. package/dist/esm/modules/ApplyForce.d.ts +4 -3
  64. package/dist/esm/modules/ApplyForce.d.ts.map +1 -0
  65. package/dist/esm/modules/ApplyForce.js +49 -43
  66. package/dist/esm/modules/ApplyForce.js.map +1 -1
  67. package/dist/esm/modules/AttractToPoint.d.ts +4 -3
  68. package/dist/esm/modules/AttractToPoint.d.ts.map +1 -0
  69. package/dist/esm/modules/AttractToPoint.js +73 -62
  70. package/dist/esm/modules/AttractToPoint.js.map +1 -1
  71. package/dist/esm/modules/BurstSpawn.d.ts +6 -18
  72. package/dist/esm/modules/BurstSpawn.d.ts.map +1 -0
  73. package/dist/esm/modules/BurstSpawn.js +56 -91
  74. package/dist/esm/modules/BurstSpawn.js.map +1 -1
  75. package/dist/esm/modules/ColorOverLifetime.d.ts +4 -3
  76. package/dist/esm/modules/ColorOverLifetime.d.ts.map +1 -0
  77. package/dist/esm/modules/ColorOverLifetime.js +65 -53
  78. package/dist/esm/modules/ColorOverLifetime.js.map +1 -1
  79. package/dist/esm/modules/ColorOverSpeed.d.ts +5 -4
  80. package/dist/esm/modules/ColorOverSpeed.d.ts.map +1 -0
  81. package/dist/esm/modules/ColorOverSpeed.js +90 -75
  82. package/dist/esm/modules/ColorOverSpeed.js.map +1 -1
  83. package/dist/esm/modules/DeathModule.d.ts +26 -10
  84. package/dist/esm/modules/DeathModule.d.ts.map +1 -0
  85. package/dist/esm/modules/DeathModule.js +38 -22
  86. package/dist/esm/modules/DeathModule.js.map +1 -1
  87. package/dist/esm/modules/Drag.d.ts +3 -2
  88. package/dist/esm/modules/Drag.d.ts.map +1 -0
  89. package/dist/esm/modules/Drag.js +43 -37
  90. package/dist/esm/modules/Drag.js.map +1 -1
  91. package/dist/esm/modules/OrbitalForce.d.ts +4 -3
  92. package/dist/esm/modules/OrbitalForce.d.ts.map +1 -0
  93. package/dist/esm/modules/OrbitalForce.js +70 -58
  94. package/dist/esm/modules/OrbitalForce.js.map +1 -1
  95. package/dist/esm/modules/RateSpawn.d.ts +7 -22
  96. package/dist/esm/modules/RateSpawn.d.ts.map +1 -0
  97. package/dist/esm/modules/RateSpawn.js +39 -71
  98. package/dist/esm/modules/RateSpawn.js.map +1 -1
  99. package/dist/esm/modules/RepelFromPoint.d.ts +4 -3
  100. package/dist/esm/modules/RepelFromPoint.d.ts.map +1 -0
  101. package/dist/esm/modules/RepelFromPoint.js +72 -62
  102. package/dist/esm/modules/RepelFromPoint.js.map +1 -1
  103. package/dist/esm/modules/RotateOverLifetime.d.ts +3 -2
  104. package/dist/esm/modules/RotateOverLifetime.d.ts.map +1 -0
  105. package/dist/esm/modules/RotateOverLifetime.js +40 -36
  106. package/dist/esm/modules/RotateOverLifetime.js.map +1 -1
  107. package/dist/esm/modules/ScaleOverLifetime.d.ts +5 -4
  108. package/dist/esm/modules/ScaleOverLifetime.d.ts.map +1 -0
  109. package/dist/esm/modules/ScaleOverLifetime.js +60 -50
  110. package/dist/esm/modules/ScaleOverLifetime.js.map +1 -1
  111. package/dist/esm/modules/SpawnModule.d.ts +15 -12
  112. package/dist/esm/modules/SpawnModule.d.ts.map +1 -0
  113. package/dist/esm/modules/SpawnModule.js +32 -28
  114. package/dist/esm/modules/SpawnModule.js.map +1 -1
  115. package/dist/esm/modules/SpawnOnDeath.d.ts +13 -9
  116. package/dist/esm/modules/SpawnOnDeath.d.ts.map +1 -0
  117. package/dist/esm/modules/SpawnOnDeath.js +41 -43
  118. package/dist/esm/modules/SpawnOnDeath.js.map +1 -1
  119. package/dist/esm/modules/Turbulence.d.ts +4 -3
  120. package/dist/esm/modules/Turbulence.d.ts.map +1 -0
  121. package/dist/esm/modules/Turbulence.js +101 -89
  122. package/dist/esm/modules/Turbulence.js.map +1 -1
  123. package/dist/esm/modules/UpdateModule.d.ts +21 -13
  124. package/dist/esm/modules/UpdateModule.d.ts.map +1 -0
  125. package/dist/esm/modules/UpdateModule.js +65 -63
  126. package/dist/esm/modules/UpdateModule.js.map +1 -1
  127. package/dist/esm/modules/VelocityOverLifetime.d.ts +7 -6
  128. package/dist/esm/modules/VelocityOverLifetime.d.ts.map +1 -0
  129. package/dist/esm/modules/VelocityOverLifetime.js +75 -73
  130. package/dist/esm/modules/VelocityOverLifetime.js.map +1 -1
  131. package/dist/esm/modules/WgslContribution.d.ts +16 -15
  132. package/dist/esm/modules/WgslContribution.d.ts.map +1 -0
  133. package/dist/esm/modules/WgslContribution.js +37 -29
  134. package/dist/esm/modules/WgslContribution.js.map +1 -1
  135. package/dist/esm/modules/index.d.ts +3 -1
  136. package/dist/esm/modules/index.d.ts.map +1 -0
  137. package/dist/esm/modules/spawnFields.d.ts +32 -0
  138. package/dist/esm/modules/spawnFields.d.ts.map +1 -0
  139. package/dist/esm/modules/spawnFields.js +31 -0
  140. package/dist/esm/modules/spawnFields.js.map +1 -0
  141. package/dist/esm/particlesBuildInfo.d.ts +1 -0
  142. package/dist/esm/particlesBuildInfo.d.ts.map +1 -0
  143. package/dist/esm/particlesBuildInfo.js +6 -4
  144. package/dist/esm/particlesBuildInfo.js.map +1 -1
  145. package/dist/esm/particlesExtension.d.ts +13 -5
  146. package/dist/esm/particlesExtension.d.ts.map +1 -0
  147. package/dist/esm/particlesExtension.js +38 -42
  148. package/dist/esm/particlesExtension.js.map +1 -1
  149. package/dist/esm/public.d.ts +11 -0
  150. package/dist/esm/public.d.ts.map +1 -0
  151. package/dist/esm/renderModes/MeshParticles.d.ts +128 -0
  152. package/dist/esm/renderModes/MeshParticles.d.ts.map +1 -0
  153. package/dist/esm/renderModes/MeshParticles.js +263 -0
  154. package/dist/esm/renderModes/MeshParticles.js.map +1 -0
  155. package/dist/esm/renderModes/ParticleBufferLayout.d.ts +59 -0
  156. package/dist/esm/renderModes/ParticleBufferLayout.d.ts.map +1 -0
  157. package/dist/esm/renderModes/ParticleBufferLayout.js +99 -0
  158. package/dist/esm/renderModes/ParticleBufferLayout.js.map +1 -0
  159. package/dist/esm/renderModes/ParticleInstanceWriter.d.ts +58 -0
  160. package/dist/esm/renderModes/ParticleInstanceWriter.d.ts.map +1 -0
  161. package/dist/esm/renderModes/ParticleInstanceWriter.js +173 -0
  162. package/dist/esm/renderModes/ParticleInstanceWriter.js.map +1 -0
  163. package/dist/esm/renderModes/ParticleMaterial.d.ts +18 -0
  164. package/dist/esm/renderModes/ParticleMaterial.d.ts.map +1 -0
  165. package/dist/esm/renderModes/ParticleMaterial.js +24 -0
  166. package/dist/esm/renderModes/ParticleMaterial.js.map +1 -0
  167. package/dist/esm/renderModes/ParticleRenderMode.d.ts +114 -0
  168. package/dist/esm/renderModes/ParticleRenderMode.d.ts.map +1 -0
  169. package/dist/esm/renderModes/ParticleRenderMode.js +99 -0
  170. package/dist/esm/renderModes/ParticleRenderMode.js.map +1 -0
  171. package/dist/esm/renderModes/QuadParticles.d.ts +55 -0
  172. package/dist/esm/renderModes/QuadParticles.d.ts.map +1 -0
  173. package/dist/esm/renderModes/QuadParticles.js +95 -0
  174. package/dist/esm/renderModes/QuadParticles.js.map +1 -0
  175. package/dist/esm/renderModes/RibbonParticles.d.ts +96 -0
  176. package/dist/esm/renderModes/RibbonParticles.d.ts.map +1 -0
  177. package/dist/esm/renderModes/RibbonParticles.js +202 -0
  178. package/dist/esm/renderModes/RibbonParticles.js.map +1 -0
  179. package/dist/esm/renderModes/shaders/mesh-particles.wgsl.js +6 -0
  180. package/dist/esm/renderModes/shaders/mesh-particles.wgsl.js.map +1 -0
  181. package/dist/esm/renderModes/shaders/mesh.vert.js +6 -0
  182. package/dist/esm/renderModes/shaders/mesh.vert.js.map +1 -0
  183. package/dist/esm/renderModes/shaders/quad-particles.wgsl.js +6 -0
  184. package/dist/esm/renderModes/shaders/quad-particles.wgsl.js.map +1 -0
  185. package/dist/esm/renderModes/shaders/ribbon-particles.wgsl.js +6 -0
  186. package/dist/esm/renderModes/shaders/ribbon-particles.wgsl.js.map +1 -0
  187. package/dist/esm/renderModes/shaders/ribbon.frag.js +6 -0
  188. package/dist/esm/renderModes/shaders/ribbon.frag.js.map +1 -0
  189. package/dist/esm/renderModes/shaders/ribbon.vert.js +6 -0
  190. package/dist/esm/renderModes/shaders/ribbon.vert.js.map +1 -0
  191. package/dist/esm/renderers/WebGl2ParticleRenderer.d.ts +48 -20
  192. package/dist/esm/renderers/WebGl2ParticleRenderer.d.ts.map +1 -0
  193. package/dist/esm/renderers/WebGl2ParticleRenderer.js +317 -321
  194. package/dist/esm/renderers/WebGl2ParticleRenderer.js.map +1 -1
  195. package/dist/esm/renderers/WebGpuParticleRenderer.d.ts +99 -18
  196. package/dist/esm/renderers/WebGpuParticleRenderer.d.ts.map +1 -0
  197. package/dist/esm/renderers/WebGpuParticleRenderer.js +542 -551
  198. package/dist/esm/renderers/WebGpuParticleRenderer.js.map +1 -1
  199. package/dist/esm/renderers/shaders/particle.frag.js +6 -0
  200. package/dist/esm/renderers/shaders/particle.frag.js.map +1 -0
  201. package/dist/esm/renderers/shaders/particle.vert.js +6 -0
  202. package/dist/esm/renderers/shaders/particle.vert.js.map +1 -0
  203. package/package.json +8 -15
  204. package/dist/esm/index.js.map +0 -1
  205. package/dist/esm/register.d.ts +0 -1
  206. package/dist/esm/register.js +0 -43
  207. package/dist/esm/register.js.map +0 -1
  208. package/dist/esm/renderers/glsl/particle.frag.js +0 -4
  209. package/dist/esm/renderers/glsl/particle.frag.js.map +0 -1
  210. package/dist/esm/renderers/glsl/particle.vert.js +0 -4
  211. package/dist/esm/renderers/glsl/particle.vert.js.map +0 -1
@@ -1,41 +1,45 @@
1
- import { UpdateModule } from './UpdateModule.js';
1
+ import { UpdateModule } from "./UpdateModule.js";
2
2
 
3
+ //#region src/modules/RotateOverLifetime.ts
3
4
  /**
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] = (rotationSpeeds[i] ?? 0) + delta;
24
- }
25
- }
26
- wgsl() {
27
- return {
28
- key: 'RotateOverLifetime',
29
- uniforms: [{ name: 'angularAcceleration', type: 'f32' }],
30
- body: `
5
+ * Adds a constant angular acceleration to every live particle each frame
6
+ * (analogous to the legacy `TorqueAffector`). The system's integrate pass
7
+ * advances `rotation` from `rotationSpeed`; this module increments
8
+ * `rotationSpeed` itself.
9
+ *
10
+ * Units: degrees per second². Negative values decelerate spin.
11
+ *
12
+ * GPU-eligible.
13
+ */
14
+ var RotateOverLifetime = class extends UpdateModule {
15
+ angularAcceleration;
16
+ constructor(angularAcceleration) {
17
+ super();
18
+ this.angularAcceleration = angularAcceleration;
19
+ }
20
+ apply(particles, dt) {
21
+ const { speed: rotationSpeeds } = particles.rotation;
22
+ const liveCount = particles.count;
23
+ const delta = this.angularAcceleration * dt;
24
+ for (let i = 0; i < liveCount; i++) rotationSpeeds[i] = (rotationSpeeds[i] ?? 0) + delta;
25
+ }
26
+ wgsl() {
27
+ return {
28
+ key: "RotateOverLifetime",
29
+ uniforms: [{
30
+ name: "angularAcceleration",
31
+ type: "f32"
32
+ }],
33
+ body: `
31
34
  rotInfo[idx].y = rotInfo[idx].y + modules.u_RotateOverLifetime.angularAcceleration * dt;
32
- `,
33
- };
34
- }
35
- writeUniforms(view, offset) {
36
- view.setFloat32(offset + 0, this.angularAcceleration, true);
37
- }
38
- }
35
+ `
36
+ };
37
+ }
38
+ writeUniforms(view, offset) {
39
+ view.setFloat32(offset + 0, this.angularAcceleration, true);
40
+ }
41
+ };
39
42
 
43
+ //#endregion
40
44
  export { RotateOverLifetime };
41
- //# sourceMappingURL=RotateOverLifetime.js.map
45
+ //# sourceMappingURL=RotateOverLifetime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RotateOverLifetime.js","sources":["../../../../src/modules/RotateOverLifetime.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAKA;;;;;;;;;AASG;AACG,MAAO,kBAAmB,SAAQ,YAAY,CAAA;AAC3C,IAAA,mBAAmB;AAE1B,IAAA,WAAA,CAAmB,mBAA2B,EAAA;AAC5C,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,mBAAmB,GAAG,mBAAmB;IAChD;IAEgB,KAAK,CAAC,MAAsB,EAAE,EAAU,EAAA;AACtD,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;AAClC,YAAA,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK;QACtD;IACF;IAEgB,IAAI,GAAA;QAClB,OAAO;AACL,YAAA,GAAG,EAAE,oBAAoB;YACzB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACxD,YAAA,IAAI,EAAE;;AAEC,YAAA,CAAA;SACR;IACH;IAEgB,aAAa,CAAC,IAAc,EAAE,MAAc,EAAA;AAC1D,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC;IAC7D;AACD;;;;"}
1
+ {"version":3,"file":"RotateOverLifetime.js","names":[],"sources":["../../../src/modules/RotateOverLifetime.ts"],"sourcesContent":["import type { ParticleBatch } from '#ParticleStorage';\n\nimport { UpdateModule } from './UpdateModule';\nimport type { WgslContribution } from './WgslContribution';\n\n/**\n * Adds a constant angular acceleration to every live particle each frame\n * (analogous to the legacy `TorqueAffector`). The system's integrate pass\n * advances `rotation` from `rotationSpeed`; this module increments\n * `rotationSpeed` itself.\n *\n * Units: degrees per second². Negative values decelerate spin.\n *\n * GPU-eligible.\n */\nexport class RotateOverLifetime extends UpdateModule {\n public angularAcceleration: number;\n\n public constructor(angularAcceleration: number) {\n super();\n this.angularAcceleration = angularAcceleration;\n }\n\n public override apply(particles: ParticleBatch, dt: number): void {\n const { speed: rotationSpeeds } = particles.rotation;\n const liveCount = particles.count;\n const delta = this.angularAcceleration * dt;\n\n for (let i = 0; i < liveCount; i++) {\n rotationSpeeds[i] = (rotationSpeeds[i] ?? 0) + delta;\n }\n }\n\n public override wgsl(): WgslContribution {\n return {\n key: 'RotateOverLifetime',\n uniforms: [{ name: 'angularAcceleration', type: 'f32' }],\n body: `\n rotInfo[idx].y = rotInfo[idx].y + modules.u_RotateOverLifetime.angularAcceleration * dt;\n `,\n };\n }\n\n public override writeUniforms(view: DataView, offset: number): void {\n view.setFloat32(offset + 0, this.angularAcceleration, true);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAa,qBAAb,cAAwC,aAAa;CACnD,AAAO;CAEP,AAAO,YAAY,qBAA6B;EAC9C,MAAM;EACN,KAAK,sBAAsB;CAC7B;CAEA,AAAgB,MAAM,WAA0B,IAAkB;EAChE,MAAM,EAAE,OAAO,mBAAmB,UAAU;EAC5C,MAAM,YAAY,UAAU;EAC5B,MAAM,QAAQ,KAAK,sBAAsB;EAEzC,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAC7B,eAAe,MAAM,eAAe,MAAM,KAAK;CAEnD;CAEA,AAAgB,OAAyB;EACvC,OAAO;GACL,KAAK;GACL,UAAU,CAAC;IAAE,MAAM;IAAuB,MAAM;GAAM,CAAC;GACvD,MAAM;;;EAGR;CACF;CAEA,AAAgB,cAAc,MAAgB,QAAsB;EAClE,KAAK,WAAW,SAAS,GAAG,KAAK,qBAAqB,IAAI;CAC5D;AACF"}
@@ -1,5 +1,5 @@
1
- import type { Curve } from "#distributions/Curve";
2
- import type { ParticleSystem } from "#ParticleSystem";
1
+ import type { Curve } from '#distributions/Curve';
2
+ import type { ParticleBatch } from '#ParticleStorage';
3
3
  import { UpdateModule } from './UpdateModule';
4
4
  import type { WgslContribution } from './WgslContribution';
5
5
  /**
@@ -11,15 +11,16 @@ import type { WgslContribution } from './WgslContribution';
11
11
  * curve up to peak then down), slow-grow (linear ramp).
12
12
  *
13
13
  * GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and
14
- * sampled with linear filtering on the GPU no curve evaluation cost in
14
+ * sampled with linear filtering on the GPU - no curve evaluation cost in
15
15
  * the inner loop.
16
16
  */
17
17
  export declare class ScaleOverLifetime extends UpdateModule {
18
18
  curve: Curve;
19
19
  constructor(curve: Curve);
20
- apply(system: ParticleSystem, _dt: number): void;
20
+ apply(particles: ParticleBatch, _dt: number): void;
21
21
  wgsl(): WgslContribution;
22
22
  uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void;
23
23
  }
24
24
  /** Texture width for the curve lookup table. Exposed for ParticleGpuState. */
25
25
  export declare const scaleLookupSize = 256;
26
+ //# sourceMappingURL=ScaleOverLifetime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScaleOverLifetime.d.ts","sourceRoot":"","sources":["../../../src/modules/ScaleOverLifetime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IAC1C,KAAK,EAAE,KAAK,CAAC;gBAED,KAAK,EAAE,KAAK;IAKf,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAelD,IAAI,IAAI,gBAAgB;IAYxB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI;CAoBnG;AAED,8EAA8E;AAC9E,eAAO,MAAM,eAAe,MAAa,CAAC"}
@@ -1,58 +1,68 @@
1
- import { UpdateModule } from './UpdateModule.js';
1
+ import { UpdateModule } from "./UpdateModule.js";
2
2
 
3
- /// <reference types="@webgpu/types" />
3
+ //#region src/modules/ScaleOverLifetime.ts
4
4
  const lookupSize = 256;
5
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; non-uniform per-axis
8
- * scaling isn't supported by this module.
9
- *
10
- * Common patterns: shrink-to-zero (start at 1, end at 0), pulse (sine-like
11
- * curve up to peak then down), slow-grow (linear ramp).
12
- *
13
- * GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and
14
- * sampled with linear filtering on the GPU no curve evaluation cost in
15
- * the inner loop.
16
- */
17
- class ScaleOverLifetime extends UpdateModule {
18
- curve;
19
- constructor(curve) {
20
- super();
21
- this.curve = curve;
22
- }
23
- apply(system, _dt) {
24
- const { scaleX, scaleY, elapsed, lifetime, liveCount } = system;
25
- const curve = this.curve;
26
- for (let i = 0; i < liveCount; i++) {
27
- const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);
28
- const s = curve.evaluate(t);
29
- scaleX[i] = s;
30
- scaleY[i] = s;
31
- }
32
- }
33
- wgsl() {
34
- return {
35
- key: 'ScaleOverLifetime',
36
- textures: [{ name: 'curve', format: 'r32float' }],
37
- body: `
6
+ * Sets every live particle's scale to a curve sampled at the particle's
7
+ * current lifetime ratio. Both axes share one curve; non-uniform per-axis
8
+ * scaling isn't supported by this module.
9
+ *
10
+ * Common patterns: shrink-to-zero (start at 1, end at 0), pulse (sine-like
11
+ * curve up to peak then down), slow-grow (linear ramp).
12
+ *
13
+ * GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and
14
+ * sampled with linear filtering on the GPU - no curve evaluation cost in
15
+ * the inner loop.
16
+ */
17
+ var ScaleOverLifetime = class extends UpdateModule {
18
+ curve;
19
+ constructor(curve) {
20
+ super();
21
+ this.curve = curve;
22
+ }
23
+ apply(particles, _dt) {
24
+ const { x: scaleX, y: scaleY } = particles.scale;
25
+ const { elapsed, lifetime } = particles.timing;
26
+ const liveCount = particles.count;
27
+ const curve = this.curve;
28
+ for (let i = 0; i < liveCount; i++) {
29
+ const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);
30
+ const s = curve.evaluate(t);
31
+ scaleX[i] = s;
32
+ scaleY[i] = s;
33
+ }
34
+ }
35
+ wgsl() {
36
+ return {
37
+ key: "ScaleOverLifetime",
38
+ textures: [{
39
+ name: "curve",
40
+ format: "r32float"
41
+ }],
42
+ body: `
38
43
  let scaleT = clamp(timing[idx].x / max(timing[idx].y, 0.000001), 0.0, 1.0);
39
44
  let scaleSample = textureSampleLevel(u_ScaleOverLifetime_curve, u_ScaleOverLifetime_curve_sampler, scaleT, 0.0).r;
40
45
  scales[idx] = vec2<f32>(scaleSample, scaleSample);
41
- `,
42
- };
43
- }
44
- uploadTextures(device, textures) {
45
- const texture = textures.get('curve');
46
- if (texture === undefined) {
47
- return;
48
- }
49
- const data = new Float32Array(lookupSize);
50
- for (let i = 0; i < lookupSize; i++) {
51
- data[i] = this.curve.evaluate(i / (lookupSize - 1));
52
- }
53
- device.queue.writeTexture({ texture }, data.buffer, { offset: 0, bytesPerRow: lookupSize * 4, rowsPerImage: 1 }, { width: lookupSize, height: 1, depthOrArrayLayers: 1 });
54
- }
55
- }
46
+ `
47
+ };
48
+ }
49
+ uploadTextures(device, textures) {
50
+ const texture = textures.get("curve");
51
+ if (texture === void 0) return;
52
+ const data = new Float32Array(lookupSize);
53
+ for (let i = 0; i < lookupSize; i++) data[i] = this.curve.evaluate(i / 255);
54
+ device.queue.writeTexture({ texture }, data.buffer, {
55
+ offset: 0,
56
+ bytesPerRow: lookupSize * 4,
57
+ rowsPerImage: 1
58
+ }, {
59
+ width: lookupSize,
60
+ height: 1,
61
+ depthOrArrayLayers: 1
62
+ });
63
+ }
64
+ };
56
65
 
66
+ //#endregion
57
67
  export { ScaleOverLifetime };
58
- //# sourceMappingURL=ScaleOverLifetime.js.map
68
+ //# sourceMappingURL=ScaleOverLifetime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ScaleOverLifetime.js","sources":["../../../../src/modules/ScaleOverLifetime.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;AAQA,MAAM,UAAU,GAAG,GAAG;AAEtB;;;;;;;;;;;AAWG;AACG,MAAO,iBAAkB,SAAQ,YAAY,CAAA;AAC1C,IAAA,KAAK;AAEZ,IAAA,WAAA,CAAmB,KAAY,EAAA;AAC7B,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;IACpB;IAEgB,KAAK,CAAC,MAAsB,EAAE,GAAW,EAAA;AACvD,QAAA,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM;AAC/D,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK;AAExB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;AAClC,YAAA,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE3B,YAAA,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACb,YAAA,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;QACf;IACF;IAEgB,IAAI,GAAA;QAClB,OAAO;AACL,YAAA,GAAG,EAAE,mBAAmB;YACxB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACjD,YAAA,IAAI,EAAE;;;;AAIC,YAAA,CAAA;SACR;IACH;IAEgB,cAAc,CAAC,MAAiB,EAAE,QAAyC,EAAA;QACzF,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;AAErC,QAAA,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB;QACF;AAEA,QAAA,MAAM,IAAI,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC;AAEzC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE;AACnC,YAAA,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC;QACrD;AAEA,QAAA,MAAM,CAAC,KAAK,CAAC,YAAY,CACvB,EAAE,OAAO,EAAE,EACX,IAAI,CAAC,MAAM,EACX,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,UAAU,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAC3D,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,CACxD;IACH;AACD;;;;"}
1
+ {"version":3,"file":"ScaleOverLifetime.js","names":[],"sources":["../../../src/modules/ScaleOverLifetime.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n\nimport type { Curve } from '#distributions/Curve';\nimport type { ParticleBatch } from '#ParticleStorage';\n\nimport { UpdateModule } from './UpdateModule';\nimport type { WgslContribution } from './WgslContribution';\n\nconst lookupSize = 256;\n\n/**\n * Sets every live particle's scale to a curve sampled at the particle's\n * current lifetime ratio. Both axes share one curve; non-uniform per-axis\n * scaling isn't supported by this module.\n *\n * Common patterns: shrink-to-zero (start at 1, end at 0), pulse (sine-like\n * curve up to peak then down), slow-grow (linear ramp).\n *\n * GPU-eligible: the curve is uploaded once as a 256-tap 1D R32F texture and\n * sampled with linear filtering on the GPU - no curve evaluation cost in\n * the inner loop.\n */\nexport class ScaleOverLifetime extends UpdateModule {\n public curve: Curve;\n\n public constructor(curve: Curve) {\n super();\n this.curve = curve;\n }\n\n public override apply(particles: ParticleBatch, _dt: number): void {\n const { x: scaleX, y: scaleY } = particles.scale;\n const { elapsed, lifetime } = particles.timing;\n const liveCount = particles.count;\n const curve = this.curve;\n\n for (let i = 0; i < liveCount; i++) {\n const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);\n const s = curve.evaluate(t);\n\n scaleX[i] = s;\n scaleY[i] = s;\n }\n }\n\n public override wgsl(): WgslContribution {\n return {\n key: 'ScaleOverLifetime',\n textures: [{ name: 'curve', format: 'r32float' }],\n body: `\n let scaleT = clamp(timing[idx].x / max(timing[idx].y, 0.000001), 0.0, 1.0);\n let scaleSample = textureSampleLevel(u_ScaleOverLifetime_curve, u_ScaleOverLifetime_curve_sampler, scaleT, 0.0).r;\n scales[idx] = vec2<f32>(scaleSample, scaleSample);\n `,\n };\n }\n\n public override uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void {\n const texture = textures.get('curve');\n\n if (texture === undefined) {\n return;\n }\n\n const data = new Float32Array(lookupSize);\n\n for (let i = 0; i < lookupSize; i++) {\n data[i] = this.curve.evaluate(i / (lookupSize - 1));\n }\n\n device.queue.writeTexture(\n { texture },\n data.buffer,\n { offset: 0, bytesPerRow: lookupSize * 4, rowsPerImage: 1 },\n { width: lookupSize, height: 1, depthOrArrayLayers: 1 },\n );\n }\n}\n\n/** Texture width for the curve lookup table. Exposed for ParticleGpuState. */\nexport const scaleLookupSize = lookupSize;\n"],"mappings":";;;AAQA,MAAM,aAAa;;;;;;;;;;;;;AAcnB,IAAa,oBAAb,cAAuC,aAAa;CAClD,AAAO;CAEP,AAAO,YAAY,OAAc;EAC/B,MAAM;EACN,KAAK,QAAQ;CACf;CAEA,AAAgB,MAAM,WAA0B,KAAmB;EACjE,MAAM,EAAE,GAAG,QAAQ,GAAG,WAAW,UAAU;EAC3C,MAAM,EAAE,SAAS,aAAa,UAAU;EACxC,MAAM,YAAY,UAAU;EAC5B,MAAM,QAAQ,KAAK;EAEnB,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;GAClC,MAAM,KAAK,QAAQ,MAAM,MAAM,SAAS,MAAM;GAC9C,MAAM,IAAI,MAAM,SAAS,CAAC;GAE1B,OAAO,KAAK;GACZ,OAAO,KAAK;EACd;CACF;CAEA,AAAgB,OAAyB;EACvC,OAAO;GACL,KAAK;GACL,UAAU,CAAC;IAAE,MAAM;IAAS,QAAQ;GAAW,CAAC;GAChD,MAAM;;;;;EAKR;CACF;CAEA,AAAgB,eAAe,QAAmB,UAAiD;EACjG,MAAM,UAAU,SAAS,IAAI,OAAO;EAEpC,IAAI,YAAY,QACd;EAGF,MAAM,OAAO,IAAI,aAAa,UAAU;EAExC,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAC9B,KAAK,KAAK,KAAK,MAAM,SAAS,IAAK,GAAe;EAGpD,OAAO,MAAM,aACX,EAAE,QAAQ,GACV,KAAK,QACL;GAAE,QAAQ;GAAG,aAAa,aAAa;GAAG,cAAc;EAAE,GAC1D;GAAE,OAAO;GAAY,QAAQ;GAAG,oBAAoB;EAAE,CACxD;CACF;AACF"}
@@ -1,30 +1,33 @@
1
- import type { ParticleSystem } from "#ParticleSystem";
1
+ import type { ParticleEmitter } from '#ParticleStorage';
2
2
  /**
3
- * Per-frame particle spawner. Subclasses decide how many particles to emit
4
- * each tick (rate-based, burst, on-demand) and write their initial values
5
- * directly into the system's typed-array slots.
3
+ * Per-frame particle spawner. Subclasses decide how many particles to emit each
4
+ * tick (rate-based, burst, on-demand) and fill each emitted particle's initial
5
+ * values.
6
6
  *
7
7
  * Implementation pattern:
8
8
  *
9
9
  * ```ts
10
- * apply(system, dt) {
10
+ * apply(emitter, dt) {
11
11
  * const count = this.computeSpawnCount(dt);
12
12
  * for (let i = 0; i < count; i++) {
13
- * const slot = system.spawn();
14
- * if (slot < 0) break; // capacity exhausted
15
- * system.posX[slot] = ...;
16
- * system.velX[slot] = ...;
17
- * system.lifetime[slot] = ...;
18
- * // ...etc
13
+ * const particle = emitter.emit();
14
+ * if (!particle) break; // capacity exhausted
15
+ * particle.position.set(x, y);
16
+ * particle.velocity.set(vx, vy);
17
+ * particle.lifetime = 2;
19
18
  * }
20
19
  * }
21
20
  * ```
22
21
  *
22
+ * A writer belongs to the emission that produced it: the next `emit()` rebinds
23
+ * it, so fill it before emitting again.
24
+ *
23
25
  * Spawn modules run before integration each frame. Multiple modules can be
24
26
  * registered on one system and execute in registration order.
25
27
  */
26
28
  export declare abstract class SpawnModule {
27
- abstract apply(system: ParticleSystem, dt: number): void;
29
+ abstract apply(emitter: ParticleEmitter, dt: number): void;
28
30
  /** Optional cleanup hook called from `ParticleSystem.destroy`. */
29
31
  destroy(): void;
30
32
  }
33
+ //# sourceMappingURL=SpawnModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpawnModule.d.ts","sourceRoot":"","sources":["../../../src/modules/SpawnModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,8BAAsB,WAAW;aACf,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IACjE,kEAAkE;IAC3D,OAAO,IAAI,IAAI;CACvB"}
@@ -1,31 +1,35 @@
1
+ //#region src/modules/SpawnModule.ts
1
2
  /**
2
- * Per-frame particle spawner. Subclasses decide how many particles to emit
3
- * each tick (rate-based, burst, on-demand) and write their initial values
4
- * directly into the system's typed-array slots.
5
- *
6
- * Implementation pattern:
7
- *
8
- * ```ts
9
- * apply(system, dt) {
10
- * const count = this.computeSpawnCount(dt);
11
- * for (let i = 0; i < count; i++) {
12
- * const slot = system.spawn();
13
- * if (slot < 0) break; // capacity exhausted
14
- * system.posX[slot] = ...;
15
- * system.velX[slot] = ...;
16
- * system.lifetime[slot] = ...;
17
- * // ...etc
18
- * }
19
- * }
20
- * ```
21
- *
22
- * Spawn modules run before integration each frame. Multiple modules can be
23
- * registered on one system and execute in registration order.
24
- */
25
- class SpawnModule {
26
- /** Optional cleanup hook called from `ParticleSystem.destroy`. */
27
- destroy() { }
28
- }
3
+ * Per-frame particle spawner. Subclasses decide how many particles to emit each
4
+ * tick (rate-based, burst, on-demand) and fill each emitted particle's initial
5
+ * values.
6
+ *
7
+ * Implementation pattern:
8
+ *
9
+ * ```ts
10
+ * apply(emitter, dt) {
11
+ * const count = this.computeSpawnCount(dt);
12
+ * for (let i = 0; i < count; i++) {
13
+ * const particle = emitter.emit();
14
+ * if (!particle) break; // capacity exhausted
15
+ * particle.position.set(x, y);
16
+ * particle.velocity.set(vx, vy);
17
+ * particle.lifetime = 2;
18
+ * }
19
+ * }
20
+ * ```
21
+ *
22
+ * A writer belongs to the emission that produced it: the next `emit()` rebinds
23
+ * it, so fill it before emitting again.
24
+ *
25
+ * Spawn modules run before integration each frame. Multiple modules can be
26
+ * registered on one system and execute in registration order.
27
+ */
28
+ var SpawnModule = class {
29
+ /** Optional cleanup hook called from `ParticleSystem.destroy`. */
30
+ destroy() {}
31
+ };
29
32
 
33
+ //#endregion
30
34
  export { SpawnModule };
31
- //# sourceMappingURL=SpawnModule.js.map
35
+ //# sourceMappingURL=SpawnModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpawnModule.js","sources":["../../../../src/modules/SpawnModule.ts"],"sourcesContent":[null],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MACmB,WAAW,CAAA;;AAGxB,IAAA,OAAO,KAAU;AACzB;;;;"}
1
+ {"version":3,"file":"SpawnModule.js","names":[],"sources":["../../../src/modules/SpawnModule.ts"],"sourcesContent":["import type { ParticleEmitter } from '#ParticleStorage';\n\n/**\n * Per-frame particle spawner. Subclasses decide how many particles to emit each\n * tick (rate-based, burst, on-demand) and fill each emitted particle's initial\n * values.\n *\n * Implementation pattern:\n *\n * ```ts\n * apply(emitter, dt) {\n * const count = this.computeSpawnCount(dt);\n * for (let i = 0; i < count; i++) {\n * const particle = emitter.emit();\n * if (!particle) break; // capacity exhausted\n * particle.position.set(x, y);\n * particle.velocity.set(vx, vy);\n * particle.lifetime = 2;\n * }\n * }\n * ```\n *\n * A writer belongs to the emission that produced it: the next `emit()` rebinds\n * it, so fill it before emitting again.\n *\n * Spawn modules run before integration each frame. Multiple modules can be\n * registered on one system and execute in registration order.\n */\nexport abstract class SpawnModule {\n public abstract apply(emitter: ParticleEmitter, dt: number): void;\n /** Optional cleanup hook called from `ParticleSystem.destroy`. */\n public destroy(): void {}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,IAAsB,cAAtB,MAAkC;;CAGhC,AAAO,UAAgB,CAAC;AAC1B"}
@@ -1,18 +1,21 @@
1
- import type { ParticleSystem } from "#ParticleSystem";
1
+ import type { ParticleDeathContext } from '#ParticleStorage';
2
+ import type { ParticleSystem } from '#ParticleSystem';
2
3
  import { DeathModule } from './DeathModule';
3
4
  import type { SpawnModule } from './SpawnModule';
4
5
  /**
5
- * Sub-emitter: triggers a child {@link SpawnModule} on a target system at
6
- * the dying particle's position. Use for explosion-on-impact, sparks at
7
- * end-of-life, multi-stage VFX.
6
+ * Sub-emitter: triggers a child {@link SpawnModule} on a target system at the
7
+ * dying particle's position. Use for explosion-on-impact, sparks at end of
8
+ * life, multi-stage VFX.
8
9
  *
9
- * The child module receives a synthesized `dt` of 0 it must spawn
10
+ * The child module receives a synthesized `dt` of 0 - it must spawn
10
11
  * immediately rather than rely on rate accumulation. {@link BurstSpawn}
11
12
  * works naturally; {@link RateSpawn} is the wrong fit here.
12
13
  *
13
- * Position is the only field forwarded child distributions decide
14
- * everything else. To keep child particles riding the parent's velocity,
15
- * configure the child's velocity distribution to match.
14
+ * Position is the only field taken from the dying particle - child
15
+ * distributions decide everything else, and their sampled positions are treated
16
+ * as offsets from the death position. To keep child particles riding the
17
+ * parent's velocity, configure the child's velocity distribution to match, or
18
+ * read {@link ParticleDeathContext.velocityX} in a custom death module.
16
19
  */
17
20
  export declare class SpawnOnDeath extends DeathModule {
18
21
  targetSystem: ParticleSystem;
@@ -20,5 +23,6 @@ export declare class SpawnOnDeath extends DeathModule {
20
23
  /** Number of times to invoke the spawner per dying particle. Default 1. */
21
24
  count: number;
22
25
  constructor(targetSystem: ParticleSystem, spawner: SpawnModule, count?: number);
23
- onDeath(parent: ParticleSystem, slot: number): void;
26
+ onDeath(_system: ParticleSystem, death: ParticleDeathContext): void;
24
27
  }
28
+ //# sourceMappingURL=SpawnOnDeath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpawnOnDeath.d.ts","sourceRoot":"","sources":["../../../src/modules/SpawnOnDeath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAa,SAAQ,WAAW;IACpC,YAAY,EAAE,cAAc,CAAC;IAC7B,OAAO,EAAE,WAAW,CAAC;IAE5B,2EAA2E;IACpE,KAAK,EAAE,MAAM,CAAC;gBAEF,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,SAAI;IAOhE,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI;CAoBpF"}
@@ -1,47 +1,45 @@
1
- import { DeathModule } from './DeathModule.js';
1
+ import { DeathModule } from "./DeathModule.js";
2
2
 
3
+ //#region src/modules/SpawnOnDeath.ts
3
4
  /**
4
- * Sub-emitter: triggers a child {@link SpawnModule} on a target system at
5
- * the dying particle's position. Use for explosion-on-impact, sparks at
6
- * end-of-life, multi-stage VFX.
7
- *
8
- * The child module receives a synthesized `dt` of 0 it must spawn
9
- * immediately rather than rely on rate accumulation. {@link BurstSpawn}
10
- * works naturally; {@link RateSpawn} is the wrong fit here.
11
- *
12
- * Position is the only field forwarded child distributions decide
13
- * everything else. To keep child particles riding the parent's velocity,
14
- * configure the child's velocity distribution to match.
15
- */
16
- class SpawnOnDeath extends DeathModule {
17
- targetSystem;
18
- spawner;
19
- /** Number of times to invoke the spawner per dying particle. Default 1. */
20
- count;
21
- constructor(targetSystem, spawner, count = 1) {
22
- super();
23
- this.targetSystem = targetSystem;
24
- this.spawner = spawner;
25
- this.count = count;
26
- }
27
- onDeath(parent, slot) {
28
- const target = this.targetSystem;
29
- const x = parent.posX[slot] ?? 0;
30
- const y = parent.posY[slot] ?? 0;
31
- // Snapshot the target's pre-spawn count so we can apply the
32
- // position to whichever slots the spawner adds.
33
- const before = target.liveCount;
34
- for (let n = 0; n < this.count; n++) {
35
- this.spawner.apply(target, 0);
36
- }
37
- const added = target.liveCount - before;
38
- for (let i = 0; i < added; i++) {
39
- const dst = before + i;
40
- target.posX[dst] = (target.posX[dst] ?? 0) + x;
41
- target.posY[dst] = (target.posY[dst] ?? 0) + y;
42
- }
43
- }
44
- }
5
+ * Sub-emitter: triggers a child {@link SpawnModule} on a target system at the
6
+ * dying particle's position. Use for explosion-on-impact, sparks at end of
7
+ * life, multi-stage VFX.
8
+ *
9
+ * The child module receives a synthesized `dt` of 0 - it must spawn
10
+ * immediately rather than rely on rate accumulation. {@link BurstSpawn}
11
+ * works naturally; {@link RateSpawn} is the wrong fit here.
12
+ *
13
+ * Position is the only field taken from the dying particle - child
14
+ * distributions decide everything else, and their sampled positions are treated
15
+ * as offsets from the death position. To keep child particles riding the
16
+ * parent's velocity, configure the child's velocity distribution to match, or
17
+ * read {@link ParticleDeathContext.velocityX} in a custom death module.
18
+ */
19
+ var SpawnOnDeath = class extends DeathModule {
20
+ targetSystem;
21
+ spawner;
22
+ /** Number of times to invoke the spawner per dying particle. Default 1. */
23
+ count;
24
+ constructor(targetSystem, spawner, count = 1) {
25
+ super();
26
+ this.targetSystem = targetSystem;
27
+ this.spawner = spawner;
28
+ this.count = count;
29
+ }
30
+ onDeath(_system, death) {
31
+ const target = this.targetSystem;
32
+ const previous = target._beginSpawnRecording();
33
+ let spawned;
34
+ try {
35
+ for (let n = 0; n < this.count; n++) this.spawner.apply(target, 0);
36
+ } finally {
37
+ spawned = target._endSpawnRecording(previous);
38
+ }
39
+ target._offsetSpawned(spawned, death.x, death.y);
40
+ }
41
+ };
45
42
 
43
+ //#endregion
46
44
  export { SpawnOnDeath };
47
- //# sourceMappingURL=SpawnOnDeath.js.map
45
+ //# sourceMappingURL=SpawnOnDeath.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SpawnOnDeath.js","sources":["../../../../src/modules/SpawnOnDeath.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAKA;;;;;;;;;;;;AAYG;AACG,MAAO,YAAa,SAAQ,WAAW,CAAA;AACpC,IAAA,YAAY;AACZ,IAAA,OAAO;;AAGP,IAAA,KAAK;AAEZ,IAAA,WAAA,CAAmB,YAA4B,EAAE,OAAoB,EAAE,KAAK,GAAG,CAAC,EAAA;AAC9E,QAAA,KAAK,EAAE;AACP,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;AAChC,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO;AACtB,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;IACpB;IAEgB,OAAO,CAAC,MAAsB,EAAE,IAAY,EAAA;AAC1D,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY;QAChC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAChC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;;;AAIhC,QAAA,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS;AAE/B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YACnC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/B;AAEA,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM;AAEvC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;AAC9B,YAAA,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC;AAEtB,YAAA,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AAC9C,YAAA,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QAChD;IACF;AACD;;;;"}
1
+ {"version":3,"file":"SpawnOnDeath.js","names":[],"sources":["../../../src/modules/SpawnOnDeath.ts"],"sourcesContent":["import type { ParticleDeathContext } from '#ParticleStorage';\nimport type { ParticleSystem } from '#ParticleSystem';\n\nimport { DeathModule } from './DeathModule';\nimport type { SpawnModule } from './SpawnModule';\n\n/**\n * Sub-emitter: triggers a child {@link SpawnModule} on a target system at the\n * dying particle's position. Use for explosion-on-impact, sparks at end of\n * life, multi-stage VFX.\n *\n * The child module receives a synthesized `dt` of 0 - it must spawn\n * immediately rather than rely on rate accumulation. {@link BurstSpawn}\n * works naturally; {@link RateSpawn} is the wrong fit here.\n *\n * Position is the only field taken from the dying particle - child\n * distributions decide everything else, and their sampled positions are treated\n * as offsets from the death position. To keep child particles riding the\n * parent's velocity, configure the child's velocity distribution to match, or\n * read {@link ParticleDeathContext.velocityX} in a custom death module.\n */\nexport class SpawnOnDeath extends DeathModule {\n public targetSystem: ParticleSystem;\n public spawner: SpawnModule;\n\n /** Number of times to invoke the spawner per dying particle. Default 1. */\n public count: number;\n\n public constructor(targetSystem: ParticleSystem, spawner: SpawnModule, count = 1) {\n super();\n this.targetSystem = targetSystem;\n this.spawner = spawner;\n this.count = count;\n }\n\n public override onDeath(_system: ParticleSystem, death: ParticleDeathContext): void {\n const target = this.targetSystem;\n\n // Which particles the spawner produced cannot be derived from the target's\n // live count: on the GPU path an emission recycles a dead slot below the\n // high-water mark, so the count can stay put while particles are added, and\n // the reused slots are scattered rather than contiguous.\n const previous = target._beginSpawnRecording();\n let spawned: readonly number[];\n\n try {\n for (let n = 0; n < this.count; n++) {\n this.spawner.apply(target, 0);\n }\n } finally {\n spawned = target._endSpawnRecording(previous);\n }\n\n target._offsetSpawned(spawned, death.x, death.y);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,IAAa,eAAb,cAAkC,YAAY;CAC5C,AAAO;CACP,AAAO;;CAGP,AAAO;CAEP,AAAO,YAAY,cAA8B,SAAsB,QAAQ,GAAG;EAChF,MAAM;EACN,KAAK,eAAe;EACpB,KAAK,UAAU;EACf,KAAK,QAAQ;CACf;CAEA,AAAgB,QAAQ,SAAyB,OAAmC;EAClF,MAAM,SAAS,KAAK;EAMpB,MAAM,WAAW,OAAO,qBAAqB;EAC7C,IAAI;EAEJ,IAAI;GACF,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,OAAO,KAC9B,KAAK,QAAQ,MAAM,QAAQ,CAAC;EAEhC,UAAU;GACR,UAAU,OAAO,mBAAmB,QAAQ;EAC9C;EAEA,OAAO,eAAe,SAAS,MAAM,GAAG,MAAM,CAAC;CACjD;AACF"}
@@ -1,9 +1,9 @@
1
- import type { ParticleSystem } from "#ParticleSystem";
1
+ import type { ParticleBatch } from '#ParticleStorage';
2
2
  import { UpdateModule } from './UpdateModule';
3
3
  import type { WgslContribution } from './WgslContribution';
4
4
  /**
5
5
  * Adds a smooth pseudo-random force field that animates over time.
6
- * Implemented as 2D value noise with cubic Hermite smoothing sampled
6
+ * Implemented as 2D value noise with cubic Hermite smoothing - sampled
7
7
  * twice per particle (offset to decorrelate x and y components) and scaled
8
8
  * by `strength`. The field evolves at `timeScale` units per second; lower
9
9
  * values produce slow-moving currents, higher values produce buzzy chaos.
@@ -24,7 +24,8 @@ export declare class Turbulence extends UpdateModule {
24
24
  timeScale: number;
25
25
  private _time;
26
26
  constructor(strength: number, frequency?: number, timeScale?: number);
27
- apply(system: ParticleSystem, dt: number): void;
27
+ apply(particles: ParticleBatch, dt: number): void;
28
28
  wgsl(): WgslContribution;
29
29
  writeUniforms(view: DataView, offset: number, dt: number): void;
30
30
  }
31
+ //# sourceMappingURL=Turbulence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Turbulence.d.ts","sourceRoot":"","sources":["../../../src/modules/Turbulence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAW,SAAQ,YAAY;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,KAAK,CAAK;gBAEC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAO,EAAE,SAAS,SAAI;IAOpD,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAqBjD,IAAI,IAAI,gBAAgB;IA4CxB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;CAWhF"}