Que fait Remotion Motion Graphics — Vidéo 2D basée sur les images ?
Remotion rend React en vidéo. Chaque image est une fonction pure de l'index d'image, donc la sortie est déterministe, différentiable et vérifiable. C'est le meilleur choix par défaut pour les vidéos axées sur le texte et les données, et le meilleur « compositeur » pour assembler des passes Blender ou Manim avec typographie, légendes et transitions.
Lisez references/REMOTION-PLAYBOOK.md pour les conventions et references/REMOTION-RECIPES.md pour des composants prêts à copier. Consultez la documentation officielle et la CLI installée pour l'API actuelle : https://www.remotion.dev/docs/
1. Configuration
node --version # 18+ requis, 20/22 LTS recommandé
npx create-video@latest my-video # choisir le modèle vierge
cd my-video
npx skills add remotion-dev/skills # compétences officielles de l'agent Remotion (recommandé)
npm run dev # Remotion Studio sur http://localhost:3000
Rendu :
npx remotion render <entry> <CompositionId> out/video.mp4 --codec=h264
npx remotion render <entry> <CompositionId> out/preview.mp4 --scale=0.5
npx remotion render <entry> <CompositionId> out/frames --sequence --image-format=png
Les indicateurs exacts varient selon la version ; confirmez avec npx remotion render --help.
Licence : Remotion est disponible sous forme de code source, mais pas sous licence open source OSI. Gratuit pour les particuliers et les petites organisations éligibles selon ses conditions actuelles ; les utilisations commerciales importantes ou automatisées peuvent nécessiter une licence payante. Consultez https://www.remotion.dev/docs/license/pricing pour le cas réel de l'utilisateur avant de promettre un livrable. Ne le décrivez pas comme « MIT » ou « gratuit pour toute entreprise ».
2. Structure du projet
Adaptez-vous au modèle de démarrage plutôt que de le combattre :
src/
Root.tsx # enregistre les compositions
compositions/
MainVideo.tsx # séquence les scènes ensemble
scenes/
Intro.tsx Feature.tsx Outro.tsx
components/
AnimatedTitle.tsx Background.tsx Grid.tsx Caption.tsx Transition.tsx
animations/
easing.ts timing.ts reveal.ts
data/
content.ts # copie et chiffres, séparés de la mise en page
styles/
tokens.ts # palette, échelle typographique, espacement
public/
audio/ fonts/ images/ video/
Règles :
- Une scène par fichier ;
MainVideone fait que les séquencer. - La copie et les données vivent dans
data/, jamais en ligne dans cinq scènes. - Les jetons de design dans
styles/tokens.ts; pas de valeurs hexadécimales magiques éparpillées. - Primitives réutilisables dans
components/, jamais dupliquées par scène. staticFile("...")pour tout ce qui se trouve souspublic/.
3. Déterminisme (la règle absolue)
Tout l'état visuel dérive de l'image courante :
import { useCurrentFrame, useVideoConfig, interpolate, spring } from "remotion";
const frame = useCurrentFrame();
const { fps, durationInFrames, width, height } = useVideoConfig();
Interdits comme moteurs d'animation : Date.now(), setTimeout, setInterval, requestAnimationFrame, les images clés CSS, Math.random() non ensemencé, les données asynchrones qui changent entre les rendus.
Aléatoire ensemencé quand la variation est souhaitée :
export const rand = (seed: number) => {
const x = Math.sin(seed * 12.9898) * 43758.5453;
return x - Math.floor(x);
};
Les ressources asynchrones doivent être résolues avant le rendu de l'image. Utilisez delayRender/continueRender correctement, en continuant toujours dans un catch, ou préchargez les ressources en dehors de l'image (recommandé).
4. Timing
durationInFramesest explicite. À 30 FPS, 10 s = 300 images, indices 0–299.- Convertissez une fois :
const s = (n: number) => Math.round(n * fps). - Les limites des scènes proviennent d'une chronologie cumulative, jamais d'arrondis par scène.
- Utilisez
<Sequence from={start} durationInFrames={len}>; vérifiez qu'aucun élément ne dépasse la composition. - Rendez les chevauchements intentionnels ; un écart d'une image est un flash visible.
- Utilisez
calculateMetadatalorsque la durée ou les dimensions proviennent des props.
5. Artisanat de l'animation
| Mouvement | Primitive |
|---|---|
| Entrée/Stabilisation | spring ou interpolate avec Easing.out(Easing.cubic) |
| Sortie | Easing.in(Easing.cubic) |
| Mouvement symétrique | Easing.inOut(Easing.cubic) |
| Mécanique/Continue | Easing.linear |
| Nombre/Couleur/Rotation | interpolate avec extrapolation clampée |
| Stagger | décaler from par élément (30–80 ms) |
const enter = spring({ frame, fps, config: { damping: 18, stiffness: 120, mass: 0.8 } });
const opacity = interpolate(frame, [0, 12], [0, 1], {
extrapolateLeft: "clamp", extrapolateRight: "clamp",
});
N'utilisez pas spring partout. N'animez pas chaque propriété. Préférez les transformations et l'opacité (GPU-friendly) aux propriétés de mise en page. Assurez-vous d'au moins ~0,8–1,2 s de temps de maintien pour un titre court, plus pour le corps du texte.
6. Typographie et design
- Définissez une échelle typographique (par exemple 96/64/40/28/20 px à 1080p) et utilisez-la partout.
- Chargez les polices depuis
public/fontsavec@remotion/fontsou le modèle documenté du starter, et attendez qu'elles soient prêtes avant le rendu. Évitez de dépendre des polices système. - Vérifiez la longueur des lignes (≈45–75 caractères), l'interlignage (1,1–1,4 pour les polices d'affichage) et le crénage.
- Gardez des marges de sécurité de 5–8 % ; vérifiez les superpositions UI de la plateforme pour les formats verticaux/sociaux.
- Pour le persan/arabe : corrigez
dir="rtl", police compatible avec la mise en forme, vérifiez les chiffres/URL mixtes, et inspectez l'image rendue — Chrome sans tête façonne le texte différemment de certains outils de conception. - Vérifiez la copie finale caractère par caractère. Les fautes de frappe dans une vidéo sont des bugs de livraison.
7. Composition et transitions
- Un point focal par temps ; animez l'œil, pas tout l'écran.
- Utilisez un vocabulaire de transition : coupe, fondu enchaîné de 6 à 10 images, masque de transition, passage par échelle, passage par flou. Réutilisez délibérément.
- Préférez couper sur un temps fort plutôt que de tout dissoudre.
- Pour les longues vidéos, construisez d'abord un tableau de timing (secondes → images → scène) et codez-le dans un seul fichier.
8. Audio et sous-titres
import { Audio, staticFile } from "remotion";
<Audio src={staticFile("audio/music.mp3")} volume={0.6} />
- Importez uniquement dans une séquence qui commence là où le son doit commencer.
- Faites un fondu entrée/sortie avec
interpolatesurvolume; évitez les clics. - Réduisez la musique sous la voix off ; gardez le dialogue intelligible.
- Sous-titres : incrustez avec
<Caption>pour les réseaux sociaux, ou exportez.srtpour les plateformes. Respectez les zones de sécurité et la vitesse de lecture (~15–20 car./s). - Vérifiez le mixage sur le fichier encodé, pas seulement sur l'aperçu.
9. Performances
- Réduisez la concurrence sur les machines à mémoire limitée :
--concurrency=4. - Évitez les gros flous, les chaînes de filtres, les énormes SVG et des milliers de nœuds DOM ; utilisez Canvas pour les graphiques denses.
- Mettez en cache les arrière-plans statiques (
<Freeze>ou image pré-rendue). - Optimisez les images (taille correcte, WebP/AVIF si pris en charge) et réduisez les ressources vidéo.
- Rendez les aperçus à
--scale=0.5et sur de courtes plages d'images d'abord.
10. Vidéo par lots et pilotée par les données
- Définissez un schéma de props et validez avant le rendu.
- Stockez les données dans JSON/CSV ; stockez la mise en page dans les composants.
- Ajustement du texte : nombre maximum de lignes, taille de police de secours, règles de troncature, tests de débordement.
- Rendez chaque variante à partir de la même composition avec des
--propsdifférents. - Écrivez un manifeste et vérifiez la durée et la taille non vide de chaque sortie.
npx remotion render src/index.ts Main out/acme.mp4 --props='{"brand":"Acme","tagline":"Build faster"}'
11. Hybride avec Blender
- Rendez le plan Blender au même FPS, à la même résolution et au même nombre d'images que la composition Remotion.
- Mappez l'image Blender 1 → index d'image Remotion 0, sauf si le projet définit un décalage.
- Pour la transparence, exportez une séquence PNG ou ProRes 4444 et vérifiez l'alpha sur un damier ; MP4 n'a pas d'alpha.
- Faites correspondre le pipeline de couleurs : encodez la passe Blender avec les mêmes hypothèses de transfert/transformée de vue que la sortie du navigateur, puis inspectez le composite.
- Placez la passe avec
<OffthreadVideo>(pas<Video>) à l'intérieur d'une<Sequence>, et définissezstartFrom/les décalages d'image à partir de la carte d'images.
12. Validation avant livraison
npx remotion compositions src/index.ts # liste les ids et dimensions
ffprobe -v error -show_entries format=duration,size \
-show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt,channels \
-of json out/video.mp4
Inspectez ensuite les images 0, chaque limite de scène, chaque transition, chaque image riche en texte, et l'image finale. Vérifiez le texte tronqué, les polices manquantes, les images noires et la dérive audio. Voir video-composition pour les recettes d'encodage/normalisation et motion-studio/references/QUALITY-CHECKLIST.md pour la validation complète.
13 Modes de défaillance courants
- Composition non trouvée → le fichier d'entrée ou l'ID est erroné ; exécutez
npx remotion compositions. - Rendu vide mais aperçu fonctionnel → le chemin de la ressource se résout dans Studio mais pas en mode sans tête ; utilisez
staticFile, vérifiez la casse depublic/. - Les polices tombent par défaut sur Times → police non chargée avant le rendu ; attendez la disponibilité.
- Sortie différente entre les rendus → temps horloge ou aléatoire non ensemencé.
- OOM ou extrêmement lent → réduisez
--concurrency, réduisez le flou/échelle, divisez le rendu. - Audio désynchronisé → mauvais
startFrom, décalage FPS, ou source à fréquence d'images variable.