A fictional city's metro diagram draws itself on white: four colored lines run at 0, 45 and 90 degrees across a pale river, station ticks and labels follow each line's head, interchange rings pop as lines meet, and a train runs one line stop by stop to its terminus.
Written and rendered by AI CSS Animations Oct 16, 2026
The schematic transit diagram gives up geographic accuracy for clarity: lines run only horizontally, vertically or at 45 degrees, stations are spaced evenly and interchanges are marked plainly. Harry Beck's 1933 London Underground map established the approach, and later diagrams such as Massimo Vignelli's 1972 New York subway map pushed it further. Designers borrow its grammar for product roadmaps, org charts and any system of connected routes.
Make a 10-second animated transit diagram for a fictional city: four lines draw themselves at 0, 45 and 90 degrees, stations tick on, interchanges join, and a train runs one line from end to end. <inputs> - City: Wrenmouth (fictional). Title: "Wrenmouth Metro". Subtitle: "Network map 2026". River: "River Wren". - Lines in drawing order, stations in order with grid points (gx, gy); "bend" is a turn with no station: - Ember Line #E2412E: Westgate Fields (4,7), Tannery Row (6,9), bend (8,11), Mill Cross (11,11), Cathedral (17,11), Beacon Square (23,11), Chalk Hill (27,11), bend (29,11), Eastmoor (33,7). - Fern Line #2E9E57: Highwood (11,4), Fernbank (11,7), Mill Cross (11,11), Brightwater (11,15), Southpark (8,18). - Tide Line #0A8FA6: Gullhaven (13,20), Quayside (15,18), bend (17,16), Ropewalk (17,13), Cathedral (17,11), Old Exchange (20,8), Harbour North (23,5), Saltings (28,5). - Saffron Line #E9A800: Kiln Park (26,8), Beacon Square (23,11), Weavers Gate (21,13), bend (19,15), Brightwater (11,15), Marsh End (6,15). - Interchanges: Mill Cross, Cathedral, Beacon Square, Brightwater. - Train: Tide Line, Gullhaven to Saltings. - Length: 10 seconds. If I don't give you something, use the default and don't ask. </inputs> <direction> Grid: one unit is 46px, and grid point (gx, gy) sits at stage (40 + 46·gx, 60 + 46·gy). Every segment runs at 0°, 45° or 90°; bends turn on a 28px-radius arc. The Saffron Line crosses the Tide Line between Ropewalk and the bend with no station. Palette: ground #FFFFFF; ink #1B1B1F for text and interchange rings; muted #6B6E76; river #D6EAF4; line colors as given, flat. Lines are 14px wide with round caps at the termini. A station is a 10px tick of its line's color on the label side; a terminus gets a 14px bar across the line. An interchange is a 30px white circle with a 5px ink ring on the shared point. The river is a 56px band on the same three angles: its centerline runs from the west edge at gy 13 east to (13,13), 45° down to (16,16), then straight down off the bottom edge, crossing lines only between stations. Its name sits along the west stretch in "Hanken Grotesk" italic 500, 22px, #5E8FA6. Type: "Hanken Grotesk" throughout. Title 800, 56px; subtitle 500, 24px, muted; station labels 500, 22px; interchange labels 700, 22px; legend 600, 22px; train board 600, 24px. Labels are horizontal only, 12px from their tick, on whichever side keeps them clear of every line, the river and other labels. Layout: title top-left at x 96, baselines y 112 and 150. Legend panel bottom-right at x 1460–1824, y 760–990: four rows (a 40px stub of the line and its name), then a 1px rule and the train board, "Tide Line to Saltings" over "Next: Quayside". Motion: each line draws from its first listed station to its last at a constant 1,300px/s via stroke-dashoffset, the head a round cap: Ember from 0.8s, Fern from 1.9s, Tide from 2.6s, Saffron from 3.6s. As a head passes a station, the tick grows 0 → 10px over 0.12s; its label fades in and slides 8px toward the station over 0.25s, starting 80ms later. An interchange circle pops when the first line reaches it (scale 0 → 1, 0.3s, cubic-bezier(0.34, 1.56, 0.64, 1)) and nudges to 1.12× and back when another line arrives. Each legend row fades in as its line finishes. Train: a white capsule 30×18px with a 4px Tide-colored outline, centered on the line and turned to its segment's angle. Between stations it accelerates and brakes on easeInOutSine, each leg's time proportional to its length, dwelling 0.25s at every stop; the board's "Next:" line changes as it leaves each station, crossfading over 0.15s. The real thing is disciplined: one line weight, three angles, steady spacing, horizontal labels that never collide. The cheap version is a geographic tangle with angled labels, glowing lines and map pins. Banned: angles other than 0°, 45° and 90°, curves beyond the bend radius, angled labels, geographic detail, real cities or real transit names, colors or symbols, map pins, shadows, glow, gradients, a fifth line color, emoji, anything flashing more than 3 times per second. </direction> <structure> 0.0–0.8s: white ground; the river band draws in from the west edge; the title and subtitle fade up; the river name sets. 0.8–4.4s: the four lines draw in turn, ticks, labels and interchanges following each head. 4.4–5.2s: the legend panel fades in; the train appears at Gullhaven (scale 0 → 1, 0.25s). 5.2–8.6s: the train runs to Saltings, stopping at every station; the board updates at each departure. 8.6–9.0s: the board changes to "Arrived: Saltings". 9.0–10.0s: hold. For other lengths, keep the drawing speed constant and give the extra time to the train run and the hold. </structure> <build> One self-contained index.html, CSS and JS inline. Google Fonts via <link> are fine; no other libraries. Draw in inline SVG whose attributes seek sets directly; no canvas or three.js needed. Await document.fonts.load() for every face before defining window.seek. The stage is 1920×1080 (16:9), scaled to fit the window. Design for 60fps. window.seek(t), t in seconds, must compute every visual from t alone: no CSS transitions or animations, no setTimeout or setInterval, no state carried between frames, and randomness only from a seeded PRNG. Build each line as one path from its grid points and measure it once with getTotalLength; the train's position comes from getPointAtLength. 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. </build> <check> Before showing me, step through one frame per second: screenshot each and look at it. Fix overlaps, clipped or cramped text, accidental edge collisions, and anything off-style or Banned. Check every segment's angle, ticks and interchange rings sitting exactly on their grid points, labels clear of every line, tick, the river and each other, and the train centered on the line in every frame. Confirm seek(duration) and seek(duration + 1) match, so the final frame holds. </check>
Ours, and free to use under CC0: copy it, change it, ship it. No credit needed.
A calm cartographic animation: smooth brown contour lines draw in from valley to summit, the terrain slowly morphs as a…
A print-style travel map that draws itself: water-lined coast, ink mountains and serif labels, then a red route line ca…
A night map seen through a phone that works like a lens, the city dimmed around it: a coral route draws along procedura…
A print-style dotted globe of a fictional world turns on warm paper while vermilion and cobalt arcs fly a new airline's…
More like this on the motion design inspiration board: Diagram animation inspirationMap animation inspiration