@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,484 @@
1
+ import { Vector3 } from 'three';
2
+ import { Particle } from './Particle.js';
3
+ import { SeededRandom } from './SeededRandom.js';
4
+ import { ParticleCache } from './ParticleCache.js';
5
+ /**
6
+ * ParticleSystem — central simulation loop.
7
+ *
8
+ * Owns the particle pool, runs emission scheduling, steps Newtonian physics,
9
+ * applies forces, and calls the renderer each frame.
10
+ *
11
+ * Blender parallel: the Particle System object on a mesh.
12
+ */
13
+ export class ParticleSystem {
14
+ constructor(opts = {}) {
15
+ this._tmpVec = new Vector3();
16
+ this._prevPos = new Vector3(); // saved before integration for collision
17
+ this._hitNorm = new Vector3();
18
+ this._hitPt = new Vector3();
19
+ this._keyedPhysics = null;
20
+ this.parameters = {
21
+ count: opts.count ?? 1000,
22
+ start: opts.start ?? 0,
23
+ end: opts.end ?? 10,
24
+ lifetime: opts.lifetime ?? 2,
25
+ lifetimeRandom: opts.lifetimeRandom ?? 0,
26
+ size: opts.size ?? 0.1,
27
+ sizeRandom: opts.sizeRandom ?? 0,
28
+ seed: opts.seed ?? 0,
29
+ randomOrder: opts.randomOrder ? 1 : 0,
30
+ // physics: 0 = none, 1 = newtonian
31
+ physics: opts.physics === 'none' ? 0 : 1,
32
+ mass: opts.mass ?? 1,
33
+ drag: opts.drag ?? 0,
34
+ brownian: opts.brownian ?? 0,
35
+ damp: opts.damp ?? 0,
36
+ gravity: opts.gravity ?? 1,
37
+ dieOnHit: opts.dieOnHit ? 1 : 0,
38
+ selfEffect: 0,
39
+ displayAmount: opts.displayAmount ?? 1,
40
+ // Rotation panel
41
+ rotationAxis: opts.rotationAxis ?? 0,
42
+ rotationRandom: opts.rotationRandom ?? 0,
43
+ rotationPhase: opts.rotationPhase ?? 0,
44
+ rotationPhaseRandom: opts.rotationPhaseRandom ?? 0,
45
+ angularVelocityMode: opts.angularVelocityMode ?? 0,
46
+ angularVelocityAmount: opts.angularVelocityAmount ?? 0,
47
+ // Children panel
48
+ childCount: opts.childCount ?? 0,
49
+ childSpread: opts.childSpread ?? 0.5,
50
+ childType: opts.childType ?? 0,
51
+ // Scale Time (Blender: Physics → Newtonian → Scale Time)
52
+ scaleTime: 1,
53
+ // Speed Limit (Blender: Physics → Newtonian → Limit Velocity)
54
+ limitVelocity: opts.limitVelocity ?? 0,
55
+ velocityLimit: opts.velocityLimit ?? 10,
56
+ };
57
+ this._pool = Array.from({ length: Math.round(this.parameters.count) }, () => new Particle());
58
+ this._emitters = [];
59
+ this._forces = [];
60
+ this._deflectors = [];
61
+ this._renderer = null;
62
+ this._rng = new SeededRandom(Math.round(this.parameters.seed));
63
+ this._childRng = new SeededRandom(Math.round(this.parameters.seed));
64
+ this._time = 0;
65
+ this._emitCursor = 0;
66
+ this._emitAccum = 0;
67
+ this._geometry = opts.geometry ?? null;
68
+ this._geometryProvider = opts.geometryProvider ?? null;
69
+ this._cache = new ParticleCache();
70
+ this._baked = false;
71
+ }
72
+ // ── Public API ─────────────────────────────────────────────────────────────
73
+ /** Package-internal pool accessor — used by ParticleCache and BoidForce. */
74
+ get pool() { return this._pool; }
75
+ /** Current number of alive particles this frame. */
76
+ get liveCount() {
77
+ let n = 0;
78
+ for (const p of this._pool)
79
+ if (p.alive)
80
+ n++;
81
+ return n;
82
+ }
83
+ /** The bake/cache object for this system. */
84
+ get cache() { return this._cache; }
85
+ /**
86
+ * Bake the simulation to a replayable cache.
87
+ * After this returns update() replays the cache instead of simulating.
88
+ */
89
+ bake(startSec, endSec, fps) {
90
+ this._cache.bake(this, startSec, endSec, fps);
91
+ this._baked = true;
92
+ this._time = 0;
93
+ }
94
+ /**
95
+ * Return to live simulation. Clears the cache, resets internal time and pool state.
96
+ */
97
+ unbake() {
98
+ this._baked = false;
99
+ this._cache.clear();
100
+ this.reset();
101
+ }
102
+ addEmitter(emitter) {
103
+ this._emitters.push(emitter);
104
+ return this;
105
+ }
106
+ addForce(force) {
107
+ this._forces.push(force);
108
+ return this;
109
+ }
110
+ addDeflector(deflector) {
111
+ this._deflectors.push(deflector);
112
+ return this;
113
+ }
114
+ setRenderer(renderer) {
115
+ this._renderer = renderer;
116
+ return this;
117
+ }
118
+ setGeometry(geo) {
119
+ this._geometry = geo;
120
+ return this;
121
+ }
122
+ /**
123
+ * Set a live geometry provider callback.
124
+ * Called once per update() — use to wire a modifier stack without any
125
+ * cross-package import. Overrides any geometry set via setGeometry().
126
+ *
127
+ * @example
128
+ * const stack = new ModifierStack(baseGeo)
129
+ * stack.add(new SubdivisionModifier({ levels: 2 }))
130
+ * system.setGeometryProvider(() => stack.apply())
131
+ */
132
+ setGeometryProvider(fn) {
133
+ this._geometryProvider = fn;
134
+ return this;
135
+ }
136
+ /**
137
+ * Show or hide the emitter mesh in the viewport.
138
+ * Blender: Render → Show Emitter toggle.
139
+ *
140
+ * Pass the same Object3D you added to the scene.
141
+ * sys.showEmitter(sphereMesh, false) // hide while particles are visible
142
+ */
143
+ showEmitter(mesh, visible) {
144
+ mesh.visible = visible;
145
+ return this;
146
+ }
147
+ /**
148
+ * Attach a KeyedPhysics blender.
149
+ * When set, keyed blending is applied after each step.
150
+ * Drive `kp.parameters.blend` via GSAP or AnimationMixer from st-keyframe.
151
+ */
152
+ setKeyedPhysics(kp) {
153
+ this._keyedPhysics = kp;
154
+ return this;
155
+ }
156
+ /**
157
+ * Advance the simulation by dt seconds.
158
+ * Call this once per frame from your render loop.
159
+ * In baked mode, seeks the cache instead of simulating.
160
+ */
161
+ update(dt) {
162
+ if (this._baked) {
163
+ this._time += dt;
164
+ this._cache.seek(this, this._time);
165
+ if (this._renderer) {
166
+ this._childRng.reset(Math.round(this.parameters.seed));
167
+ let alive = 0;
168
+ for (const p of this._pool) {
169
+ if (p.alive)
170
+ alive++;
171
+ }
172
+ this._renderer.update(this._pool, alive, this.parameters, this._childRng);
173
+ }
174
+ return;
175
+ }
176
+ const effectiveDt = dt * this.parameters.scaleTime;
177
+ this._time += effectiveDt;
178
+ // Resolve geometry once per frame — provider takes priority over static geo
179
+ if (this._geometryProvider) {
180
+ this._geometry = this._geometryProvider();
181
+ }
182
+ const p = this.parameters;
183
+ const inEmissionWindow = this._time >= p.start && this._time <= p.end;
184
+ // ── Emit new particles ──────────────────────────────────────────────────
185
+ // Rate = count / lifetime so the pool stays full at steady state.
186
+ if (inEmissionWindow && this._emitters.length > 0 && effectiveDt > 0) {
187
+ const rate = p.count / Math.max(p.lifetime * (1 - p.lifetimeRandom * 0.5), 0.001);
188
+ this._emitAccum = Math.max(0, (this._emitAccum ?? 0) + rate * effectiveDt);
189
+ const toEmit = Math.floor(this._emitAccum);
190
+ this._emitAccum -= toEmit;
191
+ for (let i = 0; i < toEmit; i++) {
192
+ this._emit();
193
+ }
194
+ }
195
+ // ── Step alive particles ────────────────────────────────────────────────
196
+ let alive = 0;
197
+ for (const particle of this._pool) {
198
+ if (!particle.alive)
199
+ continue;
200
+ particle.age += effectiveDt;
201
+ if (particle.age >= particle.lifetime || particle.age < 0) {
202
+ particle.alive = false;
203
+ continue;
204
+ }
205
+ particle.normalised = particle.age / particle.lifetime;
206
+ if (p.physics === 1) {
207
+ this._stepNewtonian(particle, effectiveDt);
208
+ }
209
+ alive++;
210
+ }
211
+ // ── Self-collision pass ──────────────────────────────────────────────────
212
+ if (p.selfEffect >= 0.5 && alive > 1) {
213
+ this._stepSelfCollision();
214
+ }
215
+ // ── Keyed physics blend ──────────────────────────────────────────────────
216
+ if (this._keyedPhysics) {
217
+ this._keyedPhysics.apply(this._pool, effectiveDt);
218
+ }
219
+ // ── Renderer update ─────────────────────────────────────────────────────
220
+ if (this._renderer) {
221
+ // Reset child RNG to the base seed each frame → stable child positions.
222
+ this._childRng.reset(Math.round(this.parameters.seed));
223
+ this._renderer.update(this._pool, alive, this.parameters, this._childRng);
224
+ }
225
+ }
226
+ /** Reset the simulation to t=0 */
227
+ reset() {
228
+ this._time = 0;
229
+ this._emitCursor = 0;
230
+ this._emitAccum = 0;
231
+ this._rng.reset(Math.round(this.parameters.seed));
232
+ this._childRng.reset(Math.round(this.parameters.seed));
233
+ for (const p of this._pool)
234
+ p.reset();
235
+ }
236
+ dispose() {
237
+ this._renderer?.dispose();
238
+ }
239
+ // ── Private ────────────────────────────────────────────────────────────────
240
+ _emit() {
241
+ const count = this._pool.length;
242
+ const useRandom = this.parameters.randomOrder > 0;
243
+ let slot = null;
244
+ if (useRandom) {
245
+ // Randomised order: search from a random starting position
246
+ const startIdx = Math.floor(this._rng.next() * count);
247
+ for (let i = 0; i < count; i++) {
248
+ const idx = (startIdx + i) % count;
249
+ if (!this._pool[idx].alive) {
250
+ slot = this._pool[idx];
251
+ break;
252
+ }
253
+ }
254
+ // All slots alive — overwrite a random slot
255
+ if (!slot) {
256
+ slot = this._pool[Math.floor(this._rng.next() * count)];
257
+ }
258
+ }
259
+ else {
260
+ // Sequential order — wrap around with cursor
261
+ for (let i = 0; i < count; i++) {
262
+ const idx = (this._emitCursor + i) % count;
263
+ if (!this._pool[idx].alive) {
264
+ slot = this._pool[idx];
265
+ this._emitCursor = (idx + 1) % count;
266
+ break;
267
+ }
268
+ }
269
+ // All slots alive — overwrite the cursor slot (oldest)
270
+ if (!slot) {
271
+ slot = this._pool[this._emitCursor];
272
+ this._emitCursor = (this._emitCursor + 1) % count;
273
+ }
274
+ }
275
+ slot.reset();
276
+ slot.alive = true;
277
+ slot.age = 0;
278
+ // Lifetime: base ± lifetimeRandom × rand (Blender: Lifetime Randomness)
279
+ const lr = this.parameters.lifetimeRandom;
280
+ slot.lifetime = Math.max(0.001, this.parameters.lifetime * (1 + lr * this._rng.signed()));
281
+ // Size
282
+ const sr = this.parameters.sizeRandom;
283
+ slot.size = this.parameters.size * (1 - sr * this._rng.next());
284
+ // Pick emitter uniformly at random
285
+ if (this._emitters.length > 0) {
286
+ const eIdx = Math.floor(this._rng.next() * this._emitters.length);
287
+ const emitter = this._emitters[Math.min(eIdx, this._emitters.length - 1)];
288
+ emitter.spawn(slot, this._geometry, this._rng);
289
+ }
290
+ this._initRotation(slot);
291
+ }
292
+ _initRotation(slot) {
293
+ const p = this.parameters;
294
+ // ── Initial rotation ────────────────────────────────────────────────────
295
+ // phase + per-particle scatter (Blender: Phase + Phase Random)
296
+ const phase = p.rotationPhase + p.rotationPhaseRandom * Math.PI * this._rng.signed();
297
+ // rotationRandom adds additional scatter (Blender: Random)
298
+ const scatter = p.rotationRandom * Math.PI * this._rng.signed();
299
+ const angle = phase + scatter;
300
+ switch (Math.round(p.rotationAxis)) {
301
+ case 0: // none — leave rotation at zero
302
+ break;
303
+ case 1: { // velocity — rotate around velocity direction using that axis as Y
304
+ const len = slot.velocity.length();
305
+ if (len > 1e-6) {
306
+ this._tmpVec.copy(slot.velocity).divideScalar(len);
307
+ slot.rotation.set(this._tmpVec.x * angle, this._tmpVec.y * angle, this._tmpVec.z * angle);
308
+ }
309
+ break;
310
+ }
311
+ case 2: // angular — spin around particle local Z
312
+ case 3: // global — spin around world Z
313
+ case 4: // local — spin around local Z
314
+ slot.rotation.z = angle;
315
+ break;
316
+ default:
317
+ break;
318
+ }
319
+ // ── Angular velocity ────────────────────────────────────────────────────
320
+ const amount = p.angularVelocityAmount;
321
+ if (amount === 0)
322
+ return;
323
+ switch (Math.round(p.angularVelocityMode)) {
324
+ case 0: // none
325
+ break;
326
+ case 1: { // velocity — spin axis aligned with velocity direction
327
+ const len = slot.velocity.length();
328
+ if (len > 1e-6) {
329
+ slot.angularVel.copy(slot.velocity).multiplyScalar(amount / len);
330
+ }
331
+ break;
332
+ }
333
+ case 2: // horizontal — spin around world Y (up axis)
334
+ slot.angularVel.set(0, amount, 0);
335
+ break;
336
+ case 3: // vertical — spin around world X
337
+ slot.angularVel.set(amount, 0, 0);
338
+ break;
339
+ case 4: // global — spin around world Z
340
+ slot.angularVel.set(0, 0, amount);
341
+ break;
342
+ case 5: { // random — spin around a random unit axis
343
+ const rx = this._rng.signed();
344
+ const ry = this._rng.signed();
345
+ const rz = this._rng.signed();
346
+ const len = Math.sqrt(rx * rx + ry * ry + rz * rz);
347
+ if (len > 1e-6) {
348
+ slot.angularVel.set(rx / len * amount, ry / len * amount, rz / len * amount);
349
+ }
350
+ break;
351
+ }
352
+ default:
353
+ break;
354
+ }
355
+ }
356
+ _stepNewtonian(particle, dt) {
357
+ const p = this.parameters;
358
+ // Apply all forces: F = ma → a = F/m → dv = a·dt
359
+ for (const force of this._forces) {
360
+ if (force.enabled)
361
+ force.apply(particle, dt);
362
+ }
363
+ // Gravity (world -Y)
364
+ particle.velocity.y -= 9.81 * p.gravity * dt / Math.max(p.mass, 0.0001);
365
+ // Air drag: dv = -drag · v · dt
366
+ if (p.drag > 0) {
367
+ particle.velocity.multiplyScalar(1 - Math.min(p.drag * dt, 1));
368
+ }
369
+ // Velocity damping
370
+ if (p.damp > 0) {
371
+ particle.velocity.multiplyScalar(1 - Math.min(p.damp * dt, 1));
372
+ }
373
+ // Brownian motion (thermal noise)
374
+ if (p.brownian > 0) {
375
+ const b = p.brownian * dt;
376
+ particle.velocity.x += (Math.random() * 2 - 1) * b;
377
+ particle.velocity.y += (Math.random() * 2 - 1) * b;
378
+ particle.velocity.z += (Math.random() * 2 - 1) * b;
379
+ }
380
+ // Guard against NaN/Infinity in velocity before integration
381
+ if (!isFinite(particle.velocity.x))
382
+ particle.velocity.x = 0;
383
+ if (!isFinite(particle.velocity.y))
384
+ particle.velocity.y = 0;
385
+ if (!isFinite(particle.velocity.z))
386
+ particle.velocity.z = 0;
387
+ // Save position before integration for collision crossing detection
388
+ this._prevPos.copy(particle.position);
389
+ // Integrate position
390
+ particle.position.addScaledVector(particle.velocity, dt);
391
+ // Guard against NaN/Infinity in position after integration
392
+ if (!isFinite(particle.position.x))
393
+ particle.position.x = 0;
394
+ if (!isFinite(particle.position.y))
395
+ particle.position.y = 0;
396
+ if (!isFinite(particle.position.z))
397
+ particle.position.z = 0;
398
+ // ── Deflector collisions ─────────────────────────────────────────────────
399
+ if (this._deflectors.length > 0) {
400
+ for (const deflector of this._deflectors) {
401
+ if (deflector.checkCrossing(this._prevPos.x, this._prevPos.y, this._prevPos.z, particle.position.x, particle.position.y, particle.position.z, this._hitNorm, this._hitPt, particle.size * 0.5)) {
402
+ if (p.dieOnHit >= 0.5) {
403
+ particle.alive = false;
404
+ break;
405
+ }
406
+ const damping = deflector.parameters.damping;
407
+ const friction = deflector.parameters.friction;
408
+ const nx = this._hitNorm.x, ny = this._hitNorm.y, nz = this._hitNorm.z;
409
+ // Reflect: v_new = v - (2 - damping) * dot(v,n) * n
410
+ // damping=0 → elastic (speed conserved), damping=1 → inelastic (normal=0)
411
+ const vDotN = particle.velocity.x * nx + particle.velocity.y * ny + particle.velocity.z * nz;
412
+ const k = (2 - damping) * vDotN;
413
+ particle.velocity.x -= k * nx;
414
+ particle.velocity.y -= k * ny;
415
+ particle.velocity.z -= k * nz;
416
+ // Friction: reduce tangential component
417
+ // v_final = (1-friction)*v_reflected + friction*dot(v_reflected,n)*n
418
+ if (friction > 0) {
419
+ const vNewDotN = particle.velocity.x * nx + particle.velocity.y * ny + particle.velocity.z * nz;
420
+ particle.velocity.x = (1 - friction) * particle.velocity.x + friction * vNewDotN * nx;
421
+ particle.velocity.y = (1 - friction) * particle.velocity.y + friction * vNewDotN * ny;
422
+ particle.velocity.z = (1 - friction) * particle.velocity.z + friction * vNewDotN * nz;
423
+ }
424
+ // Reposition to contact plane to prevent clipping
425
+ particle.position.copy(this._hitPt);
426
+ break;
427
+ }
428
+ }
429
+ }
430
+ // Speed limit (Blender: Physics → Newtonian → Limit Velocity)
431
+ if (p.limitVelocity >= 0.5) {
432
+ const limit = Math.max(0, p.velocityLimit);
433
+ const speed = particle.velocity.length();
434
+ if (speed > limit)
435
+ particle.velocity.multiplyScalar(limit / speed);
436
+ }
437
+ // Integrate rotation from angular velocity
438
+ particle.rotation.addScaledVector(particle.angularVel, dt);
439
+ }
440
+ /**
441
+ * O(n²) inter-particle collision — elastic bounce when two particles overlap.
442
+ * Only runs when parameters.selfEffect >= 0.5 (Blender: Physics → Self Effect).
443
+ */
444
+ _stepSelfCollision() {
445
+ const pool = this._pool;
446
+ const n = pool.length;
447
+ for (let i = 0; i < n - 1; i++) {
448
+ const a = pool[i];
449
+ if (!a.alive)
450
+ continue;
451
+ for (let j = i + 1; j < n; j++) {
452
+ const b = pool[j];
453
+ if (!b.alive)
454
+ continue;
455
+ const dx = a.position.x - b.position.x;
456
+ const dy = a.position.y - b.position.y;
457
+ const dz = a.position.z - b.position.z;
458
+ const dist2 = dx * dx + dy * dy + dz * dz;
459
+ const minDist = (a.size + b.size) * 0.5;
460
+ if (dist2 < minDist * minDist && dist2 > 1e-12) {
461
+ const dist = Math.sqrt(dist2);
462
+ const nx = dx / dist;
463
+ const ny = dy / dist;
464
+ const nz = dz / dist;
465
+ // Relative velocity along collision normal
466
+ const dvn = (a.velocity.x - b.velocity.x) * nx
467
+ + (a.velocity.y - b.velocity.y) * ny
468
+ + (a.velocity.z - b.velocity.z) * nz;
469
+ // Only respond if particles are approaching
470
+ if (dvn < 0) {
471
+ // Equal-mass elastic: exchange normal-component impulse
472
+ a.velocity.x -= dvn * nx;
473
+ a.velocity.y -= dvn * ny;
474
+ a.velocity.z -= dvn * nz;
475
+ b.velocity.x += dvn * nx;
476
+ b.velocity.y += dvn * ny;
477
+ b.velocity.z += dvn * nz;
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
483
+ }
484
+ //# sourceMappingURL=ParticleSystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParticleSystem.js","sourceRoot":"","sources":["../../src/core/ParticleSystem.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Seeded LCG random — same seed always produces the same sequence.
3
+ * Matches Blender's particle seed behaviour.
4
+ */
5
+ export declare class SeededRandom {
6
+ private s;
7
+ constructor(seed: number);
8
+ /** Returns a float in [0, 1) */
9
+ next(): number;
10
+ /** Returns a float in [-1, 1) */
11
+ signed(): number;
12
+ /** Returns a float in [min, max) */
13
+ range(min: number, max: number): number;
14
+ /** Reset the generator to a new seed — reuse the instance instead of allocating. */
15
+ reset(seed: number): void;
16
+ }
17
+ //# sourceMappingURL=SeededRandom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeededRandom.d.ts","sourceRoot":"","sources":["../../src/core/SeededRandom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,CAAC,CAAQ;gBAEL,IAAI,EAAE,MAAM;IAIxB,gCAAgC;IAChC,IAAI,IAAI,MAAM;IAKd,iCAAiC;IACjC,MAAM,IAAI,MAAM;IAIhB,oCAAoC;IACpC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIvC,oFAAoF;IACpF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAG1B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Seeded LCG random — same seed always produces the same sequence.
3
+ * Matches Blender's particle seed behaviour.
4
+ */
5
+ export class SeededRandom {
6
+ constructor(seed) {
7
+ this.s = seed >>> 0;
8
+ }
9
+ /** Returns a float in [0, 1) */
10
+ next() {
11
+ this.s = (Math.imul(1664525, this.s) + 1013904223) >>> 0;
12
+ return this.s / 4294967296;
13
+ }
14
+ /** Returns a float in [-1, 1) */
15
+ signed() {
16
+ return this.next() * 2 - 1;
17
+ }
18
+ /** Returns a float in [min, max) */
19
+ range(min, max) {
20
+ return min + this.next() * (max - min);
21
+ }
22
+ /** Reset the generator to a new seed — reuse the instance instead of allocating. */
23
+ reset(seed) {
24
+ this.s = seed >>> 0;
25
+ }
26
+ }
27
+ //# sourceMappingURL=SeededRandom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SeededRandom.js","sourceRoot":"","sources":["../../src/core/SeededRandom.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,YAAY;IAGvB,YAAY,IAAY;QACtB,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,CAAA;IACrB,CAAC;IAED,gCAAgC;IAChC,IAAI;QACF,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;QACxD,OAAO,IAAI,CAAC,CAAC,GAAG,UAAU,CAAA;IAC5B,CAAC;IAED,iCAAiC;IACjC,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,CAAC;IAED,oCAAoC;IACpC,KAAK,CAAC,GAAW,EAAE,GAAW;QAC5B,OAAO,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAA;IACxC,CAAC;IAED,oFAAoF;IACpF,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,CAAA;IACrB,CAAC;CACF"}
@@ -0,0 +1,43 @@
1
+ import { BufferGeometry } from 'three';
2
+ import { BaseEmitter, BaseEmitterOptions } from '../core/BaseEmitter.js';
3
+ import type { Particle } from '../core/Particle.js';
4
+ import type { SeededRandom } from '../core/SeededRandom.js';
5
+ export interface EdgeEmitterOptions extends BaseEmitterOptions {
6
+ /**
7
+ * Y threshold — only emit from edges whose midpoint Y is within
8
+ * this distance of targetY. Used for waterline foam (y ≈ 0).
9
+ * Default: Infinity (all edges).
10
+ */
11
+ yThreshold?: number;
12
+ /**
13
+ * Target Y value to test against yThreshold. Default: 0.
14
+ */
15
+ targetY?: number;
16
+ /**
17
+ * Only emit from edges whose midpoint Z is >= zMin (local space).
18
+ * Use this to restrict emission to the shore-edge of an ocean mesh.
19
+ * Default: -Infinity (all edges).
20
+ */
21
+ zMin?: number;
22
+ /**
23
+ * Only emit from edges whose midpoint Z is <= zMax (local space).
24
+ * Default: +Infinity (all edges).
25
+ */
26
+ zMax?: number;
27
+ }
28
+ /**
29
+ * EdgeEmitter — emits particles from mesh edges.
30
+ *
31
+ * Primary use case: waterline foam — edges where the ocean surface
32
+ * crosses y ≈ 0 (the shore) are the emission source.
33
+ *
34
+ * yThreshold filters to only edges near the water surface.
35
+ */
36
+ export declare class EdgeEmitter extends BaseEmitter {
37
+ /** Cached candidate edges — rebuilt when geometry reference changes */
38
+ private _edgeCache;
39
+ private _lastGeo;
40
+ constructor(opts?: EdgeEmitterOptions);
41
+ spawn(particle: Particle, geometry: BufferGeometry | null, rng: SeededRandom): void;
42
+ }
43
+ //# sourceMappingURL=EdgeEmitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EdgeEmitter.d.ts","sourceRoot":"","sources":["../../src/emitters/EdgeEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,cAAc,EAAE,MAAM,OAAO,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAU,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAE3D,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;GAOG;AACH,qBAAa,WAAY,SAAQ,WAAW;IAC1C,uEAAuE;IACvE,OAAO,CAAC,UAAU,CAAyB;IAC3C,OAAO,CAAC,QAAQ,CAAgC;gBAEpC,IAAI,GAAE,kBAAuB;IAQzC,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,EAAE,GAAG,EAAE,YAAY,GAAG,IAAI;CAoEpF"}