Diorama Skill

The skill teaches your agent to build a small animated 3D world in one file: the kernel, five themes, eleven examples, a validator and a browser check.

Installation

npx skills add educlopez/diorama -g

Installs the skill for every agent the skills CLI knows. Add -a claude-code to target Claude Code alone. Node.js 20 or later runs the scripts; Chrome or Chromium runs the look (Playwright's browser is found, or playwright-core is installed once).

git clone https://github.com/educlopez/diorama.git ~/.claude/skills/diorama

The same, with git. Nothing is needed at runtime: a finished page loads three.js r128 from cdnjs, or carries it inline with --inline.

Prompts

Type /diorama and describe the place. Say where it will live (a hero, a card, a small figure), name the place or the product, and give a colour if you have one. The agent offers two or three concepts, builds the one you pick, runs the validator and the look, and hands you diorama-<name>.html.

/diorama a hero for our logistics landing page: a yard with trucks docking
/diorama an empty state for the inbox, small and quiet, line-drawing style
/diorama a card for the docs: jobs wait in line, one runner takes them
/diorama a harbour at dusk for the top of our README, brand colour #5b4ae0

Sizes

The size sets the stage, the budget and the tempo.

SizeLivesStageMovesLines
herothe top of a landing page or a README3:2, full widththree or four loops with different periods, one pointer answer≤ 420
cardbeside text in docs or a post4:3, about 500pxone process, one pointer answer≤ 240
minia small spot: an empty state, a feature list, a sidebar, a 404, an icon-sized hero1:1, 160 to 240pxone quiet ambient motion≤ 150

Themes

A theme is a set of fields the kernel applies to every primitive; a figure never branches on it, so the same file draws five ways. Pick it from where the figure will live.

ThemeReads asKeepsUse it for
toypastel blocks, one warm sun, a cool fill, soft shadowsevery colourproduct pages, READMEs, anything warm
softthe same on cream, gentler light, desaturated accentsevery colour, shifted warmeditorial pages, paper backgrounds
monotints of ink on whiteone accentdocs, product UIs with their own accent, text-heavy pages
linea hairline drawing: white fills, ink edges, silhouettes, no shadowsone accent, as a strokeminimal or technical pages, small quiet figures
nightdusk: dark base, cool sky, warm lamps and windowsevery colour, darkerdark pages, hero sections on black
Overrides, in the figure or on mount
theme: { base: 'mono', accent: '#f2c230', shadows: false }
theme: { base: 'toy', palette: { coral: '#5b4ae0', grass: '#d8ead0' } }
theme: { base: 'line', round: true, strokeWidth: 1.4 }
theme: { base: 'night', glow: 3, lights: { sun: ['#ffd6a0', .3] } }
FieldWhat it does
bgthe stage colour, or 'transparent'
paletteoverrides of any palette entry: base, ground, grass, water, paper, ink, coral, mustard, teal, plum, …
accentthe one colour mono and line keep
lights{ hemi: [sky, ground, i], sun: [c, i], fill: [c, i] | null, ambient: [c, i] }
shadowstrue or false
finish{ roughness, metalness }
tone, tint{ paper, ink } makes any theme monochrome; tint 0..1 lets colour back in
edges, outlineink lines on flat solids, silhouettes on round ones
stroke, strokeWidththe line colour and width in css px
roundevery box becomes a rounded solid
glowa multiplier on every emissive

Minis

A mini is a small figure, 160 to 240px square: one object and one quiet motion. Use it wherever a page needs a small picture: an empty state, a feature in a list, a settings section, a 404, a sidebar. Its still frame is the picture and the ambient motion is the bonus. The canvas is transparent, so whatever sits behind it shows through. The words around it, a heading, a line, a button, are yours to write in your own UI.

Mailboxmini · toyrest

The figure file

One Diorama.figure call: a declaration, a build that makes the scene once with the toolkit and returns the parts that move, and a tick that poses them from ctx.t. No timers, no new THREE.*, no words inside the scene.

mailbox.js, abridged
Diorama.figure({
  name: 'mailbox',
  size: 'mini',                          // hero | card | mini
  theme: 'toy',                          // or { base: 'line', accent: '#cf6a4c' }
  means: 'An open letterbox with nothing inside. The flag lifts now and then.',
  title: 'Mailbox',
  still: 1,                              // the second reduced motion shows
  build: function (o) {
    var D = o.D, pal = o.pal;
    D.slab(3, 3, pal.grass, 0, 0, 0, null, { h: .5, r: .45, side: pal.base });
    var post = D.group(.15, 0, -.1);
    D.cyl(.07, .09, 1.1, pal.wood, 0, .55, 0, post, 8);
    var body = D.group(0, 1.15, 0, post);
    D.box(.95, .5, .6, pal.coral, 0, .25, 0, body);
    var flag = D.group(.1, .5, .32, body);
    D.box(.26, .16, .03, pal.mustard, .1, .02, 0, flag);
    D.props.tree(1, -.8, null, { r: .42 });
    return { flag: flag };
  },
  tick: function (ctx) {
    var D = ctx.D, t = ctx.t, check = D.smooth(D.pulse(t, 7, .36));
    ctx.parts.flag.rotation.z = D.lerp(.2, 1.45, check);
  }
});

The toolkit: D.box, D.rbox, D.cyl, D.cone, D.ball, D.dome, D.wedge, D.slab, D.torus, D.wheel, D.label; the props tree, bush, rock, cloud, person, lamp, crate, pallet, cone, flag; for motion phase, pulse, wave, the eases, spring, path, place, spin, stagger. The index at the top of kit/diorama.js lists them all.

Scripts

node ~/.claude/skills/diorama/scripts/build.mjs mailbox.js

Writes diorama-mailbox.html: three.js from cdnjs, the kernel, the figure and the bench page. Add --inline to paste three.js in.

node ~/.claude/skills/diorama/scripts/validate.mjs diorama-mailbox.html

Nine checks: the declaration, the length, the clock, self-containment, the kernel, the words, the colours, the base and the pointer.

node ~/.claude/skills/diorama/scripts/look.mjs mailbox.js --theme line

Opens the page in headless Chromium and writes one sheet: the still frame, three moments, the pointer, the tilt, the thumbnail and the page, plus the console, the fill, the motion and the answer as numbers.

Embed

The built page can be served as is or framed. For a product, keep the kernel and the figure and drop the bench. The kernel sizes the canvas to the element’s width, watches resizes, sleeps offscreen and honours prefers-reduced-motion with one still frame. Remount to change the theme.

Any page
<div id="hero" style="width:100%"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="/diorama/kit/diorama.js"></script>
<script src="/diorama/island.js"></script>
<script>
  var fig = Diorama.figures[Diorama.figures.length - 1];
  var ctx = Diorama.mount(fig, { el: document.getElementById('hero'), theme: 'night' });
</script>
React or Next.js
"use client";
import { useEffect, useRef } from "react";
import * as THREE from "three";          // npm i three@0.128
import Diorama from "./diorama.js";
import "./island.js";                   // registers the figure

export function Hero({ theme = "toy" }) {
  const el = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const fig = Diorama.figures[Diorama.figures.length - 1];
    const ctx = Diorama.mount(fig, { el: el.current!, THREE, theme });
    return () => ctx.destroy();
  }, [theme]);
  return <div ref={el} style={{ width: "100%", aspectRatio: "3 / 2" }} aria-hidden />;
}

Craft rules

Ten rules separate a diorama from a pile of cubes: the world stands on a rounded base with its zones inside the corners; the camera is true isometric, subject front-left; the palette is pale with two or three accents and one named accent; materials are matte blocks, no textures; every object is a few primitives with the two or three features that give it away; one sun and soft shadows under everything; all motion comes from the clock in tick; vehicles ride paths on a schedule with stops that have a cause; a few loops with different tempos and one rare thing; and no words inside the scene. The long form, with recipes, is in references/craft.md.

What is in the skill

FileWhat it is
SKILL.mdthe workflow: size and concept, build, check, hand over, adjust
kit/diorama.jsthe kernel: camera, lights, shadows, themes, primitives, props, paths, springs, the loop
bench.htmlthe page a figure is built into; a theme switcher and a still-frame toggle
scripts/build.mjswrites diorama-<name>.html; --inline pastes three.js in
scripts/validate.mjsnine checks: declaration, length, clock, self-contained, kernel, words, colours, base, pointer
scripts/look.mjsa sheet of eight pictures and the numbers, in headless Chromium; --theme for another theme
references/concepts, the ten craft rules and the themes, motion, the look, React
examples/eleven figures across sizes and themes, the format to write
npx skills add educlopez/diorama -g