Kaizen Media · R&D floor

The Lab.

Client sites get the professional restraint. This page doesn't. One hundred hand-written experiments — no libraries, no plugins, no templates. Every exhibit opens up: read the maths, watch the live numbers, turn the dials. If you're wondering whether your project could do something like this: yes. That's the point.

View source if you think I'm bluffing

This background: a raw WebGL fragment shader · 0 libraries · 60fps

The catalogue

One hundred experiments.

All hand-written, all running in your browser, all explained. Pick a door.

Wing I

The first thirty

Where it started. Particles, physics, algorithms and one very confident terminal.

01

Singularity

Your cursor now has gravity. Physics wasn't in the brief. Click to collapse the field — it springs back, because everything I build recovers.

How: canvas 2D · sprung particles · inverse-square field

Under the hood

Every dot remembers its home. Each frame its target becomes home plus a pull toward the cursor, capped at min(42, 3000/d) — an inverse-distance field. A damped spring integrator chases that target, which is why the field overshoots and wobbles back instead of snapping.

const pull = Math.min(42, 3000 / dist);
const tx = d.bx + (dx / dist) * pull;
d.vx = (d.vx + (tx - d.x) * 0.14) * 0.82;  // spring + damping
d.x += d.vx;
02

Shapeshifter

Two thousand particles with career ambitions. They re-organise every few seconds — click to force a reshuffle.

How: text rasterised offscreen → sampled targets → eased swarm

Under the hood

Each word is rasterised to an offscreen canvas, then alpha-sampled every 3px into a target list. Every particle is assigned a target with a prime-number stride (i × 7919 mod n) so neighbours scatter instead of clustering, then eases 7.5% of the remaining distance per frame.

if (img[(y * W + x) * 4 + 3] > 128) pts.push([x, y]);
// prime stride avoids clumping:
const t = pts[(i * 7919) % pts.length];
p.x += (p.tx - p.x) * 0.075;
03

The Playroom

Fully simulated physics. Grab a seal and throw it. It's fine. Probably.

How: hand-rolled physics — gravity, restitution, collisions, spin

Under the hood

Semi-implicit Euler with impulse collision response: overlapping seals are separated along the contact normal, then the relative velocity along that normal is reflected with restitution 0.82. Your throw velocity comes from a five-point pointer history sampled at release.

const rel = (b.vx - a.vx) * nx + (b.vy - a.vy) * ny;
if (rel < 0) {
  const imp = -rel * 0.82;   // restitution
  a.vx -= nx * imp;  b.vx += nx * imp;
}
04

Live DNA

The CSS on the left styles the card on the right — live, as you type. Break it with confidence. Refresh forgives everything.

How: your keystrokes → a <style> tag → the browser does the rest

Your Website

Looks innocent. Fully editable. This is what "custom-built" actually means.

Powered by CSS
Under the hood

There is no trick. Your keystrokes land in a style tag and the browser's CSSOM re-cascades in real time. The demo card is just markup — which is the point: this is how every custom build works underneath.

input.addEventListener("input", () => {
  styleEl.textContent = input.value;
});  // the browser does the rest
05

The Donut

A 3D torus rendered in text, spinning at 60fps. The oldest flex in graphics programming — done from scratch.

How: the classic donut maths · projected to characters · one <pre> tag

Under the hood

The legendary donut.c, reimplemented. Points on a torus (two angles), rotated by two rotation matrices, perspective-projected with 1/z, z-buffered per character cell, and lit by the surface normal — luminance indexes into the ramp .,-~:;=!*#$@.

const ooz = 1 / z;                      // perspective
const px = (COLS/2 + COLS*0.42*ooz*x) | 0;
if (ooz > zbuffer[idx]) {               // nearest wins
  out[idx] = CH[(L + 0.8) * 7 | 0];     // light ramp
}
06

The Flock

Ninety boids with three rules and no leader. Your cursor is the hawk.

How: separation, alignment, cohesion · O(n²) and proud

Under the hood

Three accumulators per boid, computed over every neighbour within 70px: separation (inverse-square push), alignment (velocity matching) and cohesion (pull to the local centroid). Your cursor injects a fourth force — flee — and speed is clamped to 60–170 px/s so panic still looks graceful.

if (d2 < 4900) {                  // neighbourhood
  cx += o.x;  avx += o.vx;  n++;  // cohesion + alignment
  if (d2 < 900) sx -= dx / d2 * 24;  // separation
}
if (pd < 130) flee(900 * (1 - pd / 130));
07

Storm

Procedural lightning. Click to call a strike down on the exact spot you're pointing at.

How: recursive midpoint displacement · two-pass glow

Under the hood

Recursive midpoint displacement: split the segment, shove the midpoint sideways by ±disp, halve disp, recurse. A 16% branch chance spawns forks with doubled offset. Each bolt is stroked twice — a fat red glow underneath and a thin hot core on top — then fades out in under half a second.

const mx = (ax + bx) / 2 + rand(-disp, disp);
sub(ax, ay, mx, my, disp / 2);   // recurse left
sub(mx, my, bx, by, disp / 2);   // recurse right
if (Math.random() < 0.16) branch(mx, my);
08

Fireworks

Click. Celebrate. Repeat. You've earned it — you scrolled this far.

How: launch physics · spark showers · additive blending

Under the hood

Rockets decelerate under gravity until apex, then burst into 70–130 sparks with random heading and speed. Sparks feel real because of three cheats: per-spark drag (0.985), gravity, and drawing onto a canvas that is faded instead of cleared — which is where the trails come from.

for (let k = 0; k < n; k++) {
  const a = Math.random() * TAU;
  sparks.push({ vx: Math.cos(a) * sp, vy: Math.sin(a) * sp });
}
fade(0.2);   // translucent fill = free motion trails
09

Currents

Two thousand particles riding an invisible wind. Click to change the weather.

How: value-noise flow field · advected particles

Under the hood

A value-noise field turned into wind: the angle at any point is noise(x, y, t) × 4π. Sixteen hundred particles are advected through it at 70px/s, each drawing a 1px segment from where it was to where it is. The canvas fades 5.5% per frame, so the rivers linger.

const a = vnoise(p.x * .004 + seed, p.y * .004 - t * .07) * TAU * 2;
p.x += Math.cos(a) * 70 * dt;
p.y += Math.sin(a) * 70 * dt;
// click: seed += 37.7  → new weather
10

Network

Everything connects when it gets close enough. Including you — move in.

How: distance-based edges · drifting nodes

Under the hood

The classic constellation, hand-rolled: every pair of nodes is tested each frame (O(n²), 3 570 pairs, still trivial for a modern CPU) and edges fade in with proximity. Edges to your cursor get the brand treatment.

if (d2 < 110 * 110) {
  const a = 1 - Math.sqrt(d2) / 110;
  stroke(`rgba(237,235,228,${a * 0.28})`);
}
11

Downpour

It's raining the brand. Someone had to do it.

How: column glyph rain · translucent trails

Under the hood

One object per column: a head position and a fall speed. The head glyph is drawn bright, one behind it in red — and that's it. The iconic trails aren't stored anywhere; they're the ghost of previous frames left behind by a 13% translucent fade.

fade(0.13);            // the trail IS the fade
ctx.fillStyle = "rgba(255,240,228,0.9)";
ctx.fillText(randomGlyph(), c.x, c.y);
ctx.fillStyle = "rgba(217,58,43,0.6)";
ctx.fillText(randomGlyph(), c.x, c.y - 15);
12

Ripples

Click to drop a stone. The waves interfere like they paid attention in physics class.

How: summed sine waves · exponential decay

Under the hood

Textbook wave interference: the height at any point is the sum over every stone of sin(0.11d − 7·age) attenuated by e^(−0.006d − 0.9·age). Sampled on a 15px grid; |height| maps to dot size and brightness, and crests above 0.55 turn red.

let h = 0;
for (const w of waves) {
  const d = Math.hypot(x - w.x, y - w.y);
  h += Math.sin(d * .11 - age * 7)
     * Math.exp(-d * .006 - age * .9);
}
13

Lava

A lava lamp with no lava, no lamp and no shame.

How: metaballs via blur + contrast thresholding

Under the hood

Metaballs without marching squares: blobs are drawn as soft radial gradients at quarter resolution, then composited through blur(14px) contrast(24). The blur merges their fields; the contrast thresholds the result into clean liquid edges. Two CSS filters doing the work of an isosurface algorithm.

o.fillStyle = radialGradient(x, y, r);   // soft blob
o.arc(x, y, r, 0, TAU); o.fill();
ctx.filter = "blur(14px) contrast(24)";  // the magic
ctx.drawImage(off, 0, 0, W, H);
14

The Flag

Cloth simulation, waving at you. Sweep your cursor through it.

How: verlet grid · pinned edge · procedural wind

Under the hood

Verlet integration: each point stores only position and previous position — velocity is implied by their difference, which makes cloth stable almost for free. Three constraint iterations per frame pull neighbours back to rest spacing. The wind is noise-scaled force, and your cursor transfers its velocity on contact.

const vx = (p.x - p.px) * 0.985;   // implied velocity
p.px = p.x;  p.x += vx + wind * dt * dt;
// constraint: pull neighbours to rest distance
const diff = (d - spacing) / d / 2;
p.x += dx * diff;  o.x -= dx * diff;
15

Slack

A rope with real slack. Grab the middle and misbehave.

How: verlet chain · distance constraints

Under the hood

The same verlet trick as the flag, but run through fourteen constraint iterations — more iterations equals stiffer rope. The grabbed node is pinned to your pointer during the solve, and both anchors stay locked, so tension propagates realistically along the chain.

for (let iter = 0; iter < 14; iter++)   // stiffness
  for (let i = 0; i < n - 1; i++)
    satisfy(pts[i], pts[i + 1], restLen);
if (grabbed) pts[g].set(pointer);        // hard pin
16

Chaos

Five double pendulums, born identical. Watch them disagree — that's chaos theory. Click to rewind time.

How: coupled pendulum equations · trail persistence

Under the hood

The full double-pendulum equations of motion — the 2 − cos(2Δ) denominator form — integrated with three substeps per frame for stability. The five pendulums start 0.002 radians apart. Watching their trails split is watching sensitive dependence on initial conditions, live.

const den = 2 - Math.cos(2 * (a1 - a2));
const acc1 = (-g * (2*sin(a1) + sin(a1 - 2*a2)) / L
  - 2*sin(Δ) * (w2² + w1² * cos(Δ))) / den;
// five copies, 0.002 rad apart → divergence
17

Orrery

Click to throw planets at a sun. Some orbit. Some don't. That's gravity's problem, not mine.

How: Newtonian attraction · velocity from your throw point

Under the hood

Newtonian gravity toward the sun: a = GM/d², semi-implicit Euler. Thrown planets get a tangential velocity of √(GM/d) times a random 0.75–1.1 — exactly circular-orbit speed, fuzzed. Under it: stable orbits, ellipses and the occasional dramatic escape.

const a = GM / (d * d);          // inverse square
p.vx += (dx / d) * a * dt;
// spawn: tangent × √(GM/d) ≈ orbital velocity
const v = Math.sqrt(GM / d) * rand(0.75, 1.1);
18

Life

Conway's Game of Life. Drag across it to paint new cells and play god a little.

How: cellular automaton · toroidal grid

Under the hood

Conway's B3/S23 on a toroidal Uint8Array, double-buffered, stepped every fourth frame. An age array colours newborn cells red, fading toward paper as they survive. If population drops below 1.5% the grid quietly reseeds — extinction is off-brand.

buf[i] = alive
  ? (n === 2 || n === 3 ? 1 : 0)   // survival
  : (n === 3 ? 1 : 0);             // birth
grid.set(buf);                     // double buffer
19

The Wayfinder

It builds a maze, then solves it, then does it all again. Forever. Some of us just enjoy work.

How: recursive backtracker · breadth-first flood

Under the hood

Two classic algorithms chained: a stack-based recursive backtracker knocks down walls to carve a perfect maze, then breadth-first search records every cell's distance from the entrance. The flood you watch is the BFS visit order replayed six cells per frame; the path walks backwards down the distance gradient.

// carve: random unvisited neighbour, knock wall
walls[cur][w1] = 0; walls[next][w2] = 0;
// solve: BFS, then descend the gradient
if (dist[n] === dist[cur] - 1) cur = n;
20

Order

Sixty bars sorted before your eyes, endlessly. Deeply satisfying. Mildly hypnotic.

How: quicksort, replayed swap by swap

Under the hood

The quicksort runs once, instantly, on a hidden copy — recording every swap into a log. What you watch is the log replayed four swaps per frame on the visible array. Visualising algorithms is mostly time travel.

qs(0, n - 1);              // real sort, recorded
swaps.push([i, j]);        // the log
// replay: 4 swaps/frame on the display array
[v[a], v[b]] = [v[b], v[a]];
21

Warp

Punch it. Steer with your cursor.

How: z-projected starfield · speed by steering

Under the hood

Stars live in a unit cube with a shrinking z. Screen position is (star − steering) / z × focal — as z approaches zero the division flings positions outward, which is the entire hyperspace effect. Each streak is a line from the previous frame's projection to this one's.

st.z -= speed * dt * 0.45;
const sx = W/2 + (st.x - steer) / st.z * f;
// line from last frame's projection = streak
ctx.moveTo(prevX, prevY); ctx.lineTo(sx, sy);
22

The Tail

A creature made of springs that thinks your cursor is food.

How: spring chain · follow constraints

Under the hood

The head is a damped spring chasing your cursor. Every segment behind it is solved with one-pass inverse kinematics: place yourself at a fixed distance along the direction to your predecessor. Tapered radii and two eyes on the velocity vector do the character design.

head.v = (head.v + (target - head) * .06) * .86;
for (const seg of segs) {
  const d = dist(seg, prev);
  seg.pos = prev + (seg - prev) / d * LINK;  // IK
}
23

Filings

Iron filings, minus the iron and the mess. You're the magnet.

How: vector field · eased rotation

Under the hood

Each filing eases its angle toward atan2(dy, dx) + 90° — the tangent of a circle around your cursor, which is roughly what iron does around a pole. The easing uses shortest-path angle wrapping so filings never spin the long way round.

let target = Math.atan2(dy, dx) + Math.PI / 2;
let diff = target - f.a;
while (diff >  Math.PI) diff -= TAU;   // shortest arc
f.a += diff * 0.1;
24

Ridgelines

A landscape of pure noise, drifting forever. Album cover sold separately.

How: layered value noise · painted occlusion

Under the hood

Seventeen rows, drawn top to bottom. Each is a value-noise line whose amplitude is shaped by a gaussian envelope (big in the middle, flat at the edges). Filling below every line with the background colour before stroking it paints the occlusion — fake 3D for the price of a fill call.

const amp = Math.exp(-cx * cx) * 90;   // gaussian
const y = baseY - vnoise(x * .008 + row * 3.7, t) * amp;
ctx.fill();     // background fill = occlusion
ctx.stroke();   // then the ridge line
25

The Plotter

A harmonograph drawing itself into exhaustion, then starting over. Relatable.

How: damped sine pairs · incremental path

Under the hood

A harmonograph: x(t) and y(t) are each sums of two damped sine waves with random frequencies and phases. Seventy points are appended per frame with no clearing, so the pen literally draws. When the decay envelope dies below 4%, it picks new parameters and starts again.

x = A1 * sin(f1*t + p1) * e^(-d1*t)
  + A2 * sin(f2*t)      * e^(-d2*t);
// 70 points/frame, never cleared — a real pen
if (Math.exp(-d1 * t) < 0.04) restart();
26

Corner Watch

The bouncing logo. You know exactly why you're still watching. The counter shares your hope.

How: reflection physics · corner detection · communal disappointment

Under the hood

Pure reflection physics — velocity components flip independently at the walls. A corner hit is both axes clamping in the same frame, and the maths makes that genuinely rare, which is why the counter matters. The tint cycles on every wall hit, as tradition demands.

if (x <= 0 || x + s >= W) { vx *= -1; hitX = true; }
if (y <= 0 || y + s >= H) { vy *= -1; hitY = true; }
if (hitX && hitY) corners++;   // the prophecy
27

Pong, obviously

You versus a very smug AI. The left paddle is yours — move your cursor. Try not to lose to maths.

How: playable canvas game · the AI is imperfect on purpose

Under the hood

The ball gains 6% speed per return and deflects by where it strikes the paddle (vy += offset × 6), so placement is strategy. The AI chases the ball with a capped speed plus a sine wobble — deliberately imperfect. If it never lost, you'd stop playing.

d.bvx = Math.abs(d.bvx) * 1.06;      // speed up
d.bvy += (ballY - paddleY) * 6;      // spin
const target = ball.y + sin(t*3) * 30;  // AI wobble
ai.y += clamp(target - ai.y, ±maxSpeed);
28

The Instrument

Twelve pads, pentatonic, impossible to play badly. Compose your masterpiece.

How: Web Audio oscillators · envelope shaping · no samples

Under the hood

One triangle oscillator per press, shaped by a gain envelope — an exponential ramp up in 12 milliseconds and out over 650. No samples, no files: the browser synthesises every note. The scale is pentatonic, so wrong notes are mathematically impossible.

const osc = actx.createOscillator();
osc.type = "triangle"; osc.frequency.value = f;
gain.exponentialRampToValueAtTime(0.22, t + 0.012);
gain.exponentialRampToValueAtTime(0.0001, t + 0.65);
29

Scratch

Scratch the panel. There's something underneath. I'm not telling you what.

How: destination-out erasing · an actual secret

You found it.

Mention the word SCRATCH when you enquire and your first month of Kaizen Care is 10% off. Our secret.

Under the hood

Your pointer draws circles with globalCompositeOperation destination-out, which erases alpha instead of painting. Every 0.8 seconds a strided getImageData pass counts how much is gone; past 45% the panel concedes and fades itself out.

ctx.globalCompositeOperation = "destination-out";
ctx.arc(P.x, P.y, 26, 0, TAU); ctx.fill();  // erase
// strided sample: cleared / total > 0.45 → reveal
30

The Terminal

A terminal on a marketing site. Type help. Yes, it answers. Yes, you can try sudo.

How: hand-rolled shell · zero regrets

guest@kaizen:~$
Under the hood

A dictionary of commands, one input and an HTML printer. That's the whole shell. The sudo response is hand-written because the alternative was you not trying it, and we both know that was never going to happen.

const CMDS = { help, whoami, hire, sudo, coffee };
const fn = CMDS[cmd];
fn ? fn() : print(`command not found: ${cmd}`);

Wing II

Nature & particles

Weather, wildlife and other things that were not in the hosting package.

31

Spiral Galaxy

Forty thousand years of rotation, compressed. The arms are a lie your eyes tell you — every star just orbits at its own speed.

How: canvas 2D · differential rotation

Under the hood

Stars sit at random radii with angular velocity proportional to 1/√r — inner stars lap outer ones and the density waves your brain reads as arms emerge on their own.

w = 0.9 / Math.sqrt(r);
a += w * dt;  // inner stars lap outer ones
x = cx + Math.cos(a + armOffset) * r;
32

Snowfall

It settles. Give it a minute and watch the drifts build. South Africans, this is what it looks like.

How: particle fall · height-map accumulation

Under the hood

Each flake falls with noise-driven sway. The floor is a height-map array: when a flake lands, its column grows — which is why drifts form under where the wind funnels them.

if (f.y >= H - ground[ix]) {
  ground[ix] += 2.4;   // the drift grows
  respawn(f);
}
33

Rain, Properly

Streaks fall, hit the ground and splash. The most South African weather on the page.

How: velocity streaks · splash particles

Under the hood

Drops are drawn as motion streaks (a line along their velocity). On impact each spawns three or four short-lived splash particles with upward velocity — that detail is 90% of the realism.

ctx.moveTo(d.x, d.y);
ctx.lineTo(d.x - d.vx * .02, d.y - d.vy * .02);
if (d.y > ground) splash(d.x, 3 + rand(2));
34

Bubbles

They rise, they wobble, they pop when you touch them. Deeply unnecessary. Completely required.

How: sine wobble · burst rings

Under the hood

Bubbles rise with a phase-offset sine sway. Touching one replaces it with an expanding, fading ring — the pop is one arc with a growing radius and a dying alpha.

b.x += Math.sin(t * b.wf + b.ph) * 0.6;
if (dist(P, b) < b.r) pop(b);   // ring: r += 140*dt, a -= 3*dt
35

The Swarm

A hundred workers who want to be near your cursor but keep overshooting. Relatable energy.

How: steering acceleration · momentum

Under the hood

Each bee accelerates toward the cursor but keeps its momentum, so it orbits and overshoots instead of arriving — steering behaviour with deliberately bad brakes.

const a = 900 / Math.max(40, d);
b.vx += (dx / d) * a * dt;
b.vx *= 0.985;   // barely any brakes
36

Slipstream

A river of particles that refuses to touch you. Move through it and watch it part around your cursor like you're famous.

How: flow + radial deflection

Under the hood

Particles stream left to right; near the cursor their velocity gains a perpendicular component scaled by 1/d — the same maths as air around a wing, give or take a physics degree.

const push = 2600 / (d * d);
p.vx += (dx / d) * push;   // radial deflection
p.vy += (dy / d) * push;
37

Sparkler

Hold and drag. You're writing with fire now. It fades because all the best things do.

How: emission from pointer · gravity + fade

Under the hood

While the pointer is down it emits 12 sparks per frame with random velocity, gravity and a lifetime. The trail is the usual translucent-fade trick — nothing is stored, everything is memory.

if (P.down) for (let i = 0; i < 12; i++)
  sparks.push({ x: P.x, y: P.y,
    vx: rand(-140, 140), vy: rand(-180, 60) });
38

Nebula Brush

Paint with clouds of ember light. This one keeps your work — it's the only canvas here that respects your art.

How: additive radial brushes · persistent canvas

Under the hood

Each drag stamp is a soft radial gradient composited with 'lighter', so overlapping strokes sum into brightness. The canvas is never cleared and is exempt from the memory reclaimer.

ctx.globalCompositeOperation = 'lighter';
g = radialGradient(x, y, 40);   // soft ember
// never cleared: cfg.keep = true
39

Sandfall

A falling-sand automaton. Click and hold to pour. The pile knows how to be a pile — nobody taught it.

How: cellular automaton · granular rules

Under the hood

Every grain checks down, then down-left or down-right, one cell per tick. That three-line rule is the entire physics of sand — slope angles and avalanches are emergent.

if (!g[below]) move(below);
else if (!g[belowL]) move(belowL);
else if (!g[belowR]) move(belowR);  // that's sand
40

Langton's Ants

Four ants, two rules each: turn by the colour, flip the colour, step. Chaos for ten thousand steps — then highways. Nobody knows why. Genuinely: nobody knows.

How: turmite automaton · emergent highways

Under the hood

On white turn right, on black turn left, flip the cell, move forward. After ~10 000 steps of apparent chaos every Langton's ant builds a diagonal highway — an unproven-in-general, universally observed mystery.

const c = grid[i];
dir = (dir + (c ? 3 : 1)) % 4;  // L or R
grid[i] = 1 - c;  step();

Wing III

The physics department

Everything falls, swings, bounces or explodes. As nature intended.

41

Newton's Cradle

Drag the end ball, let go and watch momentum do its office-desk thing. Yes, pulling two works.

How: pendulum physics · momentum transfer

Under the hood

Each ball is a pendulum solved with angular acceleration −g/L·sin θ. Collisions between neighbours swap angular velocities — which for equal masses is exactly what elastic collision maths collapses to.

a.acc = -g / L * Math.sin(a.th);
if (touching(a, b) && a.w > b.w)
  [a.w, b.w] = [b.w, a.w];   // swap momenta
42

The Trampoline

Balls raining on a stretchy line. The line disagrees with gravity on behalf of the balls.

How: verlet string · penetration response

Under the hood

The trampoline is a pinned verlet string. When a ball penetrates it, the nearest points get pushed down (stretching the string) and the ball gets the string's displacement back as upward velocity next frame.

if (ball.y + r > lineY(ball.x)) {
  pt.y += push * 0.5;        // string absorbs
  ball.vy -= push * 26;      // and returns it
}
43

Wrecking Ball

A pendulum with a job. The crates rebuild because destruction should be renewable.

How: pendulum + impulse knockdown

Under the hood

The ball is a driven pendulum; crates are boxes that take an impulse when the ball's swept circle crosses them, with torque from the hit offset. They respawn after a decent interval of rubble.

if (hit(ball, crate)) {
  crate.vx += ball.vx * 0.8;
  crate.vr += (crate.y - ball.y) * 0.02;
}
44

Dominoes

Click the first one. You know you want to. The chain reaction is 14 rectangles and one rule.

How: rotation cascade · contact tipping

Under the hood

Each domino rotates around its base corner once triggered. When its top edge sweeps into the next one's space, that one starts tipping too — the delay between falls is just geometry.

if (d.a > TRIGGER_ANGLE)
  next.falling = true;   // contact by sweep
d.a += d.va * dt;  d.va += 4.2 * dt;
45

Buoyancy

Balls in water. They bob because physics says so: displaced water pushes back exactly as hard as it was displaced.

How: sine surface · Archimedes force

Under the hood

The water surface is summed sines. Submerged depth drives an upward force proportional to displacement (Archimedes), drag slows everything, and the bobbing frequency falls out for free.

const depth = ball.y - surfaceAt(ball.x);
if (depth > 0) ball.vy -= depth * 18 * dt;  // buoyancy
ball.vy *= 0.985;                            // drag
46

Charged

Red repels red, attracts pale — Coulomb's law with the numbers filed off. Click to flip every polarity mid-flight.

How: inverse-square attraction/repulsion

Under the hood

Every pair feels a force ±k/d² along their separation vector, sign by charge product. Clicking negates all charges, which instantly turns clusters into explosions — physics' best party trick.

const f = 900 * qa * qb / (d * d);
a.vx -= (dx / d) * f * dt;
// click: charges.forEach(c => c.q *= -1)
47

The Gearbox

Five meshing gears. Tooth counts set the speeds — small ones spin like interns, the big one like management.

How: parametric gear drawing · ratio chain

Under the hood

Each gear is drawn parametrically (teeth as radial bumps). Angular velocity chains through the mesh: ω₂ = −ω₁ × T₁/T₂ — the minus is why adjacent gears counter-rotate.

g2.w = -g1.w * g1.teeth / g2.teeth;
// teeth: r + bump * sin(teeth * angle)
48

The Chain

A hanging chain of rigid links. Grab anywhere and swing it. Satisfyingly heavy for something made of maths.

How: verlet + distance joints

Under the hood

Fifteen verlet points with hard distance constraints (eight solver iterations) make the links rigid. Mass is fake — heaviness comes entirely from damping and gravity tuning.

for (let k = 0; k < 8; k++)      // rigidity
  links.forEach(satisfyDistance);
p.y += (vy + G * dt) * dt;        // weight
49

Soft Body

A pressurised blob. Poke it, drag it, watch it wobble back into shape like nothing happened. Emotional resilience, rendered.

How: spring skin + gas pressure

Under the hood

Skin nodes connect to neighbours with springs; an internal pressure force pushes outward along each node's normal, scaled by how compressed the area is versus rest. Springs pull in, pressure pushes out — the argument is the wobble.

const pressure = REST_AREA / area();
node.f += normal * pressure * 320;
spring(node, next);  spring(node, prev);
50

The Engine

Crankshaft, rod, piston — the linkage that moved the whole twentieth century, idling at 90 rpm on a marketing site.

How: crank-slider kinematics

Under the hood

Pure kinematics: the crank pin moves on a circle and the piston position solves the rod-length triangle. One line of trig every engine textbook opens with.

px = crank * cos(a) +
  Math.sqrt(rod² - (crank * sin(a))²);
// piston slides, rod connects, done

Wing IV

The mathematics wing

Two thousand years of theorems, animated without permission.

51

Pathfinder Race

Two solvers, same maze, no mercy: breadth-first (thorough, slow) versus greedy best-first (fast, occasionally embarrassing). New maze every round.

How: BFS vs greedy · same maze

Under the hood

Both search the same maze in parallel strides. BFS explores in distance order and guarantees the shortest path; greedy chases the goal by straight-line distance and sometimes pays for its optimism. The scoreboard keeps receipts.

bfs: expand FIFO — optimal, patient
greedy: expand min h(n) — fast, cocky
wins.bfs++ or wins.greedy++
52

Monte Carlo π

Throwing darts at a square to measure a circle. The estimate at the top gets better forever and is never quite right — π respects the grind.

How: random sampling · ratio estimate

Under the hood

Random points land in a square; the fraction inside the inscribed circle approaches π/4. Accuracy grows with √n, which is why the third decimal takes forever — a very honest algorithm.

if (x*x + y*y <= 1) inside++;
pi = 4 * inside / total;   // converges as 1/√n
53

The Sieve

Eratosthenes, live: each prime sweeps through and knocks out its multiples. What survives, glows. 2 200 years old and still undefeated.

How: Eratosthenes · animated strike-out

Under the hood

The grid strikes multiples of each prime in turn — the animated version of the fastest simple way humanity has to find primes. Red sweeps are composites dying; the pale survivors are the primes.

for (m = p * p; m <= N; m += p)
  composite[m] = true;   // struck
// what's never struck is prime
54

Golden Spiral

Fibonacci squares snapping into place, a quarter-circle each. The spiral your sunflower already knew.

How: square tiling · quarter arcs

Under the hood

Each square's side is the sum of the previous two; each contributes a quarter arc. The arcs approximate a golden spiral because consecutive Fibonacci ratios converge on φ.

side = fib[i]; rotate placement 90°;
arc(corner, side, quarter);
// fib[i+1]/fib[i] → 1.618…
55

Mandelbrot

The most famous fractal, rendered live. Click anywhere to dive — every zoom recomputes from raw iteration, no images anywhere.

How: escape-time iteration · click zoom

Under the hood

For every pixel, iterate z = z² + c until it escapes or the budget runs out; the escape speed picks the colour. Clicking re-centres and shrinks the window by 3× — computed fresh, because storing images would be cheating.

while (x*x + y*y < 4 && i < MAX) {
  [x, y] = [x*x - y*y + cx, 2*x*y + cy];
  i++;
}  // i chooses the colour
56

Julia Drift

The Mandelbrot's moodier sibling, morphing forever as its seed walks a circle. No two frames identical, ever.

How: escape-time · orbiting seed

Under the hood

Same iteration as the Mandelbrot but c is a constant shared by all pixels — and here c orbits slowly, dragging the whole set through its family of shapes. Rendered at low resolution and upscaled, because art forgives pixels.

c = 0.7885 * exp(i * t * 0.1);  // the seed orbits
z = z*z + c;                    // per pixel
57

Epicycles

Draw any shape. Watch a chain of spinning circles redraw it perfectly. This is the Fourier transform — the maths inside every song you've streamed — drawing with compasses.

How: hand-rolled DFT · rotating vector chain

Under the hood

Your stroke is resampled and pushed through a discrete Fourier transform, decomposing it into rotating vectors sorted by amplitude. Summed tip-to-tail they retrace your drawing — proof that any squiggle is secretly a sum of circles.

X[k] = Σ p[n] · e^(−i2πkn/N)   // your drawing
// replay: chain circles, each spinning at freq k
tip = Σ X[k] · e^(i2πkt)
58

Prime Spiral

Count in a spiral, light the primes. The diagonals appear immediately and mathematics still can't fully explain them. Sleep well.

How: Ulam spiral · trial division

Under the hood

Numbers spiral outward from centre; primes get a dot. The diagonal streaks correspond to prime-rich quadratics like n²+n+41 — observed since 1963, still without a complete explanation.

step the spiral: R, U, L, L, D, D, R, R, R…
if (isPrime(n)) glow(x, y);
// the diagonals are the mystery
59

Bézier Anatomy

Drag the four handles. The moving construction lines are de Casteljau's algorithm — the reason every font, logo and car body looks smooth.

How: de Casteljau construction · draggable

Under the hood

A cubic Bézier point is nested linear interpolation: lerp the four controls pairwise, then those results, then once more. The animated scaffolding shows all three layers meeting at the curve point.

a = lerp(p0, p1, t); b = lerp(p1, p2, t);
d = lerp(a, b2, t);   // …and once more
curve(t) = the last lonely point
60

Voronoi

Every pixel belongs to its nearest seed. Click to add seeds and redraw the borders. This is how leopard spots, ecology and mobile-tower coverage all think.

How: nearest-seed regions · drifting sites

Under the hood

Each coarse cell asks which drifting seed is closest and takes its colour; boundaries are where two seeds tie. Computed brute-force per frame because n is small and honesty is cheap.

for (each cell) best = argmin dist(cell, seed);
// borders = ties; click pushes a new seed
61

Noise Worms

Blind worms steering by an invisible field, leaving ink where they've been. They never agree on a direction and it's better that way.

How: noise-steered agents · persistent trails

Under the hood

Each worm's heading eases toward the value-noise angle at its position — same field as the Currents exhibit, but the trail persists, so you watch the field's topology get slowly discovered.

h += (noiseAngle(x, y, t) - h) * 0.08;
x += cos(h) * v;  // ink stays: no clear
62

Reaction–Diffusion

Two chemicals, four rules, and suddenly: coral, fingerprints, leopard print. Gray–Scott, computed live. Turing predicted this in 1952 and nobody believed him.

How: Gray–Scott model · live grid

Under the hood

Chemical A feeds in, B eats A and B decays, both diffuse at different rates. Iterated on a coarse grid several times per frame, those rules alone paint every animal you've ever seen — Turing patterns, live.

A' = A + (dA·∇²A − AB² + f(1−A))
B' = B + (dB·∇²B + AB² − (k+f)B)
// pattern = f and k, nothing else
63

Hailstone Numbers

Pick a number. Halve it if even, triple-and-add-one if odd. Every path ever tried crashes into 1 — and proving it always does is still an open problem worth its own Fields Medal.

How: Collatz paths · overlaid orbits

Under the hood

Random starters have their full hailstone path traced as a polyline (height = value, log scale). The Collatz conjecture — that every path reaches 1 — has been checked past 2⁶⁸ and proven never.

n = n % 2 ? 3 * n + 1 : n / 2;
path.push(n);   // always ends at 1. probably.
64

Binary Clock

The actual time, right now, in base 2. Learn to read it and you'll never be invited to parties again.

How: real time · bit dots

Under the hood

Hours, minutes and seconds are drawn as bit columns — each dot is one bit of the current time. The blink you see every second is the least significant bit doing its job.

const bits = value.toString(2);
dot.lit = bits[i] === '1';
// LSB flips every second, as it must
65

The Cipher Wheel

Caesar's cipher, twenty-two centuries later: type a message, drag the shift, watch it scramble. Rome fell; the algorithm didn't.

How: Caesar shift · live rot-N

shift13

Under the hood

Each letter shifts N places around the alphabet, wrapping at Z — encryption a schoolchild can break and an emperor trusted. The slider is the entire key space, which is precisely the problem.

out = ((code - 65 + shift) % 26) + 65;
// key space: 25. brute force: instant.

Wing V

Type & text

Letters that refuse to sit still.

66

The Wave

A sentence doing stadium duty. Every letter surfs its own offset of the same sine — which is all a wave has ever been.

How: per-letter sine offsets

Under the hood

The phrase is drawn letter by letter, each with y = sin(t·speed + index·gap)·amp. Coherent motion from independent parts — the entire concept of a wave in one line.

y = Math.sin(t * 3 + i * 0.4) * 18;
ctx.fillText(ch, x, baseY + y);
67

Gravity Type

A perfectly good headline until you click it. Letters become bodies; bodies obey gravity; gravity has no respect for typography. Click again to rebuild.

How: letters as rigid bodies

Under the hood

Each glyph is measured, positioned, then — on click — handed velocity, spin and gravity, bouncing on the floor until it settles into rubble. A second click restores the sentence, because kaizen.

letters.forEach(L => {
  L.vy += G * dt;  L.rot += L.vr * dt;
  if (L.y > floor) bounce(L);
});
68

Orbit Type

Three rings of text rotating at different speeds. Words in orbit read differently — that's not deep, it just looks great.

How: text on circles · counter-rotation

Under the hood

Each ring places its characters around a circle with per-character rotation, then the whole ring turns — outer clockwise, middle counter, inner slow. The renderer is save/rotate/translate/fillText, forty times.

ctx.rotate(ringAngle + i * step);
ctx.fillText(ch, 0, -radius);
// three rings, alternating direction
69

The Haiku Machine

Industrial poetry: five-seven-five about code, clients and continuous improvement. Press for a fresh one. Quality not guaranteed; syllables are.

How: word banks · 5-7-5 assembly


        
      
Under the hood

Three line templates draw from word banks whose entries carry syllable counts, so every poem scans 5-7-5. Meaning is the reader's job — same as all poetry.

line = pick(fives) + pick(sevens) + pick(fives);
// syllables counted; profundity emergent
70

ASCII Storm

The nebula shader's poor cousin: live value noise rendered as characters, because pixels are just letters that gave up.

How: noise field → character ramp

Under the hood

Value noise sampled on a character grid indexes into a density ramp from space to @. It's the Donut's lighting trick applied to weather — proof that any scalar field can be typeset.

const v = vnoise(x * .08, y * .1 + t * .3);
row += RAMP[(v * RAMP.length) | 0];

Wing VI

The arcade

Playable. Score-keeping. Mildly addictive. You were warned.

71

Breakout

1976 called; it's still fun. Cursor moves the paddle. The bricks are load-bearing — the wall rebuilds when you win.

How: AABB reflection · brick grid

Under the hood

The ball reflects off axis-aligned boxes; which axis flips depends on the shallowest overlap. Paddle hits add english proportional to strike offset — the entire skill ceiling of the genre in one line.

if (overlapX < overlapY) ball.vx *= -1;
else ball.vy *= -1;
ball.vx += (ball.x - paddle.x) * 3.2;  // english
72

Snake, Self-Taught

The snake plays itself: breadth-first search to the food, every move, forever. It will still eventually trap itself, because self-confidence is not pathfinding.

How: BFS autopilot · grid snake

Under the hood

Before each move the snake BFS-searches from head to food, treating its own body as walls. Optimal until the board fills and its body becomes the maze — machine hubris, visualised.

const path = bfs(head, food, body);
move(path ? path[0] : straight());
// it dies like the rest of us: boxed in
73

Minesweeper Mini

Nine by nine, ten mines, no flags — commitment only. First click is always safe because this house is merciful.

How: flood reveal · deferred mine placement

Under the hood

Mines are placed only after your first click, excluding it — that's the classic mercy rule. Zero-cells flood-fill their neighbours recursively, which is why one click can crack half the board.

if (firstClick) placeMines(except = cell);
if (count(cell) === 0) neighbours.forEach(reveal);
74

Simon Says

Four pads, one growing sequence, your working memory versus a while-loop. The tones are synthesised live — even the beeps are hand-made.

How: sequence memory · WebAudio tones

press any pad to begin

Under the hood

Each round appends a random pad and replays the whole sequence with synthesised tones (one oscillator per note). Your job is echoing it back; the loop's job is outlasting you. It will.

seq.push(rand4());
playback(seq);   // osc per pad: 330/392/494/587Hz
if (input[i] !== seq[i]) gameOver();
75

Whack-a-Seal

Seals pop out of holes; you bonk them with clicks. Thirty seconds on the clock. The high score is a personality test.

How: spawn windows · hit timing

Under the hood

Seals rise from random holes on a shrinking timer, hittable only while up. Score-chasing is pure human-benchmark: the spawn window tightens 4% per hit until your mouse hand files a complaint.

if (up && clickIn(hole)) { score++;
  window *= 0.96; }   // it gets worse for you
76

Flappy Seal

Click to flap. The pipes are procedurally heartless. Nobody has ever quit this genre feeling good and you won't either.

How: impulse flap · scrolling gates

Under the hood

Gravity pulls, clicks set a fixed upward velocity, pipe gaps scroll past at constant speed. The genre's cruelty is that both your inputs and the physics are perfectly deterministic — every death is yours.

if (click) seal.vy = -320;   // the flap
seal.vy += 900 * dt;         // the fall
if (hit(pipe)) restart();    // the truth
77

The Reflex Test

Wait for red to turn washi. Click. Get judged in milliseconds. Under 200 and you should be doing esports instead of procurement.

How: timestamp delta · anti-cheat

Under the hood

A random 1–3s wait arms the trigger; clicking early resets it with appropriate shame. The measurement is one subtraction — performance.now() at colour-flip versus at click.

armTime = now + rand(1000, 3000);
result = clickTime - goTime;  // that's you, in ms
78

The Typing Test

Type the sentence. Live words-per-minute, live accuracy, no autocorrect to save you. The sentence is about kaizen because of course it is.

How: per-keystroke diff · live WPM

0 wpm · 100% accuracy

Under the hood

Every keystroke diffs your input against the target — greens, reds and a WPM computed as (correct chars / 5) per elapsed minute, the standard nobody agreed on but everyone uses.

wpm = (correct / 5) / (elapsedMs / 60000);
span.class = typed === target ? 'ok' : 'err';
79

Memory Pairs

Sixteen cards, eight glyph pairs, one working memory. The cards flip with a fake 3D scale because drama matters.

How: state machine · match logic

Under the hood

A tiny state machine: at most two cards face-up; a match locks them, a miss flips both back after 700ms of public embarrassment. The flip is scaleX through zero — cardboard 3D.

open.push(card);
if (open.length === 2)
  match() ? lock() : setTimeout(flipBack, 700);
80

Tic-Tac-Toe

You're X. The AI runs full minimax, which means it has already seen every game that will ever be played, including this one. Best possible outcome: a draw. Good luck anyway.

How: full minimax · unbeatable

Under the hood

Minimax recursively scores every reachable position — win +10, loss −10, depth-adjusted so it prefers quick wins and slow losses. Noughts and crosses has 5 478 positions; the machine holds all of them at once.

best = max(moves.map(m =>
  -minimax(apply(m), depth + 1)));
// it cannot lose. it knows it cannot lose.

Wing VII

Other dimensions

3D, illusions and assorted lies your eyes will enjoy.

81

The Cube

A wireframe cube you can grab and throw into a spin. Eight points, twelve lines and two rotation matrices — 3D from scratch.

How: rotation matrices · perspective divide

Under the hood

The vertices are rotated by X and Y matrices, then projected by dividing by depth. Drag velocity becomes angular velocity with momentum — the throw is the feature.

y1 = y * cosX - z * sinX;  z1 = y * sinX + z * cosX;
sx = x1 / (z1 + dist) * scale;  // perspective
82

Point Sphere

Four hundred points arranged by sunflower maths, spinning as a hollow globe. Drag it. The back is dimmer because depth cueing is cheap and effective.

How: fibonacci sphere · depth shading

Under the hood

Points are distributed by the golden-angle spiral (the only way to spread points evenly on a sphere without a committee), rotated in 3D and alpha-faded by depth.

const phi = Math.acos(1 - 2 * (i + .5) / N);
const theta = i * 2.399963;   // golden angle
alpha = 0.2 + 0.8 * (z + 1) / 2;
83

The Tunnel

Concentric rings falling toward you forever. Your cursor bends the tunnel because straight tunnels are for trains.

How: ring recycling · offset lerp

Under the hood

Rings shrink toward a vanishing point that eases toward your cursor; when one collapses it respawns at the far end. Fifteen circles pretending to be infinity, successfully.

r *= 0.985;                 // approach
if (r < 2) r = MAX_R;       // recycle
centre = lerp(centre, cursor, 0.03);
84

Moiré

Two identical line gratings, one slowly rotating. The giant sweeping bands don't exist in either layer — they're an interference pattern your eyes compute for free.

How: overlaid gratings · interference

Under the hood

Layer one is static lines; layer two is the same grating rotated by a slowly oscillating angle. The bands are spatial beat frequencies — the same maths as two guitar strings slightly out of tune.

drawGrating(0);
drawGrating(Math.sin(t * 0.1) * 0.12);
// the bands are in your head. really.
85

Depth Wobble

A 3D point cloud with no glasses required: the whole scene wiggles a few degrees and your brain does the depth perception. The cheapest 3D ever shipped.

How: wigglegram · motion parallax

Under the hood

The cloud rotates through a small oscillating angle. Motion parallax — near points moving more than far ones — is enough for your visual system to reconstruct depth. Stereo vision, single eye edition.

angle = Math.sin(t * 2.2) * 0.18;  // the wiggle
// parallax does the rest, free of charge
86

The Horizon

A synthwave floor rolling toward an ember sun. Obligatory. The grid scrolls in perspective; the sun has scanlines because rules are rules.

How: perspective grid · scrolling rows

Under the hood

Horizontal lines are spaced by perspective (y ∝ 1/row) and scroll by recycling; vertical lines converge on the vanishing point. The sun is a gradient circle with gaps — the whole genre in 40 lines.

y = horizon + k / (row - scroll);  // perspective
vertical: lerp(x, vanishX, depth);
sun: arc + scanline gaps
87

Kaleidoscope

Draw anything. Get it back eight ways, mirrored and perfect. This one also keeps your work — symmetry deserves persistence.

How: 8-fold mirror stamping

Under the hood

Every stroke point is stamped eight times: rotated into each 45° sector, alternating mirrored. The symmetry group does the artistry; you just have to move.

for (let k = 0; k < 8; k++) {
  ctx.rotate(k * TAU / 8);
  if (k % 2) ctx.scale(1, -1);   // mirror
  stamp(r, 0);
}
88

Droste Zoom

Frames inside frames inside frames, zooming forever. When the innermost frame reaches full size, it has silently become the outermost. You never see the loop close.

How: self-similar recycling

Under the hood

Each frame is the previous scaled by a constant ratio; all of them grow together and the largest is culled as it passes the viewport. An infinite zoom needs only six rectangles and a modulo.

scale *= 1 + 0.4 * dt;
if (scale > RATIO) scale /= RATIO;  // the loop
draw frames at scale · ratioⁿ
89

The Torch

There's a message on this canvas. You get a torch beam the size of a biscuit. Reading is exploration now.

How: light mask compositing

Under the hood

The text is drawn, then covered in darkness except a radial gradient hole at your cursor (destination-out). Information architecture reduced to a flashlight — surprisingly tense.

drawText();
ctx.fillRect(0, 0, W, H);            // darkness
cutHole(P.x, P.y, 70, 'destination-out');
90

Parallax Field

Five layers of dots, each tracking your cursor at a different fraction. Your brain reads depth into a flat rectangle instantly and refuses to stop.

How: layered offset tracking

Under the hood

Each layer offsets by cursor distance × its depth factor (0.02 to 0.14). Nearer layers move more — the monocular depth cue every scrolling site borrowed and few credit.

layer.x = P.x * layer.depth * 0.14;
// five layers, five speeds, instant depth

Wing VIII

The gallery

Generative art: the machine draws, you take the credit.

91

The Fractal Tree

A tree grown from one rule: split, shrink, tilt, repeat. Click to plant a different one. The wind is noise; the species is a random seed.

How: recursive branching · noise sway

Under the hood

Each branch spawns two children — shorter, tilted apart by a per-tree angle. Ten levels deep is 2 047 branches, swaying by noise sampled per depth so the canopy moves more than the trunk. Genetics is one random seed.

branch(len * 0.72, ang - spread + sway);
branch(len * 0.72, ang + spread + sway);
if (len < 4) leaf();
92

Coral Growth

Particles wander randomly until they touch the structure — then they stick, forever. Diffusion-limited aggregation: how coral, frost and lightning scars all build themselves.

How: DLA · random walkers

Under the hood

Walkers jitter randomly; contact with the frozen cluster freezes them too. Branches emerge because tips catch walkers before gaps do — growth mathematics with zero blueprint, maximum coral.

walker.jitter();
if (touchesCluster(walker)) freeze(walker);
// tips win: that's the branching
93

Circle Packing

Circles rain down and grow until they touch a neighbour, then stop. Watch the gaps fill with ever-smaller survivors. Restarts when it runs out of patience.

How: growth until contact

Under the hood

Random candidate points grow radius until touching any existing circle or the walls. Rejection plus growth fills space with the classic packing texture — the algorithm behind a thousand data-viz posters.

while (!touching(c)) c.r += 0.5;
if (c.r > MIN) circles.push(c);
else rejects++;   // patience is finite
94

Truchet Drift

A grid of identical quarter-circle tiles, each randomly rotated — producing endless flowing labyrinths. Tiles flip themselves occasionally because permanence is boring.

How: quarter-arc tiles · random flips

Under the hood

Every tile holds two quarter-arcs in one of two orientations; edges always meet, so any random grid connects into mazes. A few tiles flip per second and locally rewire the entire labyrinth.

arc(0, 0, half) + arc(cell, cell, half)
// or the mirrored pair — edges always match
flip(randomTile(), every160ms);
95

Rose Curves

r = cos(kθ), the whole family, morphing through fractional k. Petal counts obey rules discovered before calculus had a name.

How: polar curves · morphing k

Under the hood

When k is an odd integer you get k petals, even integers give 2k, fractions bloom into overlapping laces. Here k drifts continuously so the rose never stops re-deciding what species it is.

r = R * Math.cos(k * theta);
x = r * cos(theta); y = r * sin(theta);
k += 0.04 * dt;   // species drift
96

The Supershape

One formula, most of biology's silhouettes: starfish, diatoms, flowers, blobs. Six parameters drifting forever — taxonomy as animation.

How: superformula · parameter drift

Under the hood

Gielis' superformula generalises the circle with six knobs; small changes in m and the exponents jump between petals, polygons and organisms. The outline you're watching is one equation surfing its own parameter space.

r(θ) = (|cos(mθ/4)/a|^n2 +
        |sin(mθ/4)/b|^n3)^(-1/n1)
// six numbers; most of biology's outlines
97

Strange Attractor

Half a million points through the same two lines of maths. Never repeats, never leaves, never stops being unreasonable to look at. De Jong's attractor, accumulating live.

How: iterated map · point accumulation

Under the hood

Each point feeds through x' = sin(a·y) − cos(b·x), y' = sin(c·x) − cos(d·y) and lands somewhere new on the same ghostly shape — chaotic orbits with additive glow, thousands per frame.

x1 = Math.sin(a * y) - Math.cos(b * x);
y1 = Math.sin(c * x) - Math.cos(d * y);
plot(x1, y1);   // ×4000 per frame, forever
98

Night Skyline

A generated city that has never existed: three parallax layers, a thousand lit windows, aircraft warning lights. Click for a different city — infinite urban planning, zero traffic.

How: layered generation · window grid

Under the hood

Three building layers scroll at different speeds; windows are a random bitmask per building, lit amber with a small flicker chance. Every click reseeds the skyline generator — instant metropolis.

for (b of layer) windows.forEach(w =>
  lit[w] = hash(seed, b, w) < 0.4);
layer.x -= speed[depth] * dt;   // parallax
99

Invented Constellations

A star field, a random walk connecting the bright ones and a generated name. 'The Lesser Invoice.' 'Kaizen Ascending.' Click for a new prophecy.

How: random stars · name grammar

Under the hood

A handful of bright stars get connected by a greedy nearest-neighbour walk (the same way ancient astronomers freelanced), then a two-part name grammar christens it. Astrology, procedurally honest.

path = nearestNeighbourWalk(brightStars);
name = pick(adjectives) + ' ' + pick(nouns);
// as scientific as the originals

The finale

One hundred

You actually made it.

100

The Century

Exhibit one hundred. The seals rain, the counter agrees and the only remaining question is what your website could be if this much care went into it. You know where the button is.

How: confetti physics · a sincere pitch

Under the hood

One hundred K-seals with confetti physics, a counting ticker and the entire page's thesis in one sentence. The code is the same playroom gravity you met 97 exhibits ago — by now, an old friend.

if (exhibit === 100) {
  rainSeals(100);
  askForTheSale();   // politely
}

Seen enough?

One hundred experiments, zero libraries. Imagine this level of care pointed at your business instead of at showing off.

Start a project →Where these fit in the real world