ISOLA

How it was made · one of 25 sites

A village built from divs, relit by variables.

ISOLA is a fictional island village of twenty-seven residents, made for anyone who has ever wanted a map to be a place. The page has one job: make you click a rooftop — and then flip the sky.

The concept

An isometric island you can visit: seven buildings, a harbour, a lighthouse, all constructed from CSS 3D transforms — no images, no canvas, no WebGL, no libraries. Every building is a clickable resident with a story, and the signature move is the day/night switch: one class on <html> swaps a set of CSS custom properties and the entire scene — sea, walls, roofs, windows, sky, page chrome — relights in a single choreographed 1.1 s transition. Windows glow, the lighthouse beam starts sweeping, the moon takes over, and Matteo's window stays dark because he goes to bed before the lamp comes on.

Palette

Every colour is argued for by the subject: Mediterranean shallows, dry grass hills, terracotta pantiles, flour-white render. The night set is not a filter — each material has a hand-picked moonlit counterpart, which is what makes the relight feel physical. Toggle the switch above to audit both sets live.

Day

Strait sea#5CB8B2
Island grass#9BC46A
Terracotta roof#D97757
Render wall#F5ECD7
Harbour sand#E6D394
Ink#1D3A3E

Night

Deep sea#16324A
Night sky#071426
Window glow#FFD98E
Moonlit render#9FA9BE
Roof at night#7C5560
Grass at night#3C5D4B

Type

Gabarito, 900 — the voice of a friendly place.

Atkinson Hyperlegible carries the body. It was designed by the Braille Institute for maximum letterform distinction, which suits a site about a village where everyone is known by name — and it stays crisp at the small sizes the story cards use. The scale is deliberate: 92 px sea-lettering, clamp(2.7–4.9 rem) display, 1.06 rem body, .78 rem letterspaced eyebrows.

Eyebrows run 22% tracking, small caps energy

The typographic bravery moment: the village name set 900-weight directly onto the water plane in 3D, tracked out like chart lettering — it reads as cartography, not caption.

Techniques

A live cuboid from the same factory the island uses — flip the sky toggle and watch color-mix() relight it. Top face is brightest, the south face catches the sun, the east face sits in shade.

The cuboid factory. Every solid on the island is one reusable pattern: a positioned .box sized --w × --d with transform-style: preserve-3d, containing up to six face elements placed by transforms — the top face is translateZ(var(--h)), the south face translate3d(0, var(--d), var(--h)) rotateX(-90deg), the east face adds rotateY(-90deg), and so on. The whole stage sits under one orthographic camera: rotateX(55deg) rotateZ(45deg) with no perspective, so the village reads as a toy, not a room.

Roofs by Pythagoras. Gable roofs keep a 3-4-5 proportion — rise is .375× depth, so each slope is exactly .625× depth long and tilts exactly 36.87°. That one constant lets a single CSS rule roof every house on the island, from the osteria to the net shed. Gable triangles are clip-pathed rectangles standing on the same transforms as walls.

The lighting model. No face carries a hard-coded colour. Each face computes color-mix(in oklab, var(--mat) k%, tint), where the material, the mix amount and the tint (warm sunlight vs. cold moonlight, dusk-blue vs. abyssal shade) are all custom properties. The day/night switch changes the variables; background-color transitions do the rest. Because filter would flatten preserve-3d, everything — shading, glow, shadow — is done with colour math and box-shadows instead.

Billboarding. Name tags, the lamp halo and the smoke puffs counter-rotate with rotateZ(-45deg) rotateX(-55deg) — the exact inverse of the camera — so they face the viewer while still living at 3D coordinates above their buildings.

What is deliberately absent. No libraries, no canvas, no rAF loop — the only JavaScript is the theme switch, the story panel and a resize handler that scales the stage (with CSS media-query fallbacks if JS never runs). Boats bob, beams sweep and gulls glide on pure CSS animations, all silenced by prefers-reduced-motion.

Iteration log

Pass 1 — Craft

  • Sea edge ring: the wave-glint overlay ended in a hard circle against the fading sea; masked it with a radial-gradient so the water dissolves instead of stopping.
  • Harbour re-plan: the net shed was placed inside the plateau footprint and sat sunk to its eaves in grass; moved the sand terrace out to a true south-east beach, re-seated the shed, pier, ferry and rowboat around it.
  • Belfry: the campanile's arch openings were oversized black blobs; reduced to 14×19 px with a smaller brass bell highlight.
  • Sea lettering: the ISOLA water-label was drowned behind the island; moved it to open water south-west, where it reads on first glance.

Pass 2 — Depth

  • Load choreography: hero copy rises in four beats, then every building pops up from its plot with a springy cubic-bezier(.3,1.45,.45,1), staggered lighthouse-first — one orchestrated sequence instead of scattered effects.
  • Second-read details: one window in Casa Blu stays dark at night (Matteo sleeps before the lamp comes on — his story says so); the stories cross-reference each other (Bruno the dog commutes on the ferry he has a chair on).
  • Life: two gulls glide across the day sky and roost at night; chimney smoke drifts up from the bakery in billboarded puffs.
  • Micro-interactions: resident-card chips tilt on hover; the sky-switch knob swells slightly; buildings lift 9 px with a dashed mooring-ring and name tag.

Pass 3 — Hardening

  • 375 px: verified in a true 375-wide viewport — stage scale floor lowered to .27 so the full island fits with no horizontal scroll; hero stacks copy above the scene.
  • Fixed a real paint bug: the moon was painted behind the opaque night-sky pseudo-element; z-indexed the celestial layer above it.
  • Reduced motion: bobbing, beam sweep, ripples, smoke, gulls, pop-in and text rise all disabled via media query; theme cross-fade shortened to .25 s. No JS animation loops exist to guard.
  • Chanel rule: removed the second cloud — it crowded the island's silhouette without earning its place.
  • Interaction audit: clicked a rooftop with a real pointer (not just .click()) to confirm 3D hit-testing; Escape closes the story; every trigger is a focusable <button> with a visible focus ring.