how many particles are alive right now
the current follow target, or null when detached
the pool, live: a renderer or a test reads active particles straight off it
Follows target, repositioning on every update tick and every burst(), plus
once right now so the position is fresh before the first tick. A second attach
replaces the first; detach() stops following and keeps the last position. A
destroyed Container target cannot move again, so it auto-detaches (thunk
targets are read unconditionally - their liveness is the caller's).
Emits count particles at once - a hit spark, an explosion.
where this burst happens and what colour it is, in the emitter's parent space, instead of the emitter's own position and tint - one emitter can then throw sparks of a different colour from each broken part without being moved or duplicated.
how many were actually emitted, which is fewer than asked when the pool is full
kills every live particle at once, without emitting anything further
stops following; the emitter keeps its last position and its emitting state
begins continuous emission at rate particles per second
stops emitting; particles already alive still finish their lives
A pooled particle emitter: sparks off a sword hit, dust under a footstep, rain over a map.
Pooled rather than allocating per particle, because this is the one primitive in the framework that can be asked to create and discard thousands of short-lived things per second, and a garbage collector pause is exactly the frame-time cost this project's own performance priority cares about. The pool is allocated once at
maxand reused forever after; asking for more particles than that whilemaxare already alive drops the request rather than growing, so a runaway emitter degrades visibly instead of eating memory.Every random draw goes through
mwg/core's seededRandom, so a replayed or seeded run produces the same spray, rather than particles being the one thing on screen that a deterministic replay cannot reproduce.Example