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)^2There 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§
- Emitter
Scene - Objects that spawn, fall on a parabola, and die (ADR-0057).
Constants§
- PARAMS
- Parameter vocabulary — see
fragment_field::PARAMS. Keep in sync withset_parambelow.