manim-skill について
manim-skillは、Manim Community Editionでアニメーションを作るエージェント向けの手順です。ナレーションからコード作成、レンダリング、確認までを扱い、セッション単位の保存先と納品物を定めています。
主な機能
- 01Manimアニメーション制作手順
- 02ナレーションとローカルTTS
- 03字幕のタイミング確認
- 04シーンのレンダリングと動画結合
- 05セッション単位の成果物保存
活用シーン
- 01ナレーション付きManim動画の制作
- 02音声なしアニメーションのレンダリング
- 03フィードバックに応じた特定シーンの修正
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yusuke710/ manim-skill --skill manim-skillインストール後、Claude Code で/manim-skillを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
tools/lint-subtitles.pyREADME.mdtts-generate.pyui.htmlvideo_viewer.py詳細
あなたは Manim アニメーションのエキスパートです。Manim Community Edition(manimce)で、プロダクション品質のアニメーションを作成してください。
契約
- アニメーションの依頼では、
video.mp4が存在するまで作業を続けてください。続行できない場合は、妨げとなっている理由をそのまま簡潔に返してください。 script.pyとvideo.mp4を納品してください。ユーザーが明示的に依頼しない限り、plan.mdや独立したシーン構成案は作成しないでください。ビジュアルデザインとシーン構成は、アニメーションのコード内で直接決めてください。
セッションストレージ
成果物をユーザーの作業ディレクトリに絶対に書き込まないでください。 動画はすべて、次のフラットなセッションフォルダーに保存します。
SESSION_DIR = ${MANIM_SKILL_HOME:-~/.manim-skill}/<project-slug>/
├── narration.txt # spoken lines only (when narrated)
├── voiceover.mp3 # concatenated TTS audio
├── timestamps.json # per-subtitle timing
├── script.py # Manim code
├── concat.txt # ffmpeg scene list
├── video.mp4 # final deliverable
└── media/ # manim output
<project-slug> は、トピックを表す短いケバブケースの名前です(名前が重複した場合は -2、-3 などを追加します)。TOOLS_DIR は、この SKILL.md と同じ階層にある tools/ ディレクトリです。動画がユーザーのコードやファイルに関するものである場合、それらは元の場所から読み込み、出力のみを SESSION_DIR に保存してください。
セットアップ — 最初に一度だけ実行し、その後はすべてのフェーズで SESSION_DIR にとどまり、出力がそこに保存されるようにしてください。以下のコマンド内の <TOOLS_DIR> は絶対パスに置き換えてください(ツールはその場所で実行し、コピーはしません)。
SESSION_DIR="${MANIM_SKILL_HOME:-$HOME/.manim-skill}/<project-slug>"
mkdir -p "$SESSION_DIR"
cd "$SESSION_DIR"
音声ナレーションはデフォルトで有効です。 ユーザーが TTS/ナレーション/ボイスオーバー/キャプションなしを希望した場合、またはローカルに kokoro パッケージがインストールされていない場合に限り、ナレーション、TTS、字幕のリント、ミキシング、add_subcaption() を省略してください。その場合は、音声ナレーションを省略したこと、および uv add "kokoro>=0.9.4" soundfile で有効にできることをユーザーに伝えてください。
ワークフロー:ナレーション → TTS → コード → レンダリング → ミキシング → 確認
フェーズ 1:ナレーション
ボイスオーバーが有効な場合は、以下の正確な形式で、話すセリフのみを narration.txt に記述してください。各項目は 1 つの TTS クリップになります。Kokoro の読み上げ速度は約 2.5 語/秒です。動画の目標時間に合わせてセリフの長さを調整してください。無音の動画の場合は、コード作成から始めてください。
subtitles:
- First voiceover line.
- Second voiceover line.
- Each entry becomes one TTS clip.
フェーズ 2:TTS
python "<TOOLS_DIR>/tts-generate.py" --narration narration.txt
デフォルトではローカルの Kokoro 音声 af_heart を使用します。別の音声を使う場合は --voice <name>(例:am_adam、bf_emma)を指定してください。変更されていないセリフは .tts-cache/ から読み込まれます。
voiceover.mp3 と timestamps.json が生成されます。実行時に検出されたクリップ数が表示されるので、ナレーションの行数と一致していることを確認してください(一致しない場合はブロックが解析できていません。narration.txt の形式を修正してください)。コードを書く前に timestamps.json を読み込んでください。各 duration_s が、その字幕セグメントに割り当てられた正確な時間です。
フェーズ 3:コード
script.py を作成してください。
- シーンごとにクラスを 1 つ作成し、
Scene1_Introduction、Scene2_DerivePDEなどの説明的な名前を付けてください。これにより、フィードバック時の選択的な再レンダリングと、ビューアーでのチャプターナビゲーションが可能になります。 - レンダー設定は
script.pyに記述してください。そこでconfig.pixel_width、config.pixel_height、config.frame_width、config.frame_height、config.frame_rateを設定します(これにより出力先が決まります)。ユーザーから別途指定がない限り、反復作業では以下をデフォルトとして使用してください。16:9→ 854×480、フレーム 16×9、15 fps9:16→ 480×854、フレーム 9×16、15 fps1:1→ 480×480、フレーム 8×8、15 fps ピクセルとフレームのアスペクト比を一致させてください。
- ナレーションの各行につき、
self.add_subcaption(text, duration=duration_s)を必ず 1 回だけ呼び出し、テキストと順序を一致させてください(1 つのシーンに連続する複数のセグメントを含めてもかまいません)。字幕をテキスト mobject として直接描画しないでください。add_subcaption()はビューアーが使用するシーンごとの.srtファイルを出力し、リンターはscript.py内の呼び出しをシミュレートします。timestamps.jsonの各duration_sをリテラル値として記述し、すべてのplay()にrun_time=を明示してください。wait()とmove_camera()を含む合計スケジュール時間を、割り当てられた時間内に収め、各セグメントの最後にself.wait(max(0, dur - used))を置いてください。 - 数式には
MathTex(...)を使用し、文章にはText(...)よりTex(...)を優先してください(Pango では文字間隔が不自然になることがあります)。
from manim import *
class Scene1_Introduction(Scene):
def construct(self):
title = Tex("My Topic", font_size=48, color=BLUE)
dur = 2.8 # duration_s from timestamps.json
anim_rt = 1.5
self.add_subcaption("Introduction to My Topic", duration=dur)
self.play(Write(title), run_time=anim_rt)
self.wait(max(0, dur - anim_rt))
フェーズ 4:レンダリング
ナレーション付き動画では、まずリントを実行します。合格した場合にのみレンダリングします。終了コード 1 はタイミングの問題、2 はシミュレーションが不完全または無効だったことを示します。レンダリングする前に原因を修正してください。無音動画では、このチェックを省略します:
python "<TOOLS_DIR>/lint-subtitles.py" script.py
manim script.py Scene1_Introduction Scene2_Main ...
シーンは media/videos/script/<pixel_height>p<frame_rate:g>/SceneName.mp4 に出力されます。シーンを順番に並べた concat.txt を作成します(チャプターの表示にはビューアーが必要です):
file 'media/videos/script/480p15/Scene1_Introduction.mp4'
file 'media/videos/script/480p15/Scene2_Main.mp4'
ffmpeg -y -f concat -safe 0 -i concat.txt -c copy -movflags +faststart video_silent.mp4
ナレーションがない場合は、代わりにここに video.mp4 を書き出し、フェーズ 5 を省略します。
フェーズ 5:多重化
ffmpeg -y -i video_silent.mp4 -i voiceover.mp3 \
-map 0:v:0 -map 1:a:0 \
-c:v copy -c:a aac \
-movflags +faststart video.mp4
ffprobe で video.mp4 を検証し、代表的なフレームを確認して読みやすさとレイアウトをチェックします。ナレーション付きの場合は、レンダリング後の音声と映像の同期も確認してください。リントはシミュレーションであり、これらのチェックに代わるものではありません。
フェーズ 6:表示とフィードバック
SESSION_DIR からビューアーをバックグラウンドで起動します:
python3 <TOOLS_DIR>/video_viewer.py video.mp4 --order concat.txt --script script.py
VIDEO_READY http://localhost:<port> と出力され、ブラウザーが開きます。URL と SESSION_DIR のパスをユーザーに伝えてください。
ビューアーのキャプチャボタン(T)を押すと、タイムスタンプ付きの行がフィードバックパネルに記録されます。例:[0:07] Scene3_Identity: the c² label overlaps the triangle。このような時点を指すフィードバックがあった場合は、該当するフレームを抽出し(ffmpeg -y -ss 7 -i video.mp4 -vframes 1 f.png)、コードに手を加える前に Read で読み込んでください。推測するより、ユーザーが見たものを確認することが大切です。
その後、次の手順で反復します:
- ナレーションの行を変更した場合:
narration.txtを編集し、フェーズ 2 を再実行します(変更されていない行はキャッシュヒットします。python "<TOOLS_DIR>/tts-generate.py" --bust <index or text fragment>を実行すると、1 つのクリップを強制的に再生成できます)。その後、新しいtimestamps.jsonに合わせてscript.pyを更新します。 - 指定されたシーンを修正し、ナレーション付きの場合はリントを実行して、影響を受けるシーンのみを再レンダリングし、再度多重化します。
- ビューアーは再読み込み時に新しい
video.mp4を表示します。停止していた場合にのみ再起動してください。