One operator wrote the brief and set the constraints. AI agents built the house, then tore it apart three times over. This page keeps the working notes: the instruction it was given, the one trick it had to prove, and every fault the critique caught on the way to the light.
Every site in this collection starts from a place with a premise, not a page of sections. This one was handed to the builder verbatim:
The puppets are not sprites. Each figure carries two arms of two bones each. Every frame, the shoulder is pinned to the leaning body and the elbow and hand are integrated as free points, then the bone lengths are re-solved eight times so the arm can whip and settle but never snap. It is the same verlet trick a rope uses, cut down to a limb:
// integrate the free joints, then solve the bones (from index.html) for(const pt of [arm.e,arm.h]){ let vX=(pt.x-pt.ox)*.88, vY=(pt.y-pt.oy)*.88; pt.ox=pt.x;pt.oy=pt.y;pt.x+=vX-accel*1.4;pt.y+=vY+grav; } for(let i=0;i<8;i++){ constrain(s,arm.e,T.l1,true); // shoulder→elbow, shoulder pinned constrain(arm.e,arm.h,T.l2,false); // elbow→hand, both float }
accel term is the body's own motion — drag a figure fast and its arms trail behind, exactly like a puppet worked by a rod.Nothing is drawn in its own colour. Every limb is painted as a single dark shape and then sheared and stretched away from the lamp — the further a figure stands from the flame, the longer and thinner its shadow throws. Move the lamp and the whole cast leans:
// cast the shadow: lean away from the lamp, stretch with distance
let k = clamp(-dx / max(240, |dy|+220), -0.4, 0.4);
const stretch = 1 + min(0.5, dist/(H*2.2));
ctx.transform(1, 0, k, stretch, 0, 0);
The first draft is never the reason these pages look the way they do. The loop is: shoot the real page on desktop and mobile, read the screenshots like a hostile art director, fix everything, then add one deliberate upgrade. Three times.