Produktvideo in Remotion
Ein fassadenloses Produkt-Demo (Format 3 in short-video-formats), programmiert als Code. Die Stimme bestimmt das Timing: Jede Skriptzeile wird gesprochen, die Takes werden Ende an Ende gelegt, und die Videoszenen sowie Untertitel folgen diesen Zeitstempeln. Die UI wird in React aus den eigenen Stilen des Produkts nachgebaut, sodass sie bei jedem Zoom scharf ist und bei Änderungen des Produkts oder des Skripts neu gerendert wird. Alles außer dem gerenderten MP4 lebt in git, sodass jede alte Version nur ein Checkout und ein Render entfernt ist.
Eingaben: Node 22, ffmpeg, ein TTS (edge-tts für Entwürfe; eine lizenzierte Stimme vor Veröffentlichung), die CSS-Tokens
und das Markup des Produkts (ein Landing-Page-Produkt-Demo ist oft die beste Quelle) und das Skript.
Workflow
1. Einrichtung
npx create-video@latest --blank reel && cd reel && npm i @remotion/google-fonts
Erstelle eine theme.ts mit dem Frame (1080×1920, 30 fps), den Layout-Bändern und den Farb-Tokens des Produkts,
übernommen aus dessen CSS. Unsere Bänder: Titelstrip zentriert bei y=118, das weiße UI-Band von y=220 für 1250 Pixel (65 % der
Höhe, volle Breite), Untertitel zentriert bei y=1640.
2. Schreibe das Skript als Daten
script.json, ein Eintrag pro Untertitelzeile; *Sterne* markieren hervorgehobene Wörter:
{ "voice": { "name": "en-US-AndrewMultilingualNeural", "rate": "+10%" }, "gap": 0.16,
"lines": [
{ "scene": "wall", "text": "I stopped *prompting* Claude Code." },
{ "scene": "wall", "text": "I *hired* it.", "pause": 0.5 },
{ "scene": "end", "text": "Hire your first *AI employee*.", "say": "Crewmark. Hire your first AI employee." }
],
"post": { "tiktok": { "caption": "…", "hashtags": [] }, "instagram": { "caption": "…", "hashtags": [] } } }
say wird verwendet, wenn die Stimme sich vom Untertitel unterscheidet; pause hält eine Szene nach einer Zeile länger.
3. Stimme → Timeline
Ein kleines Node-Skript spricht jede Zeile in eine eigene WAV-Datei, entfernt die Stille, legt sie mit gap/pause
Ende an Ende, mischt sie in public/voice.wav (adelay + amix, dann loudnorm=I=-14 für soziale Lautstärke),
und schreibt public/timeline.json mit den from/to-Werten jeder Zeile in Frames:
{ "durationInFrames": 959, "lines": [ { "scene": "wall", "text": "I stopped *prompting* Claude Code.", "from": 12, "to": 51 } ] }
Zwischenspeichere jeden Take nach Text und Stimme, sodass die Bearbeitung einer Zeile nicht den Rest neu spricht. Die durationInFrames
der Komposition stammt aus dieser Datei.
4. Szenen folgen der Timeline
Gruppiere aufeinanderfolgende Zeilen mit derselben scene in eine <Sequence>; gib jeder Szene ihre Zeilen-Offsets („Beats“), sodass
Animationen auf den Wörtern landen. Untertitel sind eine Komponente, die die aktuelle Zeile liest.
Der Schlüssel ist eine Kamera über dem UI-Band: Lege die UI in echten CSS-Pixeln aus, skaliere und verschiebe sie dann.
export function Cam({ zoom, x = 0, y = 0, children }: { zoom: number; x?: number; y?: number; children: React.ReactNode }) {
return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", background: "#fff" }}>
<div style={{ position: "absolute", width: 1080 / zoom + x, height: STAGE_H / zoom + y,
transform: `scale(${zoom}) translate(${-x}px, ${-y}px)`, transformOrigin: "0 0" }}>{children}</div>
</div>
);
}
Bei zoom = 1080 / 520 füllt ein 520 Pixel breites Layout (zwei 248-Pixel-Karten) die Breite exakt aus. Animiere zoom, x und
y mit weicher Interpolation zwischen den Beats, um auf den Button zu zoomen, der angeklickt wird.
Szenen-Ideen, die gut lesbar sind: ein Marktplatz mit Karten, ein Formular, das sich selbst ausfüllt (getippter Text mit einem Cursor), ein Board, in dem sich eine Karte zwischen Spalten bewegt, ein Aktivitätsthread, ein Diagramm, das sich selbst zeichnet (beschriftet mit „Beispieldaten“), ein Chat, in dem der Agent fragt und du zustimmst, eine Endkarte im Stil des Landing-Helden.
5. Rendern und ansehen
node voice.mjs && npx tsc --noEmit
npx remotion still src/index.ts Reel /tmp/f0.png --frame=0 # das Cover
npx remotion render src/index.ts Reel out/reel.mp4
ffmpeg -v error -y -i out/reel.mp4 -vf fps=1,scale=200:-1,tile=8x5 -frames:v 1 out/sheet.jpg
Betrachte das Kontaktblatt und einen Standframe jeder Szene: das UI-Band vollständig, nichts am unteren Rand des Bandes abgeschnitten, Untertitel innerhalb des unteren Streifens, die richtige Szene unter jeder Zeile, Frame 0 nicht leer.
6. Versionieren
Comitte die Quelle, das Skript und voice.wav/timeline.json; behalte out/ und Downloads in .gitignore. Um
einen alten Schnitt zurückzuholen, checke den Commit aus und rendere erneut.
Checkliste
- Farben, Schriftarten und Text aus dem eigenen CSS und Text des Produkts übernommen
- UI-Band ≥ 50 % der Höhe, volle Breite; Streifen nur oben und unten
- Frame 0 gerendert und als Cover geprüft
- Jede Szene zeigt eine Funktion, die das Produkt wirklich hat
- Demo-Zahlen beschriftet
- Kontaktblatt nach jedem Render überprüft
- Quelle und Stimme committet; MP4 nicht
Fallstricke, die wir getroffen haben
- Einblendung in der ersten Szene ließ Frame 0, das Cover, leer. Überspringe die Eingangsanimation für die erste Szene.
- Inhalt durch die Kamera abgeschnitten. Ein Diagramm, das für eine Zoomstufe ausgelegt war, ragte am Ende der Szene unter das Band hinaus. Überprüfe einen Standframe am Ende jeder Kamerafahrt, nicht nur am Anfang.
- Spärliche untere Hälften. Bei geringem Zoom ließen kurze Szenen den unteren Teil des weißen Bandes leer. Zoome weiter hinein oder verankere etwas am unteren Rand (eine Nachrichteneingabe, eine Fußzeile), damit das Band wie ein echter Bildschirm aussieht.
- Ein Rezensionsskript, das eine .srt benötigte. Unser altes ffmpeg-Pipeline-Review-Tool las Untertitel-Timings, die
Remotion nicht schreibt. Ein Kontaktblatt mit
fps=1,tileerfüllt denselben Zweck. - Doppeltes
transformin einem Style-Objekt (eine Drück-Animation plus eine Eingangsanimation) besteht die Typprüfung nicht. Wickle das Element ein und lege eine Transformation auf jede Ebene. - Edge TTS für den finalen Schnitt. Es ist kostenlos und für Entwürfe in Ordnung, aber roboterhaft neben allem, was menschlich aussieht, und es kommt ohne kommerzielle Lizenz. Tausche die TTS-Funktion vor der Veröffentlichung im großen Stil aus.
Verwandte Fähigkeiten
- short-video-formats: Layoutregeln und welches Format erstellt werden soll.
- social-publish: Der in
script.jsongespeicherte Beitragstext. - video-retro: Was im nächsten Render geändert werden soll.