The five IFS figures — a different kind of family
fern, tree, dragon, sierpinski and spiral are iterated function
systems, not strange attractors
(ADR-0075). Same
scene, same trails, same density / fade / palette / view surface — different
step: four affine maps, one drawn at random per particle per step, converging
onto a figure rather than onto a filigree.
Four things are different for you as an author on an IFS, and the last two are the ones that cost a session if you carry the rest of this library’s habits across. All four are measured.
a b c d are inert. An IFS’s shape lives in its affine table, not in
four scalars. What reaches the figure is the five params below — plus the four
colour channels and emergence in the next
section — and all ten are
IFS-only, inert on de_jong, clifford, thomas and lorenz, the same
way a..d already carry family-specific meanings.
| Param | Default | What it does |
|---|---|---|
morph | 0 | Position from family to [particles] morph_to. 0 is the named figure, 1 is the target, and every value between is a real figure — but not a proportionally-different one, see below. Clamped; out of range pins to an endpoint. |
curl | 0 | Radians added to every map’s rotation — fronds curl and uncurl. |
vigor | 1 | Multiplier on the figure’s contraction — a bushier, deeper, denser figure. Has a silent ceiling; see below. Inverts on a space-filling figure: the dragon’s two maps sit at exactly 0.7071, already space-filling, so vigor above 1 overfills the region and dissolves the figure into dust — measured on the loud frame; attractor_dragon ships the binding inverted below 1. |
lean | 0 | Radians every translation is rotated by — the plant bends. |
bias | 0 | Moves sampling weight from the trunk/body maps to the branch maps. Geometry is untouched; only the density distribution moves. Inert on dragon, whose two maps are both branches. |
You cannot break the figure with them, and that is the point. The maps are
carried as the singular value decomposition of their linear parts, so
contractivity is a comparison on two numbers and every reachable value —
including every intermediate morph and every combination of the four levers —
is a converging system. Drive them as hard as you like; unlike a..d on a
chaotic map, there is no cliff to fall off.
vigor’s ceiling is silent, the same shape as bloom_threshold and
perspective. Every map’s contraction is held under 0.97, and the fern’s
largest is already 0.851 — so about 17 % of headroom, and asking for more than
that gets silence rather than an error or a warning. Past the ceiling every
value renders identically. If vigor seems to stop responding, that is where it
stopped.
The framing follows morph but not the levers, deliberately. The scene
measures each figure pair’s extent at load and re-frames as the morph crosses,
so an intermediate figure fills the frame instead of drifting off it. It does
not re-frame for the levers, because a fit that did would cancel vigor
exactly — the figure would surge and the frame would shrink it back for a net
zero. The cost is that a hard vigor push can leave the frame; zoom is the
recourse.
And it does not re-frame for spin either, which matters more, because spin
defaults to on
(ADR-0103).
What the fit measures is an axis-aligned box; the projection then rotates it.
A box that is hx by hy reaches sqrt(hx² + hy²) on both axes at its worst
angle, so a figure only stays inside the frame at every angle if it is at least
1.85x taller than wide — and of the five, only the fern is
(a = hx/hy = 0.49, against a bound of 0.54). The others overrun the frame
corner at some point in the rotation: sierpinski by 34 %, tree by 41 %,
dragon by 58 %, spiral by 79 %.
So the fit’s actual guarantee is inside the frame at neutral levers and zero
rotation, and zoom is the recourse for both. That is why the shipped 2-D IFS
worlds carry a base zoom below 1 — attractor_dragon 0.92,
attractor_fernmono 0.58 (and two since-retired worlds ran 0.96). Those are
framing values, not taste: raising one back to 1.0 puts the figure’s corner off
screen at some spin phase. A new 2-D IFS world either binds spin down to a
small rock, or pays the same static zoom, or does both — which is what each of
them did independently before this was written down.
morph is a TRAVEL knob, not a little-life knob, and its visible rate is
steepest near zero — which is the opposite of what “every value between is a
real figure” suggests. Measured on fern → dragon, the lit width of the figure as
a fraction of the frame:
morph | 0.00 | 0.05 | 0.10 | 0.15 |
|---|---|---|---|---|
| lit width | 0.248 | 0.448 | 0.572 | 0.584 |
By 0.05 the fern is half again as wide and reads as a curl rather than a
plant, because a few degrees of per-map rotation compounds through the
recursion. A cross that stays recognisably the figure you named would have to
live under about 0.03, which is not a lever. So: bind morph when the
preset is meant to travel, and leave it alone when it is meant to be one
figure — the four levers are what change a figure without leaving it.
attractor_fernmono binds no morph at all; the since-retired attractor_dissolve
used the full range, and travelling was its whole point — its file remains the
worked example, in git history.
The spiral is a fine figure and a poor morph target. Anything ending there
thins into ragged streaks with half the frame empty: its dominant map contracts
at only 0.93, so the intermediate spends nearly every sample on a map that
barely contracts and the orbit spreads instead of settling. Of five pairs swept
end to end, sierpinski → fern was the best by a distance and fern → spiral
came last.
These figures are STILL, so your levers must move ~10× faster than the rest of
this library’s drifts. Every other attractor preset evolves on time sines
with 200–400 s periods, which is right for a strange attractor because the
attractor is already churning and the drift only stops it repeating. An IFS at
fixed levers is a photograph: everything a viewer sees moving is a lever moving.
Copying the slow periods gives anim around 0.018 against a 0.01 gate floor —
it passes, and looks like a still image. Around 30 s it reads as alive.
And bind spin. It defaults to 1, a full revolution every ~35 s. That is
the shipped look on a chaotic cloud, but these figures have an intrinsic up —
sierpinski is an equilateral triangle, fern is a plant — so the default
spends half of every cycle upside down and reads as a crooked frame rather than
a turning figure. A rock (sin(time * k) * 0.25) is almost always what you want.
Built from 13c7582 at version 0.158.0. This site tracks main and is not versioned per release.