PL. 114 · CURVES / PARAMETRIC / SPACE CURVE
Lissajous Knot
M. G. V. Bogle, J. E. Hearst, V. F. R. Jones and L. Stoilov, 1994 · curve form after Nathaniel Bowditch, 1815 and Jules Lissajous, 1857
OPEN THE LIVE PLATE ▸DEFINITION
x(u) = cos(n₁u) y(u) = cos(n₂u + φ₂) z(u) = cos(n₃u + φ₃) u ∈ [0, 2π); n₁, n₂, n₃ pairwise coprime
NOTES
Three perpendicular standing waves instead of two, one cosine per axis at its own integer frequency. Bowditch and Lissajous studied the two axis version in the nineteenth century, where a whole number ratio closes the path into a flat figure. Add a third axis and a closed curve in three dimensions can do something a flat one cannot: it can be knotted. Bogle, Hearst, Jones and Stoilov named these Lissajous knots in 1994 and proved that when the three frequencies are pairwise coprime and the phases are generic, the curve never crosses itself and is a genuine knot. They also showed every knot obtained this way has Arf invariant zero, which rules out roughly half of all knot types no matter what frequencies or phases are chosen. Which specific knot a given triple and phase produces is not read off the equation; that has to be worked out case by case, and this plate makes no claim about any single instance beyond the general theorem.
PROVENANCE
- Origin
- M. G. V. Bogle, J. E. Hearst, V. F. R. Jones and L. Stoilov, "Lissajous knots", Journal of Knot Theory and Its Ramifications 3(2), 1994, 121-140. Verified on Crossref against title, all four authors, year and venue (DOI 10.1142/S0218216594000095)
- Curve form
- The two axis version is Nathaniel Bowditch, 1815, independently Jules Lissajous, 1857 — plate 01 in this atlas. A third axis is the only change to the curve itself; what a closed integer ratio curve can be in three dimensions is the new content the 1994 paper adds
- Standing
- Public domain — a parametric curve and a theorem about it. No patent
- What is proved, and what is not
- Pairwise coprime frequencies with generic phases give an embedded knot, and every knot obtained this way has Arf invariant zero. Which knot type a specific frequency triple and phase pair gives is not asserted here — the source paper works this out example by example rather than in closed form, and this plate follows that same caution rather than naming a knot type for any instance it happens to render
- Coprimality by construction
- n1, n2 and n3 each draw from a disjoint family of integers — powers of 2, powers of 3, and primes above 3 — so regenerate can never land on a pair of axes sharing a factor. An ordinary shared-pool integer jitter was measured at 27-40 percent pairwise coprime across 200,000 random trials (two pool widths tested); the disjoint families measured 100 percent, checked exhaustively across all 24 reachable combinations. A curve is never blank or malformed for a non-coprime triple, it is simply not the knotted object the plate is named for, which is why construction rather than a liveness gate is what closes the gap
- Phases
- φ2 and φ3 are not exposed as sliders. They derive from PHASE, the per-plate constant this atlas already uses for bearings and orbits (see catenoid, PL. 108, and rauzy), so the knot keeps one fixed generic phase pair rather than opening a second phase control the atlas already gives to plate 01
- Source
- doi:10.1142/S0218216594000095
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. 114 · LISSAJOUS KNOT — M. G. V. Bogle, J. E. Hearst, V. F. R. Jones and L. Stoilov, 1994 · curve form after Nathaniel Bowditch, 1815 and Jules Lissajous, 1857
// x(u) = cos(n₁u)
// y(u) = cos(n₂u + φ₂)
// z(u) = cos(n₃u + φ₃)
// u ∈ [0, 2π); n₁, n₂, n₃ pairwise coprime
// 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=lissajous3d
float p_nx = 2 + chf('nx_tweak'); // n₁ — x frequency · live 2 .. 8
float p_ny = 3 + chf('ny_tweak'); // n₂ — y frequency · live 3 .. 9
float p_nz = 7 + chf('nz_tweak'); // n₃ — z frequency · live 5 .. 13
// 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)));
}
// waived: view — the azimuth the finished figure is viewed from, and Houdini has a camera of its own
// One closed period of the 3-D curve: u over 2*pi. Integer, pairwise-coprime
// p_nx/p_ny/p_nz close it into a genuine embedded knot for generic phases
// (Bogle, Hearst, Jones and Stoilov, 1994); phi_x is fixed at zero without
// loss of generality (a shift of the time origin). Nothing is waived: all
// three published constants (p_nx, p_ny, p_nz) reach the body directly.
//
// phi_y and phi_z are not p_<k> constants: on the page they derive from
// PHASE, a per-plate constant hashed from the specimen id, which has no
// equivalent inside a single Houdini cook (a cook has no clock and no
// grid of sibling plates to desynchronise from). Fixed here to PHASE's
// actual computed value for the id "lissajous3d" -- forma_phase below --
// so the phases match what the live page renders, using the same formula
// the draw function uses, not an independently chosen pair.
float TAU = 6.28318530718;
float forma_phase = 0.9007761224638671;
float forma_phiy = forma_phase * TAU + PI / 3.0;
float forma_phiz = forma_phase * TAU * 0.6180339887498949 + 2.0 * PI / 3.0;
int forma_n = 1500;
int prim = addprim(0, "polyline");
for (int i = 0; i <= forma_n; i++){
float u = float(i) / float(forma_n) * TAU;
float x = cos(p_nx * u);
float y = cos(p_ny * u + forma_phiy);
float z = cos(p_nz * u + forma_phiz);
// z-up: the curve's own z axis maps onto Houdini's y (up), the same
// mapping every z-up curve in this corpus uses (see catenoid.vex)
int pt = addpoint(0, set(x, z, y));
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
// FORMA — PL. 114 · LISSAJOUS KNOT — M. G. V. Bogle, J. E. Hearst, V. F. R. Jones and L. Stoilov, 1994 · curve form after Nathaniel Bowditch, 1815 and Jules Lissajous, 1857
// x(u) = cos(n₁u)
// y(u) = cos(n₂u + φ₂)
// z(u) = cos(n₃u + φ₃)
// u ∈ [0, 2π); n₁, n₂, n₃ pairwise coprime
// 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=lissajous3d
// 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_nx = 2 + forma_tweak("nx_tweak"); // n₁ — x frequency · live 2 .. 8
var p_ny = 3 + forma_tweak("ny_tweak"); // n₂ — y frequency · live 3 .. 9
var p_nz = 7 + forma_tweak("nz_tweak"); // n₃ — z frequency · live 5 .. 13
var p_view = 0 + forma_tweak("view_tweak"); // view azimuth ° · live -180 .. 180
// 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.9007761224638671; // 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]; }
// x = cos(n₁u), y = cos(n₂u + φ_y), z = cos(n₃u + φ_z) over one period; the two
// phases come from this plate's own fixed phase (φ_z by the golden ratio, so
// no simple rational relation to φ_y). The view is the page's: x–y spins at
// 0.05 rad/s from the same phase, z is the screen vertical, and the bound
// √2 keeps every frequency triple inside 0.42 of the frame.
var TAU = 6.283185307179586;
var nx = Math.round(p_nx), ny = Math.round(p_ny), nz = Math.round(p_nz);
var phiY = forma_phase * TAU + Math.PI / 3;
var phiZ = forma_phase * TAU * 0.6180339887498949 + 2 * Math.PI / 3;
var FORMA_DEG = Math.PI / 180;
var rot = forma_t * 0.05 + forma_phase * TAU + p_view * FORMA_DEG, co = Math.cos(rot), si = Math.sin(rot);
var s = Math.min(forma_W * 0.42 / Math.SQRT2, forma_H * 0.42);
var cx = forma_W / 2, cy = forma_H / 2, N = 1500;
var pts = [];
for (var i = 0; i <= N; i++){
var u = i / N * TAU;
var x = Math.cos(nx * u), y = Math.cos(ny * u + phiY), z = Math.cos(nz * u + phiZ);
pts.push(forma_pt(cx + (x * co + y * si) * s, cy - z * s));
}
createPath(pts, [], [], true);