Aufnahme von Demo-Videos (kostenlos, skriptgesteuert)
Erstellen Sie stille Produkt-Demo-Videos der echten App, indem Sie einen Browser steuern und dann ein MP4 rendern. Kostenlos und lokal: Playwright steuert die App, ffmpeg erstellt das Video. Keine kostenpflichtige SaaS, kein Voice-Over, kein manuelles Klicken. Dasselbe Skript dient gleichzeitig als UX-Smoke-Test und wird bei UI-Änderungen neu gerendert – genau das macht es zum nachhaltigen Weg, um viele Feature-Demos zu erstellen.
Wann verwenden
- Der Benutzer möchte ein oder mehrere Feature-Demo-/Walkthrough-Videos und möchte nicht für ein Tool bezahlen.
- Das wiederkehrende Problem „Jemand muss bei jeder neuen Funktion den Bildschirm aufnehmen“.
- Schneller visueller Nachweis, dass eine Funktion Ende-zu-Ende in der echten UI funktioniert.
Nicht geeignet für: stark animierte Marketingvideos mit Voice-Over (echten Editor verwenden) oder alles, was menschliche Reaktionen vor der Kamera erfordert.
Der Aufbau
Login-Sitzung erstellen → App mit Playwright steuern (zeichnet .webm auf) → ffmpeg → .mp4
Drei Dateien landen im Ziel-Repository unter demo/ (Kopie aus resources/):
record.mjs– die Engine. Ein CONFIG-Block (repository-spezifisch) + eine FLOWS-Map (ein Eintrag pro Video).polish.sh–.webm→.mp4, trimmt den Login-Vorspann, optional eingebrannte Untertitel.run.sh– ein Befehl: Dev auf Staging ausrichten, aufzeichnen, nachbearbeiten, aufräumen.README.md– Nutzung pro Repository.
Um ein neues Video zu erstellen: Einen FLOWS-Eintrag kopieren, url + steps ändern. Das ist die gesamte Schleife.
Setup-Checkliste (einmal pro Repository durchführen)
- Werkzeuge installieren (einmalig):
npm install -D @playwright/test && npx playwright install chromium.ffmpeg(Homebrew) erforderlich. Für eingebrannte Untertitel wird ein ffmpeg benötigt, das mitlibfreetypekompiliert wurde; andernfalls werden Untertitel automatisch übersprungen und alles andere funktioniert. - Repository-Spezifika ermitteln und den CONFIG-Block in
record.mjsausfüllen:- Dev-Befehl – wie die App lokal läuft (
npm run dev, oft in einem Unterverzeichnis wiecongrats/). - Supabase-Client-Modulpfad – normalerweise
src/integrations/supabase/client.ts. Der Recorder importiert es in die Seite, um sich anzumelden (siehe Gotcha 1). - Welche DB für die Aufzeichnung – Staging verwenden, niemals Produktion (keine echten Benutzerdaten). Finden Sie deren URL + anonymen/öffentlichen Schlüssel + Service-Key + eine direkte DB-URL. In dieser Organisation befinden sie sich im Audition-Repository unter
.env.local(VETTED_SUPABASE_*für VettedAI-Staging,STAGING_CONGRATS_SUPABASE_*für Congrats-Staging). - Eine Login-E-Mail – ein synthetisches/Testkonto, das Demo-fähige Daten besitzt. Den Benutzer immer fragen, welches Konto verwendet werden soll, bevor eine Sitzung erstellt wird (Projektregel: keine Tests mit echten Benutzern ohne Erlaubnis).
- Routen – die Deep-Link-Pfade für die Flows, die Sie aufzeichnen werden.
- Dev-Befehl – wie die App lokal läuft (
- Lokalen Dev-Server auf Staging ausrichten (siehe Gotcha 2).
- Einen Flow erstellen,
bash demo/run.sh <flow>ausführen, durch Extrahieren von Frames überprüfen (Gotcha 8).
Gotchas (die hart erarbeiteten – vor dem Debuggen lesen)
1. Über den EIGENEN Client der App anmelden, nicht durch Fälschen von localStorage
Supabase-js schreibt seine Sitzung unter einem nicht standardmäßigen Schlüssel/Envelope im Browser; das manuelle Einfügen von
localStorage['sb-<ref>-auth-token'] = JSON.stringify(session) sieht richtig aus, aber der Client liest es nicht →
die App springt zu /login. Stattdessen: Eine Sitzung serverseitig erstellen (Admin generateLink → verifyOtp gibt
access_token+refresh_token, kein Passwort nötig), dann in der Seite den Supabase-Client der App importieren
und supabase.auth.setSession({access_token, refresh_token}) aufrufen. Es schreibt den korrekten Speicher und die
Sitzung überlebt Navigationen. Dies ist der mit Abstand wichtigste Schritt.
2. --mode staging kann still ignoriert werden → .env.development.local verwenden
vite-react-ssg dev (und einige Setups) ignorieren --mode für das Laden von Umgebungsdateien, daher wird .env.staging nie geladen und
die App bleibt auf die Produktion ausgerichtet (Sie sehen Anfragen an den Produktions-Supabase-Host). Vite lädt immer automatisch
.env.development.local im Dev-Modus mit höherer Priorität als .env/.env.local. Daher kopiert run.sh Ihre Staging-Konfiguration
in .env.development.local für die Aufzeichnung und löscht sie beim Beenden (andernfalls ist jedes zukünftige
npm run dev still auf Staging – ein echtes Sicherheitsrisiko). Reine vite-Repositories können --mode beachten; testen Sie dies, indem Sie
beobachten, welchen Supabase-Host die App aufruft.
3. Staging-Schema kann hinter dem Frontend zurückbleiben → gezielte additive Angleichung
Ein Staging-Branch kann neuere Spalten vermissen, die das Frontend auswählt → die Datenabfrage 400t
(Spalte X existiert nicht) und der Bildschirm wird leer gerendert. Keine Migrationen wiederholen. Die Spalten der
wenigen Tabellen, die der Bildschirm liest, abgleichen (Staging vs. Produktion über information_schema.columns), und nur die fehlenden als
additive, nullable ALTER TABLE ... ADD COLUMN IF NOT EXISTS anwenden. Die Zustimmung des Benutzers einholen – es ist eine Staging-DB-Änderung.
4. Seed-Daten können im falschen Maßstab sein
Synthetische Seed-Scores/Werte stimmen möglicherweise nicht mit dem Formatierer der UI überein (z. B. Scores, die als 0–100 gespeichert werden, während die UI
value/5*100 verwendet → „1392%“). Den erwarteten Bereich des Formatierers mit den realen Werten der Produktion vergleichen; die
Seed-Daten bei Bedarf neu skalieren (vorher fragen – es ist eine Datenmutation).
5. Playwright-Videos zeigen den Mauscursor nicht
Einen gefälschten Cursor-Overlay per addInitScript einfügen (einen Punkt, der mousemove folgt + bei mousedown wächst).
Die Vorlage macht dies bereits. Die Maus vor dem Klicken zu den echten Koordinaten bewegen, damit sie nachverfolgt wird.
6. ffmpeg fehlt möglicherweise drawtext
Builds ohne libfreetype führen bei eingebrannten Untertiteln zu Fehlern. polish.sh erkennt drawtext und überspringt die Untertitel, falls
sie fehlen – zulassen, dass ein Untertitelfehler das MP4 blockiert.
7. Automatisches Trimmen des Login/Start-Vorspanns
Die Aufzeichnung erfasst den Login + App-Start (tote Sekunden). record.mjs misst den Vorspann und schreibt einen
.trim-Sidecar; polish.sh schneidet ihn (ffmpeg -ss).
8. Überprüfung durch Frames, niemals durch „es wurde aufgezeichnet“
ffmpeg -ss <t> -i out.mp4 -frames:v 1 frame.png zu einigen Zeitstempeln ausführen und tatsächlich ansehen. Die ersten Läufe
landen auf /login, einem Skelett oder dem falschen Tab – Frames zeigen dies.
9. Daten- und Authentifizierungssicherheit
Auf Staging mit synthetischen Daten aufzeichnen (z. B. seed_…@test.vetted.com), niemals mit einem echten Kundenprojekt
(PII). Immer den Benutzer fragen, mit welchem Konto er sich anmelden soll. Das Erstellen einer Authentifizierungssitzung ist eine echte Aktion – zuerst bestätigen.
Erstellen eines Flows
In record.mjs ist FLOWS eine Map mit { label, url, steps(page, ui) }. Die ui-Helfer decken die meisten Anforderungen ab:
ui.settle(was, [wörter])– auf Inhalt warten (networkidle + ein Wort, das das Laden des Bildschirms beweist)ui.scrollThrough(fraktion, schritte)– sanftes Scrollen nach unten und zurückui.clickFirstCandidate()/ verallgemeinern zuui.clickFirst(selektoren)– Best-Effort-Klick, niemals harter Fehlschlagui.beat(ms)– eine bewusste Pause, damit das Video gut lesbar ist
Flows selektorarm und Best-Effort halten (try/catch bei Klicks), damit ein fehlender Selektor zu „immer noch ein gutes Scroll-Demo“ anstatt zu einem Absturz führt. Großzügig takten (800–1800ms Beats); ein gutes stilles Demo ist 15–35s lang.
Ausgabe + Übergabe
mp4 landet in demo/output/ (gitignore es). open demo/output/<flow>.mp4 zum Abspielen (ein relativer Markdown-Link
wird in einer IDE nicht abgespielt – er öffnet die Datei im Editor). Den Pfad teilen oder open für den Benutzer ausführen.
Verbreitung dieser Fähigkeit (sie lebt in skill-master)
Diese Fähigkeit ist kanonisch in submodules/skill-master/.agent/skills/recording-demo-videos/ und wird in jedes
Repository unter .agent/skills/ symlinkiert. Nach der Bearbeitung zuerst das Submodule committen + pushen, dann den Parent-Repo-Zeiger,
und /distribute-skill ausführen, um es auf die Schwester-Repositories zu übertragen (vor dem Pushen den Benutzer fragen). Siehe
skill-master-submodule-sync-Regel.