Skip to the plate
FORMA PUBLIC DOMAIN GENERATIVE ATLAS / ED. 0.28
Plate 79, Gingerbreadman Map: a still of the map / piecewise linear plate as the atlas renders it, in the attractors accent.

PL. 79  ·  ATTRACTORS / MAP / PIECEWISE LINEAR

Gingerbreadman Map

Robert L. Devaney, 1984

OPEN THE LIVE PLATE ▸

DEFINITION

xₙ₊₁ = 1 − yₙ + |xₙ|
yₙ₊₁ = xₙ
area-preserving · piecewise linear

NOTES

One absolute value is the entire nonlinearity — no multiplication anywhere — and it is enough for chaos. The map preserves area, so nothing contracts onto a thin attractor; instead the plane divides into six hexagonal islands where every orbit has period six, set in a chaotic sea that orbits wander forever without escaping. The figure is named for its outline. Because no single orbit sees more than its own region, the plate seeds many and lets each run a while, which is the only honest way to draw a map that has no attractor to fall onto.

PROVENANCE

Origin
R. L. Devaney, studied from 1984; the widely cited published account is "Fractal patterns arising in chaotic dynamical systems", in H.-O. Peitgen & D. Saupe (eds.), The Science of Fractal Images, Springer, 1988
Standing
Public domain — an iterated map
Constants
Orbit length is the strongest lever on the reading: short runs give scattered dust across many regions, long ones close the hexagonal islands into solid rings. Both are true pictures of the same map

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. 79 · GINGERBREADMAN MAP — Robert L. Devaney, 1984
//   xₙ₊₁ = 1 − yₙ + |xₙ|
//   yₙ₊₁ = xₙ
//   area-preserving · piecewise linear
// 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=gingerbread

float p_run    = 150 + chf('run_tweak');        // orbit length · live 30 .. 500
float p_spread = 6 + chf('spread_tweak');       // seed spread · live 2 .. 9

// The plate's own colour: FORMA's ATTRACTORS 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.0956 + 0.1039 * cos(6.28318530718 * (t + 0)),
    0.4041 + 0.4392 * cos(6.28318530718 * (t + 0.05)),
    0.46 + 0.5 * cos(6.28318530718 * (t + 0.1)));
}

// Area-preserving, so no orbit ever shows more than its own region —
// the figure is the union of many short orbits from scattered seeds,
// the same treatment mira and the standard map need for the same reason.
int forma_pts = 120000;

float x = 0.0, y = 0.0;
int   run = int(p_run) + 1, si = 0;   // force a seed on the first step
for (int i = 0; i < forma_pts; i++){
    if (++run > int(p_run)){
        run = 0;
        // deterministic scattered restarts, mirroring the plate's seeded rng
        x = 1.0 + (random(si * 2) - 0.5) * p_spread;
        y = 1.0 + (random(si * 2 + 1) - 0.5) * p_spread;
        si++;
    }
    float nx = 1.0 - y + abs(x);
    y = x;
    x = nx;
    // canvas y runs down; negated so the figure sits as the plate shows it
    int pt = addpoint(0, set(x, -y, 0.0));
    float u = float(i) / float(forma_pts);
    setpointattrib(0, "Cd", pt, forma_ramp(0.8 + 0.3 * u));
}