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.htmlengine/main.js→~/whatif/main.jsengine/render.js→~/whatif/render.jsengine/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 であること;音声が効果音より明らかに大きいこと。