Remotion (Programmatisches Video)
Remotion rendert React-Komponenten Frame für Frame. Jeder Frame ist eine reine Funktion der Frame-Nummer, daher ist die Animation deterministisch und erneut renderbar.
Die API von Remotion ändert sich zwischen Hauptversionen. Lies die installierte Version (
npm ls remotion) und die offizielle Dokumentation auf remotion.dev, bevor du eine API verwendest, bei der du unsicher bist. Prüfe die Lizenzbedingungen von Remotion für die kommerzielle Nutzung durch Unternehmen.
Einrichtung
npx create-video@latest # das leere Template auswählen (TypeScript)
cd my-video && npm install
npx remotion studio # Live-Vorschau
npx remotion render MyComp out/video.mp4
npx remotion still MyComp out/thumb.png --frame=45
Das mentale Modell
useCurrentFrame()liefert den aktuellen Frame, beginnend bei 0.useVideoConfig()liefertfps,width,height,durationInFrames.- Nichts animiert sich von selbst. Du berechnest den Stil aus dem Frame.
- Verwende niemals CSS-Transitions,
setTimeout,Math.random()oderDate.now()für Animationen. Sie zerstören die Render-Determiniertheit. Verwende stattdessenrandom('seed')von Remotion.
Komposition
// src/Root.tsx
import {Composition} from 'remotion';
import {Explainer} from './Explainer';
export const RemotionRoot = () => (
<Composition
id="Explainer"
component={Explainer}
durationInFrames={30 * 20} // 20 s bei 30 fps
fps={30}
width={1920}
height={1080}
defaultProps={{title: 'Hallo'}}
/>
);
Animationsprimitive
import {AbsoluteFill, Sequence, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';
export const Title: React.FC<{text: string}> = ({text}) => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const opacity = interpolate(frame, [0, 15], [0, 1], {extrapolateRight: 'clamp'});
const scale = spring({frame, fps, config: {damping: 200}}); // weich, kein Prellen
return (
<AbsoluteFill style={{justifyContent: 'center', alignItems: 'center'}}>
<h1 style={{opacity, transform: `scale(${0.9 + 0.1 * scale})`, fontSize: 96}}>{text}</h1>
</AbsoluteFill>
);
};
export const Explainer = () => (
<AbsoluteFill style={{backgroundColor: '#0b1020', color: 'white'}}>
<Sequence from={0} durationInFrames={90}><Title text="Einleitung" /></Sequence>
<Sequence from={90} durationInFrames={120}><Title text="Hauptpunkt" /></Sequence>
</AbsoluteFill>
);
Übergib extrapolateLeft/Right: 'clamp' immer an interpolate, es sei denn, du möchtest, dass Werte über den Bereich hinauslaufen.
Medien
import {staticFile, Audio, OffthreadVideo, Img} from 'remotion';
<Audio src={staticFile('voiceover.mp3')} />
<Audio src={staticFile('music.mp3')} volume={0.12} />
<OffthreadVideo src={staticFile('demo.mp4')} />
<Img src={staticFile('logo.png')} />
Lege Assets in public/ ab und referenziere sie mit staticFile(). Verwende <Img> anstelle von <img>, damit das Rendering auf das Bild wartet. Neuere Remotion-Versionen bieten aktualisierte Medienkomponenten; überprüfe die Dokumentation für die installierte Version.
Szenen mit Sprachaufnahmen synchronisieren
Hartcodiere keine Szenenlängen. Leite sie aus dem Audio ab.
- Generiere sprachspezifische Voiceover-Dateien (
voiceover-tts-Skill). - Miss jede Dauer mit
ffprobeund schreibescenes.jsonmit{id, audio, seconds}. - In der Komposition konvertiere mit
Math.ceil((seconds + 0.5) * fps)und lege<Sequence>nach kumulativem Offset an. - Verwende
calculateMetadataauf der<Composition>, um die gesamtedurationInFramesaus diesen Daten zu setzen.
Wenn die Stimme neu aufgenommen wird, passt sich das Video automatisch an.
Übergänge
Installiere @remotion/transitions und verwende TransitionSeries mit fade(), slide(), wipe(). Ein Übergang überlappt zwei Szenen, sodass die Gesamtlänge um die Übergangsdauer verkürzt wird. Halte Übergänge zwischen 12 und 20 Frames bei 30 fps.
Schriftarten und Marke
Lade Schriftarten mit @remotion/google-fonts oder @remotion/fonts, damit sie vor dem ersten Frame bereit sind. Halte Farben, Schriftarten und Logo in einer brand.ts, sodass ein Rebranding eine Änderung in einer Datei ist.
Leistung und Rendering
- Vorschau im Studio; Rendern über die CLI.
--concurrency=50%begrenzt die CPU-Nutzung.--codec=h264ist Standard; verwende--codec=proresfür die Übergabe an die Bearbeitung.- Starke Unschärfe, Schatten und große SVG-Filter sind langsam. Bevorzuge vorgerenderte Assets für solche Effekte.
- Verwende
<OffthreadVideo>anstelle von<video>für Quellmaterial, um eine framegenaue Extraktion zu erhalten. - Für schnelle Entwürfe:
--scale=0.5und einen Bereich--frames=0-90.
Häufige Fehler
| Fehler | Lösung |
|---|---|
| Flimmern oder fehlendes Bild beim Rendern | Verwende <Img>, staticFile und delayRender für asynchrone Daten |
| Animation unterscheidet sich zwischen Vorschau und Render | Entferne nicht-deterministischen Code (Zeit, Zufall) |
| Text überläuft in anderen Gebietsschemata | Setze explizite Breiten; teste den längsten String |
| Video zu lang nach Hinzufügen von Übergängen | Ziehe Übergangs-Frames von der Gesamtzahl ab |
| Audio ist im Render stumm | Überprüfe den Dateipfad und dass das <Audio> innerhalb einer aktiven <Sequence> ist |
Kombiniere mit motion-design-craft für Timing- und Easing-Entscheidungen.