Generativer Film
Produziert ein 45–120 s, 1920×1080, 30 fps MP4, bei dem jedes Bild in Code gezeichnet (pycairo + Pillow) und jede Note synthetisiert (numpy/scipy) wird. Es gibt kein Stockmaterial, keine KI-Bilder und keine lizenzierte Musik. Der Referenzfilm ist SŪTRA (indische Zivilisation, 87 s). Er ist im Stil eines Risographie-Druckproofs gestaltet, und ein roter Faden zieht sich durch zehn Kapitel auf einem 96 BPM-Taktraster.
Die Qualität ergibt sich aus drei Dingen. Befolge alle drei:
- Eine Idee pro Kapitel, kein Bild pro Kapitel. Jede Szene zeigt einen Mechanismus (ein Stadtplan, der abgelaufen wird, ein Rezitationsgeflecht, ein wachsendes Fraktal, eine Flugbahn). Veranschauliche kein Substantiv.
- Ein Raster für Bild und Ton. Alles ist in Beats getaktet. Musik wird zuerst geschrieben, und jeder Schnitt, Pop und Blitz landet auf einem musikalischen Ereignis.
- Eine starke, spezifische Kunstrichtung, die nicht „Corporate Erklärvideo“ ist: Print-Chrom, falsch registrierte Farben, indigene Schriften und Ziffern, Schreibmaschinen-Untertitel und gestufte Wipes.
0 · Einrichtung (einmal pro Sitzung)
pip install --break-system-packages pycairo fonttools # numpy, scipy, Pillow sind normalerweise vorhanden
which ffmpeg && python3 -c "from PIL import features; print('raqm', features.check('raqm'))"
Raqm muss True sein, da es die komplexe Schriftformung für Devanagari, Arabisch, Tamil und ähnliche Schriften bereitstellt. Erstelle ein Arbeitsverzeichnis. Wenn der Ordner dieses Skills scripts/ enthält, kopiere engine.py und audio_kit.py in das Arbeitsverzeichnis. Andernfalls schreibe sie wörtlich aus Anhang A und B aus. Sie sind getestet, also schreibe sie nicht neu. Schriftarten werden bei erster Verwendung aus dem google/fonts GitHub-Repository heruntergeladen, was die Sandbox erlaubt.
Richte eine Aufgabenliste ein: Konzept → Musik → Szenen → Testbilder → Rendern → Qualitätssicherung → Auslieferung.
1 · Konzept (vor jeglichem Code)
Recherche. Suche jedes Datum, jede Zahl, jeden Namen und jede Behauptung, die auf dem Bildschirm erscheinen werden, im Web. Stelle unsicheren Daten ein „c." voran. Beschrifte Diagramme mit „schematisch" oder „nicht maßstabsgetreu". Halte die Fakten wenige und präzise, mit Bildunterschriften von höchstens 12 Wörtern.
Klammerobjekt. Finde ein visuelles Element, das in jedem Kapitel vorkommt und dem Film seinen Namen gibt. In SŪTRA war es ein roter Faden, der durch die Straßen geht, zu einer Schallwelle wird, die Kolam zeichnet und dann die Mondflugbahn fliegt. Andere Beispiele:
- Ozeangeschichte: ein einzelner Wellenkamm.
- Kaffee: ein Tropfen.
- Informatik: ein einzelnes Bit.
- Ein Unternehmen: die Kernbewegung seines Produkts.
Titel. Wähle ein Wort, idealerweise in der Sprache des Themas, und gib ihm eine wörterbuchartige Erläuterung auf dem Bildschirm: sūtra (n.) 1. ein Faden 2. eine Regel 3. das, was Dinge zusammenhält.
Kapitel. Verwende 6–10 Kapitel, jedes um eine eigenständige visuelle Idee herum aufgebaut. Greife auf dieses Repertoire zurück:
- Ein Diagramm, das sich selbst aufbaut: ein Stadtplan, eine Routenkarte, eine Umlaufbahn oder ein Stammbaum von Schriften.
- Zahlen als Kunst: ein Pascal/Sierpiński-Dreieck, eine sich ausbreitende π-Spirale, Binärzähler oder Objekte in einer Verdopplungsreihe.
- Rekursion oder Fraktale: ein Tempel der Tempel oder ein Baum der Bäume.
- Ein Oszilloskop des tatsächlichen Soundtracks (
wave_at(f)), hervorragend für Kapitel über Sprache oder Musik. - Eine ununterbrochene Linienzeichnung: eine Kolam- oder Spiegelkurve, eine durchgehende Porträtlinie oder eine Unterschrift.
- Eine kinetische Wortcollage, z. B. Lehnwörter, Slogans oder Ortsnamen, die im Takt gestempelt werden.
- Ein Countdown in einheimischen Ziffern, dann ein Start oder Ereignis, dann ein Treffer.
- Ein Rahmen: Das Outro reiht alle Kapitel wie Perlen auf den roten Faden und kehrt dann zum Anfangsbild zurück.
Teste jedes Kapitel: Wenn es durch ein Stockfoto ersetzt werden könnte, überdenke es.
Palette. Verwende eine Papierfarbe, eine Nachtfarbe und 5 Farben, die nach den eigenen Materialien der Kultur benannt sind. SŪTRA verwendete Indigo, Sindoor, Haldi, Rani und Mor (Pfau). Andere Beispiele:
- Japan: Sumi, Shu-Vermilion, Ai-Indigo, Kincha-Gold, Matcha.
- Mexiko: Cochenille, Mais, Talavera-Blau, Jade, Ringelblume.
- Weltraum: Vantablack, Natriumorange, Wasserstoff-Alpha-Rot, Sauerstoff-Türkis.
Wechsle zwischen hellen und dunklen Kapiteln ab und lass das Drop-Kapitel die Farben mit jedem Takt wechseln.
Schriftsystem. Verwende 4–5 Familien. Wähle eine schmale Display-Schrift für Hauptwörter, native Schrift(en) für das Thema, eine Monospace-Schrift für Bildunterschriften und Beschriftungen und eine weiche kursive Serifenschrift für poetische Zeilen. Verwende native Ziffern für die laufende Jahreszahl oder den Zähler. Nützliche google/fonts-Pfade (get_font(name, path, axes)):
| Rolle | Pfad | Achsen |
|---|---|---|
| Display | ofl/anton/Anton-Regular.ttf | – |
| Mono | ofl/spacemono/SpaceMono-Regular.ttf, …-Bold.ttf | – |
| Kursive Serife | ofl/fraunces/Fraunces-Italic[SOFT,WONK,opsz,wght].ttf | [144,380,100,1] |
| Fette Serife | ofl/fraunces/Fraunces[SOFT,WONK,opsz,wght].ttf | [144,900,100,1] |
| Devanagari | ofl/tirodevanagarisanskrit/TiroDevanagariSanskrit-Regular.ttf | – |
| Arabisch | ofl/notonaskharabic/NotoNaskhArabic[wght].ttf | [700] |
| Tamil / Bengalisch / Thai | ofl/notosanstamil/NotoSansTamil[wdth,wght].ttf (gleiches Muster) | [700,100] (wght, wdth-Reihenfolge = Schriftart) |
| CJK | ofl/notoserifjp/NotoSerifJP[wght].ttf | [700] |
| Brahmi | ofl/notosansbrahmi/NotoSansBrahmi-Regular.ttf | – |
Überprüfe die Achsenreihenfolge mit font_axes(name). Wenn ein Pfad 404 ist, durchsuche https://github.com/google/fonts/tree/main/ofl/<family> mit WebFetch.
Unkonventionelle Mittel. Wähle mehrere aus:
- Print-Proof-HUD: Registriermarken, Farbmuster, ein „PLATE 03 / 08 · NAME"-Label, eine Kapitelnummer in einem alten Zahlensystem, eine laufende Jahreszahl in nativen Ziffern und ein Fortschrittsfaden mit Kapitelperlen.
- Riso-Fehlregister bei Hauptschrift (
riso()). - Halbtonflächen.
- Vertikale Riesenwörter.
- Text auf einem Kreis (ein Stempel oder Siegel).
- Schreibmaschinen-Untertitel.
- Gestufte oder Iris-Wipes in zwei Farben.
- Glitch-Stottern an Nahtstellen, untermalt von Audio-Stottern.
- Ein weißer Blitz beim Drop.
- Filmkörnung.
Niemals:
- Eine zentrierte Titelcard, die ausblendet.
- Farbverläufe, Leuchteffekte oder Linsenflecken als Dekoration.
- Emojis oder Clipart.
- Zeichnungen urheberrechtlich geschützter Figuren, Logos oder Gesichter realer Personen.
- Nationalflaggen, die als Dekoration verwendet werden.
- Klischeebilder.
2 · Zeitachse in Beats
Verwende 90–110 BPM. Ein Kapitel ist 8–16 Beats. 96 BPM × 136 Beats ≈ 87 s. Schreibe zuerst eine Tabelle, wie die von SŪTRA:
| Beats | Kapitel | Bild | Musik |
|---|---|---|---|
| 0–12 | Intro | Ein Punkt pulsiert, dehnt sich zu einer Linie aus, Titelbuchstaben erscheinen einer pro Beat | Drohnen-Schwell, Glocke bei jedem Buchstaben, Riser |
| 12–28 | 1 | Stadtplan baut sich zusammen; Faden wandert durch die Straßen | Handtrommel-Groove + gezupfte Melodie |
| 28–40 | 2 (Atem) | Oszilloskop des Audios + Wortgeflecht | Drohne, Gesang, spärlich |
| 40–52 | 3 | Spinnendes Rad, Buchstaben werden gestempelt, Stammbaum | Geschäftigere Drums, Riser, Stottern bei 51.5 |
| 52–64 | 4 | Sternspuren beschleunigen, Ziffern spiralen | Pad + Glocken-Arpeggio, großer Riser, Blitz |
| 64–80 | DROP | Riesige Hero-Glyphe, Fraktal wächst 4 Reihen/Takt, Palette wechselt pro Takt | Kick, Clap, Sub-Bass, Hook, Boom |
| 80–92 | 5 | Rekursive Struktur wächst in der Tiefe | Halbzeit; Tihai landet auf 92 = Schnitt |
| 92–108 | 6 | Einlinienzeichnung, dann Wortcollage | Sanfter Groove, dann voller Groove |
| 108–120 | Finale | Countdown in nativen Ziffern → Flugbahn → Landetreffer | Glocken, Rumpeln, Riser, Boom |
| 120–136 | Outro | Perlen auf dem Faden, Titel kehrt zurück, Punkt | Gesang + Pad + Melodie, Ausblendung |
Die Energiekurve geht: leises Intro → Aufbau → Atem → Aufbau → Drop auf der überraschendsten Idee → Halbzeit → Finaltreffer → leiser Rahmen.
3 · Musik zuerst — audio.py
from audio_kit import *
T = Track(bpm=96, beats=136, root=138.59, scale="raga_bhairavi") # root Hz; SCALES hat viele Kulturen
T.drone_bed(0, 132, level=lambda b: 0.16 if 12 <= b < 120 else 0.3)
T.hand_drum(12, 28) # Keherwa-ähnliches Standardmuster
T.melody(12, [(2, 4, 1), (3, 5, 1.2, 6), (4, 7, 2.2)]) # (Beat, Stufe, Dauer, Gleiten-zu-Stufe)
T.riser_into(64, 4); T.at("fx", boom(), 64, 0.55) # in den Drop
T.groove(64, 80); T.stutter(51.5)
T.tihai(92) # 3× Phrase landet genau auf Beat 92
T.mixdown("music.wav", fade_beats=(133, 136)) # schreibt auch env.npy / wave.npy
- Busse sind drone, perc, kick, bass, mel, fx und pad. Verwende
T.at(bus, signal, beat, gain, pan)für jeden One-Shot. - Instrumente:
drone, pluck (buzz=0 für sauber), bell, voice, pad, sub, kick, clap, hat, drum_tone, drum_bass, drum_slap, drum_muted, riser, boom, rumble. - Passe die Tonleiter und die Instrumente an die Kultur an. Z. B. Hijaz + Rahmentrommel + oud-artiger Pluck (
buzz=0.8); in_sen + koto-artiger Pluck (buzz=0) + Glocken; dorisch + Drohne + saubere Plucks. - Jedes visuelle Ereignis bekommt einen Sound. Wipes bekommen Riser, Drops bekommen einen Boom plus Blitz, Schnitte landen auf Tihai- oder Kick-Treffern, und erscheinende Buchstaben bekommen Glocken.
- Überprüfe das Ergebnis:
- Lautstärke:
ffmpeg -i music.wav -af ebur128=framelog=quiet -f null -sollte etwa −16 bis −14 LUFS anzeigen. - Spektrogramm:
ffmpeg -i music.wav -lavfi showspectrumpic=s=1600x500:scale=log:fscale=log spec.png, dann lies das Bild und überprüfe die Abschnittsformen.
- Lautstärke:
4 · Szenen — 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")
# Berechne Geometrie auf Modulebene mit einem gesetzten rng (deterministisch über Worker-Prozesse hinweg)
def s_intro(ctx, b, f): # b = Beat (float), f = Frame
bg(ctx, NIGHT)
riso(ctx, lambda c: text(ctx, "TITEL", "anton", 400, c, W/2, 700, ax=.5, sc=back(ph(b, 4, .5))),
PAPER, INK2, dark=True)
return PAPER # Vordergrundfarbe für das HUD
def hud(ctx, b, fg): reg_marks(ctx, fg, (INK1, INK2, INK3))
SCENES = [(0, s_intro), (12, s_ch1)] # (Start-Beat, fn)
run(SCENES, 136, bpm=96, name="meinfilm", hud=hud,
wipes=[(12, INK2, INK3)], # (Beat, c1, c2[, iris_wipe])
glitches=[(51.5, 52.15)], flashes=[(64, WHITE, .5)], fade_out=134.6)
Szenenregeln:
- Zustandslos. Jeder Wert ist eine Funktion von
b, sodass Frames in beliebiger Reihenfolge über Prozesse hinweg gerendert werden können. - Eingänge verwenden
back(ph(b, start, 0.4))für Pop-Effekte,eo()für Folien undeio()für Kamerafahrten und Linienzeichnungen. Staffele Elemente um 0.2–1 Beat. - Beat-Leben kommt von
pulse(b)(1→0 jeder Beat) für Bounce- und Ringgröße,env_at(f)für Lautstärke undwave_at(f)für das Oszilloskop. - Linien live zeichnen. Verwende
path_partial(ctx, pts, cumlen(pts), frac)und platziere eine leuchtende Perle an der zurückgegebenen Spitze. - Komposition.
- Behalte ein Heldenelement, ein unterstützendes Diagramm und eine Bildunterschrift pro Szene.
- Halte 110 px Ränder ein. Die HUD-Ecken und das untere Band (y ≈ 960–1040) sind reserviert. Bildunterschriften stehen bei y ≈ 975, beginnend bei x ≈ 560 oder in der leeren Zone der Szene.
- Große Schrift ist groß: 300–800 px Hero-Glyphen. Bildunterschriften sind 18–22 px Mono.
- Kontrast. Wechsle zwischen Papier- und Nachtszenen ab. Verwende
riso(..., dark=True)auf dunklen Hintergründen. - Verwende
fit_size()für lange Wörter in Collagen undtext_circle()für Siegel. - Das HUD kann Kapitelname, Plattensatznummer, native Ziffern über eine digital map und einen Fortschrittsfaden anzeigen. Wenn der Skill-Ordner
examples/sutra/film.pyenthält, sind dessenhud()und Szenen die vollständige Referenz; seinexamples/sutra/contact_sheet.pngzeigt das fertige Aussehen.
5 · Test-Frames → Kontaktbogen → Korrektur (nicht überspringen)
python3 film.py test 2 6 10 17 25 34 45 58 66 75 86 96 104 110 114 118 125 134
Lies sheet.png und überprüfe:
- Überlappender oder abgeschnittener Text.
- Tofu-Boxen oder fehlende Glyphen. Führe
missing_glyphs(font, string)für jede Schriftart × Zeichenkette aus. Zum Beispiel fehlen Fraunces → π ∞ ṅ, und Tiro Devanagari fehlt → ≈ π. - Unleserliche Bildunterschriften in Miniaturansicht.
- Leere Frames am Kapitelanfang.
- Falsche Fakten oder Tippfehler.
- Beats, an denen sich nichts bewegt.
Wiederhole den Vorgang, bis jedes Bild ein Poster sein könnte. Normalerweise dauert es 2–3 Runden.
6 · Rendern, QA, ausliefern
nohup python3 film.py render > render.log 2>&1 &, dann mit Bash-sleep-Schleifen abfragen (Timeout ≤ 590 s pro Stück). Es rendert parallel auf allen Kernen. Die grobe Geschwindigkeit beträgt je nach Szenenkomplexität 2–10 fps insgesamt; SŪTRA dauerte etwa 20 min auf 2 Kernen.- Ausgaben sind
name_full.mp4(CRF 18, volle Qualität) undname.mp4, eine Zwei-Durchlauf-Neucodierung, die unter 29 MB bleibt, damit sie in das 30 MB Chat-Upload-Limit passt. - QA:
ffprobe -count_frameszur Bestätigung der Bildanzahl und Dauer.ffmpeg -i name_full.mp4 -vf "fps=1/3.5,scale=384:216,tile=5x5" -frames:v 1 final.png, dann lies es.- Stichprobenartige Überprüfung von 2–3 Bildern in Originalgröße, einschließlich eines nach der Komprimierung.
- Download: Sende
name.mp4mit sendUserFile (display: "render"); die Karte ermöglicht dem Benutzer das Abspielen und Herunterladen. Erwähne auch die Datei in voller Qualität. Wenn die Sitzung mit dem Computer des Benutzers verbunden ist, biete an,name_full.mp4überdevice_commit_filesin einem seiner Ordner zu speichern, oder sende es, wenn es unter 30 MB ist. - Um nur einen korrigierten Abschnitt neu zu rendern, führe
python3 film.py chunk <f0> <f1> part.mp4für die betroffenen Frames aus, verknüpfe und multiplexe die Teile dann mit ffmpeg, wie esrun()tut.
Abschließende Nachricht an den Benutzer
Gib den Titel des Films und eine Zeile zu seinem Konzept an, die Kapitel als kompakte Liste, was die Musik ist, und etwaige Annäherungen („c."-Daten, Schemata). Fasse die Schritte nicht zusammen.
Anhang A — engine.py
"""engine.py — generatives Print-Film-Toolkit (pycairo + Pillow/raqm + ffmpeg).
Ein Filmskript macht: from engine import *
dann definiert es Szenen als Funktionen scene(ctx, b, f) -> fg_color (b = Beat, f = Frame)
und ruft run(SCENES, TOTAL_BEATS, bpm=..., wipes=..., hud=...) am Ende auf.
CLI des Filmskripts:
python film.py test 4 12.5 30 # Rendert PNGs bei diesen Beats + Kontaktbogen (sheet.png)
python film.py render # Vollständiges paralleles Rendern -> film_full.mp4 + film.mp4 (<29 MB)
"""
import math, os, sys, subprocess, shutil
import numpy
…
[truncated for translation – gekürzt für die Übersetzung]