Diorama / Dither
A yard.
In hard pixels.
Build an isometric miniature on the Pixel kernel, then finish it as a dithered yard: 360 by 280, five close tones, a 4 by 4 ordered dither, a hard shadow and one tap that toggles a state. One offline HTML file of at most 70 KB.
What it is
Dither is a skill for one small place. The picture is a yard or a shore that fills the frame, one structure, one or two people doing one looping action, and a tap that changes something you can see. There is no score and no audio. The camera does not move.
The drawing is the Pixel kernel, unchanged. New helpers live in the dither finish, not in that kernel. A pixel page never loads this finish, so the three Pixel scenes stay as they are.
How it differs from Pixel
| Pixel | Dither | |
|---|---|---|
| Kernel | Pixel, on its own | The same Pixel kernel, plus the dither finish |
| Frame | 320 x 240, 24 fps | 360 x 280, 12 fps |
| Dither | 8 x 8 Bayer matrix | 4 x 4 ordered dither, five close tones |
| Shadow | A shadow map and contact shadows | One hard shadow that darkens the ground's own colour |
| Ground | An outline that dissolves into the page | A yard or a shore that fills the frame |
| Tap | A small answer: a wave, a strike, a pour | One toggled state, large enough to read |
| Page | About 55 KB | At most 71680 bytes, and at most 260 lines of scene |
Worlds is a different renderer: Three.js, articulated people, four finishes. Dither does not use it. For crisp vector figures, use Diorama SVG.
Install
npx skills add educlopez/diorama --skill diorama-dither -g--skill diorama-dither selects Dither. The others are --skill diorama (SVG), --skill diorama-worlds and --skill diorama-pixel. All four live under skills/ in the same repository. Add -a claude-code or -a codex to target one agent. Omit -g for a project-local install.
Node.js 20+ runs the build and the validator. The look (browser screenshots and checks) needs Chrome or Chromium and the skill's one dev dependency, installed once with npm ci --ignore-scripts --prefix <skill-folder>. Built pages need nothing: no WebGL, no CDN, no network.
Ask for a yard
/diorama-dither a stone forge in a mountain yard. The smith strikes the anvil, smoke leaves the chimney, and a mule waits with the cart.In agents without slash commands, ask “Use the diorama-dither skill…”. Name the yard, the one action, and the one thing a tap toggles. The agent writes the picture in four lines (ground, mass, people, life), builds the scene, validates it, runs the support check and opens the captures before handing it over.
What you get
| Part | What it does |
|---|---|
| frame | 360 x 280 internally, enlarged by a whole number with square pixels. 12 fps. An 8 second loop. |
| materials | Named ramps: meadow, earth, stone, tile, timber, water, sail, paper. Five close tones each. A report checks the ramp before a custom one is invented. |
| dither | A 4 x 4 ordered matrix between those tones. A ray uses a flat face, with a darker dithered tone on alternate segments so it does not read as one bar. |
| shadow | One sun, a hard shadow on the ground's own colour, lit ground past the shadow. Not a flat grey bar. |
| people | One or two figures from the finish's person helper, with three cloth colours far apart. The pointer names them. |
| tap | Toggles one state. The still frame starts with that state clear, and the other state has to change a mass you can see. |
| lamp and ray | A lamp is a post, a paper box and a cap. A beam is thin hard pixels. Neither is a soft wrap of light. |
Support
A piece either meets a surface or names why it does not. npm run support from the skill folder audits every example. One scene is node scripts/support.mjs examples/<name>.js. Both the script and the look check the still and the frames at a quarter, a half, three quarters and the end of the loop.
| Call | What it claims |
|---|---|
Dither.seat(node, name) | The bottom face is within one voxel of the ground. |
Dither.seat(node, name, other) | The two solids meet within one voxel. A bed on an axle, a screen on a floor. |
Dither.seat(wheel, name, 'ground', axle) | A wheel meets the ground and its axle. The bed sits on the axle. |
Dither.seat(node, name, 'water') | The water plane cuts the body. A hull sits in the water, not on it. |
Dither.afloat(node, name, reason) | The only leave-the-ground. The reason is a non-empty string: a carried sack, smoke, a ray. |
A mesh with no support fails as has no support. Sitting inside a group's box is not enough: the nearest mesh has to be within one voxel, unless the bottom is already on the ground. A blank float reason fails as floats without a reason. A figure whose body passes through a solid that is not the ground fails as stands inside. Feet on open water fail. A missing foot coordinate fails as has no place to stand, and does not silently stand at the origin.
Walls, gates, fences, lamps, trees and the person helper already seat themselves. Wheels, posts, hulls and anything you add by hand still need a seat or a reason.
Byte budget
The scene file stays at or under 260 lines. The built page stays at or under 71680 bytes. node scripts/validate.mjs examples/<name>.js assembles that page and, on a pass, prints the bytes left. The kernel takes most of the file. A longer title spends some of the rest, because the page shell writes it. When the page is over, cut decoration before the action.
| Scene | Lines | Built page | Left of 71680 |
|---|---|---|---|
| The mountain forge | 150 | 71675 bytes | 5 bytes |
| The lighthouse | 126 | 70115 bytes | 1565 bytes |
| The tea house | 143 | 71083 bytes | 597 bytes |
| The windmill | 133 | 70948 bytes | 732 bytes |
These counts come from the pages the site builds. The gallery on /dither shows the same size next to each scene.
Examples
Four yards ship with the skill. Each is one Pixel.scene file under skills/diorama-dither/examples/. Open them live, or read the source.
| Scene | What happens |
|---|---|
| The mountain forge | A smith strikes the anvil by a stone forge. Smoke leaves the chimney, and a mule waits with the cart. Hover the smith or the mule; tap the smith to rest. |
| The lighthouse | A plaster tower on a rocky islet. A hard ray crosses the water, and a small boat rocks beside the rocks. Hover the keeper or the boat; tap the keeper to toggle the beam. |
| The tea house | A timber tea house by a koi pond. Carp circle in the near water, and a tap shifts the hour from day to dusk. Hover the host or a lantern; tap the host to change the hour. |
| The windmill | A stone mill under a conical tile cap. The sails turn on the front shaft while the miller holds a sack. Hover the miller or the carter; tap the miller to brake the sails. |
Build and check
node <skill-folder>/scripts/build.mjs examples/forge.js
node <skill-folder>/scripts/validate.mjs examples/forge.js
npm run support
node <skill-folder>/scripts/look.mjs examples/forge.js work/forge-lookRun the commands from the skill folder, or pass paths that reach it. npm run support audits every example, then the cases that must fail (a lifted wheel, a floating box, a figure in water) and the cases that must pass (a figure on rock). The look opens the page with the network blocked and writes the still, four loop moments, hover, press, mobile and figure zooms. It checks fill, the loop seam, picking, the tap, reduced motion, a hidden tab, off-screen pause, hard shadows and a median frame at or under 83.3 ms. Open the images too: a pass is not a picture.
Embed
<iframe
src="/dither-forge.html?embed"
title="A smith striking the anvil at a mountain forge"
style="width:100%;aspect-ratio:360/280;border:0"
></iframe>?embed fills the frame with the canvas and leaves the words to your page; the read-out stays in a corner. The frame is 360 by 280, so the box is wider than Pixel's 4:3. To mount without a frame, load the built kernel and the scene and call Pixel.mount on the last scene. Primitives and the tick contract are the Pixel scene API. Do not copy Pixel's dissolving ground or its 320 x 240 frame into a dither scene. The finish's helpers (Dither.mat, Dither.seat, Dither.folk and the rest) are in the Dither skill.
Know the tradeoffs
The loop runs at 12 fps, sleeps offscreen and in hidden tabs, and holds the still frame under reduced motion and ?still. Do not start a timer. Pose from the clock only, and close the loop so the first frame matches the last.
People are small figures on the pixel rig, not the articulated adults of Diorama Worlds. The camera is fixed. A second light is out of the finish: evening is dark cloth, paper screens and a small hard core you show and hide, not a pool of light. Do not set glow on a material. It lifts that face to a flat brightness. Sizes, the yard recipe and the shadow checks are collected in the yard reference.