AI CSS Animations

Penrose Tiling

Glazed pine and apricot Penrose rhombs grow from a ten-triangle sun: six generations split every tile by the golden ratio as the patch swells and turns, the thick-to-thin count closes in on 1.618, then ivory and coral arcs join into unbroken rings across the never-repeating pattern.

Written and rendered by AI CSS Animations Oct 19, 2026

Type
prompt
Made with
Claude Opus 5.5 in Claude Code
Built in
Canvas
Topics
Shapes
What Claude made from the prompt below in Claude Code: one HTML file rendered frame by frame to video. Silent preview.

About this style

In the 1970s the mathematical physicist Roger Penrose found small sets of tiles that cover the plane only without ever repeating, among them a thick and a thin rhomb whose edges carry matching rules. The tiling can be grown by subdivision: splitting each rhomb into golden-ratio triangles, named Robinson triangles after the mathematician Raphael Robinson, gives a larger patch of the same tiling, and the ratio of thick to thin tiles approaches the golden ratio. Its fivefold order turned out to describe quasicrystals, discovered by Dan Shechtman in 1982 and honored with the 2011 Nobel Prize in Chemistry. Penrose patterns now appear on floors, facades, puzzles and in math illustration.

The prompt

Make a 10-second film of a Penrose rhomb tiling growing generation by generation: every glazed tile splits by the golden ratio while the patch swells, then matching arcs join into continuous curves across the never-repeating pattern.

<inputs>
If I don't give you something, use the default and don't ask.
- Maker: Calder & Finch Tile Co. (fictional).
- Title: "It never repeats."
- Line: "Penrose rhombs, grown by the golden ratio"
- Closing caption: "Thick ÷ thin → φ = 1.6180…"
- Generations: 6.
- Length: 10 seconds.
</inputs>

<direction>
- Palette, glazed tile: field ivory #F4ECDD; thick rhombs pine #1E4D45; thin rhombs apricot #F2A65A; grout #0F2A26; decoration arcs ivory #FFF6E6 and coral #EF6F5C; type #1C2B28, secondary #5C6B66, accent coral. Pine covers about 72% of the area, so apricot reads as scattered stars and the coral arcs as warm rings on deep green.
- Glaze: each rhomb's color is scaled by 1 + 0.07·cos(2(ψ − 30°)), ψ the direction of its long diagonal, so the five orientations of each shape catch the light differently; each tile also carries a soft gradient (+5% at its upper-left corner to −5% at its lower-right) and a 1px highlight 10% lighter along its upper edges.
- Construction, exact (Robinson triangles, the standard P3 subdivision), with φ = (1 + √5)/2 and vertices as complex numbers. A triangle is (type, A, B, C). Start: for k = 0…9, B = e^{i(2k − 1)π/10}, C = e^{i(2k + 1)π/10}, swapping B and C when k is even, giving (thin, 0, B, C): a decagon sun of 10 thin half-rhombs. Each subdivision:
  - thin (36° apex at A): P = A + (B − A)/φ, giving (thin, C, P, B) and (thick, P, C, A);
  - thick (108° apex at A): Q = B + (A − B)/φ, R = B + (C − B)/φ, giving (thick, R, C, A), (thick, Q, R, B) and (thin, R, Q, A).
  Every rhomb is two mirror-image triangles sharing their base BC: thin halves pair into thin rhombs (36°/144°), thick halves into thick rhombs (72°/108°). Fill each rhomb as one quadrilateral (pair the halves by their shared base) so no seam shows down its middle, fill unpaired boundary halves as triangles, and draw grout only along each triangle's legs C–A and A–B, never along a base. Grout width 0.06 × the tile edge.
- Counts, exact (halves ÷ 2, so a boundary half counts as half a rhomb): generation 0: 0 thick, 5 thin (ratio shown as a dash); 1: 5 thick, 5 thin (ratio 1.000); 2: 15 and 10 (1.500); 3: 40 and 25 (1.600); 4: 105 and 65 (1.615); 5: 275 and 170 (1.618); 6: 720 and 445 (1.6180). Fibonacci numbers times five: the ratio closes in on φ.
- Arcs, the matching decoration (verified to join edge to edge): in every triangle draw two arcs centered on its base vertices, with L the triangle's leg length |AB|: in a thin triangle, an ivory arc around B of radius L/φ² and a coral arc around C of radius L/φ²; in a thick triangle, an ivory arc around B of radius L/φ and a coral arc around C of radius L/φ². Each arc runs inside its triangle from its leg to its base. Across every shared edge it meets the neighbor's arc of the same color at the same point, perpendicular to the edge, so the arcs join into smooth unbroken curves: coral ones close into small rings, ivory ones into larger rings and long waves. Width 0.07·L, round caps.
- Layout: the patch is centered at (1230, 540) on the ivory field; text column x 120–480.
- Growth: precompute all six generations at load. The patch's circumradius is R(t) = 180·4^{e(t)} px, e(t) = easeInOutSine((t − 0.8) ÷ 5.4) clamped to 0–1, so it grows from 180 to 720 px while each generation shrinks the tile edge by φ: edges go from 180 px at the start to 40 px at generation 6. At full size the decagon's left side stays right of x 510 and its top and bottom run off the frame.
- Turning: the whole patch rotates 72° over 0.8–7.0 s on easeInOutSine. The tiling has fivefold symmetry, so it ends in the same orientation it started in.
- Each generation step (0.5 s): the new grout lines grow outward from the cut points P, Q and R along their full length over 0.3 s, and each child tile takes its color with a 0.25 s crossfade from its parent's; the step sweeps out from the center as a ring, delayed 0.15 s × (distance ÷ R). The ratio readout updates as the step completes.
- Type: the kicker in Urbanist 700, 20px, tracked 0.16em, uppercase, coral, at (120, 96); the title in Urbanist 600, 76px, #1C2B28, at (120, 180), two lines; the line in Urbanist 400, 26px, secondary, beneath. From (120, 620) the readouts at 54px intervals: labels in Urbanist 600, 20px, uppercase, tracked 0.12em, secondary; values in Overpass Mono 500, 32px, tabular, rolling to each new value over 0.3 s: Generation, Thick, Thin, Ratio (4 decimals). The closing caption in Urbanist 500, 28px, #1C2B28, at (120, 980).
- Easing: text rises 12px as it fades in over 0.6 s on cubic-bezier(0.22, 1, 0.36, 1). Tiles never move on their own; only the whole patch grows and turns.
- Premium: exact golden-ratio geometry, crisp grout, glazed tiles with five orientation tones, arcs that join into unbroken curves, counts that follow Fibonacci. Cheap: a random rhombus mosaic, a repeating wallpaper, gaps and overlaps, arcs that break at the edges.
Banned: any repeating unit, gaps or overlaps between tiles, grout drawn along the half-rhomb bases, seams inside a rhomb, arcs that fail to meet, gradients across more than one tile, drop shadows, glow, colors beyond the palette, anything flashing more than 3 times per second.
</direction>

<structure>
- 0.0–0.8s: the sun of 10 thin halves draws in at the center, 40 ms apart, on the ivory field; the kicker, title and line rise in.
- 1.0–5.9s: six generations, starting at 1.0, 1.85, 2.7, 3.55, 4.4 and 5.25 s: each splits every tile by the golden ratio in a ring from the center outward while the patch grows and turns; the readouts roll at each step, the ratio going 1.000, 1.500, 1.600, 1.615, 1.618, 1.6180.
- 5.9–6.4s: generation 6 rests, complete. The 6.0 s frame: the full patch of 720 thick and 445 thin rhombs, every tile settled.
- 6.4–7.8s: tiles dim 6% and lose 12% saturation as the arcs draw on, each from its leg end to its base end, in a ring from the center outward; rings and waves close up across the pattern.
- 7.8–8.6s: the closing caption rises in.
- 8.6–10.0s: hold, completely still.
For other lengths, change the spacing between generations and keep each step 0.5 s; keep at least 1 s 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: Canvas 2D, repainting every frame from scratch, the backing store sized from CSS size × devicePixelRatio. Canvas won't fetch fonts itself, so the awaited loads matter.
- All seven generations, the rhomb pairing and the arcs are built once at load in unit coordinates; each frame transforms them by R(t) and the rotation, both closed-form functions of t.
</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. Log the thick and thin counts for every generation (they must match the list above) and check at 4× zoom that no gap, sliver or seam shows between or inside tiles, every arc meets its neighbor exactly at the shared edge with no step or kink, the 6.0 s frame is a settled generation 6, and the patch never crosses the text column. 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.

Similar prompts

More like this on the motion design inspiration board: Motion graphics inspiration