@flighthq/particles 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 (71) hide show
  1. package/dist/applyParticleCollisions.d.ts +12 -0
  2. package/dist/applyParticleCollisions.d.ts.map +1 -0
  3. package/dist/applyParticleCollisions.js +175 -0
  4. package/dist/applyParticleCollisions.js.map +1 -0
  5. package/dist/applyParticleForces.d.ts +13 -0
  6. package/dist/applyParticleForces.d.ts.map +1 -0
  7. package/dist/applyParticleForces.js +129 -0
  8. package/dist/applyParticleForces.js.map +1 -0
  9. package/dist/curve.d.ts +35 -0
  10. package/dist/curve.d.ts.map +1 -0
  11. package/dist/curve.js +227 -0
  12. package/dist/curve.js.map +1 -0
  13. package/dist/emitParticleBurst.d.ts +15 -0
  14. package/dist/emitParticleBurst.d.ts.map +1 -0
  15. package/dist/emitParticleBurst.js +114 -0
  16. package/dist/emitParticleBurst.js.map +1 -0
  17. package/dist/index.d.ts +14 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +14 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/particleEmitterConfig.d.ts +4 -0
  22. package/dist/particleEmitterConfig.d.ts.map +1 -0
  23. package/dist/particleEmitterConfig.js +53 -0
  24. package/dist/particleEmitterConfig.js.map +1 -0
  25. package/dist/particleEmitterSignals.d.ts +20 -0
  26. package/dist/particleEmitterSignals.d.ts.map +1 -0
  27. package/dist/particleEmitterSignals.js +33 -0
  28. package/dist/particleEmitterSignals.js.map +1 -0
  29. package/dist/particleEmitterState.d.ts +7 -0
  30. package/dist/particleEmitterState.d.ts.map +1 -0
  31. package/dist/particleEmitterState.js +38 -0
  32. package/dist/particleEmitterState.js.map +1 -0
  33. package/dist/particleObjectsState.d.ts +4 -0
  34. package/dist/particleObjectsState.d.ts.map +1 -0
  35. package/dist/particleObjectsState.js +24 -0
  36. package/dist/particleObjectsState.js.map +1 -0
  37. package/dist/prewarmParticleEmitter.d.ts +5 -0
  38. package/dist/prewarmParticleEmitter.d.ts.map +1 -0
  39. package/dist/prewarmParticleEmitter.js +13 -0
  40. package/dist/prewarmParticleEmitter.js.map +1 -0
  41. package/dist/stepParticleEmitter.d.ts +38 -0
  42. package/dist/stepParticleEmitter.d.ts.map +1 -0
  43. package/dist/stepParticleEmitter.js +57 -0
  44. package/dist/stepParticleEmitter.js.map +1 -0
  45. package/dist/updateParticleEmitter.d.ts +8 -0
  46. package/dist/updateParticleEmitter.d.ts.map +1 -0
  47. package/dist/updateParticleEmitter.js +315 -0
  48. package/dist/updateParticleEmitter.js.map +1 -0
  49. package/dist/updateParticleObjects.d.ts +8 -0
  50. package/dist/updateParticleObjects.d.ts.map +1 -0
  51. package/dist/updateParticleObjects.js +151 -0
  52. package/dist/updateParticleObjects.js.map +1 -0
  53. package/dist/validateParticleEmitterConfig.d.ts +15 -0
  54. package/dist/validateParticleEmitterConfig.d.ts.map +1 -0
  55. package/dist/validateParticleEmitterConfig.js +206 -0
  56. package/dist/validateParticleEmitterConfig.js.map +1 -0
  57. package/package.json +42 -0
  58. package/src/applyParticleCollisions.test.ts +191 -0
  59. package/src/applyParticleForces.test.ts +174 -0
  60. package/src/curve.test.ts +327 -0
  61. package/src/deterministic.test.ts +54 -0
  62. package/src/emitParticleBurst.test.ts +103 -0
  63. package/src/particleEmitterConfig.test.ts +65 -0
  64. package/src/particleEmitterSignals.test.ts +125 -0
  65. package/src/particleEmitterState.test.ts +113 -0
  66. package/src/particleObjectsState.test.ts +34 -0
  67. package/src/prewarmParticleEmitter.test.ts +68 -0
  68. package/src/stepParticleEmitter.test.ts +113 -0
  69. package/src/updateParticleEmitter.test.ts +631 -0
  70. package/src/updateParticleObjects.test.ts +340 -0
  71. package/src/validateParticleEmitterConfig.test.ts +118 -0
@@ -0,0 +1,315 @@
1
+ import { invalidateNodeLocalBounds } from '@flighthq/node';
2
+ import { reserveParticleEmitter } from '@flighthq/sprite';
3
+ import { sampleParticleColorCurve, sampleParticleCurve } from './curve';
4
+ import { getParticleEmitterSignals } from './particleEmitterSignals';
5
+ import { ensureParticleEmitterStateCapacity } from './particleEmitterState';
6
+ const PARTICLE_TRANSFORM_STRIDE = 4; // must match scene-sprite/particleEmitter.ts
7
+ const TWO_PI = Math.PI * 2;
8
+ /** True once a finite, non-looping emitter has finished emitting AND all of its
9
+ * particles have died — i.e. a one-shot effect that is safe to recycle/remove.
10
+ * Always false for infinite or looping emitters (they never finish). */
11
+ export function isParticleEmitterComplete(emitter, state, config) {
12
+ if (config.duration <= 0 || config.loop)
13
+ return false;
14
+ return state.emitterAge >= config.duration && emitter.data.particleCount === 0;
15
+ }
16
+ /** Whether an emitter with the given config is still spawning, given how long it
17
+ * has been emitting. Infinite (duration <= 0) and looping emitters always emit. */
18
+ function isEmitting(config, emitterAge) {
19
+ return config.duration <= 0 || config.loop || emitterAge < config.duration;
20
+ }
21
+ export function updateParticleEmitter(emitter, state, config, deltaTime, callbacks, worldTransform) {
22
+ const data = emitter.data;
23
+ // Sync world-space flag to data so renderers can read it.
24
+ data.worldSpace = config.worldSpace;
25
+ // Guard against a zero or negative time step: no time has elapsed, so there is
26
+ // nothing to age, move, or spawn. Critically, this avoids dividing by deltaTime when
27
+ // computing emitter velocity below — a zero-deltaTime frame that still fires a burst
28
+ // would otherwise bake Infinity/NaN velocities into freshly spawned particles
29
+ // and corrupt them for the rest of their lifetime.
30
+ if (deltaTime <= 0)
31
+ return;
32
+ // ── Emitter velocity (for velocity inheritance and trail interpolation) ───────
33
+ // In world-space mode we track the world origin; in local-space mode we track
34
+ // the emitter node position in parent space.
35
+ const trackX = config.worldSpace && worldTransform != null ? worldTransform.tx : emitter.x;
36
+ const trackY = config.worldSpace && worldTransform != null ? worldTransform.ty : emitter.y;
37
+ const hasVelInherit = config.velocityInheritance !== 0;
38
+ let emitterVelX = 0;
39
+ let emitterVelY = 0;
40
+ if (!isNaN(state.prevX)) {
41
+ emitterVelX = (trackX - state.prevX) / deltaTime;
42
+ emitterVelY = (trackY - state.prevY) / deltaTime;
43
+ }
44
+ // ── Phase 1: age all live particles, compact dead ones ──────────────────────
45
+ const lifetimes = state.lifetimes;
46
+ const velocities = state.velocities;
47
+ const scales = state.scales;
48
+ const rotationSpeeds = state.rotationSpeeds;
49
+ const gx = config.gravityX * deltaTime;
50
+ const gy = config.gravityY * deltaTime;
51
+ const { colorStartR, colorStartG, colorStartB, colorEndR, colorEndG, colorEndB } = config;
52
+ const hasColorVariance = config.colorStartVarianceR !== 0 ||
53
+ config.colorStartVarianceG !== 0 ||
54
+ config.colorStartVarianceB !== 0 ||
55
+ config.colorEndVarianceR !== 0 ||
56
+ config.colorEndVarianceG !== 0 ||
57
+ config.colorEndVarianceB !== 0;
58
+ const hasColorGradient = hasColorVariance || colorStartR !== colorEndR || colorStartG !== colorEndG || colorStartB !== colorEndB;
59
+ // Opt-in lifetime curves override the linear paths below; an emitter without
60
+ // curves never touches these branches beyond a predicted-not-taken check.
61
+ const alphaCurve = config.alphaCurve;
62
+ const colorCurve = config.colorCurve;
63
+ const scaleCurve = config.scaleCurve;
64
+ const hasAlphaCurve = alphaCurve != null && alphaCurve.length > 0;
65
+ const hasColorCurve = colorCurve != null && colorCurve.length >= 3;
66
+ const hasScaleCurve = scaleCurve != null && scaleCurve.length > 0;
67
+ const hasScaleAnim = config.scaleEnd !== 1 || hasScaleCurve;
68
+ const hasColorWork = hasColorCurve || hasColorGradient;
69
+ const hasRotationSpeed = config.rotationSpeedMin !== 0 || config.rotationSpeedMax !== 0;
70
+ const hasFlipbook = config.frameCount > 1;
71
+ const onDeath = callbacks?.onDeath;
72
+ const onSpawn = callbacks?.onSpawn;
73
+ // Opt-in signals: null when enableParticleEmitterSignals has not been called on this state.
74
+ const signals = getParticleEmitterSignals(state);
75
+ let liveCount = data.particleCount;
76
+ let i = 0;
77
+ while (i < liveCount) {
78
+ const lt = i * 2;
79
+ lifetimes[lt] += deltaTime;
80
+ if (lifetimes[lt] >= lifetimes[lt + 1]) {
81
+ if (onDeath !== undefined || signals !== null) {
82
+ const tt = i * PARTICLE_TRANSFORM_STRIDE;
83
+ const dx = data.transforms[tt];
84
+ const dy = data.transforms[tt + 1];
85
+ onDeath?.(dx, dy);
86
+ signals?.onParticleDeath.emit(dx, dy);
87
+ }
88
+ liveCount--;
89
+ if (i < liveCount) {
90
+ const lt2 = liveCount * 2;
91
+ lifetimes[lt] = lifetimes[lt2];
92
+ lifetimes[lt + 1] = lifetimes[lt2 + 1];
93
+ const vt = i * 2;
94
+ const vt2 = liveCount * 2;
95
+ velocities[vt] = velocities[vt2];
96
+ velocities[vt + 1] = velocities[vt2 + 1];
97
+ const tt = i * PARTICLE_TRANSFORM_STRIDE;
98
+ const tt2 = liveCount * PARTICLE_TRANSFORM_STRIDE;
99
+ data.transforms[tt] = data.transforms[tt2];
100
+ data.transforms[tt + 1] = data.transforms[tt2 + 1];
101
+ data.transforms[tt + 2] = data.transforms[tt2 + 2];
102
+ data.transforms[tt + 3] = data.transforms[tt2 + 3];
103
+ data.alphas[i] = data.alphas[liveCount];
104
+ data.ids[i] = data.ids[liveCount];
105
+ const ct = i * 3;
106
+ const ct2 = liveCount * 3;
107
+ data.colors[ct] = data.colors[ct2];
108
+ data.colors[ct + 1] = data.colors[ct2 + 1];
109
+ data.colors[ct + 2] = data.colors[ct2 + 2];
110
+ scales[i] = scales[liveCount];
111
+ rotationSpeeds[i] = rotationSpeeds[liveCount];
112
+ if (hasColorVariance) {
113
+ state.colorBirth[ct] = state.colorBirth[ct2];
114
+ state.colorBirth[ct + 1] = state.colorBirth[ct2 + 1];
115
+ state.colorBirth[ct + 2] = state.colorBirth[ct2 + 2];
116
+ state.colorDeath[ct] = state.colorDeath[ct2];
117
+ state.colorDeath[ct + 1] = state.colorDeath[ct2 + 1];
118
+ state.colorDeath[ct + 2] = state.colorDeath[ct2 + 2];
119
+ }
120
+ }
121
+ continue;
122
+ }
123
+ const vt = i * 2;
124
+ velocities[vt] += gx;
125
+ velocities[vt + 1] += gy;
126
+ const tt = i * PARTICLE_TRANSFORM_STRIDE;
127
+ data.transforms[tt] += velocities[vt] * deltaTime;
128
+ data.transforms[tt + 1] += velocities[vt + 1] * deltaTime;
129
+ const lifeFraction = lifetimes[lt] / lifetimes[lt + 1];
130
+ data.alphas[i] = hasAlphaCurve
131
+ ? sampleParticleCurve(alphaCurve, lifeFraction)
132
+ : config.alphaStart + (config.alphaEnd - config.alphaStart) * lifeFraction;
133
+ if (hasColorWork) {
134
+ const ct = i * 3;
135
+ if (hasColorCurve) {
136
+ sampleParticleColorCurve(data.colors, ct, colorCurve, lifeFraction);
137
+ }
138
+ else if (hasColorVariance) {
139
+ data.colors[ct] = state.colorBirth[ct] + (state.colorDeath[ct] - state.colorBirth[ct]) * lifeFraction;
140
+ data.colors[ct + 1] =
141
+ state.colorBirth[ct + 1] + (state.colorDeath[ct + 1] - state.colorBirth[ct + 1]) * lifeFraction;
142
+ data.colors[ct + 2] =
143
+ state.colorBirth[ct + 2] + (state.colorDeath[ct + 2] - state.colorBirth[ct + 2]) * lifeFraction;
144
+ }
145
+ else {
146
+ data.colors[ct] = colorStartR + (colorEndR - colorStartR) * lifeFraction;
147
+ data.colors[ct + 1] = colorStartG + (colorEndG - colorStartG) * lifeFraction;
148
+ data.colors[ct + 2] = colorStartB + (colorEndB - colorStartB) * lifeFraction;
149
+ }
150
+ }
151
+ if (hasScaleAnim) {
152
+ const scaleFactor = hasScaleCurve
153
+ ? sampleParticleCurve(scaleCurve, lifeFraction)
154
+ : 1 + (config.scaleEnd - 1) * lifeFraction;
155
+ data.transforms[tt + 3] = scales[i] * scaleFactor;
156
+ }
157
+ if (hasRotationSpeed) {
158
+ data.transforms[tt + 2] += rotationSpeeds[i] * deltaTime;
159
+ }
160
+ if (hasFlipbook) {
161
+ const frame = Math.floor(lifetimes[lt] * config.frameRate) % config.frameCount;
162
+ data.ids[i] = config.regionIdMin + frame;
163
+ }
164
+ i++;
165
+ }
166
+ data.particleCount = liveCount;
167
+ // ── Phase 2: spawn new particles ─────────────────────────────────────────────
168
+ // A finite, non-looping emitter stops spawning once its duration elapses;
169
+ // existing particles keep ageing out (use isParticleEmitterComplete to detect the end).
170
+ const emitting = isEmitting(config, state.emitterAge);
171
+ if (config.duration > 0 && !config.loop)
172
+ state.emitterAge += deltaTime;
173
+ state.spawnAccumulator += emitting ? config.spawnRate * deltaTime : 0;
174
+ let toSpawn = Math.floor(state.spawnAccumulator);
175
+ state.spawnAccumulator -= toSpawn;
176
+ if (emitting && config.burstCount > 0) {
177
+ state.burstTimer -= deltaTime;
178
+ if (state.burstTimer <= 0) {
179
+ toSpawn += config.burstCount;
180
+ state.burstTimer = config.burstInterval > 0 ? config.burstInterval : Infinity;
181
+ }
182
+ }
183
+ const maxNew = config.maxParticles - liveCount;
184
+ if (toSpawn > maxNew)
185
+ toSpawn = maxNew;
186
+ if (toSpawn > 0) {
187
+ const newCount = liveCount + toSpawn;
188
+ reserveParticleEmitter(emitter, newCount);
189
+ ensureParticleEmitterStateCapacity(state, newCount, hasColorVariance);
190
+ const baseAngle = Math.atan2(config.directionY, config.directionX);
191
+ const regionRange = config.regionIdMax - config.regionIdMin;
192
+ const regionIdMin = config.regionIdMin;
193
+ const rotSpeedRange = config.rotationSpeedMax - config.rotationSpeedMin;
194
+ const hasRotSpeed = config.rotationSpeedMin !== 0 || config.rotationSpeedMax !== 0;
195
+ // World-space trail: distribute spawn origins along the path from prevPos → currentPos.
196
+ const doTrail = config.worldSpace && worldTransform != null && !isNaN(state.prevX);
197
+ const prevPathX = doTrail ? state.prevX : trackX;
198
+ const prevPathY = doTrail ? state.prevY : trackY;
199
+ for (let s = 0; s < toSpawn; s++) {
200
+ const idx = liveCount + s;
201
+ // Lifetime
202
+ const lifetime = config.lifetimeMin + state.random() * (config.lifetimeMax - config.lifetimeMin);
203
+ const lt = idx * 2;
204
+ state.lifetimes[lt] = 0;
205
+ state.lifetimes[lt + 1] = lifetime;
206
+ // Velocity direction in local/emitter space
207
+ const angle = baseAngle + (state.random() - 0.5) * 2 * config.spread;
208
+ const speed = config.speedMin + state.random() * (config.speedMax - config.speedMin);
209
+ let vx = Math.cos(angle) * speed;
210
+ let vy = Math.sin(angle) * speed;
211
+ // Spawn position (local to emitter, or shape offset)
212
+ let spawnX = 0;
213
+ let spawnY = 0;
214
+ if (config.emitterShape === 'circle' && config.emitterRadius > 0) {
215
+ const r = Math.sqrt(state.random()) * config.emitterRadius;
216
+ const a = state.random() * TWO_PI;
217
+ spawnX = Math.cos(a) * r;
218
+ spawnY = Math.sin(a) * r;
219
+ }
220
+ else if (config.emitterShape === 'rect' && (config.emitterWidth > 0 || config.emitterHeight > 0)) {
221
+ spawnX = (state.random() - 0.5) * config.emitterWidth;
222
+ spawnY = (state.random() - 0.5) * config.emitterHeight;
223
+ }
224
+ // World-space: transform spawn position and velocity into world space,
225
+ // and distribute origins along the emitter's movement path (trail interpolation).
226
+ if (config.worldSpace && worldTransform != null) {
227
+ const wt = worldTransform;
228
+ // Trail: interpolate origin between prev and current world position
229
+ const t = toSpawn > 1 ? s / (toSpawn - 1) : 1;
230
+ const originX = prevPathX + (trackX - prevPathX) * t;
231
+ const originY = prevPathY + (trackY - prevPathY) * t;
232
+ // Apply rotation+scale of world transform to shape offset, then add trail origin
233
+ const wx = wt.a * spawnX + wt.c * spawnY + originX;
234
+ const wy = wt.b * spawnX + wt.d * spawnY + originY;
235
+ spawnX = wx;
236
+ spawnY = wy;
237
+ // Rotate velocity by world transform (no translation for vectors)
238
+ const wvx = wt.a * vx + wt.c * vy;
239
+ const wvy = wt.b * vx + wt.d * vy;
240
+ vx = wvx;
241
+ vy = wvy;
242
+ }
243
+ // Velocity inheritance: blend emitter velocity into new particle velocity
244
+ if (hasVelInherit && !isNaN(state.prevX)) {
245
+ vx += emitterVelX * config.velocityInheritance;
246
+ vy += emitterVelY * config.velocityInheritance;
247
+ }
248
+ const vt = idx * 2;
249
+ state.velocities[vt] = vx;
250
+ state.velocities[vt + 1] = vy;
251
+ const spawnScale = config.scaleMin + state.random() * (config.scaleMax - config.scaleMin);
252
+ state.scales[idx] = spawnScale;
253
+ const tt = idx * PARTICLE_TRANSFORM_STRIDE;
254
+ data.transforms[tt] = spawnX;
255
+ data.transforms[tt + 1] = spawnY;
256
+ data.transforms[tt + 2] = angle;
257
+ data.transforms[tt + 3] = hasScaleCurve ? spawnScale * sampleParticleCurve(scaleCurve, 0) : spawnScale;
258
+ data.alphas[idx] = hasAlphaCurve ? sampleParticleCurve(alphaCurve, 0) : config.alphaStart;
259
+ // Color — curve takes precedence, then per-particle variance, then constants
260
+ const ct = idx * 3;
261
+ if (hasColorCurve) {
262
+ sampleParticleColorCurve(data.colors, ct, colorCurve, 0);
263
+ }
264
+ else if (hasColorVariance) {
265
+ const r0 = clamp01(colorStartR + (state.random() - 0.5) * 2 * config.colorStartVarianceR);
266
+ const g0 = clamp01(colorStartG + (state.random() - 0.5) * 2 * config.colorStartVarianceG);
267
+ const b0 = clamp01(colorStartB + (state.random() - 0.5) * 2 * config.colorStartVarianceB);
268
+ const r1 = clamp01(colorEndR + (state.random() - 0.5) * 2 * config.colorEndVarianceR);
269
+ const g1 = clamp01(colorEndG + (state.random() - 0.5) * 2 * config.colorEndVarianceG);
270
+ const b1 = clamp01(colorEndB + (state.random() - 0.5) * 2 * config.colorEndVarianceB);
271
+ state.colorBirth[ct] = r0;
272
+ state.colorBirth[ct + 1] = g0;
273
+ state.colorBirth[ct + 2] = b0;
274
+ state.colorDeath[ct] = r1;
275
+ state.colorDeath[ct + 1] = g1;
276
+ state.colorDeath[ct + 2] = b1;
277
+ data.colors[ct] = r0;
278
+ data.colors[ct + 1] = g0;
279
+ data.colors[ct + 2] = b0;
280
+ }
281
+ else {
282
+ data.colors[ct] = colorStartR;
283
+ data.colors[ct + 1] = colorStartG;
284
+ data.colors[ct + 2] = colorStartB;
285
+ }
286
+ data.ids[idx] =
287
+ regionIdMin + (config.frameCount > 1 ? 0 : regionRange > 0 ? (state.random() * regionRange) | 0 : 0);
288
+ state.rotationSpeeds[idx] = hasRotSpeed ? config.rotationSpeedMin + state.random() * rotSpeedRange : 0;
289
+ onSpawn?.(spawnX, spawnY);
290
+ if (signals !== null) {
291
+ signals.onParticleSpawn.emit(spawnX, spawnY, state.velocities[vt], state.velocities[vt + 1]);
292
+ }
293
+ }
294
+ data.particleCount = newCount;
295
+ }
296
+ // Update prev-position tracking for next frame.
297
+ state.prevX = trackX;
298
+ state.prevY = trackY;
299
+ // Mirror the live per-particle velocities into the render data so the velocity G-buffer writer can
300
+ // smear each particle by its own vector. state.velocities is kept aligned with data.transforms by the
301
+ // compaction above, so the leading particleCount entries are the live particles in render order.
302
+ const liveVelocityCount = data.particleCount * 2;
303
+ if (data.velocities.length >= liveVelocityCount) {
304
+ data.velocities.set(state.velocities.subarray(0, liveVelocityCount));
305
+ }
306
+ // Fire onEmitterComplete when a finite emitter has just finished and all particles are gone.
307
+ if (signals !== null && isParticleEmitterComplete(emitter, state, config)) {
308
+ signals.onEmitterComplete.emit();
309
+ }
310
+ invalidateNodeLocalBounds(emitter);
311
+ }
312
+ function clamp01(v) {
313
+ return v < 0 ? 0 : v > 1 ? 1 : v;
314
+ }
315
+ //# sourceMappingURL=updateParticleEmitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateParticleEmitter.js","sourceRoot":"","sources":["../src/updateParticleEmitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ParticleEmitterConfig, ParticleObject, ParticleObjectsState, ParticleObjectsUpdateOptions } from '@flighthq/types';
2
+ export type { ParticleObject, ParticleObjectsUpdateOptions };
3
+ /** True once a finite, non-looping object emitter has finished emitting AND all of
4
+ * its objects are dead (invisible) — a one-shot effect that is safe to recycle.
5
+ * Always false for infinite or looping emitters (they never finish). */
6
+ export declare function isParticleObjectsComplete(objects: readonly ParticleObject[], state: Readonly<ParticleObjectsState>, config: Readonly<ParticleEmitterConfig>): boolean;
7
+ export declare function updateParticleObjects(objects: readonly ParticleObject[], state: ParticleObjectsState, config: Readonly<ParticleEmitterConfig>, deltaTime: number, options?: ParticleObjectsUpdateOptions): void;
8
+ //# sourceMappingURL=updateParticleObjects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateParticleObjects.d.ts","sourceRoot":"","sources":["../src/updateParticleObjects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,4BAA4B,EAC7B,MAAM,iBAAiB,CAAC;AAKzB,YAAY,EAAE,cAAc,EAAE,4BAA4B,EAAE,CAAC;AAI7D;;yEAEyE;AACzE,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,EACrC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GACtC,OAAO,CAOT;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EACvC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,4BAA4B,GACrC,IAAI,CA4IN"}
@@ -0,0 +1,151 @@
1
+ import { sampleParticleCurve } from './curve';
2
+ import { ensureParticleObjectsStateCapacity } from './particleObjectsState';
3
+ const TWO_PI = Math.PI * 2;
4
+ /** True once a finite, non-looping object emitter has finished emitting AND all of
5
+ * its objects are dead (invisible) — a one-shot effect that is safe to recycle.
6
+ * Always false for infinite or looping emitters (they never finish). */
7
+ export function isParticleObjectsComplete(objects, state, config) {
8
+ if (config.duration <= 0 || config.loop)
9
+ return false;
10
+ if (state.emitterAge < config.duration)
11
+ return false;
12
+ for (let i = 0; i < objects.length; i++) {
13
+ if (objects[i].visible)
14
+ return false;
15
+ }
16
+ return true;
17
+ }
18
+ export function updateParticleObjects(objects, state, config, deltaTime, options) {
19
+ const n = objects.length;
20
+ if (n === 0)
21
+ return;
22
+ // Skip zero/negative time steps: nothing to simulate, and it avoids dividing by
23
+ // deltaTime for velocity inheritance (which would otherwise produce Infinity/NaN
24
+ // velocities on a zero-deltaTime frame and permanently corrupt spawned objects).
25
+ if (deltaTime <= 0)
26
+ return;
27
+ ensureParticleObjectsStateCapacity(state, n);
28
+ const { lifetimes, velocities, scales, rotationSpeeds } = state;
29
+ const gx = config.gravityX * deltaTime;
30
+ const gy = config.gravityY * deltaTime;
31
+ // Opt-in lifetime curves (objects have alpha + scale; color lives on the
32
+ // typed-array emitter). Absent curves keep the original linear path.
33
+ const alphaCurve = config.alphaCurve;
34
+ const scaleCurve = config.scaleCurve;
35
+ const hasAlphaCurve = alphaCurve != null && alphaCurve.length > 0;
36
+ const hasScaleCurve = scaleCurve != null && scaleCurve.length > 0;
37
+ const hasScaleAnim = config.scaleEnd !== 1 || hasScaleCurve;
38
+ const hasRotSpeed = config.rotationSpeedMin !== 0 || config.rotationSpeedMax !== 0;
39
+ // Emitter velocity for inheritance
40
+ const emitterX = options?.emitterX ?? NaN;
41
+ const emitterY = options?.emitterY ?? NaN;
42
+ let emitterVelX = 0;
43
+ let emitterVelY = 0;
44
+ if (config.velocityInheritance !== 0 && !isNaN(emitterX) && !isNaN(state.prevX)) {
45
+ emitterVelX = (emitterX - state.prevX) / deltaTime;
46
+ emitterVelY = (emitterY - state.prevY) / deltaTime;
47
+ }
48
+ // Phase 1: update live objects, kill expired ones.
49
+ const onDeath = options?.callbacks?.onDeath;
50
+ for (let i = 0; i < n; i++) {
51
+ const lt = i * 2;
52
+ if (lifetimes[lt + 1] <= 0)
53
+ continue;
54
+ lifetimes[lt] += deltaTime;
55
+ if (lifetimes[lt] >= lifetimes[lt + 1]) {
56
+ lifetimes[lt + 1] = 0;
57
+ objects[i].visible = false;
58
+ onDeath?.();
59
+ continue;
60
+ }
61
+ const vt = i * 2;
62
+ velocities[vt] += gx;
63
+ velocities[vt + 1] += gy;
64
+ objects[i].x += velocities[vt] * deltaTime;
65
+ objects[i].y += velocities[vt + 1] * deltaTime;
66
+ const lifeFraction = lifetimes[lt] / lifetimes[lt + 1];
67
+ objects[i].alpha = hasAlphaCurve
68
+ ? sampleParticleCurve(alphaCurve, lifeFraction)
69
+ : config.alphaStart + (config.alphaEnd - config.alphaStart) * lifeFraction;
70
+ if (hasScaleAnim) {
71
+ const factor = hasScaleCurve
72
+ ? sampleParticleCurve(scaleCurve, lifeFraction)
73
+ : 1 + (config.scaleEnd - 1) * lifeFraction;
74
+ const s = scales[i] * factor;
75
+ objects[i].scaleX = s;
76
+ objects[i].scaleY = s;
77
+ }
78
+ if (hasRotSpeed) {
79
+ objects[i].rotation += rotationSpeeds[i] * deltaTime;
80
+ }
81
+ }
82
+ // Phase 2: emission. A finite, non-looping emitter stops spawning once its
83
+ // duration elapses; live objects keep ageing out (use isParticleObjectsComplete).
84
+ const emitting = config.duration <= 0 || config.loop || state.emitterAge < config.duration;
85
+ if (config.duration > 0 && !config.loop)
86
+ state.emitterAge += deltaTime;
87
+ state.spawnAccumulator += emitting ? config.spawnRate * deltaTime : 0;
88
+ let toSpawn = Math.floor(state.spawnAccumulator);
89
+ state.spawnAccumulator -= toSpawn;
90
+ if (emitting && config.burstCount > 0) {
91
+ state.burstTimer -= deltaTime;
92
+ if (state.burstTimer <= 0) {
93
+ toSpawn += config.burstCount;
94
+ state.burstTimer = config.burstInterval > 0 ? config.burstInterval : Infinity;
95
+ }
96
+ }
97
+ // Phase 3: spawn into dead slots.
98
+ if (toSpawn > 0) {
99
+ const baseAngle = Math.atan2(config.directionY, config.directionX);
100
+ const rotSpeedRange = config.rotationSpeedMax - config.rotationSpeedMin;
101
+ const onSpawn = options?.callbacks?.onSpawn;
102
+ for (let i = 0; i < n && toSpawn > 0; i++) {
103
+ const lt = i * 2;
104
+ if (lifetimes[lt + 1] > 0)
105
+ continue;
106
+ const lifetime = config.lifetimeMin + state.random() * (config.lifetimeMax - config.lifetimeMin);
107
+ lifetimes[lt] = 0;
108
+ lifetimes[lt + 1] = lifetime;
109
+ const angle = baseAngle + (state.random() - 0.5) * 2 * config.spread;
110
+ const speed = config.speedMin + state.random() * (config.speedMax - config.speedMin);
111
+ const vt = i * 2;
112
+ velocities[vt] =
113
+ Math.cos(angle) * speed + (config.velocityInheritance !== 0 ? emitterVelX * config.velocityInheritance : 0);
114
+ velocities[vt + 1] =
115
+ Math.sin(angle) * speed + (config.velocityInheritance !== 0 ? emitterVelY * config.velocityInheritance : 0);
116
+ // Spawn position offset from emitter shape
117
+ let spawnX = 0;
118
+ let spawnY = 0;
119
+ if (config.emitterShape === 'circle' && config.emitterRadius > 0) {
120
+ const r = Math.sqrt(state.random()) * config.emitterRadius;
121
+ const a = state.random() * TWO_PI;
122
+ spawnX = Math.cos(a) * r;
123
+ spawnY = Math.sin(a) * r;
124
+ }
125
+ else if (config.emitterShape === 'rect' && (config.emitterWidth > 0 || config.emitterHeight > 0)) {
126
+ spawnX = (state.random() - 0.5) * config.emitterWidth;
127
+ spawnY = (state.random() - 0.5) * config.emitterHeight;
128
+ }
129
+ const spawnScale = config.scaleMin + state.random() * (config.scaleMax - config.scaleMin);
130
+ scales[i] = spawnScale;
131
+ rotationSpeeds[i] = hasRotSpeed ? config.rotationSpeedMin + state.random() * rotSpeedRange : 0;
132
+ const obj = objects[i];
133
+ obj.x = spawnX;
134
+ obj.y = spawnY;
135
+ obj.rotation = angle;
136
+ const spawnFactor = hasScaleCurve ? spawnScale * sampleParticleCurve(scaleCurve, 0) : spawnScale;
137
+ obj.scaleX = spawnFactor;
138
+ obj.scaleY = spawnFactor;
139
+ obj.alpha = hasAlphaCurve ? sampleParticleCurve(alphaCurve, 0) : config.alphaStart;
140
+ obj.visible = true;
141
+ toSpawn--;
142
+ onSpawn?.(spawnX, spawnY);
143
+ }
144
+ }
145
+ // Track emitter position for next frame's velocity inheritance.
146
+ if (!isNaN(emitterX)) {
147
+ state.prevX = emitterX;
148
+ state.prevY = emitterY;
149
+ }
150
+ }
151
+ //# sourceMappingURL=updateParticleObjects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateParticleObjects.js","sourceRoot":"","sources":["../src/updateParticleObjects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ParticleConfigIssue, ParticleEmitterConfig } from '@flighthq/types';
2
+ export type { ParticleConfigIssue };
3
+ /** Return a copy of the config with every value coerced to something the
4
+ * simulation can run safely: non-finite numbers fall back to their defaults,
5
+ * negative counts/rates/sizes are clamped to 0, integer fields are floored, and
6
+ * `frameCount` is forced to >= 1. Range inversions (e.g. lifetimeMin > max) are
7
+ * left intact since they simulate correctly — use {@link validateParticleEmitterConfig}
8
+ * to surface those to the author. Safe to call on partial input. */
9
+ export declare function normalizeParticleEmitterConfig(config?: Partial<ParticleEmitterConfig>): ParticleEmitterConfig;
10
+ /** Report problems in a particle config without modifying it — for asset-import
11
+ * validation, editor inspectors, or CI checks on authored effects. Returns an
12
+ * empty array for a clean config. Use {@link normalizeParticleEmitterConfig} to
13
+ * get a corrected config for safe runtime use. */
14
+ export declare function validateParticleEmitterConfig(config: Readonly<ParticleEmitterConfig>): ParticleConfigIssue[];
15
+ //# sourceMappingURL=validateParticleEmitterConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateParticleEmitterConfig.d.ts","sourceRoot":"","sources":["../src/validateParticleEmitterConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAIlF,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAoEpC;;;;;qEAKqE;AACrE,wBAAgB,8BAA8B,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,qBAAqB,CAqC7G;AAED;;;mDAGmD;AACnD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,mBAAmB,EAAE,CAoD5G"}