Skip to the plate
FORMA PUBLIC DOMAIN GENERATIVE ATLAS / ED. 0.28
Plate 92, Seashell Pigmentation: a still of the reaction / space-time plate as the atlas renders it, in the lattices accent.

PL. 92  ·  LATTICES / REACTION / SPACE-TIME

Seashell Pigmentation

Alfred Gierer & Hans Meinhardt, 1972 · shells: Hans Meinhardt & Martin Klingler, 1987

OPEN THE LIVE PLATE ▸

DEFINITION

∂a/∂t = s·(a²/(h·(1+γc)·(1+κa²)) + b) − rₐ·a + Dₐ·∂²a/∂x²
∂h/∂t = s·a² − r_h·h + D_h·∂²h/∂x²
∂c/∂t = r_c·(a − c)

NOTES

A shell is a record of its own growth. The animal adds material only at the lip, so whatever pattern of pigment the lip is producing at one instant becomes a single line on the finished shell, and the surface you hold is a stack of those lines — a space-time diagram of a one-dimensional process, printed by the animal as it went. Meinhardt and Klingler showed in 1987 that the patterns follow from the reaction Gierer and Meinhardt had published fifteen years earlier for something else entirely: a self-enhancing activator held in check by a faster-spreading inhibitor. This plate runs that reaction on a single row and scrolls the result downward, so what you see is not a picture of a shell but the same construction the shell uses. The saturation term is the dial that matters: without it the activator settles into fixed stripes and the shell gets lines perpendicular to its edge; with it the peaks cannot sit still, and they travel — which is why so many shells carry obliques and chevrons instead.

PROVENANCE

Origin
A. Gierer & H. Meinhardt, “A theory of biological pattern formation”, Kybernetik 12(1), 1972, 30–39, doi:10.1007/BF00289234 — local self-enhancement with longer-range inhibition
The shells
H. Meinhardt & M. Klingler, “A model for pattern formation on the shells of molluscs”, Journal of Theoretical Biology, 1987. Secondary sources cite the volume and pages three different ways (126:63–69, 126:63–89 and 128(1):63–89) and the publisher’s record is paywalled, so the year, authors and title are given here and the volume deliberately is not, rather than picking one and being confidently wrong — the same choice takagi makes about 1901 against 1903
Simulated first, differently
C. H. Waddington & R. J. Cowe, “Computer simulation of a molluscan pigmentation pattern”, Journal of Theoretical Biology 25(2), 1969, 219–225, reproduced the obliques of Oliva porphyria eighteen years before Meinhardt and Klingler and three before Gierer and Meinhardt — with no reaction and no diffusion. Their rule scatters random points of pigment initiation along the growing edge, diverges a line from each, and absorbs any new point that lands within a set distance of an existing line; the paper argues that rule has a plausible physiological reading. It is a discrete model of the same shell, now generally read as a cellular automaton, and it is not what this plate runs. Recorded because the picture on this card is old enough to have been simulated twice, and the earlier attempt is the one that gets dropped
The book
H. Meinhardt, The Algorithmic Beauty of Sea Shells, Springer, 1995, is the accessible account of this work and is often cited as its origin. It is not — it is a book about the 1972 and 1987 papers
Standing
Public domain — a reaction-diffusion system stated in the literature
Constants
Saturation κ is the control: at zero the peaks stand still and the lines run straight down; raised, they travel and the pattern goes oblique
Source
doi:10.1007/BF00289234

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. 92 · SEASHELL PIGMENTATION — Alfred Gierer & Hans Meinhardt, 1972 · shells: Hans Meinhardt & Martin Klingler, 1987
//   ∂a/∂t = s·(a²/(h·(1+γc)·(1+κa²)) + b) − rₐ·a + Dₐ·∂²a/∂x²
//   ∂h/∂t = s·a² − r_h·h + D_h·∂²h/∂x²
//   ∂c/∂t = r_c·(a − c)
// 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=shell

float p_width  = 200 + chf('width_tweak');      // cells along the lip · live 80 .. 280
float p_sat    = 0.2 + chf('sat_tweak');        // κ — activator saturation · live 0 .. 0.5
float p_memory = 0.004 + chf('memory_tweak');   // r_c — local memory rate · live 0.002 .. 0.03
float p_push   = 1.8 + chf('push_tweak');       // γ — memory strength · live 0 .. 4

// The plate's own colour: FORMA's LATTICES 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.4185 + 0.4549 * cos(6.28318530718 * (t + 0.05)),
    0.1389 + 0.151 * cos(6.28318530718 * (t + 0.1)));
}

// The lip integrated once and its history kept: a row of activator, inhibitor
// and local memory stepped forward, and every row it passes through emitted as
// a line of points. The shell is the stack, so the geometry here is the
// space-time diagram itself rather than a picture of one — x is a cell along
// the growing edge, y is time, and the plate's y runs down so it is negated.
//
// Three fields, because two are not enough: the fast-spreading inhibitor makes
// the pattern and a slow local antagonist walks it sideways. Without the third
// the peaks stand still and the shell draws straight lines. Deterministic —
// the source density and the initial scatter are random(counted seed), so
// every cook is the same shell.
int   n         = int(rint(p_width));
int   forma_rows = 256;
int   forma_iter = 14;                 // reaction steps per row, as the plate runs

float ra = 0.02, ba = 0.1, rh = 0.014;
float Da = 0.005, Dh = 0.2;
float kap = p_sat, rc_rate = p_memory, gam = p_push;

float a[], h[], c[], src[];
resize(a, n);  resize(h, n);  resize(c, n);  resize(src, n);
int seed = 1972;
for (int i = 0; i < n; i++){
    a[i] = 0.5 + random(seed) * 0.4;   seed++;
    h[i] = 0.4;
    c[i] = 0.0;
    // Meinhardt's source density: a small fixed irregularity per cell, and the
    // reason a real shell is never quite periodic. Fixed once, not per step.
    src[i] = 0.01 * (0.9 + random(seed) * 0.2);  seed++;
}

for (int row = 0; row < forma_rows; row++){
    for (int it = 0; it < forma_iter; it++){
        float na[], nh[], nc[];
        resize(na, n);  resize(nh, n);  resize(nc, n);
        for (int i = 0; i < n; i++){
            // no-flux ends: the lip is a finite edge, not a ring
            int l = max(i - 1, 0), r = min(i + 1, n - 1);
            float a2 = a[i] * a[i];
            // the local memory divides in beside the inhibitor, so a cell that
            // has just been active needs more to fire again
            float made = src[i] * (a2 / (h[i] * (1.0 + gam * c[i]) * (1.0 + kap * a2)) + ba);
            na[i] = a[i] + made - ra * a[i] + Da * (a[l] + a[r] - 2.0 * a[i]);
            nh[i] = h[i] + src[i] * a2 - rh * h[i] + Dh * (h[l] + h[r] - 2.0 * h[i]);
            nc[i] = c[i] + rc_rate * (a[i] - c[i]);
        }
        a = na;  h = nh;  c = nc;
    }
    for (int i = 0; i < n; i++){
        float m = min(a[i] / (a[i] + 1.0) * 1.334, 1.0);
        // canvas y runs down and time runs with it, so the row index is negated
        int pt = addpoint(0, set(float(i), -float(row), 0.0));
        // pigment sits in the ramp's bright lobe; the ground is carried as
        // Alpha so an underlay can be thresholded rather than guessed at
        setpointattrib(0, "Cd", pt, forma_ramp(0.82 + m * 0.26));
        setpointattrib(0, "Alpha", pt, m);
    }
}