@flighthq/particles 0.1.0 → 0.2.1-next.410.a23f189

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 (55) hide show
  1. package/dist/applyParticleCollisions.d.ts +2 -2
  2. package/dist/applyParticleCollisions.d.ts.map +1 -1
  3. package/dist/applyParticleCollisions.js +75 -30
  4. package/dist/applyParticleCollisions.js.map +1 -1
  5. package/dist/applyParticleForces.d.ts.map +1 -1
  6. package/dist/applyParticleForces.js +33 -10
  7. package/dist/applyParticleForces.js.map +1 -1
  8. package/dist/index.d.ts +1 -4
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -4
  11. package/dist/index.js.map +1 -1
  12. package/dist/particleEmitterConfig.d.ts.map +1 -1
  13. package/dist/particleEmitterConfig.js +4 -0
  14. package/dist/particleEmitterConfig.js.map +1 -1
  15. package/dist/particleEmitterState.d.ts +1 -0
  16. package/dist/particleEmitterState.d.ts.map +1 -1
  17. package/dist/particleEmitterState.js +4 -1
  18. package/dist/particleEmitterState.js.map +1 -1
  19. package/dist/stepParticleObjects.d.ts +19 -0
  20. package/dist/stepParticleObjects.d.ts.map +1 -0
  21. package/dist/stepParticleObjects.js +29 -0
  22. package/dist/stepParticleObjects.js.map +1 -0
  23. package/dist/validateParticleEmitterConfig.d.ts.map +1 -1
  24. package/dist/validateParticleEmitterConfig.js +8 -0
  25. package/dist/validateParticleEmitterConfig.js.map +1 -1
  26. package/package.json +10 -7
  27. package/src/applyParticleCollisions.test.ts +71 -32
  28. package/src/applyParticleForces.test.ts +70 -34
  29. package/src/curve.test.ts +0 -63
  30. package/src/particleEmitterConfig.test.ts +4 -0
  31. package/src/particleEmitterSignals.test.ts +0 -83
  32. package/src/particleEmitterState.test.ts +7 -44
  33. package/src/stepParticleObjects.test.ts +30 -0
  34. package/src/validateParticleEmitterConfig.test.ts +0 -32
  35. package/dist/emitParticleBurst.d.ts +0 -15
  36. package/dist/emitParticleBurst.d.ts.map +0 -1
  37. package/dist/emitParticleBurst.js +0 -114
  38. package/dist/emitParticleBurst.js.map +0 -1
  39. package/dist/prewarmParticleEmitter.d.ts +0 -5
  40. package/dist/prewarmParticleEmitter.d.ts.map +0 -1
  41. package/dist/prewarmParticleEmitter.js +0 -13
  42. package/dist/prewarmParticleEmitter.js.map +0 -1
  43. package/dist/stepParticleEmitter.d.ts +0 -38
  44. package/dist/stepParticleEmitter.d.ts.map +0 -1
  45. package/dist/stepParticleEmitter.js +0 -57
  46. package/dist/stepParticleEmitter.js.map +0 -1
  47. package/dist/updateParticleEmitter.d.ts +0 -8
  48. package/dist/updateParticleEmitter.d.ts.map +0 -1
  49. package/dist/updateParticleEmitter.js +0 -315
  50. package/dist/updateParticleEmitter.js.map +0 -1
  51. package/src/deterministic.test.ts +0 -54
  52. package/src/emitParticleBurst.test.ts +0 -103
  53. package/src/prewarmParticleEmitter.test.ts +0 -68
  54. package/src/stepParticleEmitter.test.ts +0 -113
  55. package/src/updateParticleEmitter.test.ts +0 -631
@@ -1,18 +1,6 @@
1
- import { createParticleEmitter } from '@flighthq/sprite';
2
- import type { TextureAtlas } from '@flighthq/types';
3
-
4
1
  import { createParticleEmitterConfig } from './particleEmitterConfig';
5
- import { createParticleEmitterState } from './particleEmitterState';
6
- import { updateParticleEmitter } from './updateParticleEmitter';
7
2
  import { normalizeParticleEmitterConfig, validateParticleEmitterConfig } from './validateParticleEmitterConfig';
8
3
 
9
- function makeAtlas(): TextureAtlas {
10
- return {
11
- image: null,
12
- regions: [{ id: 0, x: 0, y: 0, width: 32, height: 32, pivotX: null, pivotY: null }],
13
- } as TextureAtlas;
14
- }
15
-
16
4
  describe('normalizeParticleEmitterConfig', () => {
17
5
  it('leaves a valid config materially unchanged', () => {
18
6
  const input = createParticleEmitterConfig({ spawnRate: 25, maxParticles: 500, lifetimeMin: 1, lifetimeMax: 2 });
@@ -65,26 +53,6 @@ describe('normalizeParticleEmitterConfig', () => {
65
53
  const issues = validateParticleEmitterConfig(createParticleEmitterConfig({ alphaCurve: [0, NaN, 1] }));
66
54
  expect(issues.some((i) => i.field === 'alphaCurve' && i.severity === 'error')).toBe(true);
67
55
  });
68
-
69
- it('produces a config that simulates without NaN poisoning', () => {
70
- // A pathologically corrupt config that would otherwise inject NaN everywhere.
71
- const corrupt = createParticleEmitterConfig({
72
- spawnRate: NaN,
73
- lifetimeMin: NaN,
74
- lifetimeMax: NaN,
75
- gravityY: Infinity,
76
- speedMin: NaN,
77
- speedMax: NaN,
78
- });
79
- const safe = normalizeParticleEmitterConfig(corrupt);
80
- const emitter = createParticleEmitter({ data: { atlas: makeAtlas() } });
81
- const state = createParticleEmitterState();
82
- for (let i = 0; i < 30; i++) updateParticleEmitter(emitter, state, safe, 1 / 60);
83
- expect(emitter.data.particleCount).toBeGreaterThan(0);
84
- for (let i = 0; i < emitter.data.particleCount * 4; i++) {
85
- expect(Number.isFinite(emitter.data.transforms[i])).toBe(true);
86
- }
87
- });
88
56
  });
89
57
 
90
58
  describe('validateParticleEmitterConfig', () => {
@@ -1,15 +0,0 @@
1
- import type { ParticleEmitter } from '@flighthq/types';
2
- import type { ParticleEmitterConfig, ParticleEmitterState } from '@flighthq/types';
3
- /** Emit `count` particles immediately at an arbitrary point (in the emitter's
4
- * simulation space), independent of the emitter's own spawn rate, bursts, or
5
- * duration. Returns the number actually spawned (capped by `maxParticles`).
6
- *
7
- * This is the building block for sub-emitters: call it from an `onDeath` /
8
- * `onSpawn` callback to spawn a child effect at the event position (explosions,
9
- * debris, impact sparks), or once per live particle for trails. The child
10
- * emitter/state/config are completely independent of the parent.
11
- *
12
- * Spawn randomness is drawn from `state.random`, so a seeded child state keeps
13
- * sub-emitter output deterministic. */
14
- export declare function emitParticleBurst(emitter: ParticleEmitter, state: ParticleEmitterState, config: Readonly<ParticleEmitterConfig>, count: number, x: number, y: number): number;
15
- //# sourceMappingURL=emitParticleBurst.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emitParticleBurst.d.ts","sourceRoot":"","sources":["../src/emitParticleBurst.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAQnF;;;;;;;;;;wCAUwC;AACxC,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,CAqGR"}
@@ -1,114 +0,0 @@
1
- import { reserveParticleEmitter } from '@flighthq/sprite';
2
- import { sampleParticleColorCurve, sampleParticleCurve } from './curve';
3
- import { ensureParticleEmitterStateCapacity } from './particleEmitterState';
4
- const PARTICLE_TRANSFORM_STRIDE = 4;
5
- const TWO_PI = Math.PI * 2;
6
- /** Emit `count` particles immediately at an arbitrary point (in the emitter's
7
- * simulation space), independent of the emitter's own spawn rate, bursts, or
8
- * duration. Returns the number actually spawned (capped by `maxParticles`).
9
- *
10
- * This is the building block for sub-emitters: call it from an `onDeath` /
11
- * `onSpawn` callback to spawn a child effect at the event position (explosions,
12
- * debris, impact sparks), or once per live particle for trails. The child
13
- * emitter/state/config are completely independent of the parent.
14
- *
15
- * Spawn randomness is drawn from `state.random`, so a seeded child state keeps
16
- * sub-emitter output deterministic. */
17
- export function emitParticleBurst(emitter, state, config, count, x, y) {
18
- const data = emitter.data;
19
- const liveCount = data.particleCount;
20
- let toSpawn = Math.floor(count);
21
- const maxNew = config.maxParticles - liveCount;
22
- if (toSpawn > maxNew)
23
- toSpawn = maxNew;
24
- if (toSpawn <= 0)
25
- return 0;
26
- const hasColorVariance = config.colorStartVarianceR !== 0 ||
27
- config.colorStartVarianceG !== 0 ||
28
- config.colorStartVarianceB !== 0 ||
29
- config.colorEndVarianceR !== 0 ||
30
- config.colorEndVarianceG !== 0 ||
31
- config.colorEndVarianceB !== 0;
32
- const newCount = liveCount + toSpawn;
33
- reserveParticleEmitter(emitter, newCount);
34
- ensureParticleEmitterStateCapacity(state, newCount, hasColorVariance);
35
- const { colorStartR, colorStartG, colorStartB, colorEndR, colorEndG, colorEndB } = config;
36
- const alphaCurve = config.alphaCurve;
37
- const colorCurve = config.colorCurve;
38
- const scaleCurve = config.scaleCurve;
39
- const hasAlphaCurve = alphaCurve != null && alphaCurve.length > 0;
40
- const hasColorCurve = colorCurve != null && colorCurve.length >= 3;
41
- const hasScaleCurve = scaleCurve != null && scaleCurve.length > 0;
42
- const baseAngle = Math.atan2(config.directionY, config.directionX);
43
- const regionRange = config.regionIdMax - config.regionIdMin;
44
- const regionIdMin = config.regionIdMin;
45
- const rotSpeedRange = config.rotationSpeedMax - config.rotationSpeedMin;
46
- const hasRotSpeed = config.rotationSpeedMin !== 0 || config.rotationSpeedMax !== 0;
47
- const random = state.random;
48
- for (let sIdx = 0; sIdx < toSpawn; sIdx++) {
49
- const idx = liveCount + sIdx;
50
- const lifetime = config.lifetimeMin + random() * (config.lifetimeMax - config.lifetimeMin);
51
- const lt = idx * 2;
52
- state.lifetimes[lt] = 0;
53
- state.lifetimes[lt + 1] = lifetime;
54
- const angle = baseAngle + (random() - 0.5) * 2 * config.spread;
55
- const speed = config.speedMin + random() * (config.speedMax - config.speedMin);
56
- state.velocities[idx * 2] = Math.cos(angle) * speed;
57
- state.velocities[idx * 2 + 1] = Math.sin(angle) * speed;
58
- // Position = burst point + emitter-shape offset.
59
- let spawnX = x;
60
- let spawnY = y;
61
- if (config.emitterShape === 'circle' && config.emitterRadius > 0) {
62
- const r = Math.sqrt(random()) * config.emitterRadius;
63
- const a = random() * TWO_PI;
64
- spawnX += Math.cos(a) * r;
65
- spawnY += Math.sin(a) * r;
66
- }
67
- else if (config.emitterShape === 'rect' && (config.emitterWidth > 0 || config.emitterHeight > 0)) {
68
- spawnX += (random() - 0.5) * config.emitterWidth;
69
- spawnY += (random() - 0.5) * config.emitterHeight;
70
- }
71
- const spawnScale = config.scaleMin + random() * (config.scaleMax - config.scaleMin);
72
- state.scales[idx] = spawnScale;
73
- const tt = idx * PARTICLE_TRANSFORM_STRIDE;
74
- data.transforms[tt] = spawnX;
75
- data.transforms[tt + 1] = spawnY;
76
- data.transforms[tt + 2] = angle;
77
- data.transforms[tt + 3] = hasScaleCurve ? spawnScale * sampleParticleCurve(scaleCurve, 0) : spawnScale;
78
- data.alphas[idx] = hasAlphaCurve ? sampleParticleCurve(alphaCurve, 0) : config.alphaStart;
79
- const ct = idx * 3;
80
- if (hasColorCurve) {
81
- sampleParticleColorCurve(data.colors, ct, colorCurve, 0);
82
- }
83
- else if (hasColorVariance) {
84
- const r0 = clamp01(colorStartR + (random() - 0.5) * 2 * config.colorStartVarianceR);
85
- const g0 = clamp01(colorStartG + (random() - 0.5) * 2 * config.colorStartVarianceG);
86
- const b0 = clamp01(colorStartB + (random() - 0.5) * 2 * config.colorStartVarianceB);
87
- const r1 = clamp01(colorEndR + (random() - 0.5) * 2 * config.colorEndVarianceR);
88
- const g1 = clamp01(colorEndG + (random() - 0.5) * 2 * config.colorEndVarianceG);
89
- const b1 = clamp01(colorEndB + (random() - 0.5) * 2 * config.colorEndVarianceB);
90
- state.colorBirth[ct] = r0;
91
- state.colorBirth[ct + 1] = g0;
92
- state.colorBirth[ct + 2] = b0;
93
- state.colorDeath[ct] = r1;
94
- state.colorDeath[ct + 1] = g1;
95
- state.colorDeath[ct + 2] = b1;
96
- data.colors[ct] = r0;
97
- data.colors[ct + 1] = g0;
98
- data.colors[ct + 2] = b0;
99
- }
100
- else {
101
- data.colors[ct] = colorStartR;
102
- data.colors[ct + 1] = colorStartG;
103
- data.colors[ct + 2] = colorStartB;
104
- }
105
- data.ids[idx] = regionIdMin + (config.frameCount > 1 ? 0 : regionRange > 0 ? (random() * regionRange) | 0 : 0);
106
- state.rotationSpeeds[idx] = hasRotSpeed ? config.rotationSpeedMin + random() * rotSpeedRange : 0;
107
- }
108
- data.particleCount = newCount;
109
- return toSpawn;
110
- }
111
- function clamp01(v) {
112
- return v < 0 ? 0 : v > 1 ? 1 : v;
113
- }
114
- //# sourceMappingURL=emitParticleBurst.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emitParticleBurst.js","sourceRoot":"","sources":["../src/emitParticleBurst.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,kCAAkC,EAAE,MAAM,wBAAwB,CAAC;AAE5E,MAAM,yBAAyB,GAAG,CAAC,CAAC;AACpC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;;wCAUwC;AACxC,MAAM,UAAU,iBAAiB,CAC/B,OAAwB,EACxB,KAA2B,EAC3B,MAAuC,EACvC,KAAa,EACb,CAAS,EACT,CAAS;IAET,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC;IACrC,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,GAAG,SAAS,CAAC;IAC/C,IAAI,OAAO,GAAG,MAAM;QAAE,OAAO,GAAG,MAAM,CAAC;IACvC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAE3B,MAAM,gBAAgB,GACpB,MAAM,CAAC,mBAAmB,KAAK,CAAC;QAChC,MAAM,CAAC,mBAAmB,KAAK,CAAC;QAChC,MAAM,CAAC,mBAAmB,KAAK,CAAC;QAChC,MAAM,CAAC,iBAAiB,KAAK,CAAC;QAC9B,MAAM,CAAC,iBAAiB,KAAK,CAAC;QAC9B,MAAM,CAAC,iBAAiB,KAAK,CAAC,CAAC;IAEjC,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IACrC,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,kCAAkC,CAAC,KAAK,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAEtE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAC1F,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,MAAM,aAAa,GAAG,UAAU,IAAI,IAAI,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAClE,MAAM,aAAa,GAAG,UAAU,IAAI,IAAI,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;IACnE,MAAM,aAAa,GAAG,UAAU,IAAI,IAAI,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IACnE,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACxE,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,KAAK,CAAC,IAAI,MAAM,CAAC,gBAAgB,KAAK,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAE5B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC;QAE7B,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,GAAG,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3F,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;QACnB,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;QACxB,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;QAEnC,MAAM,KAAK,GAAG,SAAS,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;QAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/E,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QACpD,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;QAExD,iDAAiD;QACjD,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,MAAM,CAAC,YAAY,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YACjE,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC;YACrD,MAAM,CAAC,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC;YAC5B,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,MAAM,CAAC,YAAY,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,CAAC,EAAE,CAAC;YACnG,MAAM,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC;YACjD,MAAM,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC;QACpD,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpF,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;QAE/B,MAAM,EAAE,GAAG,GAAG,GAAG,yBAAyB,CAAC;QAC3C,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;QACjC,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;QAChC,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,UAAU,GAAG,mBAAmB,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACvG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QAE1F,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC;QACnB,IAAI,aAAa,EAAE,CAAC;YAClB,wBAAwB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;QAC3D,CAAC;aAAM,IAAI,gBAAgB,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;YACpF,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;YACpF,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;YACpF,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;YAChF,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;YAChF,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;YAChF,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;YAC1B,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAC9B,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAC9B,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;YAC1B,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAC9B,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/G,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,GAAG,MAAM,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;IACnG,CAAC;IAED,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;IAC9B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC"}
@@ -1,5 +0,0 @@
1
- import type { ParticleEmitter } from '@flighthq/types';
2
- import type { ParticleEmitterConfig, ParticleEmitterState } from '@flighthq/types';
3
- import type { ParticleEmitterCallbacks, WorldTransform2D } from './updateParticleEmitter';
4
- export declare function prewarmParticleEmitter(emitter: ParticleEmitter, state: ParticleEmitterState, config: Readonly<ParticleEmitterConfig>, duration: number, stepDeltaTime?: number, callbacks?: ParticleEmitterCallbacks, worldTransform?: Readonly<WorldTransform2D>): void;
5
- //# sourceMappingURL=prewarmParticleEmitter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prewarmParticleEmitter.d.ts","sourceRoot":"","sources":["../src/prewarmParticleEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEnF,OAAO,KAAK,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG1F,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,aAAa,SAAS,EACtB,SAAS,CAAC,EAAE,wBAAwB,EACpC,cAAc,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAC1C,IAAI,CAUN"}
@@ -1,13 +0,0 @@
1
- import { updateParticleEmitter } from './updateParticleEmitter';
2
- export function prewarmParticleEmitter(emitter, state, config, duration, stepDeltaTime = 1 / 60, callbacks, worldTransform) {
3
- // A non-positive step would never advance `elapsed`, spinning forever; fall back
4
- // to a single step covering the whole duration instead of hanging.
5
- const step = stepDeltaTime > 0 ? stepDeltaTime : duration;
6
- let elapsed = 0;
7
- while (elapsed < duration) {
8
- const deltaTime = Math.min(step, duration - elapsed);
9
- updateParticleEmitter(emitter, state, config, deltaTime, callbacks, worldTransform);
10
- elapsed += deltaTime;
11
- }
12
- }
13
- //# sourceMappingURL=prewarmParticleEmitter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prewarmParticleEmitter.js","sourceRoot":"","sources":["../src/prewarmParticleEmitter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,UAAU,sBAAsB,CACpC,OAAwB,EACxB,KAA2B,EAC3B,MAAuC,EACvC,QAAgB,EAChB,aAAa,GAAG,CAAC,GAAG,EAAE,EACtB,SAAoC,EACpC,cAA2C;IAE3C,iFAAiF;IACjF,mEAAmE;IACnE,MAAM,IAAI,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1D,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,OAAO,OAAO,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC;QACrD,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;QACpF,OAAO,IAAI,SAAS,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -1,38 +0,0 @@
1
- import type { ParticleCollider, ParticleEmitter, ParticleEmitterCallbacks, ParticleEmitterConfig, ParticleEmitterState, ParticleForce, ParticleObject, ParticleObjectsState, ParticleObjectsUpdateOptions, WorldTransform2D } from '@flighthq/types';
2
- /**
3
- * Convenience wrapper for the SoA typed-array emitter that folds the canonical three-step update
4
- * sequence — `applyParticleForces` → `updateParticleEmitter` → `applyParticleCollisions` — into a
5
- * single call.
6
- *
7
- * The three primitives remain exported for advanced use (custom interleaving, per-force-group
8
- * timing, etc.). Use this function for the common case where all forces and colliders apply each
9
- * frame in the documented order.
10
- *
11
- * @param emitter - The SoA particle emitter node.
12
- * @param state - Mutable per-emitter simulation state.
13
- * @param config - Immutable emitter configuration.
14
- * @param deltaTime - Elapsed time in seconds since the last step.
15
- * @param forces - Optional force fields to apply before integration (e.g. wind, attractor).
16
- * @param colliders - Optional colliders to resolve after integration (e.g. plane, circle).
17
- * @param callbacks - Optional spawn/death callbacks.
18
- * @param worldTransform - World-space transform for world-space emitters.
19
- */
20
- export declare function stepParticleEmitter(emitter: ParticleEmitter, state: ParticleEmitterState, config: Readonly<ParticleEmitterConfig>, deltaTime: number, forces?: ReadonlyArray<ParticleForce>, colliders?: ReadonlyArray<ParticleCollider>, callbacks?: ParticleEmitterCallbacks, worldTransform?: Readonly<WorldTransform2D>): void;
21
- /**
22
- * Convenience wrapper for the object-pool path that folds the canonical three-step update sequence
23
- * — `applyParticleObjectForces` → `updateParticleObjects` → `applyParticleObjectCollisions` — into
24
- * a single call.
25
- *
26
- * The three primitives remain exported for advanced use. Use this function for the common case
27
- * where all forces and colliders apply each frame in the documented order.
28
- *
29
- * @param objects - The particle object pool (one display object per slot).
30
- * @param state - Mutable per-emitter simulation state.
31
- * @param config - Immutable emitter configuration.
32
- * @param deltaTime - Elapsed time in seconds since the last step.
33
- * @param forces - Optional force fields to apply before integration.
34
- * @param colliders - Optional colliders to resolve after integration.
35
- * @param updateOptions - Optional emitter position, callbacks, and other per-frame options.
36
- */
37
- export declare function stepParticleObjects(objects: readonly ParticleObject[], state: ParticleObjectsState, config: Readonly<ParticleEmitterConfig>, deltaTime: number, forces?: ReadonlyArray<ParticleForce>, colliders?: ReadonlyArray<ParticleCollider>, updateOptions?: ParticleObjectsUpdateOptions): void;
38
- //# sourceMappingURL=stepParticleEmitter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stepParticleEmitter.d.ts","sourceRoot":"","sources":["../src/stepParticleEmitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AAOzB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EACvC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,EACrC,SAAS,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,EAC3C,SAAS,CAAC,EAAE,wBAAwB,EACpC,cAAc,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAC1C,IAAI,CAQN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EACvC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,EACrC,SAAS,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,EAC3C,aAAa,CAAC,EAAE,4BAA4B,GAC3C,IAAI,CAQN"}
@@ -1,57 +0,0 @@
1
- import { applyParticleCollisions, applyParticleObjectCollisions } from './applyParticleCollisions';
2
- import { applyParticleForces, applyParticleObjectForces } from './applyParticleForces';
3
- import { updateParticleEmitter } from './updateParticleEmitter';
4
- import { updateParticleObjects } from './updateParticleObjects';
5
- /**
6
- * Convenience wrapper for the SoA typed-array emitter that folds the canonical three-step update
7
- * sequence — `applyParticleForces` → `updateParticleEmitter` → `applyParticleCollisions` — into a
8
- * single call.
9
- *
10
- * The three primitives remain exported for advanced use (custom interleaving, per-force-group
11
- * timing, etc.). Use this function for the common case where all forces and colliders apply each
12
- * frame in the documented order.
13
- *
14
- * @param emitter - The SoA particle emitter node.
15
- * @param state - Mutable per-emitter simulation state.
16
- * @param config - Immutable emitter configuration.
17
- * @param deltaTime - Elapsed time in seconds since the last step.
18
- * @param forces - Optional force fields to apply before integration (e.g. wind, attractor).
19
- * @param colliders - Optional colliders to resolve after integration (e.g. plane, circle).
20
- * @param callbacks - Optional spawn/death callbacks.
21
- * @param worldTransform - World-space transform for world-space emitters.
22
- */
23
- export function stepParticleEmitter(emitter, state, config, deltaTime, forces, colliders, callbacks, worldTransform) {
24
- if (forces != null && forces.length > 0) {
25
- applyParticleForces(emitter, state, forces, deltaTime);
26
- }
27
- updateParticleEmitter(emitter, state, config, deltaTime, callbacks, worldTransform);
28
- if (colliders != null && colliders.length > 0) {
29
- applyParticleCollisions(emitter, state, colliders);
30
- }
31
- }
32
- /**
33
- * Convenience wrapper for the object-pool path that folds the canonical three-step update sequence
34
- * — `applyParticleObjectForces` → `updateParticleObjects` → `applyParticleObjectCollisions` — into
35
- * a single call.
36
- *
37
- * The three primitives remain exported for advanced use. Use this function for the common case
38
- * where all forces and colliders apply each frame in the documented order.
39
- *
40
- * @param objects - The particle object pool (one display object per slot).
41
- * @param state - Mutable per-emitter simulation state.
42
- * @param config - Immutable emitter configuration.
43
- * @param deltaTime - Elapsed time in seconds since the last step.
44
- * @param forces - Optional force fields to apply before integration.
45
- * @param colliders - Optional colliders to resolve after integration.
46
- * @param updateOptions - Optional emitter position, callbacks, and other per-frame options.
47
- */
48
- export function stepParticleObjects(objects, state, config, deltaTime, forces, colliders, updateOptions) {
49
- if (forces != null && forces.length > 0) {
50
- applyParticleObjectForces(objects, state, forces, deltaTime);
51
- }
52
- updateParticleObjects(objects, state, config, deltaTime, updateOptions);
53
- if (colliders != null && colliders.length > 0) {
54
- applyParticleObjectCollisions(objects, state, colliders);
55
- }
56
- }
57
- //# sourceMappingURL=stepParticleEmitter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stepParticleEmitter.js","sourceRoot":"","sources":["../src/stepParticleEmitter.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAwB,EACxB,KAA2B,EAC3B,MAAuC,EACvC,SAAiB,EACjB,MAAqC,EACrC,SAA2C,EAC3C,SAAoC,EACpC,cAA2C;IAE3C,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IACzD,CAAC;IACD,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IACpF,IAAI,SAAS,IAAI,IAAI,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,uBAAuB,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAkC,EAClC,KAA2B,EAC3B,MAAuC,EACvC,SAAiB,EACjB,MAAqC,EACrC,SAA2C,EAC3C,aAA4C;IAE5C,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,yBAAyB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IACD,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;IACxE,IAAI,SAAS,IAAI,IAAI,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,6BAA6B,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { ParticleEmitter, ParticleEmitterCallbacks, ParticleEmitterConfig, ParticleEmitterState, WorldTransform2D } from '@flighthq/types';
2
- export type { ParticleEmitterCallbacks, WorldTransform2D };
3
- /** True once a finite, non-looping emitter has finished emitting AND all of its
4
- * particles have died — i.e. a one-shot effect that is safe to recycle/remove.
5
- * Always false for infinite or looping emitters (they never finish). */
6
- export declare function isParticleEmitterComplete(emitter: ParticleEmitter, state: Readonly<ParticleEmitterState>, config: Readonly<ParticleEmitterConfig>): boolean;
7
- export declare function updateParticleEmitter(emitter: ParticleEmitter, state: ParticleEmitterState, config: Readonly<ParticleEmitterConfig>, deltaTime: number, callbacks?: ParticleEmitterCallbacks, worldTransform?: Readonly<WorldTransform2D>): void;
8
- //# sourceMappingURL=updateParticleEmitter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"updateParticleEmitter.d.ts","sourceRoot":"","sources":["../src/updateParticleEmitter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AAMzB,YAAY,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,CAAC;AAK3D;;yEAEyE;AACzE,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,EACrC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GACtC,OAAO,CAGT;AAQD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EACvC,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,wBAAwB,EACpC,cAAc,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAC1C,IAAI,CAgUN"}