threejs-diorama
Build an animated isometric 3D diorama in Three.js (a miniature world inside a cube or block, often glass water), shown as a poster with a title, clock and legend, looping and recordable to video. Use when the user asks for a 3D diorama, miniature scene, isometric scene, tiny world in a cube, or a looping Three.js animation or video of a scene, whatever the theme (flooded railway, snowy cabin, rainy street, lighthouse, forest, space station, ...).
Created date:
Updated Date:
Skill in action
Instructions
Three.js isometric diorama
Produce one self-contained index.html showing a looping miniature world, in the style of a poster. The same structure works for any theme; only the scene contents change.
1. Work out the scene (ask only if the user gave no theme)
Settle these from the user's request, inventing what is missing:
- Theme and block material: what the cube holds (glass water, ice, soil cross-section, snow, sand, clouds, a solid ground block).
- Hero: one moving main subject (a tram, boat, car, train, character, airship).
- Story beats for a 15–30 s loop: arrive → pause / do something → leave → empty moment → loop.
- Ambient life: 2–4 secondary loops (birds, fish, smoke, rain, falling leaves, blinking lights).
- Time-of-day arc: a simulated clock range (e.g. 15:40 → 17:40) driving light and background color.
- Title, one-line subtitle, 4 legend rows (
Object — Interaction), and state labels for the clock line.
Make an original scene. Do not reproduce a specific film, game or brand's characters, logos or scenes. Take only the mood from them.
2. Technical setup
- One
index.html, Three.js r160+ through an ES module import map from a CDN (threeplusthree/addons/), no build step, procedural geometry only (no model files). - Square canvas (default 1200×1200 CSS px), centered,
renderer.setPixelRatio(min(devicePixelRatio, 2)). OrthographicCameraat an isometric angle (about 35° down, 45° around) aimed at the block center; the block fills about 70% of the frame. Optional idle sway of ±2°.OrbitControlsonly with?debug.- Organize the code as
buildBlock(),buildGround(),buildProps(),buildHero(),buildAmbient(),buildOverlay(), and a puretimeline(t)that sets every animated value from loop timet.
3. The block (the signature look)
- About 10×10 units wide, 3 deep, using
RoundedBoxGeometryfor soft edges. - Open top by default. A miniature reads best when its top is open: water, snow or ground is the top surface, and tall props (poles, trees, buildings, the hero) rise above it. Build a fully closed block with a lid only when the user clearly wants it sealed ("sealed in", "trapped inside", "frozen solid"). Words like "inside an ice cube" are ambiguous, so pick open top and say in one line that a closed lid is an option.
- For a closed block, keep the top face very clear (high transmission, low roughness) and keep the hero and key props fully inside, so the lid doesn't hide them or cut through them.
- Transparent block (water/ice/glass):
MeshPhysicalMaterialwith transmission about 0.9, thickness 2, a fitting ior (water 1.33, ice 1.31), low roughness, tintedattenuationColor. A separate subdivided top surface displaced by summed sines in a vertex shader. Animated caustics on the floor. - Opaque block (soil, snow, rock): a layered cross-section with visible strata on the sides.
- Fill the inside and top densely with small low-poly props at varied scales. The diorama feel comes from density and tiny detail. Use instancing for repeated things (grass, rocks, fish, trees).
- Sway plants, cloth and water in vertex shaders, not on the CPU.
4. Hero and animation
- Make the hero rounded, toy-like and readable at small size: chunky forms, warm emissive windows or lights, one distinctive color against the block.
- Ease every move (
easeInOutCubic). Have the hero react to the world (a wake in water, tracks in snow, dust on the ground). - Add at least one small mechanical moment (a door slides, a sign blinks, a sail unfurls) and show it in the state label.
- Make objects in the legend clickable (Raycaster) to trigger their interaction early.
5. Lighting and look
HemisphereLightplus one shadow-castingDirectionalLight(PCFSoftShadowMap), a soft shadow on the page-colored ground under the block.- ACES filmic tone mapping, sRGB output. The sun color, intensity and page background gradient follow the simulated clock.
EffectComposer: subtle bloom on emissives, a light vignette, SMAA/FXAA. Optional faint tilt-shift.- Use a restrained palette: one saturated block color, one warm hero color, neutral wood, stone or metal, and a desaturated page background.
6. Poster overlay (HTML/CSS over the canvas)
- Top-left: large serif title (e.g. Cormorant Garamond from Google Fonts) and a one-line subtitle.
- Top-right: small monospace
HH:MM · Statethat updates with the timeline. - Bottom-left: a two-column monospace legend (4 rows). Bottom-right: a small signature.
- Muted text color with plenty of whitespace. The 3D scene is the focus.
7. Sound
- Add procedural Web Audio (no audio files): a looping ambient bed that fits the theme (wind, waves, rain, crowd), a hum or engine sound faded in while the hero moves, and short chimes or bells keyed to story beats in
timeline(t). - Browsers block audio until the user interacts, so start the
AudioContexton the first click or key press. - Send the master output to a
MediaStreamDestinationtoo, so the recording can include it.
8. Recording
- With
?record: drive time from the frame count at a fixed 60 fps (t = frame / 60), hide the cursor, draw the overlay into the canvas (or composite it onto a 2D canvas each frame), wait for one click (needed to start audio), then record exactly one loop withcanvas.captureStream(60)plus the audio track, usingMediaRecorder(video/webm;codecs=vp9,opus, high bitrate), then downloaddiorama.webm. - Make the loop seamless: every value in
timeline(t)must match att = 0andt = LOOP. - Tell the user how to convert it for sharing:
ffmpeg -i diorama.webm -c:v libx264 -crf 18 -pix_fmt yuv420p diorama.mp4As a quick alternative, they can record the canvas area with macOS Cmd+Shift+5.
9. Finish
Serve the folder locally (e.g. npx serve .), open it, check that there are no console errors and that the loop and the clock labels work, and take a screenshot to check the framing before handing over. Then give the user a short list of easy tweaks (block material, hero, palette, loop length).
Reference example
A flooded seaside railway: a glass water cube with a seabed of rocks, coral, sea grass, fish and a stone lantern; a wooden trestle track just above the waterline; three utility poles with sagging catenary wires (TubeGeometry); a blinking crossing sign. A red-and-cream tram arrives, stops, slides its door open, and departs. Gulls circle and swap perches on the poles. Clock 15:40→17:40, with states "Departing / Beyond the light / Arriving / Bell ringing". Title "Tidal Line", subtitle "Nothing you forget is lost. It is only underwater."
Frontmatter · all metadata
name: threejs-diorama description: Build an animated isometric 3D diorama in Three.js (a miniature world inside a cube or block, often glass water), shown as a poster with a title, clock and legend, looping and recordable to video. Use when the user asks for a 3D diorama, miniature scene, isometric scene, tiny world in a cube, or a looping Three.js animation or video of a scene, whatever the theme (flooded railway, snowy cabin, rainy street, lighthouse, forest, space station, ...).
View original SKILL.md
---
name: threejs-diorama
description: Build an animated isometric 3D diorama in Three.js (a miniature
world inside a cube or block, often glass water), shown as a poster with a
title, clock and legend, looping and recordable to video. Use when the user
asks for a 3D diorama, miniature scene, isometric scene, tiny world in a cube,
or a looping Three.js animation or video of a scene, whatever the theme
(flooded railway, snowy cabin, rainy street, lighthouse, forest, space
station, ...).
---
# Three.js isometric diorama
Produce one self-contained `index.html` showing a looping miniature world, in the style of a poster. The same structure works for any theme; only the scene contents change.
## 1. Work out the scene (ask only if the user gave no theme)
Settle these from the user's request, inventing what is missing:
- **Theme and block material**: what the cube holds (glass water, ice, soil cross-section, snow, sand, clouds, a solid ground block).
- **Hero**: one moving main subject (a tram, boat, car, train, character, airship).
- **Story beats** for a 15–30 s loop: arrive → pause / do something → leave → empty moment → loop.
- **Ambient life**: 2–4 secondary loops (birds, fish, smoke, rain, falling leaves, blinking lights).
- **Time-of-day arc**: a simulated clock range (e.g. 15:40 → 17:40) driving light and background color.
- **Title, one-line subtitle, 4 legend rows** (`Object — Interaction`), and state labels for the clock line.
Make an original scene. Do not reproduce a specific film, game or brand's characters, logos or scenes. Take only the mood from them.
## 2. Technical setup
- One `index.html`, Three.js r160+ through an ES module import map from a CDN (`three` plus `three/addons/`), no build step, procedural geometry only (no model files).
- Square canvas (default 1200×1200 CSS px), centered, `renderer.setPixelRatio(min(devicePixelRatio, 2))`.
- `OrthographicCamera` at an isometric angle (about 35° down, 45° around) aimed at the block center; the block fills about 70% of the frame. Optional idle sway of ±2°. `OrbitControls` only with `?debug`.
- Organize the code as `buildBlock()`, `buildGround()`, `buildProps()`, `buildHero()`, `buildAmbient()`, `buildOverlay()`, and a pure `timeline(t)` that sets every animated value from loop time `t`.
## 3. The block (the signature look)
- About 10×10 units wide, 3 deep, using `RoundedBoxGeometry` for soft edges.
- **Open top by default.** A miniature reads best when its top is open: water, snow or ground is the top surface, and tall props (poles, trees, buildings, the hero) rise above it. Build a fully closed block with a lid only when the user clearly wants it sealed ("sealed in", "trapped inside", "frozen solid"). Words like "inside an ice cube" are ambiguous, so pick open top and say in one line that a closed lid is an option.
- For a closed block, keep the top face very clear (high transmission, low roughness) and keep the hero and key props fully inside, so the lid doesn't hide them or cut through them.
- **Transparent block** (water/ice/glass): `MeshPhysicalMaterial` with transmission about 0.9, thickness 2, a fitting ior (water 1.33, ice 1.31), low roughness, tinted `attenuationColor`. A separate subdivided top surface displaced by summed sines in a vertex shader. Animated caustics on the floor.
- **Opaque block** (soil, snow, rock): a layered cross-section with visible strata on the sides.
- Fill the inside and top densely with small low-poly props at varied scales. The diorama feel comes from density and tiny detail. Use instancing for repeated things (grass, rocks, fish, trees).
- Sway plants, cloth and water in vertex shaders, not on the CPU.
## 4. Hero and animation
- Make the hero rounded, toy-like and readable at small size: chunky forms, warm emissive windows or lights, one distinctive color against the block.
- Ease every move (`easeInOutCubic`). Have the hero react to the world (a wake in water, tracks in snow, dust on the ground).
- Add at least one small mechanical moment (a door slides, a sign blinks, a sail unfurls) and show it in the state label.
- Make objects in the legend clickable (Raycaster) to trigger their interaction early.
## 5. Lighting and look
- `HemisphereLight` plus one shadow-casting `DirectionalLight` (PCFSoftShadowMap), a soft shadow on the page-colored ground under the block.
- ACES filmic tone mapping, sRGB output. The sun color, intensity and page background gradient follow the simulated clock.
- `EffectComposer`: subtle bloom on emissives, a light vignette, SMAA/FXAA. Optional faint tilt-shift.
- Use a restrained palette: one saturated block color, one warm hero color, neutral wood, stone or metal, and a desaturated page background.
## 6. Poster overlay (HTML/CSS over the canvas)
- Top-left: large serif title (e.g. Cormorant Garamond from Google Fonts) and a one-line subtitle.
- Top-right: small monospace `HH:MM · State` that updates with the timeline.
- Bottom-left: a two-column monospace legend (4 rows). Bottom-right: a small signature.
- Muted text color with plenty of whitespace. The 3D scene is the focus.
## 7. Sound
- Add procedural Web Audio (no audio files): a looping ambient bed that fits the theme (wind, waves, rain, crowd), a hum or engine sound faded in while the hero moves, and short chimes or bells keyed to story beats in `timeline(t)`.
- Browsers block audio until the user interacts, so start the `AudioContext` on the first click or key press.
- Send the master output to a `MediaStreamDestination` too, so the recording can include it.
## 8. Recording
- With `?record`: drive time from the frame count at a fixed 60 fps (`t = frame / 60`), hide the cursor, draw the overlay into the canvas (or composite it onto a 2D canvas each frame), wait for one click (needed to start audio), then record exactly one loop with `canvas.captureStream(60)` plus the audio track, using `MediaRecorder` (`video/webm;codecs=vp9,opus`, high bitrate), then download `diorama.webm`.
- Make the loop seamless: every value in `timeline(t)` must match at `t = 0` and `t = LOOP`.
- Tell the user how to convert it for sharing:
`ffmpeg -i diorama.webm -c:v libx264 -crf 18 -pix_fmt yuv420p diorama.mp4`
As a quick alternative, they can record the canvas area with macOS Cmd+Shift+5.
## 9. Finish
Serve the folder locally (e.g. `npx serve .`), open it, check that there are no console errors and that the loop and the clock labels work, and take a screenshot to check the framing before handing over. Then give the user a short list of easy tweaks (block material, hero, palette, loop length).
## Reference example
A flooded seaside railway: a glass water cube with a seabed of rocks, coral, sea grass, fish and a stone lantern; a wooden trestle track just above the waterline; three utility poles with sagging catenary wires (`TubeGeometry`); a blinking crossing sign. A red-and-cream tram arrives, stops, slides its door open, and departs. Gulls circle and swap perches on the poles. Clock 15:40→17:40, with states "Departing / Beyond the light / Arriving / Bell ringing". Title "Tidal Line", subtitle "Nothing you forget is lost. It is only underwater."