@gtanczyk/diorama 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -0
  2. package/app/src/actions/fix.ts +28 -10
  3. package/app/src/actions/story.ts +28 -1
  4. package/app/src/actions/style.ts +3 -2
  5. package/app/src/commands/backdrop.ts +23 -3
  6. package/app/src/commands/clip.ts +7 -0
  7. package/app/src/commands/derive.ts +9 -0
  8. package/app/src/commands/export.ts +1 -0
  9. package/app/src/commands/language.ts +2 -1
  10. package/app/src/commands/layout.ts +9 -4
  11. package/app/src/commands/masks.ts +2 -1
  12. package/app/src/commands/paint.ts +15 -7
  13. package/app/src/commands/play.ts +1 -0
  14. package/app/src/commands/playthrough.ts +2 -2
  15. package/app/src/commands/world.ts +9 -6
  16. package/app/src/play/car.ts +2 -0
  17. package/app/src/play/geometry.ts +12 -2
  18. package/app/src/play/parallax.ts +2 -0
  19. package/app/src/qa/route.ts +12 -2
  20. package/app/src/scene/cast.ts +4 -2
  21. package/app/src/scene/critic.ts +3 -2
  22. package/app/src/scene/derive.ts +46 -1
  23. package/app/src/scene/layers.ts +52 -0
  24. package/app/src/scene/layout.ts +13 -5
  25. package/app/src/scene/paint-layout.ts +2 -1
  26. package/app/src/scene/paint.ts +15 -8
  27. package/app/src/scene/photo.ts +25 -2
  28. package/app/src/scene/status.ts +2 -1
  29. package/app/src/scene/vehicle.ts +22 -0
  30. package/app/src/scene/verify.ts +12 -0
  31. package/app/src/setup/checks.ts +2 -2
  32. package/app/src/sound/plan.ts +6 -1
  33. package/app/src/story/engine.ts +9 -4
  34. package/app/src/story/fixes.ts +11 -2
  35. package/app/src/studio/agent.ts +21 -8
  36. package/app/src/studio/repair.ts +1 -1
  37. package/app/src/world/design.ts +1 -0
  38. package/app/src/world/drawings.ts +47 -14
  39. package/app/src/world/schema.ts +5 -0
  40. package/app/web/living.ts +36 -0
  41. package/app/web/main.ts +192 -18
  42. package/docs/releasing.md +22 -0
  43. package/docs/scenes.md +10 -1
  44. package/docs/studio.md +3 -1
  45. package/package.json +2 -2
package/docs/scenes.md CHANGED
@@ -29,6 +29,15 @@ Walk geometry still comes from the accepted painting, not the rough plan. The bu
29
29
  - **Rim light.** Each person gets a thin warm edge on the side the light comes from (against the way shadows fall; a place with no measured light gets none), as illustrators separate a figure from a busy background. `?rim=0` off, `?rim=1.5` wider.
30
30
  - **Focus** (off by default). `?focus=1` softens and pales what is behind the hero with its depth, like a close-up camera. It only separates far things, so it stays opt-in.
31
31
 
32
+ ## Drive: the hero's car
33
+
34
+ A place with `"kind": "drive"` in world.json is the hero's car: it stands at the kerb with the engine running and the hero at the wheel, and from it the player picks where to drive. Its one thing is the car (role exit) with an exit through it to every place it drives to; each of those places has the car parked in it (a thing with role exit) leading back. The world designer makes one only when the idea gives the hero a car.
35
+
36
+ - **Layout and paint.** The car stands in the middle, seen from behind at three-quarters, the hero painted at the wheel (the critic and the composition check let that one person stay); the top right quarter stays calm for the board. Masks, derive and verify run as anywhere: the street is the floor, and every thing there is a card of its own.
37
+ - **One car everywhere.** Each place is painted on its own, so the car as painted in the drive place (cut out by its mask, `scene/vehicle.ts`) goes to every place it is parked in as the last image of its painting, and Muse parks that same car there. A place painted before the drive place keeps its car until it is painted again.
38
+ - **In the page.** The car's card trembles with the idling engine and exhaust puffs from behind it; its lights glow as the painting's lights do. A board in the top right lists the places it drives to (their names). Picking one revs the engine (harder shaking, more smoke), the picture fades and the hero steps out beside the car where it is parked there. Clicking the car in a place walks the hero to it and in. There is no driving animation. The hero is the one painted at the wheel, so no figure is drawn and their lines come from the car.
39
+ - **The story.** One thing that leads to several places makes `go` actions with `to` (the destination); `playthrough` and `clip` click the board's row for it (`window.diorama.destinationPoint(to)`).
40
+
32
41
  ## Weather: rain, snow and drips
33
42
 
34
43
  `diorama weather <slug>` (a build step, after `backdrop`) reads what falls on each place and where water drips, into `places/<key>/weather.json`; the page animates it all, so nothing in the painting is a frozen streak:
@@ -55,7 +64,7 @@ To change it, tell the Studio agent ("no rain in the hut", "it should pour", "wa
55
64
 
56
65
  ## Checking a world
57
66
 
58
- `diorama build` ends with `verify`, which writes `verify.json` per place and prints which places are playable and what was flagged on the way. Places are built side by side and independently, and no place waits for another: each goes through its own steps and is told playable (`place.verdict`) as soon as its verify and free repairs are done, while the rest are still being made. The world's own steps start as soon as what they read is there (`app/src/world/schedule.ts`): the cast is painted from world.json while the places are, voices once the story is, an item's icon once its place is cut out, sprites once every place has its walking routes, sound once every place is painted. A place whose step breaks is set aside with why, and the others go on to the end, characters and sound included. Each model has a cap on requests open at once so the overlap does not run into rate limits (`DIORAMA_LANES="muse=8,spark=12,sam=16"`, the defaults). The report gives each error its playbook (`app/src/scene/playbook.ts`): where to look, the fix tools to try in order, and the costly last resort (a camera too close, `SCALE_NEAR` or a floor cut off once derive shut the front rows for it, is rerun derive first, then relayout and repaint); `place_status` hands the same to the Studio agent, which repairs one place at a time with the fix tools. The `masks` step also checks that each mask holds its thing: one Spark look per place at the painting with every mask box numbered (`app/src/scene/maskcheck.ts`), since a box and its mask can agree and both sit on the neighbour. When Spark points to where the thing really is, that is `MASK_WRONG` in verify (an error for any thing, props too). When it finds the thing nowhere and what it sees in the box is another kind of thing (hay where a horse should be), the thing was never painted: `THING_NOT_PAINTED`, an error whose play is to paint it in. A doubt about details only (a bronze bell for a brass one) is the flag `MASK_DOUBT`. Spark is asked to judge the kind of thing, not its details, and a box someone fixed is taken as given. Before anyone is asked, the build makes the cheap fixes itself (`app/src/scene/autofix.ts`): a gap of up to three 60 px cells with nothing solid in it, or up to six along stairs or a gangway (a walk-on thing) whose mask reaches both floors, is bridged with a floor brush stroke (two passes, as one bridge can bring the next patch within reach; stairs that lead somewhere else, with water between the floors, bridge nothing: that place needs a floor in the layout or a repaint, so it goes to the agent), a stand spot off the floor moves to the nearest reachable point (both without a model call), and a `MASK_WRONG` thing gets the box Spark saw it in (one SAM call). A card flagged `CARD_CUT` gets the cut part brushed onto its mask (a lantern on a boat's gunwale), so the card carries it and the backdrop is made again without it (once per cut). A `THING_NOT_PAINTED` thing left after them gets one Muse edit at its layout box (once per thing, kept as a repaint correction) and the place is rebuilt from paint. They are ordinary corrections, so `corrections_get` lists them and `corrections_clear` takes them back; `build.json` keeps them under `repairs`, and `--repair off` skips them. What the free fixes leave, the Studio hands to the agent at once: a build that ends with places unplayable wakes it with the places and their errors (`budget_set autoRepair:false` turns that off). It repairs with the fix tools in the playbook's order; after three fixes of a place in a row that leave it unplayable the fix tools refuse it and it tells you what it tried, which is your turn. `place_view` is how the agent looks, as a picture it sees (layer `walk`, `masks` or `painting`, all on the 60 px grid), so it has no need to dig through files; after three shell calls in a turn it is reminded of that once. Layer `masks` tints each thing's mask against the box it should be in and flags a mask that cut out a neighbour. Layer `walk` shows why a place cannot be walked: reached floor green, unreached red, each gap as a dashed line naming the 60 px cells to bridge (the ones `floor_cells` takes) and the things in it, and stand spots off the floor (`places/<place>/diagnose.png`; the agent gets it as an image). Every step also leaves a picture to look at: `masks/overlay.png` (what SAM found) and `walk.png` (where the hero can walk, footprints, floor lines and his size at a few depths).
67
+ `diorama build` ends with `verify`, which writes `verify.json` per place and prints which places are playable and what was flagged on the way. Places are built side by side and independently, and no place waits for another: each goes through its own steps and is told playable (`place.verdict`) as soon as its verify and free repairs are done, while the rest are still being made. The world's own steps start as soon as what they read is there (`app/src/world/schedule.ts`): the cast is painted from world.json while the places are, voices once the story is, an item's icon once its place is cut out, sprites once every place has its walking routes, sound once every place is painted. A place whose step breaks is set aside with why, and the others go on to the end, characters and sound included. Each model has a cap on requests open at once so the overlap does not run into rate limits (`DIORAMA_LANES="muse=8,spark=12,sam=16"`, the defaults). The report gives each error its playbook (`app/src/scene/playbook.ts`): where to look, the fix tools to try in order, and the costly last resort (a camera too close, `SCALE_NEAR` or a floor cut off once derive shut the front rows for it, is rerun derive first, then relayout and repaint); `place_status` hands the same to the Studio agent, which repairs one place at a time with the fix tools. The `masks` step also checks that each mask holds its thing: one Spark look per place at the painting with every mask box numbered (`app/src/scene/maskcheck.ts`), since a box and its mask can agree and both sit on the neighbour. When Spark points to where the thing really is, that is `MASK_WRONG` in verify (an error for any thing, props too). When it finds the thing nowhere and what it sees in the box is another kind of thing (hay where a horse should be), the thing was never painted: `THING_NOT_PAINTED`, an error whose play is to paint it in. A doubt about details only (a bronze bell for a brass one) is the flag `MASK_DOUBT`. Spark is asked to judge the kind of thing, not its details, and a box someone fixed is taken as given. Before anyone is asked, the build makes the cheap fixes itself (`app/src/scene/autofix.ts`): a gap of up to three 60 px cells with nothing solid in it, or up to six along stairs or a gangway (a walk-on thing) whose mask reaches both floors, is bridged with a floor brush stroke (two passes, as one bridge can bring the next patch within reach; stairs that lead somewhere else, with water between the floors, bridge nothing: that place needs a floor in the layout or a repaint, so it goes to the agent), a stand spot off the floor moves to the nearest reachable point (both without a model call), and a `MASK_WRONG` thing gets the box Spark saw it in (one SAM call). A card flagged `CARD_CUT` gets the cut part brushed onto its mask (a lantern on a boat's gunwale), so the card carries it and the backdrop is made again without it (once per cut). A `THING_NOT_PAINTED` thing left after them gets one Muse edit at its layout box (once per thing, kept as a repaint correction) and the place is rebuilt from paint. They are ordinary corrections, so `corrections_get` lists them and `corrections_clear` takes them back; `build.json` keeps them under `repairs`, and `--repair off` skips them. What the free fixes leave, the Studio hands to the agent at once: a build that ends with places unplayable wakes it with the places and their errors (`budget_set autoRepair:false` turns that off). It repairs with the fix tools in the playbook's order; after three fixes of a place in a row that leave it unplayable the fix tools refuse an exact repeat of a fix that failed and steer it to a different path (a mask brushed by hand, floor cells, taking a thing off), and after six they keep repaints and relayouts, which cost a Muse call, for you to approve; when the new path fails too it tells you briefly what it tried. `place_view` is how the agent looks, as a picture it sees (layer `walk`, `masks` or `painting`, all on the 60 px grid), so it has no need to dig through files; after three shell calls in a turn it is reminded of that once. Layer `masks` tints each thing's mask against the box it should be in and flags a mask that cut out a neighbour. Layer `walk` shows why a place cannot be walked: reached floor green, unreached red, each gap as a dashed line naming the 60 px cells to bridge (the ones `floor_cells` takes) and the things in it, and stand spots off the floor (`places/<place>/diagnose.png`; the agent gets it as an image). Every step also leaves a picture to look at: `masks/overlay.png` (what SAM found) and `walk.png` (where the hero can walk, footprints, floor lines and his size at a few depths).
59
68
 
60
69
  `diorama explore <slug>` puts the hero on every part of each floor in the real play page and checks each frame; it needs Playwright with Chromium (`diorama browsers` downloads it once). `--fix` closes the floor where he looked wrong.
61
70
 
package/docs/studio.md CHANGED
@@ -34,7 +34,7 @@ The agent can use `job_inspect` to see a job's timestamped recent activity, how
34
34
 
35
35
  Every fix is kept in a file next to what it fixes and applied again by every later build, so a rebuild never loses it: `places/<place>/corrections.json` (rebuilding only that place from the step it feeds), `story-fixes.json`, `cast/fixes.json`. A place's thing list is edited the same way: Remove takes a prop off it (kept in the picture, or painted out with one Muse edit) and Add makes something painted a thing of its own (`removed` and `added` in `corrections.json`, which every step reads with world.json); exits, items and people belong to the story. A small repaint rebuilds only what it reaches (`app/src/scene/carry.ts`): each place step keeps the painting it last ran on (`places/<place>/.ran/`), compares the new one with it tile by tile, and asks again only about what the changed tiles reach (a thing's or floor's mask, a plate, the backdrop's cards, the light, the stairs); everything else is asked about the old painting, which the memo answers for nothing, and the place keeps its scale. Lighting the lanterns of a harbour takes about 100 s instead of 270 s, and a rebuild on the same painting asks nothing new. A change over a third of the painting rebuilds everything. A place whose steps have not kept their painting (built before this, or put back by an Undo) takes the painting on disk as theirs before a repaint, so that repaint carries too. **History** lists the jobs the world went through, the agent's included, each with who ran it, when and which places it changed, and puts the world back as it was before any of them (Redo takes that back right after); a locked world or place is left alone by the agent.
36
36
 
37
- The conversation is genaicode's chat with Muse Code (default), Claude Code or Codex, picked in its header before the first message (Setup's **Default agent**, or a pick here, is remembered in `~/.config/diorama/studio.json` for new worlds; a world keeps the agent it last talked with, and `DIORAMA_AGENT=codex` overrides both); after it, "Hand over…" passes the conversation to another agent and a line marks where it changed hands. After a Studio restart the earlier turns come back on screen from `studio/sessions/`. The conversation is also kept in words in `studio/conversation.md`: a new agent session (another agent, or after the Studio restarts) is told to read it first, so nothing agreed is lost. The agent works through the same actions as the page, so its steps show live and its changes survive rebuilds; when a build leaves places unplayable it is woken to repair them, three tries a place. Every conversation is recorded in `studio/sessions/`: open one from "Recorded sessions", or `/w/<slug>?replay=<file>&speed=2`, to play it back for a film.
37
+ The conversation is genaicode's chat with Muse Code (default), Claude Code or Codex, picked in its header before the first message (Setup's **Default agent**, or a pick here, is remembered in `~/.config/diorama/studio.json` for new worlds; a world keeps the agent it last talked with, and `DIORAMA_AGENT=codex` overrides both; `DIORAMA_AGY_MODEL=gemini-4-argon-high`, `DIORAMA_CODEX_MODEL`, `DIORAMA_MUSE_MODEL`, `DIORAMA_AGENT_CLAUDE_MODEL` or `DIORAMA_AGENT_MODEL` picks the agent's model); after it, "Hand over…" passes the conversation to another agent and a line marks where it changed hands. After a Studio restart the earlier turns come back on screen from `studio/sessions/`. The conversation is also kept in words in `studio/conversation.md`: a new agent session (another agent, or after the Studio restarts) is told to read it first, so nothing agreed is lost. The agent works through the same actions as the page, so its steps show live and its changes survive rebuilds; when a build leaves places unplayable it is woken to repair them, three tries a place. Every conversation is recorded in `studio/sessions/`: open one from "Recorded sessions", or `/w/<slug>?replay=<file>&speed=2`, to play it back for a film.
38
38
 
39
39
  **Setup** shows what this machine still needs, which agents it found, and the model calls sent across all worlds, priced once you enter the per-call prices from your billing pages. Keys are only ever typed in the terminal (`diorama setup`).
40
40
 
@@ -50,6 +50,8 @@ The Story view shows conditional dialogue, optional walks and departure effects.
50
50
 
51
51
  A world can be made from what children drew and said: `diorama build <slug> --drawings photos/ --told recordings/ --places 3`, with no idea, or an idea of your own instead of the recordings. In the Studio, photograph the drawings on the home screen (📷 Camera keeps taking them; Spark tells drawings from a room or a person) and build, or add them to a world's conversation (**+ Picture** or **Camera**) and ask the agent; it uses the same workshop actions. Each drawing is kept in `drawings/`, each clip in `told/` with what Muse Voice Transcribe heard. The world keeps every drawing under its key (`drawings.json`): characters are painted from their drawing (`cast`), places and the things drawn in them follow theirs (`paint`), and the style is their crayons come alive. A world with drawings or recordings is for kids (`audience: kids` in world.json): the story is gentle and simple, every line is voiced since the players cannot read, and the text is in the language they spoke (`language`).
52
52
 
53
+ A grown-up's sketches work the same way: Spark tells a teen's or adult's sketch (pen, pencil, ink, watercolour, perspective, notes) from a child's drawing (`by` and `medium` in `drawings.json`). When every drawing is a grown-up's, the world is not for kids and its style is the sketches' own medium and hand come alive, not crayons; the painters are told it is the artist's sketch.
54
+
53
55
  To add new drawings to an existing game, the agent saves chat pictures with `kids_from_picture` and starts `world_extend` with the resulting `drawings/` paths and the person's wish. It keeps the existing script and places, adds new places and characters, and rebuilds the connecting place (its painting changes) and the new places. It checks the combined story and builds in a private copy, installing it only on success; the job costs model calls and can be undone in History. A drawing identified as something already in the world cannot yet replace or update that existing thing.
54
56
 
55
57
  On the start screen, **Video** sits beside **Photo**, **Camera** and **Say it** inside the prompt. Its button opens the native picker; the raw file input and technical instructions are hidden. After selection, the filename, player, progress and **Video tips** appear under the toolbar. It uploads an MP4, MOV, WebM, MKV, M4V or AVI brief (up to 2 GB / 4 hours). Show a drawing or object and explain its role. Uploads use 2 MB chunks; analysis works through 30-second intervals, samples a frame at the start of each 10-second window and pairs it with overlapping speech turns returned by Meta Muse Voice Transcribe’s file endpoint (`POST /v1/asr/transcribe`, DIARIZATION). Each 30-second audio clip is uploaded as mono 24 kHz PCM WAV, with a short silent tail to let the last utterance finish. Movies without audio use pictures alone; silent audio windows skip transcription. Hold each drawing steady for at least ten seconds: quick gestures or drawings between samples can be missed. Ambiguous references are marked for review, not guaranteed to be resolved.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtanczyk/diorama",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Turn a story prompt into playable painted point-and-click scenes with Meta Muse and SAM 3.1",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -54,7 +54,7 @@
54
54
  "@meta-sam/parser": "^0.1.0",
55
55
  "@preact/signals": "^2.11.3",
56
56
  "esbuild": "^0.25.0",
57
- "genaicode": "^2.25.0",
57
+ "genaicode": "^2.28.1",
58
58
  "onnxruntime-web": "^1.31.1",
59
59
  "playwright": "^1.63.0",
60
60
  "preact": "^10.29.8",