TENSEGRITY
Guide · How it was made

Six sticks, twenty-four wires, and a net that argues back.

TENSEGRITY is a one-page study of floating compression: a six-strut tensegrity icosahedron — Kenneth Snelson's 1948 trick, Buckminster Fuller's name — hanging in a bright studio. Its single job is to make you circle a structure whose rigid parts never touch, and watch the tension that holds them apart re-balance in real time.

01Concept

The subject is the expanded octahedron: three orthogonal pairs of rigid struts, no two of them meeting, laced together by twenty-four cables. Compression lives in islands; tension is continuous. The page stages exactly one object, lets a live physics relaxation find its equilibrium in front of you, and keeps it breathing so the structure reads as held, not modelled.

The audience is anyone who has seen Snelson's Needle Tower and wondered why it doesn't fall over. The single job: make the invisible half of the structure — the tension — visible, by tinting every cable with the load it carries.

02Palette

Studio fog
#ECEDE9
The bright gallery wall. Light ground so the black struts read as drawn strokes and shadows stay soft.
Strut ink
#1F2429
Compression is matter-of-fact: near-black steel for struts, nodes, and every line of type.
Cable crimson
#B5253C
Line/mark token. A cable at ease — taut but unbothered. Also the accent for eyebrows and rules.
Tension amber
#D9A13B
A cable under load. Marks only in 3D and the strain strip; text uses a derived amber-ink #8A6115 for contrast.

Body copy sets in strut ink and a slate secondary (#49525A) on studio fog — comfortably past 4.5:1. Crimson and amber are reserved for lines, marks and the cables themselves; the amber never carries small text on the light ground.

03Type

Sticks that never touch, standing anyway.
Instrument Sans — display

A grotesque with engineering posture. Set tight (−.02em) at display size for the headline; tracked wide (+.22em) for the wordmark, where TEN- picks up the crimson — tension literally carried in the name.

c14 · x—z · 4.2% strain
Geist Mono — instrument

Everything that measures: the readout, cable names, captions, this guide's body. Tabular numerals keep the live strain figures from jittering as they update.

04Technique

The topology. Twelve nodes seeded at icosahedron vertices (strut half-length / half-separation = φ). Six struts are the long diagonals; the twenty-four icosahedron edges that don't join a parallel strut pair become cables. Relaxation then pulls the shape off the icosahedron to the true tensegrity equilibrium.

React Three Fiber, no build step. The scene is real R3F 8.17 + drei 9.114 loaded through a pinned ES-module importmap (react 18.3.1 with both jsx-runtime subpaths mapped, ?external= singletons so fiber and drei share the one three.js). Markup is written as htm tagged templates — no JSX transform anywhere. drei supplies OrbitControls (damped, slow auto-rotate), a procedural Environment built from three Lightformer panels (no external HDR — the CDN allowlist stays intact), and ContactShadows for the studio floor.

The verlet net. Physics is thirty lines of position-based dynamics: each node stores position and previous position; struts are hard equality constraints (corrected to exact length every iteration), cables are one-sided — they correct only when stretched past rest, because a cable cannot push. Seven constraint iterations per 60 Hz substep, 1.8% damping, centroid re-centred each step. Cables are pre-tensioned to 94% of their seed length, so at equilibrium every one of the twenty-four carries measurable strain — that strain drives both the crimson→amber tint and the live strip chart in the readout.

Breathing. Each cable family (x–y, x–z, y–z) modulates its rest length ±3% on a slow sine, phase-shifted 120° per family with a small per-cable offset. The net visibly re-balances — tension flows around the structure in waves — while the struts drift and never meet. A pluck (click the structure, or the keyboard-reachable button in the panel) kicks every node's velocity outward from the hit point and lets the cables argue it back to stillness.

Never touching, provably. Every physics step computes the minimum segment-to-segment distance across all fifteen strut pairs (minus two strut radii) and tracks the all-time minimum. The readout shows clearance as a percentage of strut length; the page exposes it to the QA harness, which asserts it stays positive through settling, breathing and plucks.

Hardening. DPR capped at 2, physics skipped while document.hidden, WebGL feature-detect plus a webglcontextlost handler that swaps in an inline-SVG rendition of the structure, and prefers-reduced-motion runs the relaxation to convergence synchronously and renders one settled frame on a demand-mode frameloop — settled and taut, not blank.

05Iteration log

Pass 1Craft
  • Drove the signature: watched the relaxation from the seeded icosahedron — it crossed the settle threshold inside 2 s (mean node velocity flooring near 3×10⁻⁴) and minimum strut clearance stayed positive throughout, bottoming near 12% of strut length mid-settle.
  • Small-label grey failed 4.5:1 on studio fog; darkened the label ink from #6E7880 to #5C656D and moved all amber-coloured text to the derived #8A6115 amber-ink.
  • Cable radius up from 0.010 to 0.0125 and toneMapped:false basic material — at 375px the crimson wires were vanishing into the fog under ACES tone mapping.
  • Rewrote the caption to name the two tints explicitly; retimed the loading veil so the settle is already underway when it lifts.
Pass 2Depth
  • Drove the breathing for several full cycles: cable strains sweep ~2–5% as the tension waves pass family-by-family, and the all-time minimum clearance held above 12% of strut length — struts never approached each other.
  • Added the 24-bar strain strip to the readout — every cable as a live bar, height and tint by strain — and the tautest-cable line that names the wire (c14 · x—z) carrying the most load.
  • Added the pluck: click the structure (raycast hit point) or the panel button; impulse radiates from the hit, the state flips back to settling, and the net re-converges. Cables flash amber in the wake.
  • Cable thickness now scales +55% with strain, so load is legible even in silhouette.
Pass 3Hardening
  • Re-drove the signature after a simulated context loss and under reduced motion: the synchronous 900-step settle converges with clearance ~15% and renders a single taut frame; the SVG fallback keeps the same topology on WebGL failure.
  • 375px: the mid-page copy was fighting the struts — deepened the mobile scrim, gave the how-to-read caption the same frosted card as the readout, and re-framed the structure smaller and lower on narrow aspect; verified no horizontal overflow and the wordmark inside the viewport box.
  • Physics on a fixed 60Hz accumulator (max 3 substeps) so background-tab resume can't explode the net; velocities clamped at 0.12/step as a belt-and-braces guard.
  • Chanel rule: removed a planned vignette layer — the light scene didn't need it — and cut one Lightformer. Final copy read; pluck button hidden under reduced motion.