The base is huashu-art-motion(Canvas frame-by-frame rendering engine, style recipes, qa/deliver gates). This skill adds three things: a chaptering pipeline for a whole book,style kits(kits/, chosen styles made into a library, directly reusable for the next book),shared components(scripts/*.mjs and player/, no longer rewritten for every book). Before starting, read through huashu-art-motion's SKILL.md "导演的要求" and "六种做坏方式".
The voiceover is exactly the whole-chapter reading from the 书架 audiobook; no new script is written and no TTS is tuned. If the audiobook cache (R2 audiobook/<slug>/<stem>.mp3) exists, use it directly; if not, synthesize once through the audiobook interface, which writes back to the cache itself, so future user listening and future animation work cost nothing more. We never write to the audiobook cache ourselves. Duration = the reading length of the whole book (4–8 minutes per chapter).
Default: portrait 1080×1920@30 (视频号 9:16),deliver the HTML version; render MP4 only if the user asks (Mac only).
Pipeline
S=~/.claude/skills/wjs-voicedrop-creating-motion-book/scripts, project goes in ~/code/art-films/<slug>/. This skill's scripts are all .mjs(Node ≥20). Fetching the book, creating the project, fetching the voiceover, final assembly, smoke testing, packaging, and publishing do not need ffmpeg / Python / Chromium and can run on a Tokyo VPS;qa_batches、framing_sheet、render_chunks is for calling huashu-art-motion's upstream render.py / qa.py(needs uv + Chromium, and ffmpeg for MP4 concatenation), and only runs on a machine that can produce images.
| Step | What to do | Command / artifact | Where to run |
|---|---|---|---|
| 1 Fetch the book | VoiceDrop MCP list_books → read_book: slug, chapter names (written as a file with one per line), audiobook chapter stem (default 01…NN) |
ChapterName.txt | Anywhere |
| 2 Choose the style | references/选画风.md: content profile → grammar first, then style → 3 candidates for the same-sentence hero shot, independent judges score on 7 dimensions; for a new style, first make it into kits/<名>/ |
三方向/评审.md、选型结果.jpg(send to the user, don't wait for a reply) |
Producing hero shots needs Chromium: on the VPS, only select from existing kits based on the profile and the kits' fits/avoid |
| 3 Create the project | Copy the engine, install kits and fonts, write book.json and the chapter production spec | node $S/new_book.mjs <项目> --slug … --title … --kit … --chapters 章名.txt |
Anywhere |
| 4 Fetch the voiceover | Audiobook mp3 (cache first) → ASR → script = ASR text → sentence timings | node $S/narrate.mjs <项目> |
Anywhere |
| 5 Chapter production | Chapter agents in parallel, each 1–2 chapters, brief =<项目>/制作规范.md+ chapter number; recurring elements are written into scenes/book/props.js |
scenes/book/chNN.js、音频/chNN.shots.json、镜头表/chNN.md |
Self-checking still frames needs Chromium; on the VPS use node $S/smoke.mjs <项目> --film chNN to check for errors and framing |
| 6 Final assembly | Audio track (frame-level concatenation + silent frames), segment table, subtitles | node $S/assemble.mjs <项目>(for missing chapters, first check:--allow-missing) |
Anywhere |
| 6½ Smoke test (mandatory) | Run the whole book without producing pixels: startup errors, runtime errors, missing glyphs, framing (half-cut characters / entering the subtitle band / overlapping text, same criteria as qa); do not deliver if there are errors | node $S/smoke.mjs <项目> → qa/smoke/(about 15s for a 20-minute book, about 2 minutes and 124MB on the VPS) |
Any |
| 7 Review | Independent review agent looks at the qa montage + narration text, scores and lists issues → sends back to the corresponding chapter agent to fix | 审片/*.md |
Mac |
| 8 qa | What smoke tests can't catch: whether the visuals look good, near-blank frames, graphics going off-screen, determinism. Run in batches, merge; framing clues produce a two-frame montage, only fix if both frames are cropped at the edge | node $S/qa_batches.mjs <项目> <项目>/qa/vN;node $S/framing_sheet.mjs <项目> <项目>/qa/vN |
Mac |
| 9 HTML delivery | Package the shared player | node $S/build_html.mjs <项目> → Mac sends Artifact (files uses html/artifact_files.json); VPS uploads the entire html/ directory to the static site |
Any |
| 10 MP4 (only if needed) | Render in segments by chapter, resumable, concurrency auto-calculated from free memory (-j can be manual); after rendering, automatically add_cover.mjs add a 1-second book-cover intro + MP4 cover metadata (--no-cover skip, don't re-add if a cover already exists); deliver gate |
node $S/render_chunks.mjs <项目> <项目>/成片/成片_vN.mp4;uv run ~/.claude/skills/huashu-art-motion/scripts/deliver.py <mp4> --project <项目>/代码工程 --qa <qa 目录> --root <项目> --vertical yes --out <项目>/output/ |
Mac |
The order is rigid: step 4 first obtains the audiobook mp3, and all of step 5's visuals cut shots according to this mp3's ASR sentence timings. Audio has only this one source; the only place in the whole pipeline that might cost TTS money is chapters in step 4 where the audiobook cache misses (once per chapter, permanently cached afterward).
Only a few shots changed: change chNN.js → rerun step 9 (HTML takes under 1 second); for MP4 delete 成片_vN_chunks/chNN.mp4 rerun step 10, the other chapters are reused.
One-off cloud machine (one command on the Tokyo VPS, destroyed when done)
bash cloud/run_book.sh <slug> [--only ch01,ch02,ch03](Tokyo VPS root): spin up a Vultr vhp-8c-16gb-amd($0.132/hr, Tokyo) → cloud/cloud-init.sh install Node 22 / uv / Chromium / Claude Code / engine / this skill → unattended claude -p follow this skill from fetching the book to producing HTML → pull back /root/motion-book/books/<slug>/ → scripts/publish_video.mjs publish to 书架 voicedrop.cn/books//video/ → destroy. Must destroy on exit (--keep excepted);cloud/reaper.sh every 30 minutes delete motion-book machines that have been running over 6 hours.--dry Only verifies the environment, doesn't dispatch Claude.
- Credentials are read-only, not copied: Vultr key and Volcano ASR are in
/root/motion-book/secrets.env; Claude uses the book-writing engine/opt/claude-agent/.env'sCLAUDE_CODE_OAUTH_TOKEN(setup-token long-term token, not rotated, shared across machines without kicking each other off; but shares the subscription quota with the book-writing engine's Claude leg); for 书架 publishing use/opt/claude-agent/.config/voicedrop/credentials。 - unattended (
claude -p) sub-agents can only run in parallel in the foreground: send multiple Agent calls in the same message, wait for the whole batch to return before dispatching the next batch; never use background agents, never end the turn with "wait for notification" —-pas soon as the turn ends the process exits and all background agents are killed (2026-10-25 first order, 20 agents all gone halfway through).run_book.sh's prompt has this rule hardcoded; when Claude exits without producing the web version, useclaude -p --continueto continue the same session, at most 3 rounds; a restarted machine will first upload the half-finished work pulled back from the previous round and continue. - There is no VoiceDrop MCP in the cloud: to fetch the book use
node $S/fetch_book.mjs <slug> 章名.txt(read the 书架's public_src/book.json, if the chapter to be made isn't finished, exit without starting the machine). - The Vultr API key has an IP whitelist: the Tokyo VPS's IPv4 must be allowed in the console under Account → API → Access Control, curl uses
-4。 - Online entry (like listening to a book): anyone opens
voicedrop.cn/books/<slug>/video/, and if it hasn't been done it automatically places an order; the lab serviceGET|POST https://lab.jianshuo.dev/api/video-book?slug=(place order) /…/status?slug=(query only) uses systemd-run to start avideo-<slug>unit to runrun_book.sh(MB_ROOT=/opt/claude-agent/motion-book). Gate: only finished books, 1 book at a time, at most 2 books started per day (implemented in the jianshuo.dev repoclaude-agent/src/video-book.ts). When the bookshelf already hasvideo/, the interface answers done and will not redo it — to redo the whole book, first delete the R2books/<slug>/video/。 - Bookshelf marker:
publish_video.mjsAfter a successful publish, merge into the online_src/book.jsonMergevideo: {url, publishedAt, duration, chapters}(fewer chapters than the whole book = preview version); the book-writing build.mjs fetches it back from online on every full publish, so fixing the book will not erase it.
Keys to saving time
- Zero-cost reuse of narration: if the audiobook cache hits, no TTS money is spent; ASR pushes mp3 at about 40x speed, so a few chapters finish concurrently in one or two minutes.
- Kit reuse: when choosing an art style, if an existing kit scores within ≤2, use it. Existing:
kurzgesagt(science/medicine/technical mechanisms),banknote(currency/central bank/financial systems, the font is Source Han Serif OFL distributed with the kit). After finishing each new book in a new art style, collect the library into kits/. - Default HTML: rendering a long film to MP4 takes hours, while HTML packaging takes less than 1 second; the visuals are the same, and changing one shot takes effect immediately.
- Chapter parallelism: step 5 dispatches them all at once; each chapter uses local time within the chapter, they do not depend on each other, and final assembly is done last.
Delivery report
HTML link; how many chapters hit the audiobook cache and how many were newly synthesized; (when there is an MP4) path, duration, gate conclusion, and reason for yellow light; which art style was chosen and why. For pitfalls, first check references/踩坑.md。
Runtime environment
- All: Node ≥20 (20 automatically adds
--experimental-websocket), huashu-art-motion engine (~/.claude/skills/huashu-art-motion/scripts/engine, orHUASHU_ENGINEpoints to it; on VPSgit clone https://github.com/alchaincyf/huashu-art-motion), Volcano ASR credentials (environment variables, or~/code/.env, or the file pointed to byBOOK_ENV). - Mac additionally needs: uv, ffmpeg, Playwright Chromium (already installed by huashu-art-motion), only for qa / still frames / MP4. Rendering concurrency is automatically calculated by
render_chunks.mjsbased on free memory (reserve 1.5GB per process, plus another 4GB margin) and core count: about 2 on a 16GB machine, about 8 on a 64GB pro.