The making-of guide
How this tiny city was built
The concept. Microtopia is a miniature diorama that constructs itself as you scroll: four districts rise block by block, a tram starts its loop, night falls, 428 windows light up, and morning returns. The whole city is HTML. There are no images, no WebGL, no 3D engine.
The actual techniques
- CSS 3D isometrics. A JavaScript helper folds plain divs into boxes: a top face plus the two camera-facing walls, positioned with
translate3d/rotateX(90deg)/rotateY(-90deg)inside atransform-style: preserve-3dtree tilted byperspective(2300px) rotateX(55deg). Gabled and pyramid roofs are the same trick with a little trigonometry andclip-pathtriangles for the gable ends. - Scroll choreography. One GSAP ScrollTrigger timeline, scrubbed across a 900vh section, raises each district by tweening a per-building
--szcustom property used asscaleZ(), with a springyback.outease and randomized stagger. - Day/night cycle. A single inherited
--nightproperty (0 to 1), tweened on scroll, drives a translucent tint on every face via::before, the window glow via::after, lamp glows, stars and the vignette. Sky colors are tweened CSS variables. - Window grids. Each wall's windows are one background image repeated with
background-repeat: space; seven buildings flicker at night by animating a registered@property --blink. - The tram is a 26-second infinite CSS keyframe loop around the plaza; smoke, gulls, the pennant and lamp glows are billboards that counter-rotate against the camera with
calc(var(--spin) * -1deg). - Accessibility.
prefers-reduced-motionswaps the whole experience for a fully built daytime city with the story cards in normal document flow.
Three passes, honestly
The site was built with a screenshot-verify loop: render, capture desktop and mobile, read the pixels, fix, repeat.



Pass 1 exposed two real bugs: on mobile, CSS grid refused to truly center the overflowing 760px scene (fixed with absolute positioning and negative margins), and a GSAP fromTo at the dawn beat immediate-rendered the sun invisible at the top of the page (fixed with immediateRender: false). Pass 2 added the survey-plan district lettering, chimney smoke, gulls and benches. Pass 3 tuned camera drift, type rhythm and contrast, then verified the live deploy.
Prompting an agent to build this
"Build a pure CSS-3D isometric city on a diorama plate that constructs itself on scroll. Write a div-folding helper (top face + two visible walls), pin the scene, and drive construction from one scrubbed GSAP timeline: four districts, each with a story card. Tie a --night variable to scroll for a day/night cycle. Add an infinite tram loop and tiny details: a cat, laundry lines, blinking windows. Screenshot desktop and mobile after every pass, read the screenshots, and fix what you see at least three times."
The craft is in the loop, not the first render. Insist on real screenshots, insist on reading them, and insist the direction of travel is always richer.