A vermilion and gilt Victorian zoetrope on a mahogany table shows twelve horse drawings around its inner wall, spins up until its slits smoke into a band and the horse gallops through them, then slows and stops on the stride where all four hooves leave the ground.
Written and rendered by AI CSS Animations Oct 19, 2026
The zoetrope grew from the daedaleum, a slotted drum the British mathematician William George Horner described in 1834, and it became a popular parlour toy in the 1860s. A strip of sequential drawings lines the inside of an open drum below a ring of vertical slits; as the drum spins, each slit acts as a shutter, so the eye sees each drawing in turn in the same place and they fuse into motion. Eadweard Muybridge's photographs of a galloping horse in 1878 showed that all four hooves leave the ground when the legs are gathered beneath the body, not stretched out as painters had drawn them. Animators and teachers still use zoetropes to show timing and loops.
Make a 10-second 3D film of a Victorian zoetrope: a lacquered drum spins up until the horse drawn on the strip inside gallops through its slits, then slows to a stop. <inputs> If I don't give you something, use the default and don't ask. - Maker: Hartwell & Crane, Philosophical Toys (fictional), lettered in gilt on the drum. - Title: "Twelve drawings make a gallop" - Line: "Plate No. 4 · The Gallop · one turn a second" - Closing line: "Look through the slits." - Strip: twelve original drawings of a galloping horse, side view, facing right. - Length: 10 seconds. </inputs> <direction> - Look: a parlour toy filmed like a museum piece under a warm lamp: a vermilion lacquered tin drum with gilt lining on a turned walnut stand, a two-ink paper strip inside, against deep teal wallpaper. The vermilion against the teal is the color idea, two complements held apart by gilt, and the strip's red ink rhymes with the drum. - Palette: wallpaper #123B3D with a tone-on-tone damask (#184A4C, a seeded repeat of curling leaves and medallions) and a warm pool of lamplight #2B5A55 behind the drum; table mahogany #5A2A1D with grain #3F1D10 and a soft lit sheen; drum lacquer vermilion #B0332A, deepening to #7A1F1A on the shadow side; gilt #D6AA52 with highlights #F6DC92; drum interior matte black #17110E; strip paper #EEE1C3 printed in Indian red #A63A2B and sepia #4B3426; walnut stand #3D2415; brass spindle #C89B4D; type ivory #F2E8D0, secondary #A9C2BA, accent gilt. - The zoetrope, built like the real toy (1 unit = 1 cm): an open drum of radius 15 and height 20 in thin tin (wall 0.08, both faces modeled), its top edge a rolled bead (a torus, tube radius 0.3), its floor a disc joined by a folded seam ring. Twelve vertical slits 0.6 wide and 6.5 tall, evenly spaced, from height 12.5 to 19, cut through the wall as real gaps so the tin's thin edge shows. Outside: a 0.4 gilt pinstripe above and below the slit zone, and a gilt band of repeating scrolled leaves (CanvasTexture) round the lower drum with the maker's name in a small oval cartouche. The drum turns on a brass spindle on a turned walnut pedestal (LatheGeometry: a round foot 14 across, a bead, a cove, a vase-shaped column 9 tall, a collar) standing on the table. Inside, the paper strip lines the lower wall from height 1 to 8, all the way round, its two ends overlapping by 0.5 with the paper edge visible. - The strip: twelve panels, one per slit, drawn once at load into a 4096 × 340 canvas. Each drawing is 6 cm long: an Indian-red flat silhouette with sepia line detail (mane locks, tail hairs, hooves, an eye, a nostril, a few muscle lines over shoulder and quarters), standing on a sepia ground line with small tufts, its number 1–12 in tiny sepia numerals at the strip's top edge. Build the twelve drawings from one rig so they form a true cycle: a barrel-shaped body, a neck and head chain, and four legs of three segments each (forearm or gaskin, cannon, pastern and hoof), in a transverse gallop: left hind strikes at phase 0, right hind at 0.12, left fore at 0.38, right fore at 0.50, each in stance for 0.30 of the cycle, then a suspension phase where all four legs fold under the belly and no hoof touches the ground. The back rocks ±4°, the neck pumps ±6° against it, the tail streams and lifts in the suspension. Drawing 9 is that gathered suspension. - Materials: lacquer MeshPhysicalMaterial #B0332A, roughness 0.35, clearcoat 1 at roughness 0.08; gilt metalness 1, roughness 0.25; interior tin roughness 0.9; paper roughness 0.95; walnut and mahogany with generated grain CanvasTextures and matching roughness maps. - Light, warm and clear from the first frame: a key DirectionalLight #FFD8A0 at 2.6 from the upper left (elevation 50°) with soft shadows (PCFSoftShadowMap, 2048, a tight shadow camera), so the pedestal and drum shade the table softly; a HemisphereLight #FFE9CC / #1D3431 at 0.8; inside the drum, a soft PointLight #FFE6C0 on the axis at height 14 (no shadows) so the strip on the inner wall reads at about 75% of paper brightness, never lost in the dark interior. Build an environment once with PMREMGenerator.fromScene from a warm softbox at upper left and a long cool strip at right, so the lacquer carries long, soft window highlights and the gilt glints (envMapIntensity 0.8). A soft contact shadow (a blurred ellipse, #1E0D08 at 40%) under the pedestal foot. ACESFilmic, exposure 1.1. - Spin, solved in closed form: the turn count R(t) is the integral of the turn rate: at rest until 2.4s, easing up to 1 turn per second by 3.6s (easeInOutSine), held to 7.0s, easing to rest at 8.2s, counterclockwise seen from above. Choose the starting angle so the drum stops with drawing 9 straight opposite the camera. - How it animates, honestly, for a frame-by-frame render. Below 0.4 turns per second, draw everything literally: the slits are real gaps and the drawings slide past as separate pictures. Between 0.4 and 0.6 turns per second, crossfade over to the persistence-of-vision view, which holds above that speed: the slit zone renders as a smoked, time-averaged band (lacquer and dark interior blended, 55% opaque, the gilt pinstripes smeared into continuous lines), the outside decoration crossfades to a copy of its texture blurred along the direction of travel, and the far strip is replaced by the picture the eye actually sees: drawing k(t) = floor(12 · R(t)) mod 12, held still on the far wall facing the camera and seen through the band. So the horse gallops in place at 12 drawings per second, one stride a second, and slows as the drum slows. The drum never strobes, wagon-wheels or flickers. - Camera: fov 28, one continuous move on easeInOutSine. It opens high (pitch 55°) looking down into the drum, so all twelve drawings show round the inner wall and read as a sequence; it descends to slit height and pushes in until the slit band spans x 700–1800 with the horse about 460px long behind it, the camera just above the rim looking down about 20° so its line of sight through the near slits lands on the far strip; at the end it pulls back to a three-quarter hero view, the drum centered at (1200, 560) and about 640px wide, with drawing 9 showing through the slit facing us. - Filmstrip (HTML): along the bottom from x 700 to 1760 at y 930, the twelve drawings as 80 × 52 thumbnails with 8px gaps, numbered beneath in Alegreya Sans SC 500, 20px, secondary. A 2px gilt box sits on the drawing being seen: the one opposite the camera while slow, k(t) at speed. - Type (HTML over the canvas): kicker "HARTWELL & CRANE · PHILOSOPHICAL TOYS" in Alegreya Sans SC 500, 20px, tracked 0.18em, accent; title in Prata 400, 72px, ivory, two lines, top-left at (120, 110); line in Alegreya 400 italic, 28px, secondary, beneath; closing line in Alegreya 500 italic, 34px, ivory, at bottom-left with its baseline at y 860. Text rises 12px as it fades in over 0.6s on cubic-bezier(0.22, 1, 0.36, 1). The type stays left of x 660. - Premium: a real tin drum with cut slits, a rolled rim and a turned stand, lacquer and gilt that hold the lamp's highlights, drawings that form a true gallop and come alive only through the slits. Cheap: a sprite horse looping in front of a spinning cylinder, or a rocking-horse gallop with the legs stretched fore and aft. Banned: photographs or traced photo sequences, a rider, saddle or harness, strobing slits, wagon-wheel effects, motion blur over the whole frame, bloom, hands, text inside the drawings beyond their numbers, real toy brands, anything flashing more than 3 times per second. </direction> <structure> - 0.0–1.2s: the high view: the still drum under the lamp, twelve drawings around its inner wall; the kicker and title rise in. - 1.2–2.4s: the camera descends toward slit height; the filmstrip draws in left to right, its gilt box on the drawing facing us. - 2.4–3.6s: the drum spins up: the drawings slide past the slits, then the band smokes over and the horse starts to gallop, slowly at first. - 3.6–5.6s: full speed, one stride a second; the camera pushes in on the slit band; the line rises in at 4.0s. - 5.6–7.0s: held close on the gallop through the band (the 6.0s frame: the band, the horse in mid-stride, the title and filmstrip, nothing mid-fade). - 7.0–8.2s: the drum slows to rest, the gallop slows with it and stops on drawing 9, all four hooves gathered off the ground; the band resolves back into slits; the camera pulls back to the hero view. - 8.2–8.8s: the closing line rises in. - 8.8–10.0s: hold, still. For other lengths, stretch the full-speed beat; keep the spin-up, the slow-down and at least 1s of hold. </structure> <build> - One self-contained index.html (inline CSS and JS), a 1920×1080 (16:9) stage scaled to fit the window, designed for 60fps. No image, video, texture or model files: every shape and texture is generated in code. - window.seek(t), t in seconds, computes every visual from t alone: no CSS transitions or CSS animations, no setTimeout/setInterval, no state carried between frames, randomness only from a seeded PRNG. Anything cumulative is solved analytically from t or precomputed once at load at a fixed step. Past the end, seek clamps to the last frame. - Without ?render in the URL, drive seek from requestAnimationFrame so it plays in a browser (loop after a 1s end hold); with ?render, don't start that loop. - Google Fonts via <link> are fine; await document.fonts.load() for each face before defining window.seek. - Engine: three.js as an ES module pinned to three@0.160.0 through an import map on jsDelivr (`three` and `three/addons/`). WebGLRenderer with antialias, preserveDrawingBuffer: true and setPixelRatio(window.devicePixelRatio); render once at the end of every seek. Text is HTML over the canvas. - R(t), k(t), the band crossfade and the camera are closed-form functions of t; the strip, its twelve drawings, the blurred copies and every texture are drawn once at load. </build> <check> Before showing me, step through one frame per second (t = 0…10): screenshot each and look at it. Fix overlaps, clipped or cramped text, and anything off-style or Banned. Check the drum, its interior and the strip are clearly lit from the first frame, the slits are real gaps while slow, the spinning drum never strobes or wagon-wheels, the footfalls follow the transverse gallop and drawing 9 shows all four hooves gathered off the ground, the gilt box always marks the drawing being seen, and the type and filmstrip stay clear of the drum. Confirm seek(10) and seek(11) match, so the final frame holds. </check>
Ours, and free to use under CC0: copy it, change it, ship it. No credit needed.
An 8-bit attract screen: a dusk forest scrolls in parallax layers as a tiny lantern-carrying hero walks, hops a log and…
A black-and-white manga page read right to left: rooftops, narrowed eyes, a silhouetted courier leaping through focus l…
A five-panel comic page made the old way: blue pencil roughs, weighted black inks, flat process color with Ben-Day dots…
A black-and-white 1930s cartoon: Tippy, an original teakettle with rubber-hose limbs, white gloves and pie-cut eyes, da…
More like this on the motion design inspiration board: 3D motion design inspirationCharacter animation inspiration