Remotion (Vidéo programmatique)
Remotion génère les composants React image par image. Chaque image est une fonction pure du numéro d'image, ce qui rend l'animation déterministe et re-renderisable.
L'API de Remotion change entre les versions majeures. Lisez la version installée (
npm ls remotion) et la documentation officielle sur remotion.dev avant d'utiliser une API dont vous n'êtes pas sûr. Vérifiez les conditions de licence de Remotion pour une utilisation commerciale par les entreprises.
Configuration
npx create-video@latest # choisissez le modèle vide (TypeScript)
cd my-video && npm install
npx remotion studio # prévisualisation en direct
npx remotion render MyComp out/video.mp4
npx remotion still MyComp out/thumb.png --frame=45
Le modèle mental
useCurrentFrame()donne l'image actuelle, en commençant à 0.useVideoConfig()donnefps,width,height,durationInFrames.- Rien ne s'anime tout seul. Vous calculez le style à partir du numéro d'image.
- N'utilisez jamais les transitions CSS,
setTimeout,Math.random()ouDate.now()pour l'animation. Ils brisent le déterminisme du rendu. Utilisez plutôtrandom('seed')de remotion.
Composition
// src/Root.tsx
import {Composition} from 'remotion';
import {Explainer} from './Explainer';
export const RemotionRoot = () => (
<Composition
id="Explainer"
component={Explainer}
durationInFrames={30 * 20} // 20 s à 30 ips
fps={30}
width={1920}
height={1080}
defaultProps={{title: 'Hello'}}
/>
);
Primitives d'animation
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}}); // fluide, sans rebond
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="Intro" /></Sequence>
<Sequence from={90} durationInFrames={120}><Title text="Point principal" /></Sequence>
</AbsoluteFill>
);
Passez toujours extrapolateLeft/Right: 'clamp' à interpolate sauf si vous souhaitez que les valeurs dépassent la plage.
Médias
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')} />
Placez les ressources dans public/ et référencez-les avec staticFile(). Utilisez <Img> plutôt que <img> pour que le rendu attende l'image. Les versions plus récentes de Remotion fournissent des composants média mis à jour ; consultez la documentation pour la version installée.
Synchroniser les scènes avec la narration
Ne codez pas en dur les longueurs de scènes. Dérivez-les de l'audio.
- Générez les fichiers audio de voix off par scène (compétence
voiceover-tts). - Mesurez chaque durée avec
ffprobeet écrivezscenes.jsonavec{id, audio, seconds}. - Dans la composition, convertissez avec
Math.ceil((seconds + 0.5) * fps)et disposez les<Sequence>en fonction du décalage cumulé. - Utilisez
calculateMetadatasur le<Composition>pour définir ledurationInFramestotal à partir de ces données.
Si la voix est réenregistrée, la vidéo se retemporise automatiquement.
Transitions
Installez @remotion/transitions et utilisez TransitionSeries avec fade(), slide(), wipe(). Une transition chevauche ses deux scènes, donc la longueur totale se réduit de la durée de la transition. Gardez les transitions entre 12 et 20 images à 30 ips.
Polices et marque
Chargez les polices avec @remotion/google-fonts ou @remotion/fonts pour qu'elles soient prêtes avant la première image. Conservez les couleurs, polices et logo dans un seul fichier brand.ts afin qu'un changement de marque soit une modification d'un seul fichier.
Performance et rendu
- Prévisualisez dans le studio ; effectuez le rendu depuis la ligne de commande.
--concurrency=50%limite l'utilisation du CPU.--codec=h264est par défaut ; utilisez--codec=prorespour un transfert vers un logiciel de montage.- Les flous, ombres et grands filtres SVG lourds sont lents. Privilégiez les ressources pré-rendues pour ceux-ci.
- Utilisez
<OffthreadVideo>plutôt que<video>pour les séquences sources afin d'obtenir une extraction précise à l'image. - Pour les brouillons rapides :
--scale=0.5et une plage--frames=0-90.
Erreurs courantes
| Erreur | Correction |
|---|---|
| Scintillement ou image manquante au rendu | Utilisez <Img>, staticFile, et delayRender pour les données asynchrones |
| L'animation diffère entre l'aperçu et le rendu | Supprimez le code non déterministe (time, random) |
| Le texte déborde sur différentes locales | Définissez des largeurs explicites ; testez la chaîne la plus longue |
| Vidéo trop longue après l'ajout de transitions | Soustrayez les images de transition du total |
| L'audio est silencieux dans le rendu | Vérifiez le chemin du fichier et que le <Audio> est à l'intérieur d'un <Sequence> actif |
Associez avec motion-design-craft pour les choix de timing et d'assouplissement.