シネマティックビート ビデオスタイル
基本理念
映像がタイミングを決め、音声はそれに従う。 アニメーションやASCIIシーンは自然な実行時間で再生されます。音声の長さに合わせて切り詰めたり、早送りしたり、最終フレームで停止したりすることはありません。ビート間の無音は意図的なデザインであり、埋めるべき隙間ではありません。
- TTS: クリップごとに一文のみ。最大の信号対雑音比。無駄なナレーションはなし。
- 映像: 完全な自然実行時間。アニメーションをそのまま見せましょう。
- カット: ハードカットのみ。クロスフェードはなし。
- 音楽: ユーザー提供のトラック。音声部分では自動的にダッキング。
- チェックイン: 各制作フェーズの後、次の作業に進む前にアセットをユーザーに提示しレビューを仰ぐこと。
プロジェクト構造
~/videos/[project-name]/
project.md # 生きたドキュメント — ストーリーボード、決定事項、リビジョンノート
beats/ # 個別のビートアセット
beat-01/
visual.mp4 # 生成されたビジュアル(モーション付き画像またはアニメーション)
audio.mp3 # このビート用TTSクリップ(MP3のみ — 重要ルール参照)
note.txt # このビートが何を示すか、一行の説明
beat-02/
...
music/ # ユーザー提供のBGMトラック
output/ # 中間および最終レンダリング
フェーズ1: ビートスクリプト
project.md を作成し、ビートの内訳を記述します。各ビート = 1つのビジュアル + 1つのTTS文章。
ビートの書き方
TTSルール:
- ビートごとに一文のみ。絶対に。
- 最大限の信号対雑音比 — すべての単語がその存在価値を示すこと。
- 一つの考えに二文必要な場合は、二つのビートにすること。
- 目標: クリップあたり5〜15語。短いほど良い。
- 導入の冗長表現は不要(「それでは…」「では見ていきましょう…」)。要点から始める。
ビジュアルルール:
- ビジュアルが何を示すかを記述する — 持続時間は記述しない。
- ビジュアルの実行時間は、その自然な完了時間によって決まる。TTSの長さではない。
- 画像カット: 静止画像にKen Burns効果(緩やかなズーム/パン)。実行時間: 最低4〜6秒。
- アニメーションカット(p5js/manim/ascii): アニメーション全体を再生。必要なだけ — 8秒、12秒、15秒。
- ビートの長さ = max(ビジュアル_長さ, 音声_長さ) + ポーズ。
project.mdのビートテンプレート:
# [プロジェクト名]
## コンセプト
[1段落 — このビデオの内容と、狙う雰囲気]
## 音楽
- トラック: [ユーザーが提供する音楽のファイル名または説明]
- 雰囲気: [説明]
## ビート
### ビート01
**ビジュアル:** [タイプ: image | p5js | manim | ascii] — [プロンプト/説明]
**TTS:** 「一文でインパクトのある文。」
**ステータス:** [ ] ビジュアル [ ] 音声 [ ] 承認
### ビート02
...
## ノート
[決定事項、リビジョン、ユーザーフィードバックの実行ログ]
カットタイプ
| タイプ | ツール | 実行時間 | 最適な用途 |
|---|---|---|---|
image | image_generate + Ken Burns | 4〜6秒 | 写真、風景、ポートレート、導入ショット |
p5js | p5jsスキル | 自然 (8〜15秒) | ジェネラティブアート、パーティクル、データ可視化、フローフィールド |
manim | manim-videoスキル | 自然 (8〜20秒) | 数学アニメーション、図、技術解説 |
ascii | ascii-videoスキル | 自然 (6〜12秒) | ターミナル風美学、レトロコンピューティング、ハッキングトピック |
caption | ffmpeg drawtext | 4〜8秒 | 暗い背景に中央揃えのTTSテキスト — 言葉に焦点を当てる |
重要: p5js/manim/asciiビートを制作する前に、必ず skill_view(name) でスキルを読み込むこと。 これらのスキルには、ブランドパレット、フォントルール、実装パターンが含まれており、正確に従う必要があります。
フェーズ2: スクリプト承認ゲート
停止。project.md をユーザーに提示する。明示的に承認されるまでアセットを生成しないこと。
project.md のノートセクションに承認タイムスタンプを記録する。
フェーズ3: ビジュアルの生成
すべてのビジュアルアセットをタイプに従って生成する。beats/beat-XX/visual.mp4 として保存。
画像ビート(VHSフィルター適用Ken Burns)
image_generateで画像を生成- 画像にVHSフィルターを適用(粒子、スキャンライン、ビネット、色収差):
python3 scripts/vhs-filter.py \
--input beat-XX-image.png \
--output beat-XX-vhs.png \
--seed 42 \
--intensity 1.0
必要条件: pip install numpy Pillow(numpyは配列エフェクト用、Pillowは画像I/O用)。
強度レベル: 0.7(控えめ — 粒子+ビネットのみ)、1.0(標準 — すべてのエフェクト)、1.5(強 — 強い色収差、スキャンラインが目立つ)。デフォルトは 1.0。
- VHSフィルター適用済み画像にKen Burns効果を適用しMP4を作成:
ffmpeg -loop 1 -i beat-XX-vhs.png -t 5 \
-vf "zoompan=z='min(zoom+0.001,1.3)':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=125:s=1920x1080:fps=25" \
-c:v libx264 -pix_fmt yuv420p -r 25 beats/beat-XX/visual.mp4
なぜVHSを先に適用してからKen Burnsなのか? zoompanフィルターは粒子やスキャンラインをぼやけさせてしまう。VHSフィルターは静止画像に先に適用し、その上に動きを加える。VHSフィルター適用済み画像の上にKen Burns効果を重ねることで、少し劣化したCRTを通して昔の映像を見ているような、生活感のあるアナログ感覚を生み出す。
アニメーションビート(p5js/manim/ascii)
該当するスキルを最初に読み込み、その後生成する。出力を beats/beat-XX/visual.mp4 として保存。
解像度: すべてのビジュアルは1920x1080、25fpsであること。manim出力をスケーリング:
ffmpeg -y -i raw-manim.mp4 \
-vf "scale=1920:1080:flags=lanczos,setsar=1:1,fps=25" \
-c:v libx264 -pix_fmt yuv420p -r 25 beats/beat-XX/visual.mp4
image_generateの呼び出しは、6個ずつのグループにまとめてバッチ処理すること。フラグが立てられた場合は、中立的に言い換えて1回だけ再試行すること。
VHSフィルターリファレンス
VHSフィルター(scripts/vhs-filter.py)は、単一の画像に以下のエフェクトを適用します:
| エフェクト | 機能 | 視覚的結果 |
|---|---|---|
| 色収差 | R/Bチャンネルオフセット(0〜2px) | エッジに色ずれ、CRTの位置ずれのように |
| アナログノイズ | チャンネルあたり±8グレイン(強度に応じてスケーリング) | 影と中間色にフィルムライクなテクスチャ |
| スキャンライン | 4行ごとに96%に暗化 | CRT蛍光体グリッドのオーバーレイ |
| CRTビネット | エッジの暗化(強度に基づき15〜35%) | 昔のテレビのような丸みを帯びた画面隅 |
画像について: すべてのエフェクトは単一のランダムシードで一度だけ適用される。色収差とノイズは目に見える。ジッターやトラッキングラインはフレームが1つしかないため控えめ。
注: このフィルターは画像のみを対象としている — ビデオ入力は処理しない。動きをつけるには、まずフィルターを静止フレームに適用し、その上にKen Burns/zoompanを追加する。
フェーズ3.5: ビジュアルチェックインゲート
停止。各ビジュアルクリップをユーザーにレビュー用に送信する。
MEDIA: パスとともにスクリーンショットまたはMP4を含める。番号を付けて提示する:
ビート01: [MEDIAパス] — [簡単な説明]
ビート02: [MEDIAパス] — [簡単な説明]
...
質問: "音声に進む前に編集が必要ですか?"
ユーザーがビジュアルを承認するまでTTSを生成しないこと。 フィードバックを project.md のノートに記録する。
変更が要求された場合は、影響を受けるビートのみを再生成し、再チェックインする。
フェーズ4: TTS音声の生成
すべてのTTSクリップを生成 — ビートごとに1つ。text_to_speech ツールを使用し、output_path を .mp3 にする。beats/beat-XX/audio.mp3 として保存。
重要: 音声は常にMP3形式を使用すること。 OGGはTelegram配信やffmpeg concat操作でコーデック互換性の問題を引き起こす。TTSプロバイダーをOpenAIに設定し、MP3出力を指定する。
ルール:
- 呼び出しごとに一文。連結しないこと。
- 生成後、ffprobe で各クリップの長さを測定する。
- 長さを project.md の各ビートの横に記録する。
ffprobe -v error -show_entries format=duration -of csv=p=0 beats/beat-XX/audio.mp3
フェーズ4.5: 音声チェックインゲート
停止。音声クリップをユーザーに提示する。
ボイスフィルターの適用(必須)
すべてのTTSクリップにドライ/ウェットビットクラッシュチェーンを適用 — これがシグネチャーボイスです。完全なテクニックと落とし穴については references/dry-wet-bitcrush.md を参照。
2つのアプローチが利用可能:
A) 静的ミックス(シンプル、一貫性):
# ステップ1: wav中間ファイルを介してクラッシュバージョンを作成(長さを保持)
ffmpeg -y -i beats/beat-XX/audio.mp3 \
-af "aresample=resampler=soxr:osr=2000,aformat=sample_fmts=u8,aresample=resampler=soxr,lowpass=f=2500" \
temp-crushed.wav
# ステップ2: ドライ+ウェットをコンプレッションで結合
ffmpeg -y -i beats/beat-XX/audio.mp3 -i temp-crushed.wav \
-filter_complex "[0:a]volume=0.7[dry];[1:a]volume=0.3[wet];[dry][wet]amix=inputs=2:duration=first:normalize=0,acompressor=threshold=0.05:ratio=4:attack=10:release=100[out]" \
-map "[out]" beats/beat-XX/audio-filtered.mp3
rm temp-crushed.wav
B) 動的ミックス(信号劣化エフェクト — 推奨):
Pythonスクリプト(scripts/vibey-mix.py)を使用。正しいピッチでの本格的なビットクラッシュのために、ゼロ次ホールドアップサンプリングを採用。
必要条件: pip install numpy pydub(numpyは配列処理用、pydubはMP3読み書き用)。
固定パラメータ(dec5-bit8 バリアント):
- デシメーション: 5倍(5サンプルごとに間引き、その後ゼロ次ホールドで繰り返し)
- 量子化: 8ビット(固定)
- ドライ/ウェットベースライン: 80% ドライ / 20% ウェット
- ディップパターン: 約1.2秒ごとに、ドライが約35%に低下、ウェットが約65%に上昇(持続時間 約0.25秒)
- トレモロ(ウェットのみ): 4Hz 三角波、深さ70%(ウェットが30〜100%の間で変動)
- スラップバックディレイ: 80ms、-18dB(約0.12ボリューム)、最終ミックスに適用
python3 scripts/vibey-mix.py beats/beat-XX/audio.mp3
cp beats/beat-XX/audio-dynamic.mp3 beats/beat-XX/audio-filtered.mp3
チェーン内訳: クリーンなドライ信号に、極端なデジタルアーティファクト(5倍デシメーション、ゼロ次ホールドアップサンプリングによる8ビット量子化)、ウェットレベルを上げる定期的なディップによる「劣化伝送」効果、ウェット信号へのリズミカルなパルスのためのトレモロ、空間を生み出すスラップバックディレイを重ねる。チェーン構造はそのまま維持すること — 必要に応じて個々のパラメータのみを調整する。
以降のフェーズでは audio-filtered.mp3 を使用する。元の audio.mp3 は参照用に保持する。
決定事項を project.md のノートに記録する。
フェーズ5: ビートの合成
各ビートについて、ビジュアルと音声をハードカット(トランジションなし)で結合する。ビートの長さは、ビジュアルと音声のうち長い方によって決まる。
ビジュアル >= 音声の場合:
音声はビジュアル全体に渡って再生される。パディングは不要。
ffmpeg -i beats/beat-XX/visual.mp4 -i beats/beat-XX/audio-filtered.mp3 \
-c:v libx264 -pix_fmt yuv420p -c:a aac \
-shortest -r 25 output/beat-XX-composed.mp4
音声 > ビジュアルの場合:
ビジュアルは残りの時間を埋めるために最終フレームを保持する。ビデオに tpad を使用:
AUDIO_DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 beats/beat-XX/audio-filtered.mp3)
ffmpeg -i beats/beat-XX/visual.mp4 -i beats/beat-XX/audio-filtered.mp3 \
-vf "tpad=stop_mode=clone:stop_duration=$AUDIO_DUR" \
-c:v libx264 -pix_fmt yuv420p -c:a aac \
-t $AUDIO_DUR -r 25 output/beat-XX-composed.mp4
音声フィルターが適用されていない場合は、audio-filtered.mp3 の代わりに audio.mp3 を使用する。
ビート間のポーズ
ビート間に、息継ぎのための短い黒フレームを挿入する:
ffmpeg -f lavfi -i color=c=black:s=1920x1080:d=0.15:r=25 \
-c:v libx264 -pix_fmt yuv420p output/pause-XX.mp4
ASCIIキャプションビート(言葉に焦点)
ナレーション自体が焦点である場合 — ビジュアルではなく — TTSテキストを画面中央に表示するASCIIスタイルのビートを使用する。project.md でタイプ [caption] としてマークする:
ビートテンプレート:
### ビート03 [caption]
**ビジュアル:** ascii caption — 中央テキスト、暗い背景、控えめなターミナル風美学
**TTS:** 「画面に表示される正確な言葉。」
**ステータス:** [ ] ビジュアル [ ] 音声 [ ] 承認
ffmpeg drawtext を使用して、黒/暗い背景に等幅フォントとALLMINDゴールド(#C5A55A)テキストで生成:
TEXT="Your TTS sentence here"
ffmpeg -f lavfi -i color=c=black:s=1920x1080:d=6:r=25 \
-vf "drawtext=text='${TEXT}':fontsize=42:fontcolor='#C5A55A':fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf:x=(w-tex