Documentation
    Preparing search index...

    Class ParticleSystem

    Steps every tracked particle emitter once per fixed simulation step (§39 step 5).

    track takes a SteppableEmitter. It does not take a ParticleRenderable, and the demo composes accordingly (particles.track(fountain.emitter)). Three reasons, in order of weight:

    1. A simulation must be drivable without a renderer. The §112 benchmark (benchmarks/particles-100k.mjs) and the §33 golden (tests/determinism/phase9-particles.test.ts) both step 100 000 and 100 particles respectively with no scene, no canvas and no render list. If the system took renderables, headless particle simulation would require constructing a node purely to throw it away.
    2. The two halves have different owners and different cadences. The renderable's per-frame job is driven by buildRenderList (see the module header); the emitter's per-step job is driven here. Tracking the renderable would suggest this system owns both, which is exactly the confusion the header exists to prevent.
    3. ParticleRenderable.emitter is public for this. It is documented as "public because the application steps it"; system.track(r.emitter) is that sentence, spelled.

    The cost, stated: one extra .emitter at the call site, and the possibility of adding a renderable to the scene while forgetting to track its emitter — which draws a static puff of particles rather than throwing. That failure is visible in one frame, and the alternative failure (a headless simulation that cannot be built) is not.

    AnimationSystem drops a player that is finished or "stopped", because those states are unrecoverable. An emitter has no such state: one with zero live particles and no emission rate is exactly one burst away from being busy again (emitter.emit(n)), and reset() revives any emitter at all. Dropping a quiet emitter would silently break both. Emitters leave this system only when something calls ParticleSystem.untrack or ParticleSystem.clear.

    The tracked set is a Set iterated live, mirroring AnimationSystem and MotionSystem (a snapshot would allocate every step). Those are Set semantics: an emitter untracked during the step is not stepped again in that step, and one tracked during the step is stepped in the same step. Track and untrack outside the step if that distinction matters.

    fixedUpdate allocates one Set iterator per step and nothing else — the same one-per-step AnimationSystem and MotionSystem allocate, and the reason the per-particle work inside ParticleEmitter.step is the part that is strictly zero-allocation. At the §112 budget that is one small object against 100 000 particles.

    Index
    • Parameters

      Returns ParticleSystem

      RangeError if priority is given and is not a finite number — checked here as well as by the registry, so an application that builds the system long before registering it fails where the mistake was written.

    priority: number

    Execution order key (§39); default PRIORITY_PARTICLES.

    • get disposed(): boolean

      Whether ParticleSystem.dispose has run. Disposal is terminal (§83): a disposed system refuses its mutating entry points with INVALID_APPLICATION_STATE (§89) rather than silently working.

      Returns boolean

    • get emitters(): IterableIterator<SteppableEmitter>

      Tracked emitters, in the order they will be stepped.

      Returns IterableIterator<SteppableEmitter>

    • get size(): number

      Number of tracked emitters.

      Returns number

    • Stops stepping everything. The system stays registered.

      Returns void

    • Drops every tracked emitter (§39 teardown).

      Deliberately does not reset or clear them: the system is a driver, not an owner, and disposing an application should not empty pools the application may still be checksumming, serialising, or drawing one last frame from. AnimationSystem.dispose draws the same line.

      Returns void

    • Steps every tracked emitter once, in insertion order.

      The delta is time.fixedDeltaTime — the scaled simulation delta. The scheduler already applied timeScale when filling its accumulator (§10: accumulator += elapsedRealTime * timeScale), so a fixed step is one fixedDeltaTime of scaled simulation time and timeScale changes the number of steps per frame. Multiplying by time.timeScale here would scale the same time twice and particles would run at timeScale² — AnimationSystem states the identical rule.

      The time is time.simulationTime, which §39's scheduler advances before invoking a fixed step, so it is the time the step being produced ends at (step n sees n · fixedDeltaTime). That value is handed to ParticleForceField.sample(position, velocity, time, out) — §27's time argument, which an animated field (turbulence, a gusting wind) reads. Two consequences worth stating:

      • ParticleEmitter.step's own default for that argument is the emitter's local elapsed time, measured from its construction and taken at the start of the step. Driving an emitter from this system therefore feeds fields the world simulation clock, offset by one fixedDeltaTime from the emitter-local default. That is the right choice — two emitters in one scene must see one clock, or a shared wind field blows in two different directions — and it is why the argument is passed explicitly rather than left to default.
      • It is still injected, never read: §33 is satisfied because the value comes from the context, not from a wall clock.

      Emission and death bookkeeping belong to the emitter (emitter.ts pins the simulate-then-emit order and the per-spawn RNG draw count); this method adds nothing to them.

      Parameters

      Returns void

    • Whether emitter is tracked.

      Parameters

      Returns boolean

    • No per-registration setup is needed (§39).

      Returns void

    • Starts stepping emitter and returns it, so an emitter can be built and tracked in one expression. Idempotent — tracking twice keeps the original position in the iteration order and steps it once.

      Type Parameters

      Parameters

      • emitter: T

      Returns T

    • Stops stepping emitter. Returns whether it was tracked.

      Parameters

      Returns boolean