amv-maker

Verified@kingdomrushdev/amv-maker
Use it in Cohub

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

Use the skill: amv-maker. Run `npx -y @neta-art/neta-search-cli@latest skills use @kingdomrushdev/amv-maker --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 @kingdomrushdev/amv-maker
Summary

Turn an idea into a beat-synced anime music video, with a song, shots and a playable page.

  • Answer one short questionnaire: lead character, feel, music, look, length and vertical or horizontal. Skip anything you already said in your first message.
  • Music is your choice: an AI-written instrumental, an AI song with vocals, or your own uploaded track.
  • Cuts land on the beat, with punch-in zooms, flashes, glow and film grain. You can choose a light, standard or heavy effect level.
  • You get a playable video page, plus the key visual, the song and each clip laid out on your board.
  • Works best with a lead character who has a striking look and a clear mood or iconic moment you want to hit.
SKILL.md
# AMV Maker

**A song plus a run of shots that land on its beats.** This skill is a self-contained fast path: everything it needs for video, music, images, the questionnaire, the Board, publishing and handover is written here or done by `scripts/amv.py`.

**Do not load other platform skills** for this job (generate, questionnaire, board-ops, next-steps, create-web-work, pov-life-slice); what they would add is already here. Do not read the style library, do not run `params`, do not make three-view sheets or pitch boards, do not wait for the user to approve a shot list. Beat detection, excerpt choice, shot timing, prompt assembly, parallel submit, polling and editing are all done by the script. You do three things: **turn the user's words into music, look and camera descriptions**, **write one action per shot**, and **look once at the key visual**.

**No style presets.** There are no ready-made "hype / sad / sweet" recipes and no style shortlist. Feel, look, music, camera and light are written fresh from what this user said. Whatever they left open, decide from the lead character and the world, and say in one line what you chose.

## Language

- Reply to the user in the user's language — every message, the final handover included. Translate what the tools print rather than pasting it.
- Text the user sees in the deliverable follows the user's language: the Work title, the Board flow and step names, and the questionnaire and player page (pass `--lang <code>` to `ask` and `assemble` when the user's language differs from the world's `language`).
- Prompts sent to the image, video and music models are written in English.

## Paths

`$SKILL` is this skill's own directory (the folder holding this `SKILL.md`, normally `.agents/skills/amv-maker`). Run every command from the world root.

```bash
A="$SKILL/scripts/amv.py"
N="node /mods/neta/neta"
B=/mods/neta/.agents/skills/board-ops/scripts      # Board placement scripts (platform)
```

## Turn 1 — ask once

Open with one sentence that answers the user's idea, then raise the questionnaire with **one command**:

```bash
python3 $A ask [--subject "<name>" --subject "<name>"] [--skip feel] [--skip ratio] ... [--lang <code>]
```

- The questionnaire asks: lead character, the feel (free text), music source (AI instrumental / AI song with vocals / own song), the look (free text; empty keeps the world's style when it has one), length, frame, and an optional scene or iconic moment.
- The script fills the lead options from the world's characters; with none, the lead becomes a text field.
- Skip what the first message already said: named a work or characters → pass 2–5 names with `--subject`; said the feel → `--skip feel`; said the look → `--skip look`; own song or attached audio → `--skip music`; vertical/horizontal → `--skip ratio`; length → `--skip length`.
- `status: pending` → end the turn with one short line; do not repeat the questions, no next steps.
- `unavailable`, or `ok:false` twice → ask the same questions in one chat message and end the turn.
- If the first message already settles every item, skip the questionnaire and go straight to Turn 2.

## Turn 2 — build it all in one go

Recap the key choices in one line. Anything left open or handed back ("decide for me") is your call from the lead and the world; say it in the same line. Default length 30 s, default frame 9:16.

Pick `TITLE` (short, in the user's language) and `SLUG` (`amv-` plus a romanized or English kebab-case name; `ls works/webs` first to avoid a clash). `D=works/webs/$SLUG` — the CLI rewrites `works/web/` to `works/webs/`, so use `webs` from the start.

**First translate the user's words into four English blocks and reuse them everywhere:**
- `LOOK`: medium and brushwork, line, palette, texture — 2–4 concrete phrases. A single word lets the model drift back to its default anime look. Empty and the world has a style → describe the world's style.
- `CAMERA`: camera movement that follows the feel (faster feel → harder, quicker moves; slower feel → gentler, longer moves).
- `LIGHT`: light and weather.
- `MUSIC`: genre, lead instruments, **an explicit BPM number**, mood, and `instrumental, no vocals` or the vocal (name the vocal language).

### Step 1 · three calls in parallel, in one reply

**① Work shell and address**
```bash
$N work init web $D --title "$TITLE" && $N world slug get
```
Note whether the slug is `null`; never set it yourself (see Step 4).

**② Music** (timeout 600, about 2 min)
- AI song: `$N generate audio --prompt "<MUSIC>, <one line of theme>" --work-title "$TITLE · <word for 'music' in the user's language>"`. It returns two tracks; take the first output with `asset.type=audio` and a `mediaPath`; keep its `mediaPath` and `work.path`. If it fails, retry once; then ask the user to upload a song.
- Own song: `ls uploads/`; if the name is unclear take the newest audio file (mp3/wav/m4a/flac/ogg). None → ask the user to upload it in chat and stop.

**③ Key visual** (one per lead, at most 2, sync, timeout 300)
- Lead has a character card: `$N find images "<name>"` for its cover path, then
  `NETA_DEFAULT_IMAGE_MODEL=gemini-3.1-flash-lite-image $N generate image --prompt "<KV>" --image "<cover path>" --param aspect_ratio=<ratio> --work-title "$TITLE · <key visual>"`
- No card:
  `NETA_DEFAULT_IMAGE_MODEL=krea2 $N generate image --prompt "<KV>" --param size=<576x1024|1024x576|1024x1024> --work-title "$TITLE · <key visual>"`
- If the first image model errors (busy, unavailable), rerun the same command once with the other model (krea2 ↔ gemini-3.1-flash-lite-image; krea2 takes no `--image`, describe the character instead).
- `<KV>` = `<LOOK>. Key visual for a music video. <lead's appearance: hair, eyes, outfit, signature items>, <setting>, <LIGHT>, full body, face clearly visible, dynamic pose, no text, no letters, no signs, no logo.` For an IP character **write the appearance**, never just the name.
- Open the `mediaPath` with the read tool once: right person, whole face and hands. Clearly broken → redraw once with the same command, no more.

### Step 2 · beats → shots → parallel submit

```bash
python3 $A plan --audio <music file> --length <sec> --ratio <ratio> --dir $D [--bpm <BPM from MUSIC>] [--shot-sec <average shot length>]
```
- `--bpm`: always pass it for an AI song (stops half/double-tempo errors); not for the user's own song.
- `--shot-sec`: your call from the feel, 1.2–4, default 2.4. Faster and choppier → ~1.5; slow and lyrical → ~3.5.
- It prints the BPM, the chosen excerpt, the segments and the shot list `shots` (each with `id` and a time range).

**Your one creative job:** write `$D/actions.json` as a JSON array of English strings, one per shot, same order and count as `shots`:
- Plan one arc first (opening → build → climax → ending) and spread it over the shots; the shape follows the user's feel, not a template.
- 8–20 words each: `shot term + subject + one action → result`.
- Change framing between neighbours (wide / medium / close-up); every shot shows visible change; short shots for impacts and close-ups, long shots for big moves and the ending.
- One action per shot, no dialogue, no on-screen text. A requested scene or iconic moment goes in the middle and the climax.
- **Start each line with an AMV shot term**, at least 6 different ones per film; impact terms on short shots and drum hits, orbits, tracking and slow push-ins on long shots. Slow or sad films use few impact terms and more pauses. The first shot reveals the lead, the chorus or heaviest beat gets the biggest impact, the last shot holds or lingers.

  | Use | Shot terms (write them as-is) |
  |---|---|
  | Opening reveal | `Silhouette against <strong light>`, `Eye-catch extreme close-up`, `Back view, slow push-in`, `Establishing wide shot` |
  | Detail on the beat | `Insert shot` (hands, weapon, keepsake), `Extreme close-up` (eyes, lips, sweat, rain), `Rack focus` |
  | Building action | `Ground-level tracking shot`, `Whip pan`, `180-degree orbit`, `Dutch-angle wide shot`, `Crash zoom` |
  | Climax impact | `Full-screen impact frame` (optionally `black-and-white inverted flash`), `Sakuga smear-frame cut`, `Foreshortened shot: ... straight at the camera`, `Speed lines` |
  | Emotional pause | `Slow-motion close-up`, `Freeze-frame-like hold`, `Over-the-shoulder shot`, `Flashback in desaturated color` |
  | Ending | `Upward crane shot`, `Slow push-in from behind`, `Wide silhouette at the horizon` |

- `prompts` puts the **universal AMV prefix** (`AMV_PREFIX` in the script; text in `references/amv-prefix.md`, no need to read it) at the top of every segment. It only describes what every AMV shares — music-driven cutting, short key-visual shots, a moving camera, alternating framing, close-ups for emotion, lit depth, a consistent character — and **no style, genre or mood**, so it fits any genre, mood or look. Never remove it and never add style words to it; anything style-specific goes in `--look` or the shot lines.

```bash
python3 $A prompts --dir $D --subject "<lead's appearance in English>" --scene "<setting in English>" --look "<LOOK>" --camera "<CAMERA>" --light "<LIGHT>" --actions $D/actions.json --refs <number of key visuals> --title "$TITLE" \
 && python3 $A submit --dir $D --kv "<key visual 1 mediaPath>" [--kv "<key visual 2 mediaPath>"]
```
- The video model **defaults to MiniMax H3** (`minimax-h3`, 768P, follows instructions closely, takes reference images and reference music). The script sets the model itself, regardless of Studio's default video model. Pass `--model <id>` (`seedance-2-0-fast` or `seedance-2-0`) only when the user names one.
- `submit` reads the model's declaration and handles duration limits, ratio, resolution, reference images and reference music (inputs the model does not take are dropped and listed in `dropped`); all segments are submitted at once, async.
- The length options state how many clips each costs; the user's pick is the go-ahead for that spend (at most 4 clips). Do not ask again.
- Error `re-run plan with --max-seg X` → rerun `plan` with `--max-seg X`, rewrite `actions.json` for the new shot count, rerun `prompts` and `submit`.

### Step 3 · place on the Board, then wait

If the Board exists (default `board/main.board`; add `--board <path>` when the user is looking at another Board), place in **two separate commands**, naming the flow `$TITLE` and the steps in the user's language (key visual, music):
```bash
node $B/flow.mjs --flow "$TITLE" --step "<key visual>" --work <key visual work.path>
node $B/flow.mjs --flow "$TITLE" --step "<music>" --via "<composed>" --work <music work.path>
```
- The user's own song is not a Work: skip the music step.
- `--work` takes only a `work.path` a command printed, copied as-is.
- A one-off `CLI_ERROR` → rerun the same command once.
- No Board (`path_not_found`) → do not create one; say at the end that the content was made but not placed.

Then wait (timeout 900):
```bash
python3 $A wait --dir $D --minutes 12
```

### Step 4 · edit, publish, hand over

1. **Edit.** `python3 $A assemble --dir $D --title "$TITLE" --fx <0-3> [--lang <code>]` (timeout 600, about 1 min). It finds the hard cuts the video model actually made and retimes them slightly (within ±20%) onto the nearest beat (`beatSnap`; `--no-snap` only if the user wants the model's own timing), then adds the **AMV finish**, all on beats and cuts: punch-in zoom plus shake on strong beats and cuts, a light push on other beats, white flash and RGB split on cuts, and across the film glow, contrast and saturation, sharpening, film grain, vignette, fade in and out. Pick `--fx` from the feel: `3` heavy (fights, hype, fast), `2` standard (default), `1` light (lyrical, slow, sweet), `0` none (only when the user asks for the raw cut).
2. **Publish — only if the world has a public address** (the slug from Step 1 is not `null`): `$N work publish web $D --from $D/dist --output dist/amv.mp4`. If it is `null`, do not set one and do not publish; the deliverable is the file `$D/dist/amv.mp4`, and you tell the user in one line that a playable Work page needs the world's public address, which they can set.
3. **Board.** One row per clip, the final cut in its own column (step names in the user's language):
   ```bash
   node $B/flow.mjs --flow "$TITLE" --step "<clips>" --via "<beat-synced shots>" --row "<clip 1>" --work <seg1 work.path> --row "<clip 2>" --work <seg2 work.path>
   node $B/flow.mjs --flow "$TITLE" --step "<final cut>" --via "<edited to the beat>" --work $D
   ```
   Skip the final-cut card when nothing was published.
4. **Check the result.**
   ```bash
   python3 $A verify --dir $D
   ```
   Pass = `"ok": true` (final cut exists with video and audio, its length matches the plan within 0.3 s, the player page and poster are in place); the report is written to `$D/qa.json`. On `ok:false`, fix what `problems` names (usually rerun `assemble`) and verify again. Then open `$D/dist/poster.jpg` with the read tool and confirm the frame is right.
5. **Hand over — required; the run is not delivered until this is done.** Write the final reply as below, with the Work card (the interaction-components link card, target `work`) on its own line. `workId` is the `cohubWorkId` from the publish output or `$D/meta.json` — never a guessed id. When nothing was published, hand over `$D/dist/amv.mp4` as a `world-file` link card instead.

## When something fails

Handle each case once; do not pile on adjectives.

| Situation | Do | Tell the user |
|---|---|---|
| A segment's submit `error` mentions IP, copyright, face or moderation | Rewrite `--subject` as pure appearance (no work or character names), rerun `prompts`, then `submit --only <n>` | One line: reshot with a description instead of the name |
| Still blocked | Redraw the key visual as a wide or profile shot, `submit --only <n> --kv <new image>`; then once `submit --only <n> --model seedance-2-0-fast`; still blocked → stop | One line with the reason; ask whether an original-character version is fine |
| MiniMax fails for a non-moderation reason (unavailable, rejected parameter) | `submit --only <n> --model seedance-2-0-fast` once | One line: this clip used another model |
| Submit rejects the reference music | `submit --only <n> --no-audio` (the final cut still carries the song) | Nothing |
| `wait` reports a `failed` segment | `submit --only <n>` (re-renders the same card) | One line with the reason |
| `assemble` says `shorter than planned` | `submit --only <n>` → `wait` → `assemble`; never pad frames | Nothing |
| `wait` times out with `pending` segments | Stop, say it is still rendering; next turn run `wait` → Step 4, **never resubmit** | Still rendering |
| A command was cut off without a result | Check `$N work list` and `$D/plan.json`: if the Work or `taskRunId` exists, continue from it; resubmit only what never started | — |

## Revisions (later turns)

- One clip or shot is off: change only those lines in `actions.json` → `prompts` → `submit --only <n>` → `wait` → `assemble` → publish into the same `$D` (same Work address).
- New song or length: rerun `plan` (shot count changes, rewrite actions), resubmit all.
- New look or feel: rewrite `LOOK` / `CAMERA` / `LIGHT` → new key visual → `prompts` → resubmit all.
- Keep every approved shot line verbatim; change only the ones the user named.

## The final reply

In the user's language:

1. One or two sentences in the world's voice: what the film shows and the one beat worth watching.
2. The Work card on its own line:

<interaction-json>
{"version":1,"fallback":"<one sentence naming the Work>","component":{"kind":"link","target":{"type":"work","workId":"<cohubWorkId>"},"presentation":{"subtitle":"<length · BPM>"}}}
</interaction-json>

3. One line on what you checked: length, clip count, BPM and how many cuts were snapped to the beat, all from the `plan` and `assemble` output; say so if anything was `dropped` or a fallback was used. If the lead is new to this world, offer in one clause to save them as a character card (do not create it unasked).
4. Two or three next steps as an options block (`subtitle` is the exact message sent when tapped, in the user's language; `title` ≤ 40 and `subtitle` ≤ 80 counting a full-width character as two; never repeat last turn's options). The first goes deeper into this film (longer, new song, sequel); the others come from the world:

<interaction-json>
{"version":1,"fallback":"<the same options in one sentence>","component":{"kind":"options","options":[{"title":"<title>","subtitle":"<message sent on tap>"},{"title":"<title>","subtitle":"<message sent on tap>"}]}}
</interaction-json>

Fill these blocks in the user's language; they show the shape only. Each `<interaction-json>` tag sits alone on its line with no code fence around it; strict JSON, no extra fields, no trailing commas; the `fallback` reads on its own. No commands, paths or raw JSON in the reply, and no talk of beat detection or segments unless the user asks. Never call a video that is still rendering finished.

## Out of scope

- Changing world settings: no `world slug set`, no `config set`, no visual style, no world cover.
- Creating, editing or deleting characters, locations or other materials (offer a character card; never make one unasked).
- Deleting or overwriting files that existed before the run, or touching other Works; everything this skill writes lives in `$D` plus the Works its generate commands create.
- More than 4 video clips per film, or any generation beyond the music, the key visual(s), the clips and the stated retries.
- Lip-sync, dialogue or narration; text or captions burned into the video.
- Acting in any other world.