Werbetrailer-Produktion (lokale Toolchain)
Agentenagnostisch: geschrieben für jeden KI-Coding-Agenten, der Dateien lesen und Shell-Befehle ausführen kann – installiert nativ für Claude Code, GitHub Copilot CLI / Microsoft Scout und Google Antigravity via install.sh; nutzbar aus Cursor, Codex, Windsurf und anderen als Plain-Markdown-Runbook.
Die Toolchain wurde erstmals von Idan Shimon (Microsoft, github.com/idanshimon) demonstriert – sein 58-sekündiges Konzept-Erklärvideo, das ein KI-Agent mit diesem Stack lokal zu $0 erstellt hat, ist die Grundlage dieses Skills.
Gehe nicht von einem Installationsort aus: setze PROMO_VIDEO_SKILL_DIR auf das Verzeichnis, das diese SKILL.md enthält. Das Verzeichnis scripts/ enthält das TTS-Skript, den Aussprache-Helfer und die TTS-Anforderungen; assets/ enthält das Kompositionsskelett, räumliche Komponentenvorlagen und das Entscheidungslog-Schema; references/ enthält die einmalige Toolchain-Installation (install.md).
Kernprinzip: Das Skript wird zuerst erstellt; jede nachgelagerte Zahl wird aus der gemessenen Audiospur ABGELEITET, niemals geraten.
Werbetrailer, kein Erklärvideo: Dieser Skill verkauft das WARUM – Zielgruppe, Problem, Transformation, Beweis, ein Call-to-Action (CTA). Der Mechanismus („Wie es funktioniert“) bekommt maximal einen Satz, und nur wenn der Nutzer es anfordert; Anfragen, etwas zu erklären, gehören zum Companion-Skill explainer-video.
Tool-Profile
| Tool | Ort | Version getestet | Lizenz | Rolle | Aufruf |
|---|---|---|---|---|---|
| OpenMontage | ~/OpenMontage | Checkout Juli 2026 | AGPLv3 (nur Tooling; nichts wird im Video ausgeliefert) | Pipeline-Governance: Stage-Reihenfolge, Entscheidungslog, Tore, Post-Render-Selbstprüfung | Lies AGENT_GUIDE.md + pipeline_defs/animation.yaml; du (der Agent) bist der Orchestrator – kein Daemon läuft |
| Kokoro | PyPI | Kokoro-82M (hexgrad), kokoro==0.9.4 | Code Apache-2.0; Modellgewichte Apache-2.0 | Erzählungs-TTS, 24 kHz mono WAV pro Szene | Python 3.12 venv; KPipeline(lang_code="a"), Stimme af_heart, speed-Parameter |
| HyperFrames | ~/hyperframes | 0.7.57, aus dem Quellcode gebaut | Apache 2.0 | HTML/CSS/GSAP-Komposition → deterministisches MP4 via Headless Chrome | node ~/hyperframes/packages/cli/dist/cli.js <cmd> |
| FFmpeg | ~/FFmpeg Quelle; Binary in einem Build-Verzeichnis | git master (N-125608 Ära) | GPL-Build (libx264 aktiviert) | Musiksynthese (aevalsrc), Encoding, ffprobe-QA, Lautstärke, Plattform-Packaging | Build-Verzeichnis vor HyperFrames-Befehlen auf PATH setzen |
| bun | npm-global | 1.3.14 | – | Baut das HyperFrames-Monorepo | npm i -g bun (brew cask hat einmal stillschweigend versagt) |
| Node.js | nvm | 24.x (≥22 erforderlich) | – | Führt HyperFrames CLI aus | – |
| Python | uv-managed | 3.12 | – | Kokoro-Inferenz | IMMER ein venv (uv venv --python 3.12 .venv); black + pylint sauber |
| espeak-ng | Homebrew oder apt | beliebig | GPL | Kokoro G2P-Fallback (erforderlich) | macOS: brew install espeak-ng; Debian/Ubuntu: sudo apt install espeak-ng |
| gsap | vendored file | 3.x gsap.min.js | GSAP Standardlizenz | Zeitachsen-Animation innerhalb der Komposition | Kopiere nach video/assets/ – NIE ein CDN <script src> (Offline-Determinismus) |
Umgebungsprüfung (einmal pro Maschine)
export FFMPEG_BUILD_DIR="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}"
export HYPERFRAMES_DIR="${HYPERFRAMES_DIR:-$HOME/hyperframes}"
export PATH="$FFMPEG_BUILD_DIR:$PATH"
node "$HYPERFRAMES_DIR/packages/cli/dist/cli.js" doctor
FFmpeg, FFprobe, Node und Chrome müssen alle vor der Produktion bestehen (andere doctor-Zeilen sind optionale Komponenten, die dieser Skill nicht nutzt). Wenn eine der vier fehlschlägt, folge $PROMO_VIDEO_SKILL_DIR/references/install.md – die vollständige einmalige Bootstrap-Installation: Systempakete (macOS/Linux), Klonen der Quell-Tools (einschließlich des OpenMontage-Referenz-Checkouts), Source-Build von FFmpeg mit libx264, Bau der HyperFrames CLI und Agenten-Berechtigungstipps. Lade diese Datei nicht, wenn doctor bereits besteht.
Chrome: Die CLI verwendet automatisch ein gecachtes chrome-headless-shell unter ~/.cache/puppeteer/ (wird einmalig heruntergeladen, falls nicht vorhanden). Der erste TTS-Durchlauf lädt ebenfalls Python-Pakete und Kokoro-82M-Gewichte herunter. Nach diesen einmaligen Downloads haben Synthese, Validierung, Rendering und Packaging einen Offline-Pfad.
Projektstruktur (pro Video erstellen, eigenes Git-Repo, atomare Commits)
<projekt>/
.venv/ # uv venv, python 3.12
.gitignore # .venv/ __pycache__/ video/snapshots/ .DS_Store
README.md # Wie es gemacht wurde + Reproduktion (zuletzt schreiben)
production/
research/research-brief.md # Fakten mit Quellen + ehrliche Wettbewerbstabelle
proposal.md # Konzept, Szenenliste, Lieferversprechen, Laufzeitentscheidung
script/script.md # GESPERRTES Skript
scene_plan/scene-plan.md # Visuelles pro Szene + Bewegungsnotizen
checkpoints/decision-log.json # Append-Only; (Kategorie, Betreff) ist der Schlüssel
checkpoints/self-review.md # Post-Render-Nachweise
assets/audio/ # Kokoro WAVs + durations.json
renders/ # Master + Plattform-Ableitungen
youtube/ # metadata.md + thumbnail.jpg
tools/tts_generate.py # Kopie aus diesem Skill, bearbeite SCENE_NARRATIONS
tools/tts_pronounce.py # Aus scripts/, Akronym-Aussprache (nicht bearbeiten)
tools/pronunciation.local.json # Optionales Projekt-Lexikon-Overlay
video/
index.html # DIE Komposition
assets/gsap.min.js # Vendored
assets/audio/ # Kopien der WAVs (kompositionsrelative Pfade)
Stage 1 – Recherche (Offline-first)
Durchforste das eigene Repo/README/Docs des Themas – suche nach Ergebnissen und Beweisen (Zahlen, Adoption, Vorher/Nachher-Resultate), nicht nach Architektur. Erstelle research-brief.md mit:
- Positionierungsblock (erforderlich – das Skript kann ohne ihn nicht gesperrt werden). Ein Satz pro Punkt: Zielgruppe (für wen ist das), Problem (was fühlen sie heute), Transformation (was ändert sich für sie), Differenzierungsmerkmal (der eine Grund, dies zu wählen). Dies ist die Botschaft; jede nachgelagerte Stage dient ihr.
- Produktfakten, jeweils gegen die Quelle verifiziert – nur behalten, wenn sie einen Nutzen unterstützen (der „Na und?"-Test: Was bekommt der Betrachter?).
- Eine Wettbewerbstabelle (Schwäche → wie das Thema sie adressiert). Ehrlichkeitsregel: Räume echte Punkte gegenüber Wettbewerbern ein (ein ✓ in ihrer Spalte kauft Glaubwürdigkeit für deine).
- Eine „Für das Skript freigegebene Behauptungen"-Liste.
Stage 2 – Vorschlag + Entscheidungen
Schreibe proposal.md: Wiederhole den Positionierungsblock, 5–7 Szenen-Konzept, Ziel ≈60s, Lieferversprechen („bewegungsgeführt, keine Dia-Show"), Toolchain-Tabelle. Protokolliere im decision-log.json – beginne mit dem leeren Schema aus $PROMO_VIDEO_SKILL_DIR/assets/decision-log.json (Felder: category, subject, selected, options_considered, rejected_because, confidence): pipeline_selection, render_runtime_selection (notiere Remotion als in Betracht gezogene Alternative – OpenMontage harte Regel), composition_mode (atelier für Hauptarbeit), voice_selection, music_selection, output_profile, approval_gates und cta_selection – genau EIN Call-to-Action (Repo starren / installieren / Demo ansehen / Website besuchen); Werbetrailer sterben, wenn sie mit einer Feature-Liste statt einer Aufforderung enden. Wenn das Nutzer-Briefing eine Wahl festgelegt hat, markiere approved_by: "user brief". Änderst du eine Entscheidung später? HÄNGE einen neuen Eintrag mit dem gleichen (category, subject) an – bearbeite niemals den alten.
Stage 3 – Skript (der Sperrpunkt)
~150–155 Wörter ≈ 60s bei Kokoro af_heart Geschwindigkeit 1.1. Werbetrailer-Bogen (verkaufe das Warum): Einsätze/Problem-Haken → Enthüllung (Name + die Transformation, die es verspricht) → Vorteile in der Welt des Betrachters → Beweis (ehrlicher Vergleich, echte Ergebnisse) → Vision → der einzelne CTA aus dem Entscheidungslog. Features erscheinen nur als Beleg für einen Nutzen: Jeder Satz muss den „Na und?"-Test bestehen (was bekommt der Betrachter?) oder umgeschrieben werden. MAXIMAL EIN Wie-es-funktioniert-Schlag, und nur wenn der Nutzer es anweist – Mechanismus zu lehren ist Aufgabe des explainer-video-Skills. Stimme: zweite Person, Präsens, kurze prägnante Sätze („du lieferst schneller aus", nicht „es ermöglicht schnellere Auslieferung"). Schreibe Akronyme natürlich („OID", „MCP", „AI") sowohl im Skript als auch im Bildschirmtext – zum Zeitpunkt der Synthese leitet tools/tts_pronounce.py die gesprochene Form (Wort vs. Buchstabe für Buchstabe) aus seinem Lexikon ab, und unbekannte Akronyme werden Buchstabe für Buchstabe buchstabiert und gemeldet. Klassifiziere Domänenbegriffe in einem optionalen tools/pronunciation.local.json ({"NASA": "word", "ECG": "letters", "NGINX": "engine X"}). Vermeide GROSSSCHREIBUNG-Betonung: Ein Wort in Großbuchstaben wird als Akronym behandelt. Wortbudget pro Szene ≈ ihr Anteil an 60s × 2.55 Wörter/s.
Stage 4 – Erzählung + Timing-Ableitung (der tragende Trick)
Erstelle die Python 3.12-Umgebung des Projekts aus den mitgelieferten, fixierten direkten Abhängigkeiten, kopiere die generische Vorlage und bearbeite nur SCENE_NARRATIONS:
uv venv --clear --python 3.12 .venv
uv pip install --python .venv/bin/python \
-r "$PROMO_VIDEO_SKILL_DIR/scripts/tts-requirements.txt"
mkdir -p tools
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_generate.py" tools/tts_generate.py
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_pronounce.py" tools/tts_pronounce.py
PYTORCH_ENABLE_MPS_FALLBACK=1 .venv/bin/python tools/tts_generate.py
mkdir -p video/assets
curl -fL https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js \
-o video/assets/gsap.min.js
Die erste Synthese lädt Kokoro-82M-Gewichte herunter (~330 MB); spätere Läufe verwenden den Cache und können offline sein. Sie schreibt szenenweise WAVs + durations.json. Wenn der Lauf eine WARNUNG zu unbekannten Akronymen ausgibt, klassifiziere diese Tokens in tools/pronunciation.local.json und führe den Lauf erneut aus, bevor du das Timing ableitest.
Behandle 150–155 Wörter bei Geschwindigkeit 1.1 als Startschätzung, nicht als Kalibrierung. Gesamt >62s? Erhöhe die Geschwindigkeit oder kürze Wörter, dann messe erneut.
Leite die Zeitleiste ab (Puffer ≈0.3–0.5s zwischen Szenen):
n_start[0] = 0.5 # Einleitung
scene_start[i] = n_start[i] - 0.15..0.4 # Visuelles kommt kurz vor VO
n_start[i+1] = n_start[i] + dur[i] + 0.3..0.35
TOTAL = letztes n_end + 0.6..0.9 Nachlauf (Ausblenden auf Schwarz)
Diese Zahlen gehen an DREI Orte, die übereinstimmen müssen: Szenen data-start/data-duration, <audio data-start>-Werte und die JS const S1..Sn-Zeitleisten-Konstanten. Kopiere die WAVs nach video/assets/audio/.
Stage 5 – Musikbett (keine Downloads)
Erzeuge einen deterministischen synthetisierten Pad mit dem aus dem Quellcode gebauten FFmpeg. Setze TOTAL_SECONDS auf die abgeleitete Gesamtkomposition; keine externe Sample oder private Referenz ist nötig:
TOTAL_SECONDS=60.5
FADE_SECONDS=3.5
FFMPEG_BIN="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}/ffmpeg"
FADE_OUT_START="$(awk -v total="$TOTAL_SECONDS" -v fade="$FADE_SECONDS" \
'BEGIN { printf "%.3f", total - fade }')"
mkdir -p production/assets/audio
"$FFMPEG_BIN" -hide_banner -y \
-f lavfi \
-i "aevalsrc=0.07*(sin(2*PI*110*t)+0.65*sin(2*PI*110.7*t)+0.45*sin(2*PI*164.81*t)+0.30*sin(2*PI*220.9*t)):s=48000:d=${TOTAL_SECONDS}" \
-af "highpass=f=55,lowpass=f=1200,afade=t=in:st=0:d=2,afade=t=out:st=${FADE_OUT_START}:d=${FADE_SECONDS},pan=stereo|c0=c0|c1=c0" \
-c:a pcm_s16le production/assets/audio/music-bed.wav
Halte es sparsam; bei data-volume="0.12..0.16" gemischt wirkt es als Atmosphäre – für Werbetrailer-Energie bewege dich am oberen Ende dieses Bereichs, niemals über der Erzählung. Kopiere die WAV nach video/assets/audio/ und verwende eine separate Audiospur.
Stage 6 – Kompositionserstellung (HyperFrames-Vertrag)
Beginne mit $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html (es enthält jede unten stehende Regel); bevor du HTML schreibst, überfliege $HYPERFRAMES_DIR/skills/hyperframes-core/SKILL.md.
Struktur: eigenständiges index.html, Root-<div data-composition-id="X" data-start="0" data-duration="TOTAL" data-width="1920" data-height="1080">, Szenen als <section class="clip" data-start data-duration data-track-index="1">, EINE gsap.timeline({paused:true}), synchron bei window.__timelines["X"] registriert, Tween-Positionen = S<i> + local_offset.
Regeln, die echte Debugging-Zeit kosten – befolge sie von Anfang an:
- Jedes
<video>/<audio>braucht eine explizite, nicht-leereid. In HyperFrames kann Audio ohne eine solche in der Browser-Vorschau abgespielt werden, rendert aber STILL (Lint-Fehler; ignoriere sie nicht). - Setze niemals ein anfängliches
transform:in CSS auf ein GSAP-getwientes Element – verwendetl.fromTo(el, {y:24, opacity:0}, {y:0, opacity:1, ...}); GSAP besitzt das gesamte Transform. (opacity: 0allein in CSS ist für reine.to()-Einblendungen in Ordnung.) - Hintergrundfüllung gehört auf ein vollflächiges KIND (
position:absolute; inset:0), niemals auf das Root-Element (Root-Hintergrund kann schwarz rendern). - Medienelemente sind direkte Kinder des Root-Elements,
data-track-indexauf separaten Audiospuren (z.B. 7=VO, 8=Musik). - Keine unendlichen Wiederholungen (
repeat: -1verboten – verwende endliche, z.B. Cursor-Blinkenrepeat: 9, yoyo: true), keinDate.now/Math.random, keine Netzwerkabrufe, keine CDN-Skripte. - Eindeutige
idüberall; animiere nur transforms/opacity (+strokeDashoffsetfür SVG-Linienzüge). - Elemente, die mitten in der Szene erscheinen: versteckter Anfangszustand + Tween bei
S<i>+offset.fromTohatimmediateRender, so dass Pre-Tween-Suchen den from-Zustand zeigen – das macht es suchsicher. - Design-Tokens in
:rootCSS-Variablen = das Theme; tausche ground/ink/accent + Schriftfamilie aus, um es neu zu gestalten. Verwende eine Schrift, die der Renderer mitliefert (JetBrains Mono) – Systemschriften werden ohnehin ersetzt (Lint-Info zeigt dir die Zuordnung). - Halte sekundären Text ≥ WCAG AA auf der Ground-Farbe –
checkFAILT Builds bei Kontrast und gibt die konforme Farbe zur Verwendung aus. - Absichtliche Überlappungen/Scroll-Unterschreitungen: markiere mit
data-layout-allow-overflow/-overlap/-occlusion, anstatt Funde unerklärt zu lassen.
Szenen-Motiv-Ratschläge: Zeige den ERGEBNIS-Zustand – die verbesserte Welt des Betrachters (Vorher/Nachher-Kontrast, das verschwundene Problem, das Ergebnis auf dem Bildschirm). Ziehe unterstützende Einblicke aus der tatsächlichen UI/Domäne des Themas (gefälschte Suchpalette, Terminal, Baum, Tabelle) als Beleg für einen Nutzen, nicht als Mechanismus-Rundgang. Die Narrationsbögen sind Vorlagen; die Motive dürfen es nicht sein. $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html hat Platzhalter für "Hero"-Szene, "Pain"-Szene usw. – passe die data-start/data-duration in <section> an deine abgeleitete Zeitleiste an.