Skip to main content

Module emitter

Module emitter 

Source
Expand description

Emitter scene: objects that spawn, follow an analytic ballistic path, age, and are retired — the first scene in the engine whose population is not fixed (ADR-0057).

It exists beside the swarm rather than inside it. The swarm’s world is a torus (ADR-0044): bounds(aspect) wraps every particle back into frame, deliberately, so the field stays populated with no respawn hitches. A cascade is the opposite requirement — a thing that falls out of shot and does not come back — so the two worlds cannot share one scene without a mode switch that changes the world topology.

§Position is a closed form, not an accumulator

Each object stores its spawn time, spawn position, launch velocity and the gravity it was launched under; its position at scene time t is

p(t) = p0 + v0 * (t - t0) + 0.5 * a * (t - t0)^2

There is no dt in the position at all, so the trajectory is exactly frame-rate independent by construction rather than by tuning — the SCENE_DT class of divergence (Plan 0014) cannot reappear here. It also makes the arithmetic checkable: an object launched with vertical speed v0 against gravity g reaches its apex at t = v0 / g and at height v0^2 / (2 g), on any cadence. See an_object_follows_the_closed_form_parabola.

Retirement is a closed form too, and that is not decoration. Sampling “is this object outside the frame?” once per frame would make the population a function of where the frames happened to land — an object that arcs above the top bound and falls back would be culled by a cadence that sampled while it was out and survive one that did not. So each object’s death time is solved at spawn: the earliest of its lifetime, the time it leaves through a side (linear in t), and the last time it is above the bottom bound (the larger root of the quadratic). Retirement is then time >= death_time, monotone in scene time, and the whole scene is a pure function of (seed, scene time).

§The pool is fixed and spawning is clamped to it

Spawn/die is the one place this scene could allocate on the hot path, so it cannot: the object array and its free list are sized once from TierConfig::emitter_objects and never grow. When the pool is full a spawn is dropped — not queued, not allocated for — and the spawn loop is capped at one pool’s worth of spawns per frame so an absurd spawn_rate costs bounded work rather than a stall.

Objects draw through the swarm’s sprite idiom — vec4(colour * g, g) on gpu::ADDITIVE_LIGHT_SATURATING_COVERAGE — so this is the third pipeline that writes directly into the post chain’s input and it owes the third lit-backdrop guard (ADR-0056).

Structs§

EmitterScene
Objects that spawn, fall on a parabola, and die (ADR-0057).

Constants§

PARAMS
Parameter vocabulary — see fragment_field::PARAMS. Keep in sync with set_param below.