Cartoon短編:アイデア → スクリプト → ナレーション → 完成MP4
見た目:カラフルな3D世界で、プラム色の輪郭を持つキャンバス描きの「豆頭」カートゥーンキャラクター(「カード」)。黒インクの輪郭、ペイントテクスチャ、被写界深度、滑らかなカメラワーク。出力は1080x1920、30fps、ナレーションと全く同じ長さ。ユーザーの声はそのまま。音楽と効果音は合成され、ナレーションレベルの**50%**に設定されます。「決して去らなかった兵士」(19.7秒、8ショット)で実証済み。
ルール
- ストーリー、キャラクター、ショットは常にオリジナル。他のクリエイターの動画をショットごとに再現しない。代わりに同じアイデアのオリジナル解釈を提供する。
- 実在する名前のある人物、ブランドのマスコットやロゴは使用不可。
- ユーザーが希望しない限り、キャプションはなし。作中テキスト(刻まれたメッセージ、看板)はOKで、正しく読めること(反転していないこと)。
- ナレーションの編集やタイミング変更は絶対にしない。映像はナレーションに合わせてタイミングが取られ、すべての視覚的反応はその単語の0〜3フレーム前に配置される。
- オーディオレベル: 音楽はナレーションレベルの50%(−6 dB、ゲートRMS)。効果音は50%以下で、ピークがナレーションを超えないように制限。常に
mix.pyでミックスし、手動では行わない。この比率を変えるようなダッキングや圧縮は使用せず、ミックス全体には1つの線形ゲインとピークリミッターのみを適用。 - タスクリストでユーザーに進捗を伝える。長時間レンダリングの前にスチルコンタクトシートを送信する。
ステージ1:受け付け(常に最初)
オーディオファイルが既に添付されている場合は、ステージ4にスキップ。スクリプトも指定されている場合は、そのスクリプトをタイミングに使用する。 それ以外の場合は、AskUserQuestion(またはそのツールがない場合はプレーンテキスト)を1つ尋ねる:「どこから始めますか?」
- ナレーション準備完了:アップロードを依頼し、スクリプトテキストがあればそれも(スクリプトがあるとタイミングが正確になります)。到着したらステージ4へ。
- スクリプトはあるが、ナレーションが必要:必要に応じてステージ3でスクリプトを調整し、録音のヒントと一緒に返し、アップロードを依頼。その後ステージ4へ。
- 動画のアイデアとスクリプトが必要:ステージ2へ。 また、ターゲットの長さも尋ねる(まだ言っていない場合)。デフォルトは20〜30秒。45〜60秒も許可。
ステージ2:10個の動画アイデア
1つの返信で正確に10個のアイデアを番号付きで提供し、ユーザーに番号(または「もっと」)で返信するよう依頼する。各アイデアには以下を含める:
- タイトル(5〜8語、好奇心を刺激するもの。「決して去らなかった兵士」など)。
- フックライン:最初に話される文章。パラドックスを事実として述べる(「ある男がエッフェル塔を売った。二度も。」)。
- どんでん返し(1行で。動画を締めくくる皮肉な落ち)。
- なぜアニメーションに適しているか:2〜3の大きな視覚的瞬間(崩壊、暴露、追跡)。
- 真実か伝説か:文書化された歴史なのか、異論のある話なのか、民間伝承なのかを明確に述べる。
このフォーマットに「完璧な」アイデアの条件:
- 物理的な因果関係を示せる、驚きのある1つのストーリー。
- 明確な一般人のキャラクター、エスカレートする stakes、最後の行でのどんでん返し。
- シンプルな3D形状とカートゥーンカードで構築できる設定(町、橋、船、城、砂漠、研究所、宮殿)。
- 10個を時代とテーマで混ぜる:古代、中世、1800年代、現代、科学、動物、発明、災害、奇妙な法律、幸運な偶然。
- 事実として提示するものについては、提供する前にウェブ検索で主要な事実を確認する。バイラルな伝説を事実として提示しない。ユーザーがどうしても希望する場合は「伝説によると」と枠組みする。
- 実在する人物を冗談の対象にしない。過激な内容や政治的な内容は禁止。
ステージ3:スクリプト(ユーザーが選択した後)
ナレーションのみを記述(話されるテキストにステージ指示は含めない)。速度は約3.7語/秒:20秒 ≈ 75語、30秒 ≈ 110語、60秒 ≈ 220語。公式:
- フック(文1、前置きなし):不条理な事実。
- 設定(1〜2行):いつ、どこで、誰が、具体的な詳細。
- エスカレーション(2〜4ビート、それぞれがより大きくなる)。他者は疑ったり嘲笑したりする。誇張ジョークを1つ使う。
- 謎または転換:「しかし…」「実は…」で実際のメカニズムを導入。日常的な類推を伴うことが多い。
- どんでん返し/落ち:短く、皮肉的で、動画の最後の言葉。 平易な話し言葉の英語、短縮形、8〜15語程度の文、数字は言葉で書く。視聴者が既に見ているものを説明しない。
次に返信する内容:
- 語数と推定時間を記載した、コピー可能なブロック内のスクリプト。
- 1段落のビジュアルプラン(アニメーション化するショット)。
- 録音のヒント:安定した温かいナレーターの声1つ。ElevenLabsが適している(深みのあるナレーターの声、速度約1.05〜1.1、安定性約45〜55%)。Mp3またはwavで可。文の終わりで自然な間を残す。音楽なしでエクスポート。
- 依頼:「ナレーションの準備ができたらアップロードしてください。フル動画を作成します。」 最終的なスクリプトテキストを保持する。ステージ4でのタイミングを決定するため、音声認識は不要。変更されたバージョンが録音された場合は、最終テキストを尋ねる。
ステージ4:動画をビルドする(ナレーションがアップロードされた後)
ここからは止まらずにすべて実行する。タイミングが解決できない場合のみ質問する。
4.0 キットを入手する
コードキットはこのスキルフォルダ内の kit/ にあります(エンジン、ツール、実例、およびgithub.com/mromidev/claude-animated-shortsからベンダリングしたthree.js r160とtoon.tsペンライブラリ、両方MIT)。find / -name SKILL.md -path "*cartoon-audio-short*" 2>/dev/nullでフォルダを見つけ、そのkit/を読み取り専用として扱います。
次に bash <skill>/kit/tools/setup.sh ~/shorts/<slug> を実行します。エンジンとツールをプロジェクトにコピーし、ベンダリングされたthree.jsをインストールし、Node 22 module.stripTypeScriptTypesでtoon.tsから型を除去し、Playwrightをリンクします。ネットワークは不要。ベンダリングされたファイルがない場合は、npmまたはgitクローンにフォールバックします。
- 要件:Node 22.6+、Python 3(numpy + Pillow)、ffmpeg、およびChromiumをインストールしたPlaywright(
npm i -g playwright && npx playwright install chromiumでインストール可能)。 - パッケージレジストリがブロックされている場合、GitHub経由のgitは通常機能します。TLSを無効にしたり、プロキシを迂回したりしないでください。
- Chromium:
--use-angle=swiftshader --enable-unsafe-swiftshader --ignore-gpu-blocklistを使用して、プリインストールされたPlaywrightブラウザを使用します。これにより、CPU WebGLが約3〜10秒/フレームで動作します。
4.1 タイミング
python3 timing.py voice.mp3 script.txt --out work を実行します。
- whisperまたはfaster-whisperがインストールされている場合、ワードタイムスタンプを使用します。
- それ以外の場合は、スクリプトのフレーズ(句読点で分割)を、サイレンス検出された発話セグメントに、音節を継続時間に一致させ、セグメント内の文末とフレーズ内の長いギャップにペナルティを課すDPを使用してアライメントします。
- ASRがなくスクリプトもない場合は、スクリプトを尋ねてください。Claudeは音声を聞くことができません。
work/phrases.jsonを確認:休止は文末に来るべき。総フレーム数 = round(継続時間 × 30)。
4.2 ショット計画(コードの前に work/PLAN.md)
ショットごとに1行:フレーム、単語、設定、照明、カメラ移動、キャラクター/ポーズ/表情、エフェクト、効果音キュー。
- フレーム0はすでにフックイメージ。
- 通常、フレーズごとに1ショット。小さなフレーズは次のショットにマージ。
- すべての文を文字通りに図解。小道具がジョークを運ぶ。
- ショットサイズを変える:フックMCU → ワイドリビール → ツーショット → キーオブジェクトのインサートクローズアップ → リアクションクローズアップ → ペイオフのための環境移動。
- ライトをビートに使用:通常は昼、衰退やドラマはゴールデン、説明には夜の青。時間の飛躍は6フレームの白いフラッシュ。
- どんでん返しのラインにはスティング(音楽停止、低いヒット、ロールを伴うプッシュイン)。最後のショットの物理的なペイオフは最後の単語に合わせる。
4.3 ワールド(web/main.js)
エンジンセクションは維持する:トゥーンマテリアル、インクコントラクト、add/tbox、空、ライト、カード、レンダーターゲット/ポスト、applyLight、drawActors、swapForNd、renderFrame。// ---------- world ---------- と // ---------- cards ---------- の間のサンプルワールド、および worldState() のストーリー部分を置き換える。
- ペイントされたキャンバステクスチャ(
paint.js:板、梁、腐った木、石、苔/蔦、草、土、左官、屋根瓦、大理石、バナー、刻まれたテキスト)を持つプリミティブから構築。同じフラットで暗い継ぎ目のスタイルで新しいペインターを書く。 - 一定のテクセル密度、2段階トゥーングラデーション、フォグ = 地平線カラーに
tboxを使用。 - 背景:丘(埋められた半球)、山(円錐 + 雪帽子)、ヒノキ/松の木、遠くの家、ペイントされた雲のビルボード。
- セットピース(崩壊、落下、ドア)は、
worldAt(f)からの0..1進行度で駆動され、イージングとずらしのあるパーツを持つピボットグループ。 - 曲線の作中テキストは平面UVを使用。反転していないことを確認。
4.4 キャスト(web/roman.js → web/toon.js)
romanFront(p, outfitKey, opts)は、靴底がy=975にある600x1000のデザインキャンバスに描画。カードは2.25 mの高さなので、1単位 = 0.00225 m。- アウトフィットを
OUTFITS(チュニック/ケープ/鎧/兜/髪/帽子/髭/エプロン/ドレス/トーガ)に追加し、同じスタイルで新しい頭飾りや小道具を追加。 - 腕のポーズ:下げ、槍、指差し、上げ、振る、腰、腹、こめかみ(+渦巻き)、持ち上げ、リーチ(+持ち上げ)、頬、盾、交差、親指。
- 表情:toon.tsのFACEセットに加え、いびき、頑固、目を細める。必要に応じてFACEを拡張。
- 編集後、
cat web/toonbase.js web/roman.js > web/toon.jsで再ビルド。新しいデザインを使用する前に、キャラクターテストシートをレンダリング。 - ビルボードはヨーのみで回転し、コンタクトブロブとアルファテストシャドウを取得し、ワールドパスでインク処理されない。
q()で丸めた値からカードキーを構築(キャンバスは表示変更時にのみ再描画)。- 切り離されたパーツ(例:持ち上げられた兜)は独自のカードで、
headCenter(seed)で整列:y = DECK + (partY − hc) × 0.00225。
4.5 モーション:スムーズで生き生き(web/motion.js)
- カメラ:
camFromKeys(keys, f, {kicks})。スムーザーステップグライド(18〜45 f)、リビールやホイップにはeaseOut、曲線移動にはCatmull-Rom経由点のpathを使用。すべてのホールドは微動し、4フレーム以上静止しない。ドラマには3〜5°のロール、インパクトには7フレームのフリップシェイクを使用。 - 連続性:連続的な動きを優先(クローズアップからワイドへの引き、ラックフォーカス、デッキをクレーン、オブジェクトにプッシュ)。場所や時間のジャンプのみハードカット、フラッシュを伴う。
- キャラクターは決してフリーズしない:すべてのカードに
idle(f, seed)を適用、blinkAtで瞬き、強調された単語で頭の揺れ。 - アクション:予備動作 →
backオーバーシュート →springセトル。スタンプは2フレームのディップ + ダストパフ + キック。笑いは交互の傾きと揺れ。 - 二次モーション:バナーの布の波、葉/埃/水滴/Zzzエフェクトカード、流れる水。常に何かが動いている。
- 歩行:
walk()は距離と歩行フェーズを与える。足は地面に固定、ボブは3〜7%。 - レンズ:クローズアップとミディアムで被写界深度(CInf 8〜14 px)、目に焦点。ワイドはシャープ。ラックフォーカスは約14 f。
4.6 見た目のチェック(フルレンダリング前)
各ショットの中間点、トランジション、キーアクションでスチルをレンダリング:node render.mjs stills/a "5,40,..." 次に python3 sheet.py stills/a stills/sheet_a.jpg。シートを見て以下のトラップを修正:
- 狭い垂直フレーム:水平半幅 = d·tan(hfov/2)、hfov = 2·atan(tan(vfov/2)·0.5625)。4 m、fov 40では ±0.8 m なので、キャラクターを奥行き方向に配置。
- 顔の前の手すりや柱(カメラは手すりの内側または約2.5 m上)。家、屋根、茂みを通るカメラパス。約2 m未満の前景プロップ。柱の後ろに隠れたヒーロー。
- 反転したテキスト。切り離されたパーツカードのオフセットが間違っている。
- 押し出しマテリアルグループ:0 = キャップ、1 = 側面+上面。
- インクの欠落:エッジのみの出力をデバッグ。インク半径約2.5 px(1080時)。空は遠い深度としてカウントされ、カードではない。 シートをショットの1行要約とともにユーザーに送信し、フルレンダリングを開始。
4.7 サウンド(audio.py → ステム → mix.py)
ストーリーに合わせてキュー表を書き換え;シンセはそのまま。audio.py はステムのみ書き出す(music.wav、sfx.wav)。
- 音楽:短いマーチ風ループ(キック/スネア、プラックベース、ブラスパッド)。どんでん返しのラインで停止し、その後低いドローンが続く。
- 効果音はイベント(フレーム/30単位):大きな動きにはウィッシュ、スタンプにはサンク、崩壊にはランブル+クラッシュ、金属にはスクレイプ、リビールにはティン、どんでん返しにはスティング、きしみ、スナップ、スプラッシュ、いびき、葉っぱ、水のアンビエンス。
python3 mix.py voice.mp3 music.wav sfx.wavでミックス。音楽をナレーションのゲートRMSの正確に50%(−6 dB)に設定し、効果音を50%以下でピークがナレーションピークの0.7倍に制限。測定レベルを出力:音楽がナレーションに対して−6.0 dB、効果音がそれ以下であることを確認。- サウンドを作成する前に画像のタイミングを確定。タイミングの変更は、audio.pyとmix.pyの再実行を意味する。
4.8 レンダリング + 仕上げ
node render.mjs frames "0-<N-1>"をBashrun_in_backgroundで実行し、Monitループで進捗を監視し、エラーやプロセス終了をキャッチ。RESUME=1で中断後に継続。小型マシンでは同時に重いPythonを実行しない。bash finish.sh "Title"を実行。1つの線形ゲインを約−14 LUFSに適用し、−1 dBFSピークリミッターを適用。H.264 CRF 17 + AACでエンコードし、フリーズ/ブラックとラウドネスのQAを実行、out/qa_sheet.jpgを書き出す。シートを確認。0.4秒以上のフリーズスパンまたはブラックフレームは修正が必要。- MP4をSendUserFileで配信し、各ショットの内容を数行で説明。キャプション、微調整、またはリストの次のアイデアを提供。
エンジンの落とし穴(キットに保管;再ビルドする場合は保持)
#include <fog_vertex>/<fog_fragment>は独自の行に記述。- 最終パスは
linearToOutputTexel(...)を書き出す(レンダーターゲットは線形HalfFloat)。 - 法線+深度パスはメッシュごとにマテリアルを交換:ワールド → 法線/深度、カード → アルファテストマスク(rgb 0、a = 深度)、ブロブ/雲/空は非表示、水 → フラット法線。この間、フォグとシャドウはオフ。
- インクは深度ジャンプの近傍のみに描画。折り目は法線ドットから。カード隣接はスキップ。インクは約140〜520 mでフェード。
- 被写界深度:48タップ、サンプルごとのCoCテスト(前景のにじみなし)。
- 太陽はライトプリセットごとのaz/elから。シャドウカメラは各ショットのアクションを中心に。
アーキテクチャ(キット編集のための参考)
web/index.htmlはローカルHTTPサーバー上でmain.js(ESモジュール)を読み込む。main.js:レンダラー、トゥーンマテリアル、ワールド、カード(1200x2000 CanvasTexture平面、原点は靴底)、パス(カラーRTサンプル4) → 法線/深度 → インク+グレーディング(彩度、ゲイン/リフト)