Communitygithub.com

adao-max/agent-skills

用 Manim 代码画动画、配中文旁白,做 3Blue1Brown 风格的概念讲解视频(explainer video),1 到 5 分钟,交付 1080p MP4。用户要用视频或动画讲解一个概念、算法、模型结构、论文、规范或机制时使用,例如"做个视频讲讲 X""用动画讲解 X""3b1b 风格讲一下"。

agent-skills 是什么?

agent-skills is a Claude Code agent skill that 用 Manim 代码画动画、配中文旁白,做 3Blue1Brown 风格的概念讲解视频(explainer video),1 到 5 分钟,交付 1080p MP4。用户要用视频或动画讲解一个概念、算法、模型结构、论文、规范或机制时使用,例如"做个视频讲讲 X""用动画讲解 X""3b1b 风格讲一下"。.

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/adao-max/agent-skills/tree/HEAD/skills/explainer-video

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Programmatic Explainer Video

Environment

  • Install Manim: uv tool install manim. If it reports pycairo missing pkg-config, run brew install pkgconf first.
  • Voiceover and transcription use MiniMax's CLI tool mmx. Install: npm install -g mmx-cli, then log in with mmx auth login --api-key <your MiniMax API Key>. If mmx reports not logged in or insufficient balance, stop and inform the user.
  • contact_sheet.py uses Pillow from the system Python, also requires ffmpeg and ffprobe (brew install ffmpeg).
  • macOS defaults to PingFang SC. On Linux, install a Chinese font first, e.g., fonts-noto-cjk on Debian/Ubuntu. The base class checks if the font exists and stops if missing. Custom fonts can be specified with EXPLAINER_CN_FONT and EXPLAINER_EN_FONT; the font must support all characters in the body text. On other systems, use the respective package manager to install Manim, Pillow, and FFmpeg.
  • Most 3Blue1Brown examples online are written with manimlib; their API is different from Manim Community. Do not copy them directly.
  • scripts/ in this skill:
    • gen_audio.py: Generates voiceover and word-level timestamps.
    • explainer_base.py: Scene base class, subtitle splitting, timing, layout, and cleanup.
    • contact_sheet.py: Extracts frames based on animation nodes and the longest subtitle per segment, prioritizing two-line subtitle layout.
    • verify_video.py: Verifies subtitle glyphs, audio timing, and decoding results of the final video.
    • test_subtitles.py: Reproduces old bugs using real Manim rendering and validates subtitle regression.

Workflow

Place the project directory at ~/video-studio/explainers/<topic>/.

  1. Write an outline. Follow the order "pose a question → concrete example → how the example changes → general rule → test with a new example → answer the question". Split into 5 to 10 segments, each covering only one point. If the total length exceeds 3 minutes, send the outline to the user for confirmation.
  2. Write narration.json. Keys are segment names (s1, s2...), values are the narration. Write the narration in spoken style, short sentences, one idea per sentence. If the chinese-writing-style skill is installed, follow its style. Each segment should have 3 to 6 sentences. If TTS might misread an English word or abbreviation, use a dict {"text": "text shown on screen and for alignment", "tts": "pronunciation for TTS"} as the value.
  3. Run python3 <skill>/scripts/gen_audio.py <project directory>. The default voice for narration is Chinese (Mandarin)_Warm_Girl. Write years, dates, and other numbers in Chinese pronunciation in tts, but keep Arabic numerals in text for on-screen display. To redo only certain segments, add --only s3,s5. If the output says "transcription and narration do not match", determine if TTS misread a keyword. If so, fix the tts for that segment and redo with --only. If character-level timestamps are missing, first repair the transcription; do not deliver subtitles estimated by proportion of segment length.
  4. Create a symbolic link to the shared scripts/explainer_base.py, then write scene.py. For existing projects, first remove local subtitle implementations and overrides of start/finish, keep visual logic, then back up the old base class and replace it with the link. The project should only code the visual explanations; subtitles are generated uniformly by the base class.
  5. In the project directory, run manim -ql --disable_caching scene.py <ClassName>. If it reports "animation cannot keep up with narration", shorten the run_time of the corresponding animation or remove the animation, then re-render.
  6. Run python3 <skill>/scripts/contact_sheet.py <preview video> <project directory> and examine each contact sheet. Check subtitle layout, element overlap, and arrow direction. For animated phrases with estimated timing, verify against the character timestamps in audio/<segment>.words.json.
  7. Run manim --resolution 1920,1080 --frame_rate 30 --disable_caching scene.py <ClassName>. Do not use -qh (60fps). Run <skill>/scripts/verify_video.py <final video> <project directory> with the Python that installed Manim. For uv tool install manim, the corresponding interpreter is $(uv tool dir)/manim/bin/python.
  8. The verification command must exit with code 0, and qa/video-check.json must have passed equal to true. If glyphs, audio timing, or subtitle positioning fail, check the report, screenshots, and corresponding words.json, fix, re-render, and verify again. Estimated subtitles cannot be approved based on screenshots alone.
  9. After verification, copy the final video to <topic>-explanation.mp4, inform the user of the video path, and if the current environment can send files, send it directly. Delete low-resolution previews under media/.

Scene Code

from explainer_base import *

class Topic(ExplainerScene):
    def s1(self):
        self.start("s1")              # Play voiceover and automatically display synchronized subtitles
        title = cn("learning rate", 60, HI)
        self.play(Write(title))
        self.until("learning rate too small")       # Wait until narration reads this phrase
        self.play(title.animate.to_edge(UP))
        self.finish()                 # Wait for voiceover to finish, clean up subtitles and fade out
  • Write a method named after each segment.
  • Do not override start, finish, or the subtitle updater inside the project. If the user explicitly does not want subtitles, set the class attribute SUBTITLES = False.
  • When transitioning between visuals within a segment, only fade out or remove objects you created. Keep the base class subtitles. Do not clear all self.mobjects or call self.clear().
  • The phrase in until() must appear verbatim in the text of that segment's narration, and appear only once.
  • Use cn() for Chinese, en() for English. Font size should not be smaller than 22.
  • Use only the base class's 4 colors: MAIN for main body, HI for emphasis, OK for correct, BAD for error. A single color must have only one meaning throughout the whole video.
  • At most 3 groups of elements on screen at a time. Fade out content no longer being discussed before bringing in new content.
  • Leave the bottom 20% of the screen for subtitles; place charts and explanatory text above this area.
  • When the narration mentions an element, that element should appear, change color, or move.

Common Pitfalls

  • After modifying shared subtitle code, run test_subtitles.py with the Python that installed Manim. It must pass checks for real waiting, inter-segment transitions, two-line subtitles, repeated short phrases, long sentence pagination, and different pronunciation alignment. Manually setting renderer.time and calling the updater alone cannot verify Manim's static waiting behavior.
  • Text does not automatically wrap long lines; use \n to break lines.
  • For text placed inside a bounding box, restrict width with fit(text, bounding_box_width * 0.8).
  • When crossing out an option with Cross, only cross out the text, not the arrow; change the arrow to the BAD color instead.
  • To color specific words in a sentence, use Text(..., t2c={"word": color}).

相关技能