Skip to the plate
FORMA PUBLIC DOMAIN GENERATIVE ATLAS / ED. 0.28
Plate 16, Chaos Game: a still of the ifs / vertex jump plate as the atlas renders it, in the fractals accent.

PL. 16  ·  FRACTALS / IFS / VERTEX JUMP

Chaos Game

Michael Barnsley, 1988 · Sierpiński, 1915

OPEN THE LIVE PLATE ▸

DEFINITION

pₙ₊₁ = pₙ + r·(vₖ − pₙ),  vₖ a random vertex

NOTES

Mark some vertices, start anywhere, and repeatedly jump a fixed fraction of the way toward a randomly chosen one. With three vertices and r = ½ you get Sierpiński's triangle — a shape defined by removal, arrived at by pure accumulation. Other vertex counts and ratios give lattices nobody has bothered to name.

PROVENANCE

Origin
The game is Barnsley's; the triangle is Sierpiński, 1915
Standing
Public domain
Constants
r = 1/2 with 3 vertices is the classic; try 5 vertices at 0.63

HOUDINI · VEX

The same published mathematics as a Detail Wrangle body. Paste it into a Wrangle with Run Over set to Detail; every constant is the published value plus a tweak channel, so Create Spare Parameters gives a slider that starts where the paper does.

// FORMA — PL. 16 · CHAOS GAME — Michael Barnsley, 1988 · Sierpiński, 1915
//   pₙ₊₁ = pₙ + r·(vₖ − pₙ),  vₖ a random vertex
// Paste into a Detail Wrangle (Run Over: Detail), no inputs needed.
// Written from the published mathematics, not adapted from any code.
// Constants arrive at their published values. Press the node's Create
// Spare Parameters button and every tweak becomes a slider — starting
// at 0, the published figure, and moving in the constant's own units.
// https://forma-gen.com/#plate=chaosgame

float p_v = 5 + chf('v_tweak');       // vertices · live 3 .. 9
float p_r = 0.63 + chf('r_tweak');    // r — jump ratio · live 0.3 .. 0.8
float p_n = 2600 + chf('n_tweak');    // points per shot · live 500 .. 6000

// The plate's own colour: FORMA's FRACTALS accent as a cosine ramp,
// brightest near t = 0 and t = 1, near-black around t = 0.5.
vector forma_ramp(float t){
  return set(
    0.46 + 0.5 * cos(6.28318530718 * (t + 0)),
    0.1389 + 0.151 * cos(6.28318530718 * (t + 0.05)),
    0.1912 + 0.2078 * cos(6.28318530718 * (t + 0.1)));
}

// Mark p_v vertices on a circle, start at the centre, and jump the fraction
// p_r of the way toward a randomly chosen vertex, forever — Sierpiński's
// triangle at three vertices and r = ½, unnamed lattices elsewhere. The
// plate plots p_n points a shot; forma_shots shots is the same exposure
// fully developed, near the other exposures' ~120k budget. The first
// landings are discarded, as the plate's expose() does. Deterministic: the
// vertex choice is random(counted seed). The circle is unit radius.
int forma_shots = 48;
int forma_skip  = 20;

int nv = int(rint(p_v));
int total = int(rint(p_n)) * forma_shots;
// the vertices, spaced as the plate spaces them — the first at the top
float vxs[], vys[];
for (int i = 0; i < nv; i++){
    float a = -3.14159265359 / 2.0 + float(i) / float(nv) * 6.28318530718;
    push(vxs, cos(a));  push(vys, sin(a));
}
float x = 0.0, y = 0.0;
int rc = 11;                      // the plate's own seed, counted upward
for (int i = 0; i < total + forma_skip; i++){
    int k = int(floor(random(rc) * float(nv)));  rc++;
    x += (vxs[k] - x) * p_r;
    y += (vys[k] - y) * p_r;
    if (i < forma_skip) continue;
    // canvas y runs down; negated so the figure sits as the plate shows it
    int pt = addpoint(0, set(x, -y, 0.0));
    // colour sweeps the bright lobe of the ramp across the exposure
    float u = float(i) / float(total + forma_skip);
    setpointattrib(0, "Cd", pt, forma_ramp(0.8 + 0.3 * u));
}