make-ai-short — Generative Kurzfilme, Ende-zu-Ende
Die Pixel stammen von einem Videomodell; Remotion komponiert nur Clips + Untertitel. Bewährt auf
Blau-Mann #1 "Die Tür". Geschwister von /make-short (100 % TSX) — gleiche Disziplin, plus drei
Tore, die TSX nie brauchte: Kosten vor der Generierung genannt, Charakter über
character.json gesperrt, Loop über Endbild-Steuerung festgelegt.
Alles vom Repository-Stammverzeichnis ausführen. Benötigt FAL_KEY (Clips + Bilder) und ELEVENLABS_API_KEY
(Stimme) in .env.
Die drei eisernen Regeln
- Generiere einen Charakter NIEMALS zweimal aus Text.
ai-shorts/<char>/character.json+character.pngist die gesperrte Referenz. Jedes Standbild, das den Charakter benötigt, wird mitgen_image.py --ref character.pngerstellt; jeder Clip ist Bild-zu-Video von einem Frame, der ihn bereits enthält. Falls ein Charakterblatt noch nicht existiert, ist das Erstellen EINES (und die Sichtprüfung durch den Benutzer) ein eigener Schritt vor allem anderen. - NENNE DIE KOSTEN, BEVOR SIE AUSGEGEBEN WERDEN. Abgeleitet, nicht zitiert: Seedance 1080p ohne Audio =
h×w×24×dur/1024Tokens × 1,2 $/1 M ≈ 0,0583 $/s (fal-Preise-API validiert am 14.07.2026 — siehe ai-shorts/IDEAS.md für die vollständige Tabelle + die Wan/Veo-Lite-Fallen). Immergenerate_audio:false— Stimme kommt von ElevenLabs, Sound aus unserer SFX-Pipeline. - Loop durch Einschränkung, nicht durch Glück. Der echte Frame 0 von Shot 1 (aus dem Clip extrahiert, nicht
aus dem Prompt-Bild) ist das Loop-Ziel. Der letzte Shot übergibt ihn als
end_image_url(Seedance/Kling), und die Komposition endet auf genau diesem Standbild über die letzten ~10 Frames (LoopSettle-Muster inremotion/src/shots/ai-1/Ai1Door.tsx).
Artefakt-Vertrag
ai-shorts/<name>/
script.md · beats.json — Gleicher Vertrag wie bei /make-short (vo[] mit echten Wortzeiten)
character.json — DIE GESPERRTE REFERENZ (+ video_model-Block = das gewählte Modell)
shots/NN-slug.png — START-Frame pro Shot (gen_image.py --ref character.png [--ref scene])
shots/NN-slug.json — gen_clip-Seitenwagen (Modell, Nutzlast, Anfrage-ID)
shots/upload-urls.json — fal-Speicher-URLs (Uploads sind über Neuversuche hinweg wiederverwendbar)
voice/ · sfx-plan.json · output/ [voice/output gitignored]
remotion/src/shots/ai-N/ — Komposition + vo.gen.ts
media/projects/<name>/ — DIE Clip-Kopien für staticFile() (committed — Pixel sind
nicht reproduzierbar; shots/*.mp4-Arbeitskopien sind gitignored)
Arbeitsablauf (Stimme vor Pixeln)
- Skript — script.md + beats.json. Hook auf Frame 0 komponiert; These sollte den Loop WOLLEN (Blau-Mann #1: "Ankunft ist ein Mythos" → Ende = auf die gleiche Tür zugehen). ~80–100 Wörter, 2,5–2,7 Wörter pro Sekunde Fenster. Kein Engagement-CTA-Outro, jemals — Ende auf dem Höhepunkt, der Loop ist das Ende.
- Stimme ZUERST —
python tools/gen_voice.py --beats ... --emit-ts remotion/src/shots/ai-N/vo.gen.ts(Stimme und Modell aus.env, oder ein"voice"-Block in beats.json, wenn eine Serie einen Erzähler wie GeorgeJBFqnCBsd6RMkjVDRZzbmit eleven_v3-Tags verwenden soll; auf die LINE CHECK-Flags reagieren wie in make-short Stufe 4, bevor ein Clip generiert wird). Echte Wortzeiten bestimmen die Shot-Fenster; Seedance benötigt ganze 4–12 s Dauern, also Shot-Längen AUFRUNDEN von Fenstern. Dialog (zwei oder mehr Charaktere): beats.json"cast"ordnet jedem Sprecher seinecharacter.jsonzu (deren"voice"-Block verwendet wird), jede VO-Zeile nennt ihren Sprecher in"who", und--pack 0.3legt die Zeilen Ende-an-Ende von ihren echten Längen, anstatt sie in geschätzte Fenster zu quetschen. Eine Stimme pro Charakter lebt in seiner character.json, nirgendwo sonst. - Start-Frames — einer pro Shot,
python tools/gen_image.py --model pro --aspect 9:16 --ref character.png(+ das Szene-Standbild von Shot-1 als 2. Referenz, wenn ein Ort/Requisit shots-übergreifend übereinstimmen muss). QA jedes PNG vor jedem Video-Aufruf — hier ist Drift günstig zu beheben.- Achte auf Hände, Kleidungsdetails, Proportionen — benenne sie explizit im Prompt bei Neuversuchen.
- Clips — Nenne die abgeleiteten Gesamtkosten, dann
python tools/gen_clip.pypro Shot parallel (--set image_url=<fal storage url> --set 'duration="N"' --set resolution=1080p --set generate_audio=false, letzter Shot--set end_image_url=<frame0 url>). Referenzen einmal hochladen viabakeoff_clip.upload_ref; URLs in shots/upload-urls.json behalten. - Clip-QA, Frame für Frame — Start/Mitte/Ende-Streifen pro Clip + ein Side-by-Side des letzten Frames des letzten Clips mit dem Loop-Ziel. Fehlschläge neu versuchen (Nenne die Neuversuchskosten); ein 5 s 1080p-Neuversuch kostet ~0,29 $ — billig im Vergleich zum Ausliefern eines Klons.
- Komposition — Sequenzen von
OffthreadVideoüber EINE Timeline, ~8-Frame-Überblendungen (Clips sind ~1 s länger als ihre Fenster — das ist der Spielraum),Captions+ProgressBarauf der Wurzel,LoopSettle-Auflösung am Ende. Kopiere finale Clips nachmedia/projects/<name>/.npm run gen, frames.mjs an Grenzen + Helden, JEDES PNG lesen, dann render-all --scale=1 und voice.wav muxen. - SFX — /suggest-sfx-Ablauf. Gappy-VO-Kalibrierung (Blau-Mann #1): Cues in VO-Lücken erhalten keine Maskierung und kein Duck — sie benötigen ~7–8 dB WENIGER als der Tabelle für dichte Erzählung (Lücken- Whooshes -9..-13, nicht -3..-5). Verifiziere mit volumedetect RMS gegen eine Sprach-Referenz; Helden-Layer darf einmal das Sprachniveau berühren. Misch-Audition wartet auf das Ohr des Benutzers (hartes Tor).
- Zurückspeichern — catalog used_in, beats.json echte Zeitangaben (gen_voice schreibt sie), Seitenwagen committed, Kostenbuch im Abschlussbericht.
Fertig =
Charakter konsistent in jedem Frame jedes Clips (Frame-für-Frame-QA) · Loop verifiziert
(Letzter Frame vs. Frame 0 Side-by-Side) · Untertitel auf echten Wortzeiten · Kosten vor jeder
Ausgabe genannt und danach summiert · SFX-Audition gerendert, wartet auf das Ohr des Benutzers · kein CTA-Outro.
· tools/check_text.py sauber für gesprochenen und Bildschirm-Text · Telefon-Kopie erstellt mit
tools/export_phone.py · ein datierter Eintrag in LESSONS.md (und das Skill aktualisiert, in allgemeinen Begriffen,
falls die Lektion seine Funktionsweise ändert).