advent-calendar

Community@xixi/advent-calendar
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: advent-calendar. Run `npx -y @neta-art/neta-search-cli@latest skills use @xixi/advent-calendar --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/advent-calendar
Summary

Turn your world into a calendar of closed doors that open one day at a time, ending in a private final door.

  • A web page with 3 to 31 doors, windows, drawers or wax seals, each opening on its day to reveal an object from your world and a short line.
  • You press and hold a door until a ring fills to open it. Future doors stay visible and tell you the date they unlock.
  • The last door stays shut until every other one is open, then shows a gold frame and an extra paragraph meant for one person.
  • Opened days are remembered after a reload, and you can preview any date without touching what a visitor has opened.
  • Works best with a world that has a character, a place and objects, so each day can carry one small, specific thing.
SKILL.md
# Advent Calendar

A season becomes a calendar of closed doors. Each day is locked until its date, opens with a short press-and-pull, and reveals one in-world object with a line or two. The final door is different: it stays sealed until every other door has been opened, and it carries one extra paragraph that belongs to a single person. Progress survives a reload; the author gets a preview clock.

Read this file fully before generating anything or writing files. Resolve relative paths from this skill's directory.

## 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, dates, door labels, reveal copy, locked messages, the exclusive badge — follows the user's language; lines the user supplied stay as written.

## When to use / when not

Use when the user wants one small thing revealed per day, with a real sense of a closed container, and often a final day that is personal. This skill makes one web Work.

Not for a 3D gift box or orbitable building (`countdown-box`), a plain countdown timer, a poster, or a merchandise catalog. For those, say what this skill makes and stop.

## Inputs

| Item | Required | Counts as given when |
|---|---|---|
| Occasion and span | yes | A start date and a day count (3–31), or a named occasion with a resolvable date. "A countdown" alone does not count. |
| Contents | yes | A list of in-world objects / moments for each day, or a world rich enough that each day can be sourced from a material. |
| Finale | no — default the last day | A specific final scene, or "the last day is hers". The default is the last calendar day. |
| Exclusive line | no — default written from material | One extra paragraph for the final door. If absent, write it from the character material and mark it as written. |
| Look | no — default from world | A visual style, a reference image, or the world's own style. |

Ask once, in one message, if the span or the contents are missing, then stop. If both are given, build; state the image budget in one line before generating.

## Cost model — read before generating

Each day needs an object image. Generating 24 separate images is expensive, so the default production is **one 4×4 asset sheet per 16 days**:

- One `sheet` generation yields 16 square object tiles on a plain background, sliced locally by `scripts/slice-sheet.mjs`.
- 7 days = 1 background + 1 sheet. 16 days = 1 background + 1 sheet. 24 days = 1 background + 2 sheets.
- The finale image is one extra generation, or a tile from the last sheet.
- Say this budget in the handover: "N days · X generated images".

Never silently swap a requested 24-day calendar for a 7-day one.

## The calendar, in numbers

- Stage: `max-width: 980px` desktop, full width on mobile. Grid: 6 columns above 720 px, 4 columns below, gap 10 px; a 24-day calendar is 4 rows of 6.
- Door: `aspect-ratio: 1/1`, `border-radius: 10px`, 2 px inner border, a small date at the top-left and a one-word label at the bottom.
- Open gesture: press and hold 550 ms, or drag 36 px. A ring around the door fills while holding; releasing early cancels. This is what makes it a door rather than a button.
- Opening animation: 520 ms. Wax seal cracks into two halves and falls 12 px; ribbon slides 40 px sideways; paper tears along a jagged clip-path; drawer slides down 54%; curtain parts from the centre.
- Reveal panel: full-stage overlay, image frame `max-height: 52vh`, copy 16 px / 1.9, close button 44 px tall. Content never scrolls behind the overlay.
- Locked copy: the door stays visible, dimmed to 55%, and a tap says the date it opens. Do not hide future doors; the waiting is the point.
- Finale: gold frame, a small "exclusive" badge, one extra paragraph in a lighter colour. Available only when `opened.length === days.length` and the finale date is reached; in preview, when all are opened.
- Save: `localStorage` key includes the Work title plus `:preview` for the author clock. A player never sees preview progress.

## Steps

1. **Read the world.** `neta atom list` → `neta atom get` for the person, place and objects. Pick 3–31 things that can each carry one sentence. Write `$RUN/contents.md` with the source of every day.
2. **Write the plan.** `$RUN/plan.json` per `references/plan-schema.md`. Dates must be consecutive and start on `start`. Each day: `date`, `title`, `text`, `tile` (0–15) or `image`, `open` style. The finale is separate.
3. **Generate two images per 16 days.** Through the bundled script:
   ```bash
   node scripts/gen.mjs --kind image --state $RUN/gen-bg.json --prompt "<scene prompt>" \
     --work-title "<Work title>" --param aspect_ratio=16:9 --param image_size=1K --models "<fallbacks>"
   node scripts/gen.mjs --kind image --state $RUN/gen-sheet.json --prompt "<4x4 object sheet prompt>" \
     --work-title "<Work title>" --param aspect_ratio=1:1 --param image_size=1K --models "<fallbacks>"
   ```
   Rerun while `generating`/`busy`; the script resumes the accepted task. Then `node scripts/slice-sheet.mjs --sheet <file> --out $RUN/tiles --cols 4 --rows 4`.
4. **Validate and build.**
   ```bash
   node scripts/build.mjs --plan $RUN/plan.json --assets $RUN --out $RUN/site --lang <locale> --check
   node /mods/neta/neta work init web works/webs/<slug> --title "<title>"
   node scripts/build.mjs --plan $RUN/plan.json --assets $RUN --out works/webs/<slug> --lang <locale>
   ```
5. **Open it as a player and as the author.** Player: today's door opens, yesterday's stays open, tomorrow's says its date, finale refuses until all are open. Author: `?preview=<date>` moves the clock without touching player progress. Hold-release-early cancels. Reload restores. Test 375 px width. Write `$RUN/qa.md`.
6. **Publish and hand over.** See Deliver.

`$RUN` = `_runs/advent-calendar/<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, open the current day, confirm the finale is still locked.
3. In the user's language, state the span, the total day count, the exclusive finale, the image budget and how to preview.
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, delete files that existed before the run, or edit memory, character cards, installed scripts or existing Works.
- Do not make a 3D scene, a timer-only page, a shop, or a daily push notification.
- Do not reduce the requested day count to save images; report the budget and let the user decide.
- Make only the requested Work; do not act on your own next-step suggestions.

## When to stop

- No span or no contents: ask once, then stop.
- The dates cannot be resolved (a fictional calendar with no conversion): ask for explicit Gregorian dates, then stop.
- No image model and no usable world images: offer a text-only calendar with typographic doors; if the user declines, stop.

## Gotchas

- `new Date("2026-12-01")` is UTC midnight in most engines and shows the previous day in negative time zones. Build dates with `new Date(y, m-1, d)` and compare date strings (`YYYY-MM-DD`), not timestamps.
- A 4×4 sheet with a visible grid line or drop shadow slices into tiles with seams. Ask for "no grid lines, no borders, even spacing, flat background" and inset each crop by 4 px.
- The finale must not be reachable by opening only the last door in preview; gate it on `opened.length === days.length`, then on date.
- Holding a door on mobile also triggers the context menu. Set `touch-action: none` and `-webkit-touch-callout: none` on the door.
- Two calendars in one world share `localStorage`; include the Work title in the key or they overwrite each other's opened days.