Trefoil

Design & build guide

How Trefoil was made

The concept: a fictional single-room gallery that treats torus knots as studio ceramics. The audience is anyone who has ever picked at a shoelace; the page's single job is to make one mathematical fact feel physical — a knot's numbers cannot be undone. One vessel on one pedestal, re-thrown live through the T(p,q) family while its museum placard keeps the ledger: crossings, genus, catalogue mark.

Palette

Cold, precise, and argued from the kiln: charcoal for the darkened gallery, oxblood for the classic copper-red reduction glaze, celadon — the other great reduction glaze — demoted to lines and marks only, and a warm plaster-white for everything you actually read.

Gallery charcoal#17161A

The room with the lights cut. Every surface starts here.

Celadon glaze#9FC6B8

Lines, rules, eyebrows, the pedestal's trim ring. Never body copy.

Oxblood ceramic#7A2E2E

The glaze itself — sang-de-boeuf, fired in reduction. Material only; too dark for type on charcoal.

Placard ink#EDEAE4

Primary reading ink, ~13:1 on charcoal. A dimmed sibling #A8A49D (≈6.6:1) carries secondary copy.

Type

Marcellus for display — a single-weight face drawn from Roman inscriptional capitals, which is exactly what museum wall text wants to be. It carries the wordmark, the vessel names, and the headings. IBM Plex Mono for everything ledger-like: placard specs, catalogue marks in Alexander–Briggs notation (3₁, 5₁, 7₁, 8₁₉), body copy set narrow and quiet. The bravery moment is the placard itself: a Marcellus artefact name over a mono spec line, exactly as a real gallery sets them.

Techniques

Vanilla three.js (0.160, module CDN). No bloom, no haze, no post-processing — the concept demanded cold studio light, so the whole render budget went into the material and the lamps: MeshPhysicalMaterial with full clearcoat over rough oxblood (wet glaze over fired clay), a PMREM-filtered procedural RoomEnvironment for the ceramic's soft window reflections, and a three-point rig — warm spot key with 2048px soft shadows, cool directional fill, celadon rim from behind.

The signature element — the (p,q) morph: every knot is built by one tube builder with identical topology: 560 rings × 26 vertices, centreline (2+cos qu)·(cos pu, ·, sin pu) with sin qu for height, framed by parallel transport rather than Frenet frames (Frenet normals flip at inflections and would shear the tube mid-morph). The frame mismatch left over when a closed loop's transported normal returns home is measured and distributed as a counter-twist along the full length, so the seam ring is watertight for any (p,q) and indices never change. Morphing does not lerp vertices — blending two circular cross-sections point-by-point degenerates the ring into a flat blade mid-morph. Instead the engine eases the ring skeleton: centreline, transported frame and tube radius are interpolated with smootherstep over 2.6 s, re-orthonormalised, and every cross-section is rebuilt as a true circle each frame, so the clay stays a round tube for the whole re-throw while the placard cross-fades to the next entry.

Everything else is discipline from the collection's quality floor: DPR capped at 2, rAF paused on document.hidden with a clamped delta, resize re-layout with a view offset that keeps the vessel clear of the placard, prefers-reduced-motion honoured in CSS and JS (a settled frame: the trefoil mid-rotation under full light), and a WebGL context-loss fallback that swaps in an SVG trefoil with the collection intact in text.

Iteration log

Links

Enter the gallery · Generative Assets index