@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.
- package/dist/applyParticleCollisions.d.ts +12 -0
- package/dist/applyParticleCollisions.d.ts.map +1 -0
- package/dist/applyParticleCollisions.js +175 -0
- package/dist/applyParticleCollisions.js.map +1 -0
- package/dist/applyParticleForces.d.ts +13 -0
- package/dist/applyParticleForces.d.ts.map +1 -0
- package/dist/applyParticleForces.js +129 -0
- package/dist/applyParticleForces.js.map +1 -0
- package/dist/curve.d.ts +35 -0
- package/dist/curve.d.ts.map +1 -0
- package/dist/curve.js +227 -0
- package/dist/curve.js.map +1 -0
- package/dist/emitParticleBurst.d.ts +15 -0
- package/dist/emitParticleBurst.d.ts.map +1 -0
- package/dist/emitParticleBurst.js +114 -0
- package/dist/emitParticleBurst.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/particleEmitterConfig.d.ts +4 -0
- package/dist/particleEmitterConfig.d.ts.map +1 -0
- package/dist/particleEmitterConfig.js +53 -0
- package/dist/particleEmitterConfig.js.map +1 -0
- package/dist/particleEmitterSignals.d.ts +20 -0
- package/dist/particleEmitterSignals.d.ts.map +1 -0
- package/dist/particleEmitterSignals.js +33 -0
- package/dist/particleEmitterSignals.js.map +1 -0
- package/dist/particleEmitterState.d.ts +7 -0
- package/dist/particleEmitterState.d.ts.map +1 -0
- package/dist/particleEmitterState.js +38 -0
- package/dist/particleEmitterState.js.map +1 -0
- package/dist/particleObjectsState.d.ts +4 -0
- package/dist/particleObjectsState.d.ts.map +1 -0
- package/dist/particleObjectsState.js +24 -0
- package/dist/particleObjectsState.js.map +1 -0
- package/dist/prewarmParticleEmitter.d.ts +5 -0
- package/dist/prewarmParticleEmitter.d.ts.map +1 -0
- package/dist/prewarmParticleEmitter.js +13 -0
- package/dist/prewarmParticleEmitter.js.map +1 -0
- package/dist/stepParticleEmitter.d.ts +38 -0
- package/dist/stepParticleEmitter.d.ts.map +1 -0
- package/dist/stepParticleEmitter.js +57 -0
- package/dist/stepParticleEmitter.js.map +1 -0
- package/dist/updateParticleEmitter.d.ts +8 -0
- package/dist/updateParticleEmitter.d.ts.map +1 -0
- package/dist/updateParticleEmitter.js +315 -0
- package/dist/updateParticleEmitter.js.map +1 -0
- package/dist/updateParticleObjects.d.ts +8 -0
- package/dist/updateParticleObjects.d.ts.map +1 -0
- package/dist/updateParticleObjects.js +151 -0
- package/dist/updateParticleObjects.js.map +1 -0
- package/dist/validateParticleEmitterConfig.d.ts +15 -0
- package/dist/validateParticleEmitterConfig.d.ts.map +1 -0
- package/dist/validateParticleEmitterConfig.js +206 -0
- package/dist/validateParticleEmitterConfig.js.map +1 -0
- package/package.json +42 -0
- package/src/applyParticleCollisions.test.ts +191 -0
- package/src/applyParticleForces.test.ts +174 -0
- package/src/curve.test.ts +327 -0
- package/src/deterministic.test.ts +54 -0
- package/src/emitParticleBurst.test.ts +103 -0
- package/src/particleEmitterConfig.test.ts +65 -0
- package/src/particleEmitterSignals.test.ts +125 -0
- package/src/particleEmitterState.test.ts +113 -0
- package/src/particleObjectsState.test.ts +34 -0
- package/src/prewarmParticleEmitter.test.ts +68 -0
- package/src/stepParticleEmitter.test.ts +113 -0
- package/src/updateParticleEmitter.test.ts +631 -0
- package/src/updateParticleObjects.test.ts +340 -0
- 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"}
|