@triforge/particle-core 0.1.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 (153) hide show
  1. package/dist/core/BaseEmitter.d.ts +50 -0
  2. package/dist/core/BaseEmitter.d.ts.map +1 -0
  3. package/dist/core/BaseEmitter.js +53 -0
  4. package/dist/core/BaseEmitter.js.map +1 -0
  5. package/dist/core/BaseForce.d.ts +21 -0
  6. package/dist/core/BaseForce.d.ts.map +1 -0
  7. package/dist/core/BaseForce.js +15 -0
  8. package/dist/core/BaseForce.js.map +1 -0
  9. package/dist/core/BaseRenderer.d.ts +96 -0
  10. package/dist/core/BaseRenderer.d.ts.map +1 -0
  11. package/dist/core/BaseRenderer.js +190 -0
  12. package/dist/core/BaseRenderer.js.map +1 -0
  13. package/dist/core/DeflectorCollider.d.ts +46 -0
  14. package/dist/core/DeflectorCollider.d.ts.map +1 -0
  15. package/dist/core/DeflectorCollider.js +113 -0
  16. package/dist/core/DeflectorCollider.js.map +1 -0
  17. package/dist/core/Particle.d.ts +29 -0
  18. package/dist/core/Particle.d.ts.map +1 -0
  19. package/dist/core/Particle.js +41 -0
  20. package/dist/core/Particle.js.map +1 -0
  21. package/dist/core/ParticleCache.d.ts +73 -0
  22. package/dist/core/ParticleCache.d.ts.map +1 -0
  23. package/dist/core/ParticleCache.js +206 -0
  24. package/dist/core/ParticleCache.js.map +1 -0
  25. package/dist/core/ParticleSystem.d.ts +192 -0
  26. package/dist/core/ParticleSystem.d.ts.map +1 -0
  27. package/dist/core/ParticleSystem.js +484 -0
  28. package/dist/core/ParticleSystem.js.map +1 -0
  29. package/dist/core/SeededRandom.d.ts +17 -0
  30. package/dist/core/SeededRandom.d.ts.map +1 -0
  31. package/dist/core/SeededRandom.js +27 -0
  32. package/dist/core/SeededRandom.js.map +1 -0
  33. package/dist/emitters/EdgeEmitter.d.ts +43 -0
  34. package/dist/emitters/EdgeEmitter.d.ts.map +1 -0
  35. package/dist/emitters/EdgeEmitter.js +78 -0
  36. package/dist/emitters/EdgeEmitter.js.map +1 -0
  37. package/dist/emitters/MeshEmitter.d.ts +83 -0
  38. package/dist/emitters/MeshEmitter.d.ts.map +1 -0
  39. package/dist/emitters/MeshEmitter.js +240 -0
  40. package/dist/emitters/MeshEmitter.js.map +1 -0
  41. package/dist/emitters/PointEmitter.d.ts +22 -0
  42. package/dist/emitters/PointEmitter.d.ts.map +1 -0
  43. package/dist/emitters/PointEmitter.js +26 -0
  44. package/dist/emitters/PointEmitter.js.map +1 -0
  45. package/dist/forces/BoidField.d.ts +58 -0
  46. package/dist/forces/BoidField.d.ts.map +1 -0
  47. package/dist/forces/BoidField.js +82 -0
  48. package/dist/forces/BoidField.js.map +1 -0
  49. package/dist/forces/BoidForce.d.ts +54 -0
  50. package/dist/forces/BoidForce.d.ts.map +1 -0
  51. package/dist/forces/BoidForce.js +233 -0
  52. package/dist/forces/BoidForce.js.map +1 -0
  53. package/dist/forces/ChargeForce.d.ts +22 -0
  54. package/dist/forces/ChargeForce.d.ts.map +1 -0
  55. package/dist/forces/ChargeForce.js +35 -0
  56. package/dist/forces/ChargeForce.js.map +1 -0
  57. package/dist/forces/CurveGuideForce.d.ts +43 -0
  58. package/dist/forces/CurveGuideForce.d.ts.map +1 -0
  59. package/dist/forces/CurveGuideForce.js +118 -0
  60. package/dist/forces/CurveGuideForce.js.map +1 -0
  61. package/dist/forces/DragForce.d.ts +19 -0
  62. package/dist/forces/DragForce.d.ts.map +1 -0
  63. package/dist/forces/DragForce.js +31 -0
  64. package/dist/forces/DragForce.js.map +1 -0
  65. package/dist/forces/FlowFieldForce.d.ts +72 -0
  66. package/dist/forces/FlowFieldForce.d.ts.map +1 -0
  67. package/dist/forces/FlowFieldForce.js +68 -0
  68. package/dist/forces/FlowFieldForce.js.map +1 -0
  69. package/dist/forces/ForceField.d.ts +26 -0
  70. package/dist/forces/ForceField.d.ts.map +1 -0
  71. package/dist/forces/ForceField.js +41 -0
  72. package/dist/forces/ForceField.js.map +1 -0
  73. package/dist/forces/GravityForce.d.ts +9 -0
  74. package/dist/forces/GravityForce.d.ts.map +1 -0
  75. package/dist/forces/GravityForce.js +12 -0
  76. package/dist/forces/GravityForce.js.map +1 -0
  77. package/dist/forces/HarmonicForce.d.ts +22 -0
  78. package/dist/forces/HarmonicForce.d.ts.map +1 -0
  79. package/dist/forces/HarmonicForce.js +31 -0
  80. package/dist/forces/HarmonicForce.js.map +1 -0
  81. package/dist/forces/LennardJonesForce.d.ts +23 -0
  82. package/dist/forces/LennardJonesForce.d.ts.map +1 -0
  83. package/dist/forces/LennardJonesForce.js +38 -0
  84. package/dist/forces/LennardJonesForce.js.map +1 -0
  85. package/dist/forces/MagneticForce.d.ts +21 -0
  86. package/dist/forces/MagneticForce.d.ts.map +1 -0
  87. package/dist/forces/MagneticForce.js +30 -0
  88. package/dist/forces/MagneticForce.js.map +1 -0
  89. package/dist/forces/TextureForce.d.ts +37 -0
  90. package/dist/forces/TextureForce.d.ts.map +1 -0
  91. package/dist/forces/TextureForce.js +56 -0
  92. package/dist/forces/TextureForce.js.map +1 -0
  93. package/dist/forces/TurbulenceForce.d.ts +21 -0
  94. package/dist/forces/TurbulenceForce.d.ts.map +1 -0
  95. package/dist/forces/TurbulenceForce.js +39 -0
  96. package/dist/forces/TurbulenceForce.js.map +1 -0
  97. package/dist/forces/VortexForce.d.ts +21 -0
  98. package/dist/forces/VortexForce.d.ts.map +1 -0
  99. package/dist/forces/VortexForce.js +29 -0
  100. package/dist/forces/VortexForce.js.map +1 -0
  101. package/dist/forces/WindForce.d.ts +21 -0
  102. package/dist/forces/WindForce.d.ts.map +1 -0
  103. package/dist/forces/WindForce.js +29 -0
  104. package/dist/forces/WindForce.js.map +1 -0
  105. package/dist/index.d.ts +56 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +44 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/physics/KeyedPhysics.d.ts +43 -0
  110. package/dist/physics/KeyedPhysics.d.ts.map +1 -0
  111. package/dist/physics/KeyedPhysics.js +73 -0
  112. package/dist/physics/KeyedPhysics.js.map +1 -0
  113. package/dist/physics/SPHPhysics.d.ts +27 -0
  114. package/dist/physics/SPHPhysics.d.ts.map +1 -0
  115. package/dist/physics/SPHPhysics.js +119 -0
  116. package/dist/physics/SPHPhysics.js.map +1 -0
  117. package/dist/renderers/BillboardRenderer.d.ts +75 -0
  118. package/dist/renderers/BillboardRenderer.d.ts.map +1 -0
  119. package/dist/renderers/BillboardRenderer.js +106 -0
  120. package/dist/renderers/BillboardRenderer.js.map +1 -0
  121. package/dist/renderers/CollectionRenderer.d.ts +83 -0
  122. package/dist/renderers/CollectionRenderer.d.ts.map +1 -0
  123. package/dist/renderers/CollectionRenderer.js +161 -0
  124. package/dist/renderers/CollectionRenderer.js.map +1 -0
  125. package/dist/renderers/HaloRenderer.d.ts +3 -0
  126. package/dist/renderers/HaloRenderer.d.ts.map +1 -0
  127. package/dist/renderers/HaloRenderer.js +4 -0
  128. package/dist/renderers/HaloRenderer.js.map +1 -0
  129. package/dist/renderers/InstanceRenderer.d.ts +70 -0
  130. package/dist/renderers/InstanceRenderer.d.ts.map +1 -0
  131. package/dist/renderers/InstanceRenderer.js +86 -0
  132. package/dist/renderers/InstanceRenderer.js.map +1 -0
  133. package/dist/renderers/LineRenderer.d.ts +52 -0
  134. package/dist/renderers/LineRenderer.d.ts.map +1 -0
  135. package/dist/renderers/LineRenderer.js +96 -0
  136. package/dist/renderers/LineRenderer.js.map +1 -0
  137. package/dist/renderers/NoneRenderer.d.ts +19 -0
  138. package/dist/renderers/NoneRenderer.d.ts.map +1 -0
  139. package/dist/renderers/NoneRenderer.js +24 -0
  140. package/dist/renderers/NoneRenderer.js.map +1 -0
  141. package/dist/renderers/ObjectRenderer.d.ts +3 -0
  142. package/dist/renderers/ObjectRenderer.d.ts.map +1 -0
  143. package/dist/renderers/ObjectRenderer.js +4 -0
  144. package/dist/renderers/ObjectRenderer.js.map +1 -0
  145. package/dist/renderers/StrandRenderer.d.ts +169 -0
  146. package/dist/renderers/StrandRenderer.d.ts.map +1 -0
  147. package/dist/renderers/StrandRenderer.js +235 -0
  148. package/dist/renderers/StrandRenderer.js.map +1 -0
  149. package/dist/renderers/TrailRenderer.d.ts +54 -0
  150. package/dist/renderers/TrailRenderer.d.ts.map +1 -0
  151. package/dist/renderers/TrailRenderer.js +114 -0
  152. package/dist/renderers/TrailRenderer.js.map +1 -0
  153. package/package.json +45 -0
@@ -0,0 +1,29 @@
1
+ import { Vector3 } from 'three';
2
+ /**
3
+ * A single particle — all mutable state lives here.
4
+ * Allocated once in a pool, reset on each re-emit.
5
+ */
6
+ export declare class Particle {
7
+ /** World-space position */
8
+ position: Vector3;
9
+ /** World-space velocity */
10
+ velocity: Vector3;
11
+ /** World-space angular velocity (for rotation) */
12
+ angularVel: Vector3;
13
+ /** Euler rotation angles in radians */
14
+ rotation: Vector3;
15
+ /** Current age in seconds */
16
+ age: number;
17
+ /** Total lifetime in seconds */
18
+ lifetime: number;
19
+ /** Size in world units */
20
+ size: number;
21
+ /** Normalised age [0,1] — updated each tick */
22
+ normalised: number;
23
+ /** Whether this slot is currently alive */
24
+ alive: boolean;
25
+ /** Which emitter spawned this particle (index into emitter array) */
26
+ emitterIndex: number;
27
+ reset(): void;
28
+ }
29
+ //# sourceMappingURL=Particle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Particle.d.ts","sourceRoot":"","sources":["../../src/core/Particle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B;;;GAGG;AACH,qBAAa,QAAQ;IACnB,2BAA2B;IAC3B,QAAQ,UAAmB;IAC3B,2BAA2B;IAC3B,QAAQ,UAAmB;IAC3B,kDAAkD;IAClD,UAAU,UAAiB;IAC3B,uCAAuC;IACvC,QAAQ,UAAmB;IAC3B,6BAA6B;IAC7B,GAAG,SAAY;IACf,gCAAgC;IAChC,QAAQ,SAAO;IACf,0BAA0B;IAC1B,IAAI,SAAW;IACf,+CAA+C;IAC/C,UAAU,SAAK;IACf,2CAA2C;IAC3C,KAAK,UAAc;IACnB,qEAAqE;IACrE,YAAY,SAAI;IAEhB,KAAK,IAAI,IAAI;CAWd"}
@@ -0,0 +1,41 @@
1
+ import { Vector3 } from 'three';
2
+ /**
3
+ * A single particle — all mutable state lives here.
4
+ * Allocated once in a pool, reset on each re-emit.
5
+ */
6
+ export class Particle {
7
+ constructor() {
8
+ /** World-space position */
9
+ this.position = new Vector3();
10
+ /** World-space velocity */
11
+ this.velocity = new Vector3();
12
+ /** World-space angular velocity (for rotation) */
13
+ this.angularVel = new Vector3();
14
+ /** Euler rotation angles in radians */
15
+ this.rotation = new Vector3();
16
+ /** Current age in seconds */
17
+ this.age = 0;
18
+ /** Total lifetime in seconds */
19
+ this.lifetime = 1;
20
+ /** Size in world units */
21
+ this.size = 1;
22
+ /** Normalised age [0,1] — updated each tick */
23
+ this.normalised = 0;
24
+ /** Whether this slot is currently alive */
25
+ this.alive = false;
26
+ /** Which emitter spawned this particle (index into emitter array) */
27
+ this.emitterIndex = 0;
28
+ }
29
+ reset() {
30
+ this.position.set(0, 0, 0);
31
+ this.velocity.set(0, 0, 0);
32
+ this.angularVel.set(0, 0, 0);
33
+ this.rotation.set(0, 0, 0);
34
+ this.age = 0;
35
+ this.lifetime = 1;
36
+ this.size = 1;
37
+ this.normalised = 0;
38
+ this.alive = false;
39
+ }
40
+ }
41
+ //# sourceMappingURL=Particle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Particle.js","sourceRoot":"","sources":["../../src/core/Particle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE/B;;;GAGG;AACH,MAAM,OAAO,QAAQ;IAArB;QACE,2BAA2B;QAC3B,aAAQ,GAAM,IAAI,OAAO,EAAE,CAAA;QAC3B,2BAA2B;QAC3B,aAAQ,GAAM,IAAI,OAAO,EAAE,CAAA;QAC3B,kDAAkD;QAClD,eAAU,GAAI,IAAI,OAAO,EAAE,CAAA;QAC3B,uCAAuC;QACvC,aAAQ,GAAM,IAAI,OAAO,EAAE,CAAA;QAC3B,6BAA6B;QAC7B,QAAG,GAAW,CAAC,CAAA;QACf,gCAAgC;QAChC,aAAQ,GAAM,CAAC,CAAA;QACf,0BAA0B;QAC1B,SAAI,GAAU,CAAC,CAAA;QACf,+CAA+C;QAC/C,eAAU,GAAI,CAAC,CAAA;QACf,2CAA2C;QAC3C,UAAK,GAAS,KAAK,CAAA;QACnB,qEAAqE;QACrE,iBAAY,GAAG,CAAC,CAAA;IAalB,CAAC;IAXC,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC1B,IAAI,CAAC,GAAG,GAAS,CAAC,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAI,CAAC,CAAA;QAClB,IAAI,CAAC,IAAI,GAAQ,CAAC,CAAA;QAClB,IAAI,CAAC,UAAU,GAAG,CAAC,CAAA;QACnB,IAAI,CAAC,KAAK,GAAO,KAAK,CAAA;IACxB,CAAC;CACF"}
@@ -0,0 +1,73 @@
1
+ import type { ParticleSystem } from './ParticleSystem.js';
2
+ /**
3
+ * Bake / cache system for ParticleSystem — records a range of the simulation
4
+ * to a frame-indexed snapshot array and replays it deterministically.
5
+ *
6
+ * Blender parallel: the Cache panel on a particle system.
7
+ *
8
+ * Layout per particle per frame (12 floats):
9
+ * [0..2] position xyz
10
+ * [3..5] velocity xyz
11
+ * [6..8] rotation xyz
12
+ * [9] size
13
+ * [10] normalised (0–1)
14
+ * [11] alive flag (1 = alive, 0 = dead)
15
+ */
16
+ export declare class ParticleCache {
17
+ /** All public scalar inputs — GSAP / keyframe compatible */
18
+ parameters: Record<string, number>;
19
+ private _frames;
20
+ private static readonly _FPP;
21
+ get isBaked(): boolean;
22
+ get frameCount(): number;
23
+ constructor();
24
+ /**
25
+ * Run the simulation from startSec to endSec at fps steps/sec and record
26
+ * each frame as a flat number[] snapshot. The system is reset and warmed
27
+ * up to startSec before recording begins, so the result is fully
28
+ * deterministic for any given seed.
29
+ *
30
+ * Stored parameters are updated but the caller's parameters object is never
31
+ * touched — baking is non-destructive toward external state.
32
+ */
33
+ bake(sys: ParticleSystem, startSec: number, endSec: number, fps: number): void;
34
+ /**
35
+ * Restore the particle pool to the interpolated state at timeSec.
36
+ * Clamps to first / last frame if timeSec is outside the baked range.
37
+ *
38
+ * Zero allocations — writes directly into existing Particle instances.
39
+ */
40
+ seek(sys: ParticleSystem, timeSec: number): void;
41
+ /** Drop all baked frames. */
42
+ clear(): void;
43
+ /**
44
+ * Bake all systems over the same time range in a single shared simulation
45
+ * loop — one pass rather than N independent passes.
46
+ *
47
+ * Blender parallel: Cache → Bake All Dynamics.
48
+ *
49
+ * Each system's built-in `.cache` is populated. Systems are reset, warmed
50
+ * up, and recorded in lock-step so the total cost is one shared loop rather
51
+ * than N independent loops.
52
+ */
53
+ static bakeAll(systems: ParticleSystem[], startSec: number, endSec: number, fps: number): void;
54
+ /**
55
+ * Serialise to a plain JSON-compatible object.
56
+ * frames are stored as Array<number> so JSON.stringify / JSON.parse
57
+ * round-trips without loss.
58
+ */
59
+ toJSON(): {
60
+ parameters: Record<string, number>;
61
+ frames: number[][];
62
+ };
63
+ /**
64
+ * Restore from a value previously returned by toJSON().
65
+ */
66
+ fromJSON(data: {
67
+ parameters: Record<string, number>;
68
+ frames: number[][];
69
+ }): void;
70
+ private _snapshot;
71
+ private _restoreParticle;
72
+ }
73
+ //# sourceMappingURL=ParticleCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParticleCache.d.ts","sourceRoot":"","sources":["../../src/core/ParticleCache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAa;IACxB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAElC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAK;IAEjC,IAAI,OAAO,IAAO,OAAO,CAAmC;IAC5D,IAAI,UAAU,IAAI,MAAM,CAAgC;;IAMxD;;;;;;;;OAQG;IACH,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAsB9E;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA4ChD,6BAA6B;IAC7B,KAAK,IAAI,IAAI;IAIb;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,CACZ,OAAO,EAAG,cAAc,EAAE,EAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAI,MAAM,EAChB,GAAG,EAAO,MAAM,GACf,IAAI;IAoCP;;;;OAIG;IACH,MAAM,IAAI;QAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAA;KAAE;IAOpE;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAA;KAAE,GAAG,IAAI;IAUhF,OAAO,CAAC,SAAS;IAsBjB,OAAO,CAAC,gBAAgB;CAczB"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Bake / cache system for ParticleSystem — records a range of the simulation
3
+ * to a frame-indexed snapshot array and replays it deterministically.
4
+ *
5
+ * Blender parallel: the Cache panel on a particle system.
6
+ *
7
+ * Layout per particle per frame (12 floats):
8
+ * [0..2] position xyz
9
+ * [3..5] velocity xyz
10
+ * [6..8] rotation xyz
11
+ * [9] size
12
+ * [10] normalised (0–1)
13
+ * [11] alive flag (1 = alive, 0 = dead)
14
+ */
15
+ export class ParticleCache {
16
+ get isBaked() { return this._frames.length > 0; }
17
+ get frameCount() { return this._frames.length; }
18
+ constructor() {
19
+ this._frames = [];
20
+ this.parameters = { startSec: 0, endSec: 5, fps: 30, step: 0 };
21
+ }
22
+ /**
23
+ * Run the simulation from startSec to endSec at fps steps/sec and record
24
+ * each frame as a flat number[] snapshot. The system is reset and warmed
25
+ * up to startSec before recording begins, so the result is fully
26
+ * deterministic for any given seed.
27
+ *
28
+ * Stored parameters are updated but the caller's parameters object is never
29
+ * touched — baking is non-destructive toward external state.
30
+ */
31
+ bake(sys, startSec, endSec, fps) {
32
+ this._frames = [];
33
+ this.parameters.startSec = startSec;
34
+ this.parameters.endSec = endSec;
35
+ this.parameters.fps = fps;
36
+ this.parameters.step = 0;
37
+ const dt = 1 / fps;
38
+ const totalFrames = Math.ceil((endSec - startSec) * fps) + 1;
39
+ // Reset and warm up to startSec
40
+ sys.reset();
41
+ const warmupSteps = Math.round(startSec * fps);
42
+ for (let i = 0; i < warmupSteps; i++)
43
+ sys.update(dt);
44
+ // Record frames — snapshot before stepping so frame[0] = t=startSec
45
+ for (let f = 0; f < totalFrames; f++) {
46
+ this._frames.push(this._snapshot(sys.pool));
47
+ if (f < totalFrames - 1)
48
+ sys.update(dt);
49
+ }
50
+ }
51
+ /**
52
+ * Restore the particle pool to the interpolated state at timeSec.
53
+ * Clamps to first / last frame if timeSec is outside the baked range.
54
+ *
55
+ * Zero allocations — writes directly into existing Particle instances.
56
+ */
57
+ seek(sys, timeSec) {
58
+ if (this._frames.length === 0)
59
+ return;
60
+ const { startSec, fps } = this.parameters;
61
+ const relTime = timeSec - startSec;
62
+ // Clamp the fractional frame position before splitting into f0/t
63
+ const clampedF = Math.max(0, Math.min(this._frames.length - 1, relTime * fps));
64
+ const f0 = Math.floor(clampedF);
65
+ const f1 = Math.min(this._frames.length - 1, f0 + 1);
66
+ const t = (f0 === f1) ? 0 : (clampedF - f0);
67
+ const pool = sys.pool;
68
+ const fpp = ParticleCache._FPP;
69
+ if (t === 0) {
70
+ // Exact frame — direct copy, no interpolation
71
+ const frame = this._frames[f0];
72
+ for (let i = 0; i < pool.length; i++) {
73
+ this._restoreParticle(pool[i], frame, i * fpp);
74
+ }
75
+ }
76
+ else {
77
+ // Sub-frame — linear interpolate between f0 and f1
78
+ const fr0 = this._frames[f0];
79
+ const fr1 = this._frames[f1];
80
+ const t1 = 1 - t;
81
+ for (let i = 0; i < pool.length; i++) {
82
+ const base = i * fpp;
83
+ const p = pool[i];
84
+ p.position.x = fr0[base] * t1 + fr1[base] * t;
85
+ p.position.y = fr0[base + 1] * t1 + fr1[base + 1] * t;
86
+ p.position.z = fr0[base + 2] * t1 + fr1[base + 2] * t;
87
+ p.velocity.x = fr0[base + 3] * t1 + fr1[base + 3] * t;
88
+ p.velocity.y = fr0[base + 4] * t1 + fr1[base + 4] * t;
89
+ p.velocity.z = fr0[base + 5] * t1 + fr1[base + 5] * t;
90
+ p.rotation.x = fr0[base + 6] * t1 + fr1[base + 6] * t;
91
+ p.rotation.y = fr0[base + 7] * t1 + fr1[base + 7] * t;
92
+ p.rotation.z = fr0[base + 8] * t1 + fr1[base + 8] * t;
93
+ p.size = fr0[base + 9] * t1 + fr1[base + 9] * t;
94
+ p.normalised = fr0[base + 10] * t1 + fr1[base + 10] * t;
95
+ p.alive = fr0[base + 11] > 0.5; // alive = alive in the source frame
96
+ }
97
+ }
98
+ }
99
+ /** Drop all baked frames. */
100
+ clear() {
101
+ this._frames = [];
102
+ }
103
+ /**
104
+ * Bake all systems over the same time range in a single shared simulation
105
+ * loop — one pass rather than N independent passes.
106
+ *
107
+ * Blender parallel: Cache → Bake All Dynamics.
108
+ *
109
+ * Each system's built-in `.cache` is populated. Systems are reset, warmed
110
+ * up, and recorded in lock-step so the total cost is one shared loop rather
111
+ * than N independent loops.
112
+ */
113
+ static bakeAll(systems, startSec, endSec, fps) {
114
+ if (systems.length === 0)
115
+ return;
116
+ const dt = 1 / fps;
117
+ const totalFrames = Math.ceil((endSec - startSec) * fps) + 1;
118
+ const warmupSteps = Math.round(startSec * fps);
119
+ // Initialise each system's cache and reset simulation state
120
+ const pairs = [];
121
+ for (const sys of systems) {
122
+ const cache = sys.cache;
123
+ cache['_frames'] = [];
124
+ cache.parameters.startSec = startSec;
125
+ cache.parameters.endSec = endSec;
126
+ cache.parameters.fps = fps;
127
+ cache.parameters.step = 0;
128
+ sys.reset();
129
+ pairs.push({ cache, sys });
130
+ }
131
+ // Shared warm-up
132
+ for (let i = 0; i < warmupSteps; i++) {
133
+ for (const { sys } of pairs)
134
+ sys.update(dt);
135
+ }
136
+ // Shared recording loop
137
+ for (let f = 0; f < totalFrames; f++) {
138
+ for (const { cache, sys } of pairs) {
139
+ cache['_frames'].push(cache['_snapshot'](sys.pool));
140
+ }
141
+ if (f < totalFrames - 1) {
142
+ for (const { sys } of pairs)
143
+ sys.update(dt);
144
+ }
145
+ }
146
+ }
147
+ /**
148
+ * Serialise to a plain JSON-compatible object.
149
+ * frames are stored as Array<number> so JSON.stringify / JSON.parse
150
+ * round-trips without loss.
151
+ */
152
+ toJSON() {
153
+ return {
154
+ parameters: { ...this.parameters },
155
+ frames: this._frames.map(f => Array.from(f)),
156
+ };
157
+ }
158
+ /**
159
+ * Restore from a value previously returned by toJSON().
160
+ */
161
+ fromJSON(data) {
162
+ this.parameters.startSec = data.parameters.startSec ?? 0;
163
+ this.parameters.endSec = data.parameters.endSec ?? 5;
164
+ this.parameters.fps = data.parameters.fps ?? 30;
165
+ this.parameters.step = data.parameters.step ?? 0;
166
+ this._frames = data.frames.map(f => Array.from(f));
167
+ }
168
+ // ── Private ─────────────────────────────────────────────────────────────────
169
+ _snapshot(pool) {
170
+ const fpp = ParticleCache._FPP;
171
+ const data = new Array(pool.length * fpp);
172
+ for (let i = 0; i < pool.length; i++) {
173
+ const p = pool[i];
174
+ const base = i * fpp;
175
+ data[base] = p.position.x;
176
+ data[base + 1] = p.position.y;
177
+ data[base + 2] = p.position.z;
178
+ data[base + 3] = p.velocity.x;
179
+ data[base + 4] = p.velocity.y;
180
+ data[base + 5] = p.velocity.z;
181
+ data[base + 6] = p.rotation.x;
182
+ data[base + 7] = p.rotation.y;
183
+ data[base + 8] = p.rotation.z;
184
+ data[base + 9] = p.size;
185
+ data[base + 10] = p.normalised;
186
+ data[base + 11] = p.alive ? 1 : 0;
187
+ }
188
+ return data;
189
+ }
190
+ _restoreParticle(p, frame, base) {
191
+ p.position.x = frame[base];
192
+ p.position.y = frame[base + 1];
193
+ p.position.z = frame[base + 2];
194
+ p.velocity.x = frame[base + 3];
195
+ p.velocity.y = frame[base + 4];
196
+ p.velocity.z = frame[base + 5];
197
+ p.rotation.x = frame[base + 6];
198
+ p.rotation.y = frame[base + 7];
199
+ p.rotation.z = frame[base + 8];
200
+ p.size = frame[base + 9];
201
+ p.normalised = frame[base + 10];
202
+ p.alive = frame[base + 11] > 0.5;
203
+ }
204
+ }
205
+ ParticleCache._FPP = 12; // floats per particle
206
+ //# sourceMappingURL=ParticleCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParticleCache.js","sourceRoot":"","sources":["../../src/core/ParticleCache.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,aAAa;IAOxB,IAAI,OAAO,KAAiB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA,CAAC,CAAC;IAC5D,IAAI,UAAU,KAAc,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA,CAAC,CAAC;IAExD;QANQ,YAAO,GAAe,EAAE,CAAA;QAO9B,IAAI,CAAC,UAAU,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;IAChE,CAAC;IAED;;;;;;;;OAQG;IACH,IAAI,CAAC,GAAmB,EAAE,QAAgB,EAAE,MAAc,EAAE,GAAW;QACrE,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACnC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAK,MAAM,CAAA;QACjC,IAAI,CAAC,UAAU,CAAC,GAAG,GAAQ,GAAG,CAAA;QAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,GAAO,CAAC,CAAA;QAE5B,MAAM,EAAE,GAAY,CAAC,GAAG,GAAG,CAAA;QAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;QAE5D,gCAAgC;QAChC,GAAG,CAAC,KAAK,EAAE,CAAA;QACX,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAA;QAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE;YAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAEpD,oEAAoE;QACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YAC3C,IAAI,CAAC,GAAG,WAAW,GAAG,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACzC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,GAAmB,EAAE,OAAe;QACvC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAErC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAA;QACzC,MAAM,OAAO,GAAI,OAAO,GAAG,QAAQ,CAAA;QACnC,iEAAiE;QACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,OAAO,GAAG,GAAG,CAAC,CAAC,CAAA;QAC9E,MAAM,EAAE,GAAS,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,EAAE,GAAS,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAA;QAC1D,MAAM,CAAC,GAAU,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAA;QAElD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAA;QACrB,MAAM,GAAG,GAAI,aAAa,CAAC,IAAI,CAAA;QAE/B,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACZ,8CAA8C;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,GAAG,CAAC,CAAA;YAChD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAC5B,MAAM,EAAE,GAAI,CAAC,GAAG,CAAC,CAAA;YACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,IAAI,GAAG,CAAC,GAAG,GAAG,CAAA;gBACpB,MAAM,CAAC,GAAM,IAAI,CAAC,CAAC,CAAC,CAAA;gBACpB,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,CAAC,GAAO,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,GAAO,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;gBACtD,CAAC,CAAC,IAAI,GAAU,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAA;gBACxD,CAAC,CAAC,UAAU,GAAI,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;gBACxD,CAAC,CAAC,KAAK,GAAS,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,GAAG,CAAA,CAAE,oCAAoC;YAC5E,CAAC;QACH,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;IACnB,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,OAAO,CACZ,OAA0B,EAC1B,QAAgB,EAChB,MAAgB,EAChB,GAAgB;QAEhB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAEhC,MAAM,EAAE,GAAY,CAAC,GAAG,GAAG,CAAA;QAC3B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;QAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAA;QAE9C,4DAA4D;QAC5D,MAAM,KAAK,GAAyD,EAAE,CAAA;QACtE,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;YACvB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA;YACrB,KAAK,CAAC,UAAU,CAAC,QAAQ,GAAG,QAAQ,CAAA;YACpC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAK,MAAM,CAAA;YAClC,KAAK,CAAC,UAAU,CAAC,GAAG,GAAQ,GAAG,CAAA;YAC/B,KAAK,CAAC,UAAU,CAAC,IAAI,GAAO,CAAC,CAAA;YAC7B,GAAG,CAAC,KAAK,EAAE,CAAA;YACX,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;QAC5B,CAAC;QAED,iBAAiB;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,KAAK;gBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAC7C,CAAC;QAED,wBAAwB;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,KAAK,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,KAAK,EAAE,CAAC;gBACnC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YACrD,CAAC;YACD,IAAI,CAAC,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC;gBACxB,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,KAAK;oBAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,MAAM;QACJ,OAAO;YACL,UAAU,EAAE,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE;YAClC,MAAM,EAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjD,CAAA;IACH,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAgE;QACvE,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,IAAI,CAAC,CAAA;QACxD,IAAI,CAAC,UAAU,CAAC,MAAM,GAAK,IAAI,CAAC,UAAU,CAAC,MAAM,IAAM,CAAC,CAAA;QACxD,IAAI,CAAC,UAAU,CAAC,GAAG,GAAQ,IAAI,CAAC,UAAU,CAAC,GAAG,IAAS,EAAE,CAAA;QACzD,IAAI,CAAC,UAAU,CAAC,IAAI,GAAO,IAAI,CAAC,UAAU,CAAC,IAAI,IAAQ,CAAC,CAAA;QACxD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACpD,CAAC;IAED,+EAA+E;IAEvE,SAAS,CAAC,IAAgB;QAChC,MAAM,GAAG,GAAI,aAAa,CAAC,IAAI,CAAA;QAC/B,MAAM,IAAI,GAAG,IAAI,KAAK,CAAS,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAA;QACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,MAAM,CAAC,GAAM,IAAI,CAAC,CAAC,CAAC,CAAA;YACpB,MAAM,IAAI,GAAG,CAAC,GAAG,GAAG,CAAA;YACpB,IAAI,CAAC,IAAI,CAAC,GAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAI,CAAC,CAAC,IAAI,CAAA;YACxB,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAA;YAC9B,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACnC,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,gBAAgB,CAAC,CAAW,EAAE,KAAe,EAAE,IAAY;QACjE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC9B,CAAC,CAAC,IAAI,GAAU,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;QAC/B,CAAC,CAAC,UAAU,GAAI,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,CAAA;QAChC,CAAC,CAAC,KAAK,GAAS,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,GAAG,CAAA;IACxC,CAAC;;AA9MuB,kBAAI,GAAG,EAAE,AAAL,CAAK,CAAG,sBAAsB"}
@@ -0,0 +1,192 @@
1
+ import { BufferGeometry } from 'three';
2
+ import { Particle } from './Particle.js';
3
+ import { ParticleCache } from './ParticleCache.js';
4
+ import { DeflectorCollider } from './DeflectorCollider.js';
5
+ import type { BaseEmitter } from './BaseEmitter.js';
6
+ import type { BaseForce } from './BaseForce.js';
7
+ import type { BaseRenderer } from './BaseRenderer.js';
8
+ import type { KeyedPhysics } from '../physics/KeyedPhysics.js';
9
+ export interface ParticleSystemOptions {
10
+ /** Total particle count — pool size (Blender: Number) */
11
+ count?: number;
12
+ /** Emission start in seconds (Blender: Frame Start → seconds) */
13
+ start?: number;
14
+ /** Emission end in seconds (Blender: End → seconds) */
15
+ end?: number;
16
+ /** Base lifetime per particle in seconds (Blender: Lifetime) */
17
+ lifetime?: number;
18
+ /** Lifetime variation 0–1 (Blender: Lifetime Randomness) */
19
+ lifetimeRandom?: number;
20
+ /** Base particle size in world units (Blender: Size) */
21
+ size?: number;
22
+ /** Size variation 0–1 (Blender: Size Random) */
23
+ sizeRandom?: number;
24
+ /** Random seed — same seed = same simulation (Blender: Seed) */
25
+ seed?: number;
26
+ /** Randomise emission order (Blender: Random Order) */
27
+ randomOrder?: boolean;
28
+ /** Physics type (Blender: Physics Type) */
29
+ physics?: 'newtonian' | 'none';
30
+ /** Particle mass — affects force response (Blender: Mass) */
31
+ mass?: number;
32
+ /** Air resistance 0–1 (Blender: Drag) */
33
+ drag?: number;
34
+ /** Thermal random motion magnitude (Blender: Brownian) */
35
+ brownian?: number;
36
+ /** Velocity damping per second 0–1 (Blender: Damp) */
37
+ damp?: number;
38
+ /** Gravity multiplier (Blender: Gravity) */
39
+ gravity?: number;
40
+ /** Kill particle on collision (Blender: Die on Hit) */
41
+ dieOnHit?: boolean;
42
+ /** % of particles shown in viewport 0–1 (Blender: Display Amount) */
43
+ displayAmount?: number;
44
+ /** Enable speed clamping (Blender: Physics → Newtonian → Limit Velocity). 0/1 toggle. */
45
+ limitVelocity?: number;
46
+ /** Maximum speed in world units/s when limitVelocity is enabled (Blender: Velocity Limit) */
47
+ velocityLimit?: number;
48
+ /** Source geometry for mesh-based emitters */
49
+ geometry?: BufferGeometry | null;
50
+ /**
51
+ * Live geometry provider callback — called once per update() to obtain
52
+ * the current source geometry. Use this to wire a modifier stack so
53
+ * particles always emit from the post-modifier surface without any
54
+ * cross-package import.
55
+ *
56
+ * @example
57
+ * const stack = new ModifierStack(baseGeo)
58
+ * stack.add(new SubdivisionModifier({ levels: 2 }))
59
+ * system.geometryProvider = () => stack.apply()
60
+ */
61
+ geometryProvider?: () => BufferGeometry;
62
+ /**
63
+ * Initial rotation axis (Blender: Orientation Axis).
64
+ * 0=none · 1=velocity · 2=angular · 3=global · 4=local
65
+ */
66
+ rotationAxis?: 0 | 1 | 2 | 3 | 4;
67
+ /** Random initial rotation factor 0–1 (Blender: Random) */
68
+ rotationRandom?: number;
69
+ /** Initial rotation offset in radians (Blender: Phase) */
70
+ rotationPhase?: number;
71
+ /** Per-particle phase scatter 0–1 (Blender: Phase Random) */
72
+ rotationPhaseRandom?: number;
73
+ /**
74
+ * Angular velocity axis (Blender: Angular Velocity Axis).
75
+ * 0=none · 1=velocity · 2=horizontal · 3=vertical · 4=global · 5=random
76
+ */
77
+ angularVelocityMode?: 0 | 1 | 2 | 3 | 4 | 5;
78
+ /** Spin speed in rad/s (Blender: Angular Velocity Amount) */
79
+ angularVelocityAmount?: number;
80
+ /**
81
+ * Number of child particles per parent (Blender: Amount).
82
+ * 0 = disabled. GSAP-animatable integer.
83
+ */
84
+ childCount?: number;
85
+ /**
86
+ * Scatter radius around parent for Simple children (Blender: Roughness).
87
+ * 0 = children spawn exactly at the parent position. GSAP-animatable.
88
+ */
89
+ childSpread?: number;
90
+ /**
91
+ * Child type — stored as a number for GSAP compatibility.
92
+ * 0 = none (disabled) · 1 = simple (sphere scatter) · 2 = interpolated
93
+ */
94
+ childType?: 0 | 1 | 2;
95
+ }
96
+ /**
97
+ * ParticleSystem — central simulation loop.
98
+ *
99
+ * Owns the particle pool, runs emission scheduling, steps Newtonian physics,
100
+ * applies forces, and calls the renderer each frame.
101
+ *
102
+ * Blender parallel: the Particle System object on a mesh.
103
+ */
104
+ export declare class ParticleSystem {
105
+ /** All public parameters — GSAP / keyframe compatible */
106
+ parameters: Record<string, number>;
107
+ private _pool;
108
+ private _emitters;
109
+ private _forces;
110
+ private _deflectors;
111
+ private _renderer;
112
+ private _rng;
113
+ private _childRng;
114
+ private _time;
115
+ private _emitCursor;
116
+ private _emitAccum;
117
+ private _geometry;
118
+ private _geometryProvider;
119
+ private readonly _tmpVec;
120
+ private readonly _prevPos;
121
+ private readonly _hitNorm;
122
+ private readonly _hitPt;
123
+ private _cache;
124
+ private _baked;
125
+ private _keyedPhysics;
126
+ constructor(opts?: ParticleSystemOptions);
127
+ /** Package-internal pool accessor — used by ParticleCache and BoidForce. */
128
+ get pool(): Particle[];
129
+ /** Current number of alive particles this frame. */
130
+ get liveCount(): number;
131
+ /** The bake/cache object for this system. */
132
+ get cache(): ParticleCache;
133
+ /**
134
+ * Bake the simulation to a replayable cache.
135
+ * After this returns update() replays the cache instead of simulating.
136
+ */
137
+ bake(startSec: number, endSec: number, fps: number): void;
138
+ /**
139
+ * Return to live simulation. Clears the cache, resets internal time and pool state.
140
+ */
141
+ unbake(): void;
142
+ addEmitter(emitter: BaseEmitter): this;
143
+ addForce(force: BaseForce): this;
144
+ addDeflector(deflector: DeflectorCollider): this;
145
+ setRenderer(renderer: BaseRenderer): this;
146
+ setGeometry(geo: BufferGeometry): this;
147
+ /**
148
+ * Set a live geometry provider callback.
149
+ * Called once per update() — use to wire a modifier stack without any
150
+ * cross-package import. Overrides any geometry set via setGeometry().
151
+ *
152
+ * @example
153
+ * const stack = new ModifierStack(baseGeo)
154
+ * stack.add(new SubdivisionModifier({ levels: 2 }))
155
+ * system.setGeometryProvider(() => stack.apply())
156
+ */
157
+ setGeometryProvider(fn: (() => BufferGeometry) | null): this;
158
+ /**
159
+ * Show or hide the emitter mesh in the viewport.
160
+ * Blender: Render → Show Emitter toggle.
161
+ *
162
+ * Pass the same Object3D you added to the scene.
163
+ * sys.showEmitter(sphereMesh, false) // hide while particles are visible
164
+ */
165
+ showEmitter(mesh: {
166
+ visible: boolean;
167
+ }, visible: boolean): this;
168
+ /**
169
+ * Attach a KeyedPhysics blender.
170
+ * When set, keyed blending is applied after each step.
171
+ * Drive `kp.parameters.blend` via GSAP or AnimationMixer from st-keyframe.
172
+ */
173
+ setKeyedPhysics(kp: KeyedPhysics): this;
174
+ /**
175
+ * Advance the simulation by dt seconds.
176
+ * Call this once per frame from your render loop.
177
+ * In baked mode, seeks the cache instead of simulating.
178
+ */
179
+ update(dt: number): void;
180
+ /** Reset the simulation to t=0 */
181
+ reset(): void;
182
+ dispose(): void;
183
+ private _emit;
184
+ private _initRotation;
185
+ private _stepNewtonian;
186
+ /**
187
+ * O(n²) inter-particle collision — elastic bounce when two particles overlap.
188
+ * Only runs when parameters.selfEffect >= 0.5 (Blender: Physics → Self Effect).
189
+ */
190
+ private _stepSelfCollision;
191
+ }
192
+ //# sourceMappingURL=ParticleSystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParticleSystem.d.ts","sourceRoot":"","sources":["../../src/core/ParticleSystem.ts"],"names":[],"mappings":"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"}