location-postcards

Verified@baize/location-postcards
Use it in Cohub

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

Use the skill: location-postcards. Run `npx -y @neta-art/neta-search-cli@latest skills use @baize/location-postcards --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.
Use in Neta Studio Open it in Neta Studio and see what people made with it.
Install from a terminal
npx -y @neta-art/neta-search-cli@latest skills use @baize/location-postcards
Summary

Turn any place in your world into four postcards of different moments, each with a handwritten note on the back.

  • Four postcards of one place: dawn, rain, night and a festival day by default, or seasons or any moments you ask for.
  • Draw them in your world's own art style, or pick from 100+ styles such as Chinese ink, woodblock, picture book or cinematic photography.
  • Flip each card to read a short note written to you by someone who lives there, such as a character from your world.
  • Every set goes into one postcard album page for your world. Flip through it, save one card, a set or everything, and share it.
  • Works best with a place that has a distinct look, signature objects and people who work there. It asks at most one question first.
SKILL.md
# Location postcards

Four cards of **one** place: same place, same look, four moments. On the back of each card, a note
in the voice of someone from this world. The creator gets the world's postcard album — a page they
can flip through, save from and share — not four loose images.

## Requirements

This skill decides *what* the cards are; the neta platform's `generate` skill does the generating.

- Step 1 (place and look, maybe one questionnaire round) comes first. Only once both are settled,
  read `/mods/neta/.agents/skills/generate/SKILL.md` and
  `/mods/neta/.agents/skills/generate/playbooks/image.md` and follow their core loop (declaration,
  references, submit, look). Steps 2–5 run inside that loop.
- If `/mods/neta` does not exist in this world, say image generation is not available here and stop.
- `<skill-dir>` = the folder this SKILL.md sits in. The scripts need `python3` and ImageMagick
  (`magick` or `convert`), both in the Studio sandbox.

## Inputs

| Input | Required | Counts as given when |
|---|---|---|
| Place | yes | the message names a place of this world or carries a selected location card. A description that matches no card, or "here", does not count → ask (step 1). |
| Look | asked when not given | the message names a look: "like the world", a style name, a style id or an old handraw number |
| Moments | no (dawn · rain · night · a festival of this world) | the user asks for others ("four seasons", "a busy market day") — always four |
| Language | no | the user's language; the world's language if the user wrote none |

Ask at most **one** round, with the platform questionnaire, only for what is open (see
[`references/questionnaire.md`](references/questionnaire.md)). Everything else has a default.

## Looks

| Look | When | How it is made |
|---|---|---|
| **world** | asked for, picked in the questionnaire, or the questionnaire skipped | the world's own `visualStyle` (in `world/WORLD.md`) with the place's cover as the reference image, on the creator's own image model |
| **styled** | the user names one of the tested styles, or picks it in the questionnaire | style first: the style's sample image is the only image, the place is described in words, on GPT Image 2.5 |

Styled looks: in `references/postcard-styles.json`, each tested by drawing the same teahouse. Do not
read the file whole; use `python3 <skill-dir>/scripts/styles.py` — `find "<words>"` (a name in any
language, a keyword, an id like `FE-049`, an old handraw number), `get <id>` (`prompt`, `note`,
`sample`, `preview`), `tiles --kind guofeng|modern|nature|fantasy` (the questionnaire's choices).
Add `--lang <user language>` for names. Not in the list → the closest `find` result, and say which.
When the creator asks which styles there are, give the gallery page
(`gallery` in `postcard-styles.json`): every style with its sample, searchable, in their language.

## Deliver

**One album per world**: a published web Work, `works/web/<world-slug>-postcards`. Places are
grouped; a new set of four cards for a place goes on top of that place, and the place moves to the
top of the album. Every card flips to its note; save one card, a set, or everything as a zip; page
UI in the user's language. Re-publishing the same Work keeps one album card on the Board. Handed
over with an interaction-components work card and the four moments with their senders, then
next-steps. The four generated images stay ingredient image works, not placed on the Board.

## Steps

1. **Place and look.** Read `manifest.json`.
   - The place is *given* only when the message names a place of this world or carries a selected
     location material. Once given, read it (`node /mods/neta/neta atom get "world/locations/<Name>.md"`)
     and the world (`world/WORLD.md`).
   - The look is given when the message names one (above).
   - Anything open → one questionnaire round per [`references/questionnaire.md`](references/questionnaire.md).
     Nothing is generated before the answers are back.

2. **Write the four cards.** For each card: a `moment` label (short, the user's language: "Dawn",
   "雨", "夜", "上元灯节"…), a scene line for the picture, and the note on the back.
   - **Moments**: default dawn, rain, night and a festival — pick a festival this world would have
     (its WORLD.md, its culture; a lantern festival, a harvest fair, a first-snow market…). The four
     should look clearly different: light, weather, crowd, colour.
   - **Scene line**: what this place looks like at that moment, from the card's own details (its
     signature objects, who works there, the creatures around). People and characters are small
     and incidental; the place is the subject. No readable text in the picture.
   - **The note** (back of the card): from someone who lives in or comes to this place — a
     character card of this world when one fits (their way of talking, their habits), otherwise a
     plausible local ("the ferryman's apprentice"). Written to "you", in the user's language,
     1–3 short sentences (≤ 60 CJK characters or ≤ 140 Latin characters), warm or funny, about this
     moment. Four different senders when the world has them. Only what the cards say; nothing that
     contradicts the world.
   - Do not stop to confirm — show the four in the reply.

3. **Generate four cards** (one image each, 3:2 landscape). Read the declaration first
   (`node /mods/neta/neta generate image params`, with the model prefix below for styled looks):
   `size` → `1536x1024`, `aspect_ratio` → `3:2`. Submit the four **synchronously as parallel tool
   calls**, each with `--work-title "<Place> · <moment>"`.
   - **World look**: prompt = "A postcard view of <place>: <scene line>. Art style: <the world's
     visualStyle>. The place is the hero, characters small. No text, no signature, no watermark.";
     pass the place's cover with `--image <its media path>` if it has one.
   - **Styled look**: prefix each command with `NETA_DEFAULT_IMAGE_MODEL=gpt-image-2.5`; fill
     [`references/postcard-prompt.md`](references/postcard-prompt.md) with `styles.py get <id>`;
     `--image <sample URL>` is the only image. Say in one short line that it takes 1–2 minutes.
   - If the provider blocks one card: soften that card's scene line once (no weapons, no injuries,
     no named franchise) and resubmit it alone; if it is blocked again, finish the set with three
     and say so. At most 6 submits for one set.

4. **Look, then file them into the album.**
   - Open each card: the place recognisable as this card's place, the look right, the moment
     right, no garbled text. One card wrong → one rework of that card (`--target-work`), then go on.
   - Find or create the album and add the set:

     ```bash
     A=<skill-dir>/scripts/album.py
     python3 $A find                                   # {"work": "works/webs/<world-slug>-postcards", ...} or {"work": null}
     # album found: WORK=<the "work" find printed>, skip to `next`.
     # no album yet: settle the world slug first, then build the path from it
     node /mods/neta/neta world slug get               # null → node /mods/neta/neta world slug set <readable-kebab-case-from-the-world-name>
     WORK="works/web/<world-slug>-postcards"
     node /mods/neta/neta work init web "$WORK" --title "<World> · <Postcards in the user's language>"
     WORK=<the workDir init printed>                   # it may normalise works/web/ → works/webs/; use it as printed
     python3 $A init --work "$WORK" --title "<World> · …" --subtitle "<world name>" --lang <code> --file-base <world-slug>
     # either way:
     DIR=$(python3 $A next --work "$WORK" --place "<Place>" | python3 -c "import sys,json;print(json.load(sys.stdin)['dir'])")
     # cards.json: [{"image": "<mediaPath>", "moment": "…", "from": "<sender>", "message": "…"}, …] in card order
     python3 $A add --work "$WORK" --place "<Place>" --label "<the place's name in the user's language>" \
       --dir "$DIR" --style "<look name in the user's language>" --cards-file cards.json
     ```

     `--place` is always the location card's own name (`world/locations/<Name>.md`), in `next`,
     `add` and `replace` alike: it keeps one place in one group whatever language the request was
     in. `--label` is what the album shows (九盏茶楼 for Nine Cups Teahouse).
     The look name: "World style" / "原画风" for the world look, the style's `name` otherwise.
     `init` on an album that already exists keeps it (`"kept"`) — carry on with `next`.
   - The album directory's last part is always `<world-slug>-postcards` (`works/web/` or `works/webs/`
     before it, whichever `find` or `init` printed). Never a test name or a name without the
     `-postcards` ending.
   - **Check before publishing**: `ls "$WORK/$DIR"` must list `01.webp`, `02.webp`… — one per card.
     `add` is the only command that files the cards; if any are missing, run `next` and `add`
     again (never hand-edit `album.js`), then check again.

5. **Publish and place.**

   ```bash
   cp <skill-dir>/templates/index.html "$WORK/index.html"
   cp -r <skill-dir>/templates/neta "$WORK/"
   T=$(python3 -c "import json;t=open('$WORK/album.js').read();print(json.loads(t[t.index('{'):t.rindex('}')+1])['title'])")
   sed -i "s|{{ALBUM_TITLE}}|$T|" "$WORK/index.html"
   node /mods/neta/neta work publish web "$WORK"
   node /mods/neta/.agents/skills/board-ops/scripts/place.mjs --title "$T" --work "$WORK"
   ```

   - `world_slug_required` → set a readable kebab-case world slug (`neta world slug set`), publish again.
   - Publishing fails → place the four image works instead and say plainly the album did not publish.

6. **Reply and close.** Hand over the album with an **interaction-components** link card to the work
   (`{ "type": "work", "workId": "<jq -r .cohubWorkId "$WORK/meta.json">" }`, a real
   `<interaction-json>` block). Under it, the four cards as `moment — what the picture shows · from
   <sender>`, describing what you **saw**. Then **next-steps**: first "the same place in another look"
   (no look named, so the questionnaire comes up), then another place of this world by name, then
   this place in four seasons.

## Changing one card later

"Change the rain one", "make the night card darker": rework that card's image work with
`--target-work`, same look and prompt with the scene line changed, then
`album.py replace --work "$WORK" --place "<Place>" --dir <the set's dir> --card <N> --image <new mediaPath>`
(`--message` / `--from` to change the note) and publish the same Work again.

## Out of scope

- No changes to world settings, location or character cards; the album only adds its own works.
- No deleting files that existed before the run.
- No maps, no 360° views, no animated cards; no real-world places or real people.

## Not this skill

- A map of the world → a map skill. A 360° view → the panorama skill. A mood illustration with
  characters as the subject → `generate`.
- Stickers of a character → `character-emotes`.