Skip to content
Русский

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.

ParamDefaultWhat it does
morph0Position 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.
curl0Radians added to every map’s rotation — fronds curl and uncurl.
vigor1Multiplier 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.
lean0Radians every translation is rotated by — the plant bends.
bias0Moves 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:

morph0.000.050.100.15
lit width0.2480.4480.5720.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.