drawer-world

Community@xixi/drawer-world
Community skill — not reviewed. It was shared by 西西 and has not been checked by Neta. Read SKILL.md below before letting an agent use it.
Use it in Cohub

Paste this into your agent's chat — it fetches the skill and follows it.

Use the skill: drawer-world. Run `npx -y @neta-art/neta-search-cli@latest skills use @xixi/drawer-world --via site` and follow what it prints. Read its complete output, redirecting it to a temporary file first if necessary, and resolve relative paths from the skill directory it prints.
Install from a terminal
npx -y @neta-art/neta-search-cli@latest skills use @xixi/drawer-world
Summary

Turn your characters into tiny pixel residents who live on their own inside a drawer you can look in on.

  • Your characters become small pixel figures that wander around the drawer, hang out with each other, and go on with their day without you directing them.
  • Drop objects onto them, poke them, or pick them up and move them. Each one reacts in character, and their feelings toward each other shift.
  • Tap a resident to open a card showing their mood, thoughts, relationships and recent memories. A running log tells you what happened while you weren't watching.
  • It's a single web page that works on phones and keeps each resident's memories when you come back. There's no goal, no score and no ending.
  • Works best with 1 to 6 characters who each have a clear temperament, a way of speaking, and a signature object.
SKILL.md
# Drawer World

A drawer becomes a small apartment for miniature residents. The player watches them move between landmarks, drops in objects, pokes or lifts them, opens a card to see mood, thoughts, relationships and memory, and reads a log of what happened while nobody was directing them. The characters are adapted from the user's own world — not renamed copies with new colours.

Read this file fully before generating anything or writing files. Resolve relative paths from this skill's directory, called `$SKILL` below. The target world's root is `$SPACE_ROOT`.

## Language

Reply in the user's language, whatever language this file is in. This holds for every message of the run, above all the final handover; translate what the scripts print, don't paste it. All visible text — Work title, character bios, item names, buttons, log lines — follows the user's language; character names and quoted canon stay as written.

## When to use / when not

Use when the user wants a persistent, self-running micro world built from their characters and everyday objects. This skill makes one browser web Work: a single self-contained pixel page, no framework build and no server.

Not for a chat roleplay (`create-roleplay`), a branching visual novel (`create-avg`), a combat or quest game, or a static character page. For those, say what this skill makes and stop.

## Inputs

| Item | Required | Counts as given when |
|---|---|---|
| Cast | yes | Character cards in this world, or 1–6 characters the user names with one trait and one signature object each. "My OCs" alone does not count. |
| Drawer premise | no — default "a drawer the keeper opens" | The user names what the drawer is (a desk drawer, a sewing tin, a ship's cabinet). |
| Player role | no — default "the drawer's keeper" | The user says who the player is and whether a relationship is allowed. |
| Items | no — default 4 from the world | The user names objects, or the cast material suggests them. |

If no cast and no description exists, ask once for 1–6 characters with one trait and one object each, then stop. If the cast exists, build without a plan-approval round.

## What must survive adaptation

- **Identity, not decoration.** Keep each character's role, address form, temperament, boundaries and known relationships. A silent character does not become loud because the scene needs energy.
- **Every mapped field has a basis.** `explicit` (in the material), `inferred` (a reading, marked as such), or `unknown`. Do not turn "looks like" into fact.
- **Private material stays private.** Secrets not cleared for sharing stay out of the plan and the page.
- **The drawer is a frame, not the plot.** Do not reproduce the original main storyline, powers or factions as mechanics. Daily life is the point; the world supplies the vocabulary.
- **No tasks and no ending.** There is no goal, no score and no final day. The piece is a place to look in on.

## The sim, in numbers

- Canvas 960×600 logical pixels, scaled to fit, `image-rendering: pixelated`. Drawer interior: warm wood, a shelf line at y=180, floor at y=470.
- 3–6 residents, each 24×36 px, drawn from a palette (hair, outfit, skin, accent) plus one accessory shape. No external images.
- Landmarks: 4–6 points on the shelf or floor (bed, stool, pencil, coin, notebook, lamp). Each has a name and a remark pool.
- Tick: 1.2 s. Each resident has energy and social, drifting down; at a threshold it chooses a landmark whose type fits its highest need and walks there at 26 px/s.
- Autonomy: every 9–18 s an idle resident may act toward another (approach, share a find, sit nearby) weighted by `sociable`, `kind`, `playful`. A log line records it.
- Relationships: `affinity` and `trust` in 0..1. A gift raises affinity by `0.08 + likes`, a poke by `0.02` if `bold` is high, otherwise lowers it by `0.03`.
- Memory: the last 6 events per resident, each `{kind, otherId?, itemId?, at}`; the profile shows them as short lines.
- Drag: an item from the tray can be dropped on a resident; a resident can be lifted and dropped. A 6 px threshold separates pick-up from tap.

## Steps

1. **Read the world.** `neta atom list` → `neta atom get` for each character; also read `WORLD.md`. If a setting exists only in chat, search the world's chats and read the relevant turn, not the whole history. Write `$RUN/cast.md` with a source line per fact.
2. **Map the cast.** For each character: role, one-line bio, seven trait values, five `likes` tags, four to six lines (greet / idle / poke / gift / refuse / lift), and directed relationships with a label. Unknown values stay neutral and go into `unknowns`. More than six: propose batches, let the user choose.
3. **Write the plan.** `$RUN/plan.json` per `references/plan-schema.md`: cast, items, landmarks, palette. Run:
   ```bash
   node scripts/build.mjs --plan $RUN/plan.json --out $RUN/site --lang <locale> --check
   ```
4. **Build the Work.**
   ```bash
   node /mods/neta/neta work init web works/webs/<slug> --title "<title>"
   node scripts/build.mjs --plan $RUN/plan.json --out works/webs/<slug> --lang <locale>
   ```
5. **Look in on it.** Serve it and let it run untouched for two minutes: residents should choose different places and produce different log lines. Then drop an item on a resident who likes it and one who does not, poke, lift, open a card, reload and confirm memory restores. Test 375 px width. Write `$RUN/qa.md`.
6. **Publish and hand over.** See Deliver.

`$RUN` = `_runs/drawer-world/<timestamp>/`.

## Deliver

One browser web Work.

1. Publish: `node /mods/neta/neta work publish web works/webs/<slug> --title "<same title>"`.
2. Open the published entry; confirm the cast, one autonomous log line and one profile card.
3. In the user's language, state the cast, what was kept, what was inferred, what is unknown, and that there is no task or ending.
4. **Hand over with a card — the run is not delivered until this step is done.** One `interaction-components` card on its own line, target `{ "type": "work", "workId": "<id>" }`, the id from the publish output (fallback: `cohubWorkId` in `works/webs/<slug>/meta.json`). Never a made-up id, a folder path, or a `world-file` link to `index.html`.

## Out of scope

- Do not change world settings (including `WORLD.md`, visual style or slug), delete files that existed before the run, or edit memory, character cards, installed scripts or existing Works.
- Do not publish private notes, secrets the user did not clear, or the extraction notes.
- Do not build combat, a main-quest adaptation, or a chat interface. The page is a life sim, not a novel.
- Make only the requested Work; do not act on your own next-step suggestions.

## When to stop

- No cast and no description: ask once, then stop.
- A required body feature cannot be represented and the character would be unrecognisable: offer an approximation or a different character, then wait.
- Asked for a chat roleplay or a combat game: say what this skill makes and stop.

## Gotchas

- The same name in two cards is not the same character. De-duplicate by id, alias and time point; never merge conflicting canon silently.
- Seven traits filled from one tag produce a cast that behaves identically. Change one trait at a time and check the log for a different choice.
- A resident that walks to the same landmark every tick is stuck: its need never crosses the threshold. Give each need a floor and a decay, not a single target.
- Dragging a resident with `left/top` on a canvas requires converting pointer coordinates through the canvas scale; using CSS pixels directly makes the character drift away from the cursor on a phone.
- `localStorage` is per origin; a preview and the published page do not share a life. Include the Work title in the key.
- Lifting a resident while it is mid-action leaves the action closure alive. Clear the action on pick-up or it finishes in the air.