Generative Film
1920×1080、30 fps、45〜120秒のMP4を生成します。すべてのフレームはコードで描画(pycairo + Pillow)され、すべての音符はシンセサイズ(numpy/scipy)されます。ストック映像、AI画像、ライセンス音楽は一切使用しません。参考作品はSŪTRA(インド文明、87秒)です。リソグラフ印刷の校正刷りのようなスタイルで、赤い糸が96 BPMのビートグリッド上で10のチャプターを通り抜けます。
品質は以下の3点にかかっています。すべてに従ってください:
- チャプターごとに「絵」ではなく「アイデア」を。 各シーンはメカニズムを示します(歩かれる都市グリッド、朗読の組み紐、成長するフラクタル、飛行する軌道)。名詞を図示しないでください。
- 映像と音声で同じグリッドを使用。 すべてはビートでタイミングが決められます。音楽を先に書き、すべてのカット、ポップ、フラッシュが音楽イベントに乗るようにします。
- 強く、具体的なアートディレクション。これは「企業説明ビデオ」ではありません。印刷校正クロム、位置ずれインク、現地の文字と数字、タイプライターキャプション、ステップワイプ。
0 · セットアップ(セッションごとに1回)
pip install --break-system-packages pycairo fonttools # numpy、scipy、Pillowは通常導入済み
which ffmpeg && python3 -c "from PIL import features; print('raqm', features.check('raqm'))"
RaqmがTrueである必要があります。これは、デーヴァナーガリー、アラビア文字、タミル文字などの複雑なスクリプトのシェーピングを提供するためです。作業ディレクトリを作成します。このスキルのフォルダにscripts/がある場合は、engine.pyとaudio_kit.pyを作業ディレクトリにコピーします。ない場合は、付録AとBからそのまま書き出してください。これらはテスト済みなので、書き直さないでください。フォントは初回使用時にgoogle/fontsのGitHubリポジトリからダウンロードされます(サンドボックスで許可されています)。
タスクリストを設定します:コンセプト → 音楽 → シーン → テストフレーム → レンダリング → QA → 納品。
1 · コンセプト(コードの前に)
リサーチ。 画面に表示されるすべての日付、数字、名前、主張をWeb検索します。不確かな日付の前には「c.」を付けます。図には「模式図」または「縮尺不問」とラベルを付けます。事実は少数かつ正確に保ち、キャプションは12語以下にします。
通底するオブジェクト。 すべてのチャプターに登場し、映画にタイトルを与える視覚的デバイスを1つ見つけます。SŪTRAでは、通りを歩き、音波になり、コーラムを描き、月の軌道を飛行する赤い糸でした。他の例:
- 海洋の歴史:一つの波頭。
- コーヒー:一滴。
- コンピューティング:一つのビット。
- ある会社:その製品の中核となる動作。
タイトル。 できれば対象の言語から1語を選び、画面上に辞書的なグロスを表示します:sūtra (n.) 1. 糸 2. 規則 3. 物事をまとめるもの。
チャプター。 6〜10を使用し、それぞれが明確に異なる視覚的アイデアを中心に構成します。以下のレパートリーから描画します:
- 自己構築する図:都市グリッド、路線図、軌道、文字の家系図。
- アートとしての数字:パスカル/シェルピンスキーの三角形、πの螺旋、2進カウンター、倍々に増えるオブジェクト。
- 再帰またはフラクタル:寺院の中の寺院、木の中の木。
- 実際のサウンドトラックのオシロスコープ(
wave_at(f))。これは音声や音楽に関するチャプターに最適です。 - 途切れない一本線の描画:コーラムやミラーカーブ、連続線の肖像画、署名。
- 運動する言葉のコラージュ:借用語、スローガン、地名をビートに合わせてスタンプ。
- 現地の数字でのカウントダウン、そして打ち上げまたはイベント、そしてヒット。
- ブックエンド:アウトロで通底するオブジェクトの糸にすべてのチャプターをビーズとして通し、最初のイメージに戻ります。
各チャプターをテストします:もしストック写真で代用できるなら、考え直してください。
パレット。 紙色、夜の色、そして5つのインクを、その文化独自の素材にちなんで命名します。SŪTRAでは、インディゴ、シンドール、ハルディ、ラニ、モール(クジャク)を使用しました。他の例:
- 日本:墨、朱、藍、金茶、抹茶。
- メキシコ:コチニール、トウモロコシ、タラベラブルー、翡翠、マリーゴールド。
- 宇宙:ヴァンタブラック、ナトリウムオレンジ、水素アルファレッド、酸素ティール。
明るいチャプターと暗いチャプターを交互に配置し、ドロップチャプターでは小節ごとに色を変えます。
タイプシステム。 4〜5ファミリーを使用します。ヒーローワード用のコンデンスディスプレイフェイス、対象の現地文字、キャプションとラベル用のモノフェイス、詩的な行用のソフトイタリックセリフ。経過年やカウンターには現地の数字を使用します。便利なgoogle/fontsパス(get_font(name, path, axes)):
| 役割 | パス | axes |
|---|---|---|
| ディスプレイ | ofl/anton/Anton-Regular.ttf | – |
| モノ | ofl/spacemono/SpaceMono-Regular.ttf、…-Bold.ttf | – |
| イタリックセリフ | ofl/fraunces/Fraunces-Italic[SOFT,WONK,opsz,wght].ttf | [144,380,100,1] |
| ヘビーセリフ | ofl/fraunces/Fraunces[SOFT,WONK,opsz,wght].ttf | [144,900,100,1] |
| デーヴァナーガリー | ofl/tirodevanagarisanskrit/TiroDevanagariSanskrit-Regular.ttf | – |
| アラビア文字 | ofl/notonaskharabic/NotoNaskhArabic[wght].ttf | [700] |
| タミル文字 / ベンガル文字 / タイ文字 | ofl/notosanstamil/NotoSansTamil[wdth,wght].ttf(同パターン) | [700,100](wght, wdthの順序はフォントに依存) |
| CJK | ofl/notoserifjp/NotoSerifJP[wght].ttf | [700] |
| ブラーフミー文字 | ofl/notosansbrahmi/NotoSansBrahmi-Regular.ttf | – |
軸の順序はfont_axes(name)で確認します。パスが404になる場合は、https://github.com/google/fonts/tree/main/ofl/<family> をWebFetchで参照します。
型にはまらないデバイス。 いくつか選択します:
- 印刷校正HUD:トンボ、インク見本、「PLATE 03 / 08 · NAME」ラベル、古代の数字体系のチャプター番号、現地の数字の経過年、チャプタービーズ付き進行スレッド。
- ヒーロータイプのリソ位置ずれ(
riso())。 - ハーフトーン塗りつぶし。
- 垂直巨大単語。
- 円形に設定されたテキスト(スタンプまたはシール)。
- タイプライターキャプション。
- 2色インクのステップまたはアイリスワイプ。
- 継ぎ目でのグリッチスタッター、オーディオスタッターと同期。
- ドロップでの白いフラッシュ。
- フィルムグレイン。
絶対にしないこと:
- フェードする中央揃えのタイトルカード。
- 装飾としてのグラデーション、グロー、レンズフレア。
- 絵文字やクリップアート。
- 著作権で保護されたキャラクター、ロゴ、実在の人物の顔の描画。
- 装飾としての国旗。
- ステレオタイプ的なイメージ。
2 · ビートのタイムライン
90〜110 BPMを使用します。チャプターは8〜16ビートです。96 BPM × 136ビート ≈ 87秒。最初に、SŪTRAのような表を書きます:
| ビート | チャプター | 映像 | 音楽 |
|---|---|---|---|
| 0–12 | イントロ | 点が脈動し、線に伸び、タイトル文字がビートごとに1文字ずつポップ | ドローンのうねり、各文字に鐘の音、ライザー |
| 12–28 | 1 | 都市グリッドが組み立てられる;糸が通りを歩く | ハンドドラムグルーブ+撥弦メロディー |
| 28–40 | 2(息継ぎ) | オーディオのオシロスコープ+言葉の組み紐 | ドローン、詠唱、まばら |
| 40–52 | 3 | 回転する輪、文字がスタンプされる、系図の樹 | より忙しいドラム、ライザー、51.5でスタッター |
| 52–64 | 4 | 星の軌跡が加速、数字が螺旋 | パッド+ベルアルペジオ、大きなライザー、フラッシュ |
| 64–80 | ドロップ | 巨大なヒーローグリフ、フラクタルが1ビートあたり4行成長、小節ごとにパレット変更 | キック、クラップ、サブベース、フック、ブーム |
| 80–92 | 5 | 再帰的構造が深さに応じて成長 | ハーフタイム;ティハイが92で着地=カット |
| 92–108 | 6 | 一本線の描画、次に言葉のコラージュ | ソフトグルーブ、次にフルグルーブ |
| 108–120 | フィナーレ | 現地の数字のカウントダウン → 軌道 → 着地ヒット | 鐘、ランブル、ライザー、ブーム |
| 120–136 | アウトロ | 糸のビーズ、タイトルが戻る、点 | 詠唱+パッド+メロディー、フェード |
エネルギーのカーブ:静かなイントロ → ビルド → 息継ぎ → ビルド → 最も驚くべきアイデアでのドロップ → ハーフタイム → フィナーレヒット → 静かなブックエンド。
3 · 音楽を先に — audio.py
from audio_kit import *
T = Track(bpm=96, beats=136, root=138.59, scale="raga_bhairavi") # root Hz; SCALESには多くの文化のものがあります
T.drone_bed(0, 132, level=lambda b: 0.16 if 12 <= b < 120 else 0.3)
T.hand_drum(12, 28) # keherwa風デフォルトパターン
T.melody(12, [(2, 4, 1), (3, 5, 1.2, 6), (4, 7, 2.2)]) # (beat, degree, dur, glide-to degree)
T.riser_into(64, 4); T.at("fx", boom(), 64, 0.55) # ドロップへ
T.groove(64, 80); T.stutter(51.5)
T.tihai(92) # 3×フレーズが正確にビート92で着地
T.mixdown("music.wav", fade_beats=(133, 136)) # env.npy / wave.npyも書き出します
- バスは、drone、perc、kick、bass、mel、fx、padです。任意のワンショットには
T.at(bus, signal, beat, gain, pan)を使用します。 - 楽器:
drone, pluck (buzz=0でクリーン), bell, voice, pad, sub, kick, clap, hat, drum_tone, drum_bass, drum_slap, drum_muted, riser, boom, rumble。 - スケールと楽器を文化に合わせます。例:hijaz + フレームドラム + ウード風撥弦(
buzz=0.8);in_sen + 琴風撥弦(buzz=0)+ 鐘;ドリアン + ドローン + クリーン撥弦。 - すべての視覚的イベントには音があります。 ワイプにはライザー、ドロップにはブームとフラッシュ、カットはティハイまたはキックヒットに乗り、文字のポップには鐘の音。
- 結果を確認:
- ラウドネス:
ffmpeg -i music.wav -af ebur128=framelog=quiet -f null -で約−16〜−14 LUFSになっているはず。 - スペクトログラム:
ffmpeg -i music.wav -lavfi showspectrumpic=s=1600x500:scale=log:fscale=log spec.png、次に画像を読んでセクションの形状を確認。
- ラウドネス:
4 · シーン — film.py
from engine import *
PAPER, NIGHT, INK = hx("F1E6CF"), hx("0A0D26"), hx("14121C")
INK1, INK2, INK3 = hx("1B2A6B"), hx("EE3B1E"), hx("FFB21A")
get_font("anton", "ofl/anton/Anton-Regular.ttf")
get_font("mono", "ofl/spacemono/SpaceMono-Regular.ttf")
# シード付きrngで幾何学をモジュールレベルで事前計算(ワーカープロセス間で決定論的)
def s_intro(ctx, b, f): # b = ビート(浮動小数点数), f = フレーム
bg(ctx, NIGHT)
riso(ctx, lambda c: text(ctx, "TITLE", "anton", 400, c, W/2, 700, ax=.5, sc=back(ph(b, 4, .5))),
PAPER, INK2, dark=True)
return PAPER # HUDの前景色
def hud(ctx, b, fg): reg_marks(ctx, fg, (INK1, INK2, INK3))
SCENES = [(0, s_intro), (12, s_ch1)] # (開始ビート, 関数)
run(SCENES, 136, bpm=96, name="myfilm", hud=hud,
wipes=[(12, INK2, INK3)], # (ビート, c1, c2[, iris_wipe])
glitches=[(51.5, 52.15)], flashes=[(64, WHITE, .5)], fade_out=134.6)
シーンのルール:
- ステートレス。 すべての値は
bの関数であるため、フレームは任意の順序でプロセス間レンダリング可能。 - エントランスには、ポップ用に
back(ph(b, start, 0.4))、スライド用にeo()、カメラ移動と線描画用にeio()を使用します。アイテムを0.2〜1ビートずつずらします。 - ビートの命は、バウンスとリングサイズ用の
pulse(b)(ビートごとに1→0)、ラウドネス用のenv_at(f)、オシロスコープ用のwave_at(f)から得られます。 - 線はライブで描画。
path_partial(ctx, pts, cumlen(pts), frac)を使用し、返された先端に光るビーズを配置します。 - 構図。
- シーンごとに、1つのヒーロー要素、1つの補助図、1つのキャプションを維持。
- 110ピクセルのマージンを維持。HUDコーナーと下部バンド(y ≈ 960〜1040)は予約済み。キャプションはx ≈ 560から始まるy ≈ 975、またはシーンの空きゾーンに配置。
- 大きなタイプは大きく:300〜800ピクセルのヒーローグリフ。キャプションは18〜22ピクセルのモノ。
- コントラスト。 紙色のシーンと夜のシーンを交互に配置。暗い背景では
riso(..., dark=True)を使用。 - コラージュ内の長い単語には
fit_size()を、シールにはtext_circle()を使用。 - HUDには、チャプター名、プレート番号、数字マップを介した現地の数字、進行スレッドを表示できます。スキルフォルダに
examples/sutra/film.pyがある場合、そのhud()とシーンが完全なリファレンスです。examples/sutra/contact_sheet.pngが完成したルックを示しています。
5 · テストフレーム → コンタクトシート → 修正(スキップしない)
python3 film.py test 2 6 10 17 25 34 45 58 66 75 86 96 104 110 114 118 125 134
sheet.pngを読み、以下をチェック:
- 重なったりクリップされたテキスト。
- 豆腐ボックスや欠落グリフ。すべてのフォント×文字列に対して
missing_glyphs(font, string)を実行。例:Frauncesはπ ∞ ṅを欠き、Tiro Devanagariは≈ πを欠く。 - サムネイルサイズで読めないキャプション。
- チャプター開始時の空白フレーム。
- 誤った事実やタイプミス。
- 何も動かないビート。
すべてのフレームがポスターになり得るまで反復。通常2〜3ラウンドかかります。
6 · レンダリング、QA、納品
nohup python3 film.py render > render.log 2>&1 &、その後Bashsleepループでポーリング(各タイムアウト ≤ 590秒)。全コアで並列レンダリング。おおよその速度はシーンの複雑さに応じて合計2〜10 fps。SŪTRAは2コアで約20分かかりました。- 出力は
name_full.mp4(CRF 18、フル品質)とname.mp4(2パス再エンコード、30 MBのチャットアップロード制限に収まるよう29 MB未満に維持)。 - QA:
ffprobe -count_framesでフレーム数と長さを確認。ffmpeg -i name_full.mp4 -vf "fps=1/3.5,scale=384:216,tile=5x5" -frames:v 1 final.png、次に読み取り。- 圧縮後のものを含め、2〜3のフルサイズフレームをスポットチェック。
- ダウンロード:
name.mp4をSendUserFile(display: "render")で送信。カードからユーザーが再生とダウンロード可能。フル品質のファイルについても言及します。セッションがユーザーのコンピュータにリンクされている場合は、device_commit_filesを介してname_full.mp4をユーザーのフォルダの1つに保存することを提案するか、30 MB未満の場合は送信します。 - 修正されたセクションのみを再レンダリングするには、影響を受けるフレームに対して
python3 film.py chunk <f0> <f1> part.mp4を実行し、run()が行うようにffmpegでピースを連結してマルチプレクサします。
ユーザーへの最終メッセージ
映画のタイトルとコンセプトの一文、チャプターの簡潔なリスト、音楽の内容、および近似(「c.」の日付、模式図)を示します。手順の要約は不要です。
付録A — engine.py
"""engine.py — generative print-style film toolkit (pycairo + Pillow/raqm + ffmpeg).
A film script does: from engine import *
then defines scenes as functions scene(ctx, b, f) -> fg_color (b = beat, f = frame)
and calls run(SCENES, TOTAL_BEATS, bpm=..., wipes=..., hud=...) at the bottom.
CLI of the film script:
python film.py test 4 12.5 30 # render PNGs at those beats + contact sheet (sheet.png)
python film.py render # full parallel render -> film_full.mp4 + film.mp4 (<29 MB)
"""
import math, os, sys, subprocess, shutil
import numpy
…
[翻訳のため省略]