Swarm flow-field structure
field_freq is the swarm’s spatial lever and the one that decides how many
distinct streams a frame can hold. The scene steers every particle by a scalar
potential sampled at world * field_freq, so it sets the size of a current
relative to the frame. Default 2.3, which is the constant it replaced — a preset
that does not bind it is unchanged. Measured across the range on Drift:
| value | what the frame does |
|---|---|
| 0.8 | the field’s structure is larger than the frame, so there are no legible channels at all — a uniform dense mass with one slow convergence front migrating across it over tens of seconds |
| 2.3 | broad rolling currents with visible density waves: crests gathering, wakes thinning |
| 6.0 | a few sharply resolved sinuous ribbons with genuinely empty dark space between them |
Note which direction reads as busier: it is the low end, not the high one. A
high field_freq does not make confetti — it separates the swarm into distinct
streams and gives back negative space, while a low one packs the frame edge to
edge because every particle is inside the same enormous current.
Read it against spin, which is the temporal lever and a different question
entirely: field_freq says how finely the field is divided, spin how fast it is
rewritten. The family’s apparent flocking is not a per-particle rule — it emerges
from neighbours falling onto the same streamline and travelling together — so a
coarse field (low field_freq) with a near-frozen one (low spin) is the
formation-holding end, and raising either dissolves the flock toward shimmer.
spin integrates a phase (ADR-0132),
the same shape fragment_field’s
field_speed / fold_speed,
warp_mesh’s warp_speed and parametric_curve’s spin take — so it is safe to
bind to audio. A rate that instead multiplied the shared clock is what makes this
matter: swarm_shatter and swarm_drift both bind spin to mid, and under that
older form a 0.75 swing a hundred seconds into a set advanced the field clock about
four seconds in one frame against a nominal 0.019 — a re-roll of the whole field,
growing without bound as a set runs. Both worlds are tuned for the integrated form, so a
spin range lifted from either file is a range for what ships.
The swarm’s marks individuate the way the emitter’s do —
same names, same semantics (see Individuation).
size_spread widens the per-mark size as a fraction either side of size; the
swarm’s seeded scatter already varies mildly on its own, and this opens that
distribution further. twinkle is a per-mark brightness oscillation whose
rate and phase both come off the seed, so the field shimmers while the
whole-frame light sits still — which is what separates it from binding
brightness to an oscillator, which flashes the frame as one sheet. Both
default 0; an unbound preset is byte-unchanged. This is the pair that makes a
sparse starfield able to twinkle at all (backlog 0068).
The swarm also carries reseed, the attractor family’s percussive accent with
the attractor’s semantics: a rising edge past
0.5 disturbs the population where it is — a seeded kick of ±6 % of the
domain per axis — rather than respawning it into a box, so it reads as the
field being shaken, never erased, and the flow re-gathers it within a few
seconds. It is edge-triggered: bind a gate (reseed = "onset > 0.6"), not a
level — a held high fires once, not continuously. It is also the recovery
lever for a sustained-force pile-up (backlog 0085); note that the minutes
horizon of that recovery is outside what the test suite can see, so a world
leaning on it owes a one-off soak check of its own.
Two things the swarm does on its own, with nothing to bind.
The toroidal domain follows the render target and extends a quarter past the
frame, so the wrap seam is off-screen. That is what retired the bright top/bottom
bar, and it is why zoom below 1.0 no longer exposes a hard domain rectangle —
the camera is usable down to about 0.84. Note that figure is the near depth
layer’s, not the domain’s: 1.25 * zoom alone would reach the frame edge at
0.80, but the near layer takes 1.25x of the zoom deflection too, so it is the
first thing to show an edge and it does so at 1.25 * (1 + (zoom - 1) * 1.25) = 1.
Pan pulls that further up — see the arithmetic in swarm_drift.toml.
And every particle carries a depth, 0 far to 1 near, fixed for its life from
the seeded scatter. It scales the sprite (0.55x–1.5x), fades brightness with
distance, gives the particle its own parallax against zoom/pan_* — a near one
traverses the frame about 1.9x faster than a far one, so panning now sweeps the
near field past the far one instead of sliding a flat sheet — and offsets which
current it rides, so the layers follow different streamlines rather than the same
ones at several sizes. There is no sorting and no perspective: the scene blends
additively, so draw order does not matter, and two particles at different depths
that overlap simply sum. That means no occlusion — the illusion is strongest
on a sparse field and flattens as density rises, so a very dense preset is the one
place depth reads weakest.
Both cost visible density — the margin puts about a quarter of the particles
off-screen, and the fade dims the far half — which is priced into the shipped
presets’ size and brightness. A swarm preset carried over from before Plan
0043 will read dimmer and sparser than it used to; raise those two rather than
assuming something broke.
The swarm’s mark is no longer only a round blob: shape and points give it a
silhouette — see
Shaped marks, which covers
this scene and the emitter together.
Built from a8ce055 at version 0.115.0. This site tracks main and is not versioned per release.