Low-poly Isometric Island — our demo

One example among many. Don't reuse its story, arc, shots, props or timings.

Demo: The Island That Grew (53 s) · lowpoly-island.mp4 · source in demo/

Story & structure

An empty sea with only a buoy that knows one note; tiles, trees and houses rise from the sea one by one, each landing with a note, so the island and its song are written together — until at night the boat that went out cannot find its way home, and the last "note" is a lighthouse.

The film's shape: a small world that grows, lives through a day, and meets one problem that the final piece solves — one subject (an island), one goal (to become a home), one turn (night falls, the boat is lost). It is only this film's shape, not the way to adapt any topic.

Emotional arc (53 s): emptiness → first note → accelerating joy of building → a lived-in day → dusk warmth → silent night with one thing missing → the final piece ignites (climax) → pull back to scale, with an echo of the opening.

Native powers spent: procedural growth (the whole first act), the orthographic gaze (the final ×25 zoom), turntable (the growth shot), flat shading × light (the day time-lapse), emissive blocks (windows at dusk, the beam at night).

"Building is composing", as the demo paid it off: every growth event is exported from the page with a MIDI note, and the score's melody voice is synthesized from those events. The lighthouse beam turns once every 12 beats and passes one ring cell per beat; the eight houses standing on those cells light up and chime as it passes, so the notes laid down in a shuffled build order are replayed in spatial order as the complete theme. The second ring around the centre cell has 12 cells at exactly 30° steps, which makes this beat-synced sweep possible.

Shots

Beat Camera Why
Opening Close ortho (frustum 7.5) on one lonely object, empty faceted sea, sky band at the top Give the viewer nothing to look at; the first tile then becomes an event
Growth Turntable (azimuth +45° over ~5 s) with a slow zoom-out, intercut on beats with close-ups: a peak rising with a splash (elevation 23°, frustum 5.2), floors stacking (26°, 6), dock planks and the boat drop (27°, 6.6) Wide shots show the shape growing; close-ups sell the bounce and the splash
Day Medium on the village, sun sweeping 100° in 2.5 s (time-lapse shadows) Light is the time machine
Departure Side angle computed from the dock direction, camera trails the boat The boat must move across the frame, not toward the lens
Dusk Fixed 3/4 wide, slow push, windows light one per eighth note Let the lights be the only motion
Night Very wide, elevation 21°, island lower left, one tiny light far out in the dark Negative space = danger
Climax High angle (50°) turning at 0.22× the beam speed, then easing down to 25° so the starry sky "rises" You must see the beam sweep over every house; then the sky opens up
Ending Pure orthographic zoom ×25; an echo object far away in the lower right Scale reveal and echo

Camera settings used: azimuth 45° by default, elevation 30° (build), 33–35° (day detail), 20–25° (night — a lower angle widens the sky band so stars show), 50° (top-down-ish when the beam sweeps). Frustum height 5–7 for close-ups, 12–16 for the whole island, up to 420 for the final scale reveal.

Score structure

Palette & props

End card

The night scale-reveal frame, darkened; the same title block (static), hex icon, LOW-POLY ISLAND · LEMO-OPUSCAR, LemoLab × Claude Opus 5.5, credits, laid out so the tiny lit island stays visible in a gap between the text blocks. The "LemoLab × Claude Opus 5.5" sign-off (and the LEMO-OPUSCAR line) belongs to this library's demo only; a user's film carries no LemoLab credit and no copy of this card.

Build notes

styles/lowpoly-island/demo/
  story.js   timeline (96 BPM grid), VO, chords, day/night keyframes, shots
  world.js   hex layout, all props, growth schedule → EV (with notes), per-frame animation
  sea.js     faceted wave shader, shallow-lagoon map, beam-lit water
  post.js    ortho post: GTAO → sky/haze + stars → tilt-shift → bloom → grade
  main.js    renderer, lights, cameras per shot, HUD (title, subtitles, end card), EV export
  music/score.py   event-driven score (+ check.py: librosa onset/pitch check vs events)
  mix.py     foley + ambience + voice + ducking     subs.py  subtitle cues
  build.sh   one-command rebuild
  1. node core/render/still.mjs styles/lowpoly-island/demo --range 0.5:52.5:1 + core/render/sheet.py — overview sheets, iterate.
  2. core/tts/tts.py lines.json voices → core/tts/asr_check.py until all OK.
  3. node core/render/events.mjs styles/lowpoly-island/demo → music/score.py → music/check.py → mix.py.
  4. node core/render/video.mjs styles/lowpoly-island/demo --fps 24 --workers 3 (1272 frames, 2× SSAA + GTAO).
  5. sh core/render/mux.sh out/video24.mp4 mix.wav lowpoly-island.mp4 24 0. Or just sh demo/build.sh.

Pitfalls tied to this demo's props: