Skip to the plate
FORMA PUBLIC DOMAIN GENERATIVE ATLAS / ED. 0.28
Plate 05, Harmonograph: a still of the damped / pendulum pair plate as the atlas renders it, in the curves accent.

PL. 05  ·  CURVES / DAMPED / PENDULUM PAIR

Harmonograph

Hugh Blackburn, 1844

OPEN THE LIVE PLATE ▸

DEFINITION

x(t) = Σ Aᵢ·sin(fᵢ·t + φᵢ)·e^(−dᵢ·t)
y(t) = Σ Aⱼ·sin(fⱼ·t + φⱼ)·e^(−dⱼ·t)

NOTES

A Victorian drawing machine: two or three pendulums swinging on perpendicular axes, a pen on the last one. The exponential term is friction. What makes the figures beautiful is that the decay tightens the envelope while the phase keeps drifting, so the curve never quite retraces itself.

PROVENANCE

Origin
Hugh Blackburn, Glasgow, 1844
Standing
Public domain — a physical instrument, described openly
Constants
Frequencies near-but-not-equal give the slow beat

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. 05 · HARMONOGRAPH — Hugh Blackburn, 1844
//   x(t) = Σ Aᵢ·sin(fᵢ·t + φᵢ)·e^(−dᵢ·t)
//   y(t) = Σ Aⱼ·sin(fⱼ·t + φⱼ)·e^(−dⱼ·t)
// 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=harmonograph

float p_f1 = 2.01 + chf('f1_tweak');    // f₁ · live 1 .. 8
float p_f2 = 3 + chf('f2_tweak');       // f₂ · live 1 .. 8
float p_f3 = 3.01 + chf('f3_tweak');    // f₃ · live 1 .. 8
float p_f4 = 2 + chf('f4_tweak');       // f₄ · live 1 .. 8
float p_d  = 0.006 + chf('d_tweak');    // damping · live 0.001 .. 0.03

// The plate's own colour: FORMA's CURVES 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.11 + 0.1196 * cos(6.28318530718 * (t + 0)),
    0.46 + 0.5 * cos(6.28318530718 * (t + 0.05)),
    0.2453 + 0.2667 * cos(6.28318530718 * (t + 0.1)));
}

// Two damped sines per axis at unit amplitude, the second pendulum damped
// 1.4× harder — the plate's own ratio. The path is open: a harmonograph
// spirals inward as the pendulums die, it never closes.
int   forma_n  = 12000;
float forma_dt = 0.06;

int prim = addprim(0, "polyline");
for (int i = 0; i < forma_n; i++){
    float u  = float(i) * forma_dt;
    float e1 = exp(-p_d * u);
    float e2 = exp(-p_d * 1.4 * u);
    float x = sin(p_f1 * u) * e1 + sin(p_f2 * u) * e2;
    float y = sin(p_f3 * u) * e1 + sin(p_f4 * u) * e2;
    // 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 along the path
    float uu = float(i) / float(forma_n);
    setpointattrib(0, "Cd", pt, forma_ramp(0.8 + 0.3 * uu));
    addvertex(0, prim, pt);
}

AFTER EFFECTS · EXPRESSION

The same published mathematics as a Shape Layer path expression. Paste it onto a Path property; every constant is the published value plus a Slider Control named _tweak, so a bare paste already draws the figure and each slider moves one constant in its own units. Trim Paths is the comet.

// FORMA — PL. 05 · HARMONOGRAPH — Hugh Blackburn, 1844
//   x(t) = Σ Aᵢ·sin(fᵢ·t + φᵢ)·e^(−dᵢ·t)
//   y(t) = Σ Aⱼ·sin(fⱼ·t + φⱼ)·e^(−dⱼ·t)
// After Effects port — paste onto a Shape Layer's Path property
// (Contents › Shape › Path). Written from the published mathematics, not
// adapted from any code. Constants arrive at their published values; add a
// Slider Control (Effect › Expression Controls) named <k>_tweak and that
// constant moves in its own units, starting at 0 — the published figure.
// The plate's comet and its reveal are Trim Paths; the stroke colour is
// FORMA's CURVES accent, #3DFF88. Animation runs on time.
// https://forma-gen.com/#plate=harmonograph

// A missing slider reads 0, so a bare paste already draws the figure.
function forma_tweak(n){ try { return effect(n)("Slider"); } catch (e){ return 0; } }
var p_f1 = 2.01 + forma_tweak("f1_tweak");  // f₁ · live 1 .. 8
var p_f2 = 3 + forma_tweak("f2_tweak");     // f₂ · live 1 .. 8
var p_f3 = 3.01 + forma_tweak("f3_tweak");  // f₃ · live 1 .. 8
var p_f4 = 2 + forma_tweak("f4_tweak");     // f₄ · live 1 .. 8
var p_d  = 0.006 + forma_tweak("d_tweak");  // damping · live 0.001 .. 0.03

// The frame: the plate's W × H canvas is this comp, with the origin at the
// layer's anchor; canvas y already runs down, as After Effects' does.
var forma_W = thisComp.width, forma_H = thisComp.height, forma_t = time;
var forma_phase = 0.6707494691945612;   // this plate's own fixed phase, as the page has it
function forma_pt(x, y){ return [x - forma_W / 2, y - forma_H / 2]; }

// Two damped pendulums per axis: x = R(sin(f₁u)e^(−du) + sin(f₂u)e^(−1.4du)),
// likewise y with f₃, f₄ — 12,000 steps of 0.06 s, an open path that decays
// toward the centre. On the page it draws itself in over ~25 s; that reveal
// is Trim Paths, End animated 0 → 100%.
var R = Math.min(forma_W, forma_H) * 0.22, N = 12000, dt = 0.06;
var pts = [];
for (var i = 0; i <= N; i++){
  var u = i * dt;
  var e1 = Math.exp(-p_d * u), e2 = Math.exp(-p_d * 1.4 * u);
  pts.push(forma_pt(forma_W / 2 + R * (Math.sin(p_f1 * u) * e1 + Math.sin(p_f2 * u) * e2),
                    forma_H / 2 + R * (Math.sin(p_f3 * u) * e1 + Math.sin(p_f4 * u) * e2)));
}
createPath(pts, [], [], false);