/pitch-deck-video
Erzeuge ein vertontes Produkt-Demo-Video aus einer laufenden lokalen Web-App. Der Schnitt ist abgeleitet, nie manuell getaktet, sodass du bei Änderungen am Frontend neu aufnimmst und der Schnitt folgt – keine Frame-Nummern, die repariert werden müssen.
Entwickelt für den Fall, der tatsächlich eintritt: Die UI ist noch in Bewegung, während du das Video brauchst.
Verwendung
/pitch-deck-video # Filme die App im aktuellen Verzeichnis
/pitch-deck-video <Pfad-zur-App> # Filme eine bestimmte App
/pitch-deck-video --rebuild # Neu aufnehmen und schneiden eines bestehenden Videoprojekts
/pitch-deck-video --script # Nur die Erzählung geändert; Letzte Aufnahme wiederverwenden
/pitch-deck-video --render # Nur Karten/Beschriftungen geändert; Neu rendern
Der Aufbau
Vier generierte Dateien steuern alles. Nur die erste wird von einem Menschen geschrieben.
| Datei | Enthält | Geschrieben von |
|---|---|---|
shots.json | Was gesagt wird, die Stimme, die Musik, das Thema und was der Browser tut | Dir |
src/vo-durations.json | Wie lange jede Zeile tatsächlich dauert | scripts/tts.mjs |
capture/marks.json | Wann jeder Shot im Take begann und wo hingesehen werden soll | scripts/record.mjs |
src/frames.json | Wie viele Frames aus dem Take kamen | scripts/frames.mjs |
src/timeline.ts leitet den gesamten Schnitt daraus ab. Szenenlängen stammen aus der gemessenen Erzähl-Audio. Das Filmmaterial wird passend gedehnt. Kamerabewegungen stammen aus Element-Bounding-Boxen, die live während der Aufnahme gemessen werden, sodass ein verschobener Button den Shot verschiebt, anstatt ihn zu brechen.
Workflow
1 · Gerüst
Kopiere template/ aus diesem Skill in <App-Name>-video/ neben die App, dann npm install. Die Vorlage enthält Seed-JSON, sodass sie vor der ersten Aufnahme typgeprüft und gerendert wird.
Bearbeite niemals Dateien unter ~/.claude/skills/pitch-deck-video/template/ für ein einzelnes Projekt – das ist die gemeinsame Vorlage. Bearbeite die Kopie.
2 · Zuerst nach einem gespeicherten Login suchen
Wenn die App eine Authentifizierung hat, suche nach einem Playwright-Speicherzustand, den das Repository bereits für seine eigenen E2E-Tests bereithält (.auth/*.json, storageState, playwright/.auth/). Weise app.storageState darauf, und die Aufnahme startet eingeloggt ohne Login-Ablauf vor der Kamera. Baue nur dann einen Login-Shot, wenn es keine solche Datei gibt – und verwende dann {"type": {"sel": "…", "env": "DEMO_PASSWORD"}}, damit das Passwort niemals in shots.json geschrieben wird.
3 · Lerne die App kennen, bevor du ein Wort schreibst
Starte den Dev-Server der App und mache Screenshots von jeder Route bei 1920×1080, lies dann die Bilder. Schreibe keine Erzählung aus dem Quellcode. Du schreibst darüber, was ein Juror sehen wird, und nur die Screenshots sagen dir das.
// Einmal-Skript; Playwright wird mit der Vorlage mitgeliefert
for (const r of routes) {
await p.goto(base + r, { waitUntil: 'networkidle' });
await p.waitForTimeout(700);
await p.screenshot({ path: `/tmp/shots/${r}.png` });
console.log(r, await p.evaluate(() => document.documentElement.scrollHeight));
}
Notiere die Scrollhöhen: Alles über 1080 benötigt eine scroll-Aktion, sonst erscheint es nie vor der Kamera.
4 · Schreibe shots.json
Beginne mit template/shots.example.json. Siehe references/shots-reference.md für jedes Feld und jede Aktion.
Übernimm die theme.colors aus den eigenen Design-Tokens der App, damit die Karten und das Filmmaterial wie aus einem Guss wirken. Fülle cards.arch.nodes mit der tatsächlichen Architektur – welche Boxen sind Modellaufrufe und welche deterministischer Code. Dieser Punkt unterscheidet eine Demo von einem Wrapper, und Juroren achten darauf.
Wichtige Regeln für die Erzählung:
- 12–16 Beats, 1:30–1:50 insgesamt. Unter einem 2:00-Limit, lasse 10 Sekunden Puffer.
- Eine Idee pro Beat. Der Beat endet, wenn die Idee endet.
- Nenne die Zahl. „Sechs Personen haben Punkte erzielt, Priya gewinnt“ schlägt „es wählt jemanden aus.“
- Erzähle nie die UI. Nicht „hier klicken wir auf Genehmigen“ – sag, was es bedeutet.
- Beginne mit dem Problem in den Worten des Benutzers, bevor der Produktname existiert.
- Beende mit einem Satz, der auf dem Bildschirm bleiben soll.
5 · Bauen
APP_DIR=/pfad/zur/app npm run all
Erzählung → Aufnahme → Frames → Rendern. Es startet den Dev-Server, wenn nichts unter app.url bereitgestellt wird, und liest das eigene dev-Skript der App, um herauszufinden, wie dieses Framework einen Port verwendet. Setze app.devCommand, falls etwas Spezifisches benötigt wird. Typische vollständige Neuerstellung: ~2 Minuten.
shots.json wird zuerst validiert, sodass eine doppelte ID oder eine unbekannte Aktion in zwei Sekunden fehlschlägt, anstatt zwei Minuten später ein verwirrendes Video zu produzieren.
6 · Qualitätssicherung durch Anschauen – das ist nicht optional
npm run qa # Ein Standbild pro Shot, zu Kontaktbögen zusammengefügt
npm run qa 3 # Drei pro Shot, wenn du einen Übergang überprüfen möchtest
Dann lies die Bögen als Bilder. Das Durchspulen des Videos ist langsam, und du wirst Dinge übersehen; ein Kontaktbogen dauert Sekunden und erfasst genau die Fehler, die zählen.
Prüfe: capture/marks.json → warnings ist leer (ein fehlender Selektor ist eine Warnung, kein Absturz – du erhältst trotzdem ein Video und eine Liste dessen, was kaputt ist). Dann: Trifft jede Beschriftung auf einen Frame, der sie unterstützt? Gibt es leere oder weiße Frames? Ist kleiner Text lesbar, oder benötigt er einen focus?
references/troubleshooting.md enthält jeden Fehler, den diese Pipeline tatsächlich getroffen hat, und die Lösung dafür. Lies es, bevor du von Grund auf debuggen beginnst.
Nach UI-Änderungen neu schneiden
Das ist der Sinn der Sache.
APP_DIR=/pfad/zur/app npm run all
Die meisten Änderungen benötigen nichts weiter – verschobene Elemente, neu gestaltete Seiten, neuer Inhalt. Was dennoch ein Urteil erfordert:
- Eine Seite wurde gelöscht oder umbenannt → Zeige auf diesen Shot neu oder ersetze ihn.
- Eine Funktion wurde umgeschrieben → Die Erzählung für diesen Beat ist jetzt eine Behauptung über etwas, das nicht mehr existiert. Schreibe die Zeile neu.
- Ein Selektor ist wirklich verschwunden → Überprüfe die Warnungsliste und behebe es dort.
Die Erzählung wird pro Zeile zwischengespeichert, sodass nur bearbeitete Zeilen neu synthetisiert werden.
Stimme
Die Stimme ist der größte Qualitätsunterschied im fertigen Video, und der Fallback ist wirklich schlecht. Sage das deutlich vor dem ersten Build, nicht danach.
tts.provider: "minimax"– gut. Frage den Benutzer, wo sein MiniMax-Schlüssel lebt, und weisetts.envFileauf diese Datei. Stimmen-IDs stammen aus der Systemstimmenliste von MiniMax; das Sprach-Tag einer Stimme ist ein Hinweis, keine Einschränkung (eine ukrainisch getaggte Stimme liest Englisch gut mitlanguageBoost: "English").tts.provider: "say"– der eingebaute Synthesizer von macOS, und normalerweise sind nur die Legacy-Stimmen installiert. Er ist roboterhaft, spricht Produktnamen falsch aus und ist für jeden Zuschauer offensichtlich. Für Timing-Prüfungen nutzbar, schwach für alles, was ein Juror oder Kunde sehen wird.- Eine menschliche Aufnahme schlägt beide. Lege
<id>.wav-Dateien inpublic/vo/ab und führenpm run scriptaus; die Dauern werden neu gemessen und das gesamte Video taktet sich ohne weitere Bearbeitung neu.
Wenn es keinen Schlüssel gibt, baue das Video trotzdem – aber sage dem Benutzer gleich zu Beginn, dass die Stimme der schwache Teil ist und dass entweder ein Schlüssel oder zehn Minuten mit einem Mikrofon das Problem beheben. Versende nicht stillschweigend ein say-Voiceover, als ob es fertig wäre.
MiniMax fällt pro Zeile auf say zurück, wenn die API nicht erreichbar ist, sodass ein Lauf niemals vollständig fehlschlägt.
Kopiere niemals einen API-Schlüssel in das Projekt. scripts/tts.mjs liest MINIMAX_API_KEY / MINIMAX_GROUP_ID aus der Umgebung und parst sie ansonsten aus der Datei, die tts.envFile angibt. Frage den Benutzer, wo sein Schlüssel lebt, und weise envFile darauf.
Eine menschliche Aufnahme schlägt jeden Synthesizer: Lege <id>.wav-Dateien in public/vo/ ab und führe npm run script aus – es misst sie neu und taktet das gesamte Video neu.
Musik
scripts/music.mjs ruft den in music.url genannten Track mit yt-dlp ab und schneidet einen Hintergrund auf die aktuelle Videolänge. Sage dem Benutzer, die Lizenz des Tracks vor der Veröffentlichung zu überprüfen – Bibliothekstracks sind normalerweise kostenlos mit Namensnennung in der Beschreibung und kostenpflichtig ohne. Titel und URL werden in public/music/SOURCE.txt gespeichert, damit die Quellenangabe leicht zu kopieren ist.
Verbote
- Keine manuellen Timing-Anpassungen. Wenn ein Beat gehetzt wirkt, ist die Erzählung zu lang für den Shot – korrigiere
shots.json, nicht die Timeline. - Setze
<Screen />nicht innerhalb eines<Sequence>. Es liest standardmäßig absolute Zeit;useCurrentFrame()innerhalb einer Sequence gibt Sequence-lokale Frames zurück. Dies hat das Video bereits beschädigt, und das Symptom (Filmmaterial subtil aus dem Takt mit der Stimme) ist schwer zu erkennen. - Lass keine Einrichtungszeit vor der Kamera erscheinen. Navigation, Daten laden und das Schließen eines Banners finden alle innerhalb des Aufnahmefensters des Shots statt und werden unter der Erzählung gestreckt. Setze
{"cut": true}nach den Einrichtungsschritten; das Filmmaterial beginnt dann von dort. - Nimm nichts auf, das nur ein Platzhalter ist. Wenn ein Button „Verbinde das Backend“ zurückgibt, lass es weg und sage dem Benutzer, welchen Shot hinzugefügt werden muss, wenn es fertig ist.
- Versende nicht ohne die Warnungsliste zu überprüfen.
- Erzähle keine Zahl, die du zwischen Läufen schwanken siehst, und beschreibe niemals einen Bildschirm als voll, wenn die Version dieses Kontos leer ist. Ein Juror, der eine falsche Behauptung entdeckt, zieht den Rest in Zweifel.