SuperAPI AI Directory

motion-explainer

Design & creation

View repository

Updated 10-19 01:28

About this skill

Motion explainer — from a single sentence to an explainer animation

This skill strings together "search the web for information → write the script → Chinese narration → build the animation frame by frame → subtitles → color scheme → self-review → export MP4" into one fixed pipeline. It stands on the shoulders of three things:

  • HyperFrames(open-sourced by HeyGen, HTML + GSAP output to MP4) and its official skills, especially the /hyperframes entry point and the /faceless-explainer workflow.The official version is authoritative for how to do it.
  • This repo's motion-design(taste rules: easing, pacing, holds, Chinese typography) and review-loop(contact sheet self-review).These two are authoritative for whether it looks good.
  • The tools in this folder, scripts/ , fill in what the official workflow doesn't handle well: Chinese narration, subtitles, font consistency, and the three-color theme.

references/lessons.md covers the pitfalls hit in real projects,required reading before starting work, and every one of them actually happened on the first video.

Path codes: the commands below are run inside the project folder, and the tools use codes to point to the skill folders. Find the actual locations before starting:

Code What it is Common location
<me> This skill's folder ~/.claude/skills/motion-explainer(Claude Code)、~/.agents/skills/motion-explainer(Codex)
<fe> HyperFrames official faceless-explainer skill hyperframes skills update faceless-explainer Where it's installed, usually ~/.agents/skills/faceless-explainer or ~/.claude/skills/faceless-explainer
<review-loop> This repo's review-loop skill and <me> are in the same skills folder
ls -d ~/.claude/skills/{motion-explainer,faceless-explainer,review-loop} ~/.agents/skills/{motion-explainer,faceless-explainer,review-loop} 2>/dev/null

PowerShell (when Windows has no bash):

Get-ChildItem "$HOME\.claude\skills","$HOME\.agents\skills" -Directory -ErrorAction SilentlyContinue | Select-Object FullName

Other agents (e.g. Gemini CLI): look for the folder with the same name in its skills folder.

Agents without sub-agents(some Codex and Gemini setups) can also run the whole process: in section 6, "dispatch one sub-agent per frame" becomes doing it yourself frame by frame in order, and the files read and the order for each frame stay the same. The other steps are all ordinary terminal commands.

0. Environment check (on first use)

  • Run python <me>/scripts/hw_check.py --project <專案>first: it detects CPU, memory, GPU, and disk, and suggests which narration engine to use, how much--workers to set, and whether to dispatch sub-agents in batches. Tell the user according to what references/hardware.md says; those suggestions are estimates, not benchmarks.
  • Node.js 22+、ffmpeg/ffprobe、Python 3 + Pillow + fonttools(pip install pillow fonttools; if brotli font is installed, it outputs woff2, otherwise it outputs ttf).
  • HyperFrames CLI:npm install -g hyperframes, then run hyperframes doctor(Docker, Whisper, Kokoro, and MusicGen are all optional).
  • Official skills:hyperframes skills update, and making this kind of video also needs hyperframes skills update faceless-explainer. After installing, find the location of <fe> (see above).
  • Anonymous usage statistics are on by default; ask the user whether to hyperframes telemetry disable。
  • TTS (pick one, ask the user):
    • edge-tts (default):pip install edge-tts, no GPU needed, requires an internet connection when generating. Taiwanese accents include zh-TW-HsiaoChenNeural(female),zh-TW-HsiaoYuNeural(female),zh-TW-YunJheNeural(male).
    • Breeze TTS 2 (Advanced): Local NVIDIA GPU (about 7.7 GB VRAM, 12 GB or more recommended; model files about 7 GB). You can design voices with text descriptions, then do voice cloning; it offers the finest control over accent and emotion.
    • Other engines work too: as long as they can output for each sentence assets/voice/raw/NN.wav. For English videos, you can use the built-in Kokoro/HeyGen in HyperFrames.

1. Research (when web search is available)

  • Search for the latest information on the topic, using at least two independent sources. Write down any places where the numbers don't match, and use the one the sources agree on.
  • Classify each number into one of three categories, which must all be labeled on screen later:Official claims/Measured or reported/Own estimates。
  • Do simple physics or math estimates yourself so viewers can "work it out"—that is the most valuable part of an educational video. Estimates must always be checked against reality (e.g., "a typical car can do at most 1.2 g" is overturned by production cars doing 0–100 km/h in 1.8 seconds, so it should be changed to 1.5 g).
  • Do not use brand photos or logos; use your own drawn schematic diagrams for the main visuals, labeled "schematic diagram."

2. Requirements interview (follow /hyperframes 's intent layer, ask everything at once)

Be sure to confirm: playback platform (determines aspect ratio: class/YouTube → 16:9), length (60–90 seconds recommended; narration length will determine the actual video length), whether narration is needed (recommended), whether to review the storyboard first, and whether to automate or adjust together as you go.

Also ask about three colors(new in this skill), like a presentation template:

  • Background color、Primary color(text and line art),Accent color(only for answers, conclusions, key numbers, and section cards).
  • If there is no preference, recommend: black background #121212, white text #F2F0EA, orange accent #FF7A1A。
  • Font: use one font throughout the video. The default isGenSeki Gothic Bold(OFL licensed; use it for Chinese, English, numbers, and subtitles). If the user specifies a font, switch to it, but confirm that the font can be used freely.
  • Write both the colors and the font into the project's theme.json(example <me>/templates/theme.example.json; for the meaning of each field and how to fill in source , see references/theme-json.md)。

Compile into a requirements summary, divided into two sections: "User answers" and "My inferences." Start work only after the user confirms.

3. Create the project and storyboard

  1. hyperframes init videos/<kebab-name> --non-interactive --example=blank --skill=faceless-explainer, then write BRIEF.md, then follow /faceless-explainer 's Steps 0–2 (capture/extracted/, choose a frame preset to generate frame.md)。
  2. When choosing a preset, prioritize one with clear line art(e.g., cobalt-grid). It is only a "source color scheme"; it will eventually be replaced by theme.py with the user's three colors.
  3. In frame.md , add Traditional Chinese overrides(font, weight, letter spacing, line height, minimum font size for projectors), with content per motion-design Section 5.
  4. Run bash <me>/scripts/fetch_fonts.sh <project>, and put GenSeki Gothic Bold (downloaded from the official GitHub release), the Latin font used when the frame worker was made, and Noto TC all into assets/fonts/,Do not rely on Google Fonts online loading。
  5. Write STORYBOARD.md and SCRIPT.md(format per the official storyboard-format / script-format). The narration shouldSplit by "clause"; each comma is a point in time at which a frame is revealed. Write numbers as Chinese characters ("zero point eight one seconds") so TTS does not mispronounce them.

4. Narration

  1. Generate assets/voice/raw/NN.wav(one file per sentence, NN is the storyboard frame number):
    • edge-tts:python <me>/scripts/edge_tts_voice.py --project <p> --voice zh-TW-HsiaoChenNeural [--rate=-5%]. Use the same voice throughout the video, so the voice is naturally consistent;--list zh-TW can list all voices.
    • Breeze TTS 2:python <me>/scripts/breeze_voice.py --project <p> --breeze-repo … --model … --voice "<聲音描述>" --only-ref, first designareference voice for the user to listen to, and after confirmation remove --only-ref to generate all sentences (each sentence copies this reference voice). If there is a batch runner, use <me>/scripts/tts_jobs.py to generate the work list.
    • If the user has not installed it yet, or is unsure which one to choose: follow references/tts-setup.md to give a recommendation, confirming step by step; do not install anything on your own.
  2. First let the user preview the first one or two sentences; the accent and emotion are decided by the user by ear, not replaced by a score. If unsatisfied, switch to another voice or change the speech rate, delete the old WAV, and regenerate.
    • Discovering a mispronounced word only after the whole video is done(e.g., an English brand name, a heteronym): do not re-record the whole sentence, or the animation timing of that frame will all be thrown off. Instead: with the same voice and the same sentence, generate 4–6 candidates; you can change the seed or change the spelling, e.g., Road-ster or characters with the same sound and tone, while the subtitles still use the original text; put them in assets/voice/fix/cand/NN_X.wav. edge-tts has no seed, so create differences with spelling,--rate、--pitch :python <me>/scripts/edge_tts_voice.py --project . --line N [--text "<換拼法的整句>"] [--rate=-3%] --out assets/voice/fix/cand/NN_B.wav; for Breeze, change the seed and regenerate the same sentence. Then run python <me>/scripts/fix_voice.py --project . audition --line N --clauses <那個詞所在的子句>to concatenate the key segments into a preview file for the user to choose by ear. After choosing, run apply --line N --take NN_X, which will take the new sentenceand scale the whole sentence proportionally back to its original length, align the volume to the original sentence, then recompute the subtitle timing for that sentence, keeping each frame's length unchanged. Next, rebuild the subtitles → patch_captions.py → theme.py(it will automatically recognize the new subtitles) → re-output.Do not split the re-recorded sentence into clauses by pauses and then align the timing: the pause positions in the re-recording are different, so the split points will fall in the middle of words, resulting in missing or repeated words (this has actually happened). ASR can only be used to filter out obviously wrong ones; ASR cannot tell whether the tone is correct (real example: ASR judged "輪胎" as correct, but it sounded wrong to the user).
  3. python <me>/scripts/voice_meta.py --project <p>: trim the leading and trailing silence, measure the time of each clause, write audio_meta.json。
  4. node <fe>/scripts/audio.mjs sync-durations --audio-meta ./audio_meta.json --storyboard ./STORYBOARD.md
  5. Loudness: the final video should be about −14 LUFS, true peak ≤ −1 dBFS. First measure the final video:ffmpeg -hide_banner -nostats -i renders/video.mp4 -af ebur128=peak=true -f null -, look at Integrated loudness(I). Whatever the difference is (G = −14 − I), add the same G dB toeach narration sentenceand then limit the peak, preserving the relative volume between sentences, and re-output:
    for f in assets/voice/[0-9]*.wav; do ffmpeg -v error -y -i "$f" -af "volume=${G}dB,alimiter=limit=0.89" "${f%.wav}.tmp.wav" && mv "${f%.wav}.tmp.wav" "$f"; done
    

5. Shot design (Step 4)

  • In shots.json(see <me>/templates/shots.example.json), write each frame as "which clause → what appears on screen", run python <me>/scripts/apply_shots.py --project <p> to convert to real seconds, and write it back to STORYBOARD.md。
  • blueprint . The field can only be <id> (Adapt)、<id> (Reproduce) or compose; put the explanation separately in note。
  • First use hyperframes catalog --query to find existing components, and draw them yourself only if you cannot find any.
  • For protagonists that appear repeatedly across multiple frames (cars, people, instruments), first draw a shared SVG, fix the coordinates of each component; all workers must copy them exactly. Otherwise, the main subject in each cell will look different.

6. Work on each cell in parallel

  1. node <fe>/scripts/frame-packets.mjs --project <p> --storyboard <p>/STORYBOARD.md
  2. From <me>/templates/dispatch_context.md copy a version to .hyperframes/frame-packets/_dispatch_context.md, and fill in the project's values: Video direction, shared assets, timing rules, fonts.
  3. Assign one sub-agent to each cell, all in parallel. The prompt reads in order:_role.md → _dispatch_context.md → that cell's packet → frame.md → shared assets.When there are no sub-agents, do it yourself cell by cell in cell-number order, reading these files in the same order for each cell; after finishing a cell, take a few screenshots to confirm, then move on to the next cell.
  4. When adjacent cells need to continue the same frame(for example, the same ruler), the precise geometry reported by the cell that finishes first must be passed immediately to the cell that is still working.
  5. After everything comes back:python <me>/scripts/unify_frames.py --project <p>, unify the typeface and the positions of hairline strokes.

7. Assembly, subtitles, color scheme

node <fe>/scripts/captions.mjs build --storyboard ./STORYBOARD.md --audio-meta ./audio_meta.json --hyperframes . --out ./caption_groups.json
node <fe>/scripts/assemble-index.mjs --storyboard ./STORYBOARD.md --hyperframes .   # 要在字幕之後:輸出要看到 captions (track 2): yes
python <me>/scripts/patch_captions.py --project .     # 中文字幕字型與粗細(預設粗體 700)
python <me>/scripts/theme.py --project .              # 套用 theme.json 的三色與字型(index、每一格、字幕)
node <fe>/scripts/transitions.mjs inject --storyboard ./STORYBOARD.md --hyperframes .
node <fe>/scripts/transitions.mjs verify --storyboard ./STORYBOARD.md --index ./index.html
hyperframes lint && hyperframes check

(<fe> = the installed faceless-explainer skill folder.) Every time subtitles are rebuilt, you must rerun patch_captions.py and then run theme.py。theme.json 's accents to specify which elements in each cell use the accent color (block/fill/text/stroke).theme.py automatically recognizes regenerated files (those without the (theme.py) marker) and uses them as the new source files; but when manually editing a file that already has colors applied,.hyperframes/pre-theme/ must be edited as well.transitions.mjs inject lengthens each cell: every time theme.py finishes running, you must inject once more, but do not inject twice in a row (if theme.py was not run in between, the length will be extended twice);font replaces all text in every cell and subtitle with the same font and font weight, overriding the font settings originally written by the workers. After changing the font, the text becomes wider, so rerun hyperframes check to check for overflow or overlap.

Only at the very last step, slim the font:python <me>/scripts/subset_fonts.py --project .. It keeps only the Chinese characters used in the video (reducing a CJK font from 12–17 MB to a few hundred KB), and changes each cell's @font-face to point to the slimmed file. After any action that changes text, subtitles, or color scheme, rerun:theme.py each time reapplies colors from the pre-color source file, and the source file points to the full font; if newly added characters are not in the slimmed file, it falls back to the system font.

8. Review (review-loop)

  • First hyperframes check, then output the whole video at draft quality (hyperframes render --quality draft --workers <hw_check 建議值> --output renders/draft.mp4; always use draft during the review stage), and0.15 seconds before the end of each clausecapture one frame (taking the settled state), stitch them into a contact sheet,and open every single one to look at it with your own eyes:
    python <review-loop>/scripts/sheet.py --video renders/draft.mp4 --at "$(python <me>/scripts/review_times.py --project .)" --out review --name draft
    
  • Check item by item against the checklist in references/lessons.md , fix, re-output, and re-check until a full round has no problems.
  • Only after reviewing, output the final version:hyperframes render --skill=faceless-explainer --quality high --output renders/video.mp4, then measure loudness again.

9. Delivery

Deliver the MP4 path, duration, and an overview contact sheet, and list: which sources were used, which numbers are claims, which are estimates, where it differs from the requirements (for example, the duration exceeds the limit), and what was not done (for example, no music).