Communitygithub.com

What-If Reel Maker

Make a 60-second vertical 'What if…' 3D science reel (Three.js scene, narrator, captions, sound) from a one-line idea for @the.whatif.studio.

What-If Reel Maker とは?

このスキルは、ユーザーが1行のアイデア(例:「もしも月が5秒間消えたら?」)を与えるだけで、60秒の縦型科学リール(1080x1920、30fps、ナレーション、キャプション、効果音付き)を完全自動生成し、`final.mp4` と `caption.txt` を納品します。Three.js を使用した低ポリゴン3Dシーンをコードから構築し、Kokoro ONNX による音声合成、Playwright によるレンダリング、ffmpeg による合成を行います。物理的正確性を重視し、反直感的な「ひねり」をフックにしたスクリプトを生成。Claude Code, Cursor, Codex などの AI エージェント上で動作し、プラットフォーム非依存(Node 18+、Python 3.10+、ffmpeg が必要)です。スキルの `engine/` フォルダから共有エンジンファイルをコピーし、各動画ごとに `scene.js` と `mix.py` を編集する方式で、品質チェックリストに従った最終出力を保証します。

対応~Claude Code~Codex CLI~Cursor
npx skills add gitbasitmalik/viral-3d-videos

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

What-If Reel Maker は何をしますか?

ユーザーが1行(例:「もしも月が5秒間消えたら?」)を入力します。あなたはそれ以外のすべてを行い、final.mp4(1080x1920、30fps、60秒、ナレーション・キャプション・効果音付き)と caption.txt(Instagram用)を納品します。アイデアが不明瞭でない限り質問はせず、適切なデフォルト値を選び、どのデフォルトを選んだかを説明してください。

ハウススタイルは、コード(Three.js)で構築された低ポリゴン3Dの実世界ロケーションです。左上にカウントダウンHUD、イタリック体のセリフキャプション、白アウトライン・黒背景の「X線」セクション、全体像ショット(惑星/宇宙/微生物)、エスカレートする余波、そしてフォローボタン付きのエンドカードが含まれます。ハンドル: @the.whatif.studio。

0. 初回セットアップ(確認し、不足しているものだけをインストール)

Node 18+、Python 3.10+、およびPATHにffmpegが必要です(winget install ffmpeg / brew install ffmpeg)。

プロジェクトルート: ~/whatif/(なければ作成)。共有エンジンファイルはルートに配置し、各動画は videos/<slug>/ に格納します。

mkdir -p ~/whatif/models ~/whatif/videos && cd ~/whatif
npm init -y && npm i [email protected] playwright @fontsource/cormorant-garamond @fontsource/ibm-plex-mono
npx playwright install chromium
pip install kokoro-onnx soundfile scipy numpy
curl -L -o models/kokoro-v1.0.onnx https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx
curl -L -o models/voices-v1.0.bin https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/voices-v1.0.bin

次に、このスキルの engine/ フォルダからエンジンファイルをルートにコピーします(存在しない場合。セクション9を参照)。Windowsでは python3 の代わりに python を使用します。

1. 物理が最優先(最も重要)

コメント投稿者は科学的正確性をチェックします。何かを書き始める前に:

  • 実際に何が起こるかを解明します。推論とすべての数値を videos/<slug>/physics.md に書き、簡単なPython計算で数値を算出します。
  • 反直感的な「ひねり」を探します(例:重力オフ:最初は何も起こっていないように見える。なぜなら、押し縮められた岩、水、空気が外側に跳ね返り、その押しが重力のように感じられるからです)。このひねりがフックです。
  • 重要な主張はウェブ検索で検証します(利用可能な場合)。不確かなことは、表現を柔らかくし(「数分間」「数キロメートル」など)、正確な数値をでっち上げないでください。

2. スクリプト(videos/<slug>/script.json)

以下の60秒ビートテンプレートに従ってください(ストーリーに応じて時間を調整可):

時間ビート映像HUD
0–8日常世界、フックロケーションをゆっくりドリー撮影;タイトル 0.2–3.9<イベント> IN カウントダウン 8.00 S→0、サブ = ロケーション
8.0イベント発生リップル + クロマパルス—
8–28イベントウィンドウ、スロー表示(例:実際の5秒を4倍速)最初は通常ビュー、次にX線<イベント終了> IN 5.00 S、サブ 4Xスロー表示 · <ライブ統計>
16–24隠されたメカニズムアウトラインモード + 発光パーティクル同じ
24–28全体像別シーン(惑星/宇宙/細胞)、白フラッシュイン・アウト同じ
28復帰フラッシュ + ブーム<物体> は / 戻った
28–52余波がエスカレート震動、亀裂、波、破片などキースタット(例:176 KM/H)
~46決めゼリフ—「そうです。<結果>。」
51.2–52フェードアウト
52–60エンドカード事実行 + さらにWhat-Ifをフォロー、ボタン押下 ~57.3—

ナレーション: 14–16行、毎秒3ワード以下、落ち着いたドキュメンタリートーン。0.3秒の1行目はタイトルの疑問文。エンドカードは2行:1文の事実(~52.7)と「Follow for more what ifs.」(~56.6)。キャプションはナレーション行の短縮版(2行以内、<br>で改行)。

{
 "handle": "@the.whatif.studio",
 "voice": "am_michael",
 "title": "What if gravity disappeared<br>for 5 seconds?",
 "titleEnd": 3.9,
 "endTitle": "What if gravity disappeared for 5 seconds?",
 "endFact": "You never feel gravity. You feel the ground pushing back.",
 "duration": 60, "endStart": 52, "press": 57.3,
 "narration": [[0.3, "What if gravity disappeared... for five seconds?"], [4.1, "Right now, gravity is pulling on every atom in this park."]],
 "captions": [[4.1, 7.9, "Right now, gravity is pulling<br>on every atom in this park."]]
}

3. 音声を先に、その後タイミングを調整

python3 gen.py <slug> を実行します。videos/<slug>/audio/lNN.wav と durs.json を書き出し、各行の長さを表示します。行が次の行やビート変更と重なる場合は、テキストを短くするか移動し、再実行します。その後、各キャプションを [start, start + duration + 0.35, text] に設定します。音声: am_michael(デフォルト男性)、af_heart(最良女性)、bm_george(英国男性)。

4. シーンの構築(videos/<slug>/scene.js)

動画ごとに新しいシーンを記述します。build(h)、update(t, h)、hud(t) をエクスポートする必要があります(テンプレートはセクション9)。ルール:

  • 決定論的: ビルド時には h.rnd()/h.R(a,b)(シード付き)のみ使用。update 内のすべては t の純粋関数。Math.random、Date、performance.now は絶対に使用しない。
  • スローモーション はワールド時間を使用: w = t<8 ? t : t<28 ? 8+(t-8)/4 : 13+(t-28)。人、水、雲は w でアニメーション。
  • 見た目: flatShading の低ポリゴンプリミティブ。実際の場所を大まかにモデル化(桟橋、公園、通り、ビーチ)。建物はボックス(キャンバス窓テクスチャ)、人の代わりにボックス+球体で多様な色、インスタンス化された木、白いグローブ付き黒い街灯。グラデーション空シェーダー、スプライト雲、奥行き用の THREE.Fog、影付きの1つの DirectionalLight(影カメラ ±45)+ HemisphereLight。
  • カメラ: 垂直FOV約58、アイ高1.7–2.2m、ゆっくりしたドリーと穏やかなティルト。余波では、正弦波の合計による揺れを追加。
  • X線フェーズ: outline: 0→1(約0.6秒でフェード)を返す。オンの間、建物マップを null に変更し、雲を非表示(ノイズの多いエッジを防ぐ)。オプションで overScene を返す:軌跡/パーティクル用の加算 Points シーン(depthTest false)。
  • 全体像ショット: 2番目のシーンとカメラを構築し、24–28秒間 scene/camera として返す。
  • FX は update から返す: flash(0–1の白)、chroma、ripple + rp(リング半径)、fade(51.2–52で0→1)。
  • パフォーマンス: 描画コールを約400未満に抑える(インスタンス化)。カメラ近くに大きな透明スプライトを多く配置しない(オーバードローが非常に遅い)。
  • テキストは下部20%と右端(Instagram UI)に配置しない。キャプションは y≈1240 に配置。

5. プレビュー、その後修正

node render.js preview <slug> 2,6,10,18,22,26,30,40,47,55 を実行します。JPEGが videos/<slug>/prev/ に書き出されます。開いて確認:場所が読み取れるか、キャプションが判読可能か、アウトラインモードがきれいか、全体像ショットが適切にフレーミングされているか、余波がドラマチックか。問題を修正し、再度プレビュー。静止画が良くなってからフル動画をレンダリングします。

6. レイヤーのレンダリング

シーン(プレート)とテキスト(オーバーレイ)は別々にレンダリングされるため、テキスト修正で3Dの再レンダリングは不要です。

# plate: プロセスを分割(CPUコア2つにつき1プロセス)、それぞれ別のPORTで;0..endStartのみ(残りは黒)
LAYER=plate PORT=8781 node render.js full <slug> plate1.mp4 0 26
LAYER=plate PORT=8782 node render.js full <slug> plate2.mp4 26 52
LAYER=overlay PORT=8783 node render.js full <slug> overlay.mov 0 60

これらをバックグラウンドで実行し、ログを監視します。WebGLがSwiftShader(遅い、CPU)を報告した場合は、HEADFUL=1 を試して実際のGPUを使用します。

7. サウンド(videos/<slug>/mix.py)

セクション9のミックステンプレートをコピーし、EVENTSブロックをビートに合わせて編集します:アンビエンス、カウントダウンチック、イベント前のライザー、イベントと復帰時の boom、X線での shimmer、全体像への whoosh、ランブル/亀裂などの余波音、エンドパッド、ボタンの pop。ナレーションは自動配置され、効果音は音声の下にダッキングされます。実行後、ノーマライズ:

python3 videos/<slug>/mix.py <slug>
ffmpeg -y -i videos/<slug>/mix.wav -af loudnorm=I=-14:TP=-1.5:LRA=11 -ar 48000 videos/<slug>/mix_norm.wav

8. 合成と納品

cd videos/<slug>
ffmpeg -y -i plate1.mp4 -i plate2.mp4 -f lavfi -t 8 -i "color=black:s=1080x1920:r=30" -i overlay.mov -i mix_norm.wav \
 -filter_complex "[0:v][1:v][2:v]concat=n=3:v=1:a=0,format=yuv420p,setsar=1[b];[b][3:v]overlay=format=auto,format=yuv420p[v]" \
 -map "[v]" -map 4:a -c:v libx264 -preset veryfast -crf 23 -c:a aac -b:a 192k -movflags +faststart -shortest final.mp4

(黒クリップの長さ = 期間 − endStart。)final.mp4 から8–10フレームを抽出して確認してから納品します。caption.txt を記述:フック行、実際の物理を2–3文、「Follow @the.whatif.studio for more what ifs」、12–15のハッシュタグ(#whatif #physics #science #3danimation ...)。ユーザーには、CapCutで15–20%ボリュームの静かなBGMを追加できることを伝えます。

9. エンジンファイル

再利用可能なエンジンは、このスキルの engine/ フォルダにあります。ファイルをコピーしてください — 再入力しないでください。1つの共有エンジンがすべての動画で再利用され、動画ごとに2つのファイルがコピーされ編集されます。

共有エンジン(~/whatif/ に一度コピー):

  • engine/index.html → ~/whatif/index.html
  • engine/main.js → ~/whatif/main.js
  • engine/render.js → ~/whatif/render.js
  • engine/gen.py → ~/whatif/gen.py

動画ごと(新しい動画ごとにコピーし、その後編集):

  • engine/scene.template.js → videos/<slug>/scene.js — 動画ごとにシーンを書き換え(セクション4参照)。build(h)、update(t, h)、hud(t) をエクスポートする必要があります。
  • engine/mix.py → videos/<slug>/mix.py — ビートに合わせてEVENTSブロックを編集(セクション7参照)。
# SKILL_DIR = このスキルのフォルダ;プロジェクトルート(~/whatif)から実行
cp "$SKILL_DIR"/engine/{index.html,main.js,render.js,gen.py} ~/whatif/
cp "$SKILL_DIR"/engine/scene.template.js videos/<slug>/scene.js
cp "$SKILL_DIR"/engine/mix.py            videos/<slug>/mix.py

納品前の品質チェックリスト

  • 物理が検証され、数値が計算されていること;最初の15秒でひねりが明確であること。
  • すべてのナレーション行がビートに収まり、重なりがないこと;キャプションがナレーションと一致していること。
  • プレビューが良好であったこと;最終動画が8–10フレームでスポットチェックされていること。
  • ハンドルが @the.whatif.studio と表示されていること;エンドカードが機能し、「Follow for more what ifs」の直後にボタン押下があること。
  • ラウドネスが約 −14 LUFS であること;音声が効果音より明らかに大きいこと。

関連スキル