La vidéo est partout. Démos produit, clips pour les réseaux sociaux, vidéos d’onboarding personnalisées, images Open Graph dynamiques qui sont en réalité de courtes animations. Créer tout ça manuellement dans After Effects ou Premiere ne scale pas. Remotion prend une approche radicalement différente : les vidéos sont des composants React. Chaque frame est rendue par React, stylée en CSS, animée en JavaScript, et exportée en MP4. Si vous savez construire une UI, vous savez construire une vidéo.
Une vidéo est un composant
Dans Remotion, une vidéo est un composant React qui reçoit le numéro de frame courant. On utilise cette frame pour calculer des positions, des opacités, des couleurs, tout ce qui change dans le temps. Le composant rend une fois par frame, et Remotion capture chaque rendu dans un fichier vidéo.
import { AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
export function HelloWorld() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const opacity = interpolate(frame, [0, fps], [0, 1], {
extrapolateRight: 'clamp',
});
const translateY = interpolate(frame, [0, fps], [30, 0], {
extrapolateRight: 'clamp',
});
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<h1
style={{
fontSize: 80,
color: 'white',
opacity,
transform: `translateY(${translateY}px)`,
}}
>
Hello World
</h1>
</AbsoluteFill>
);
}
useCurrentFrame() retourne le numéro de frame en partant de 0. interpolate mappe une plage de frames vers une plage de valeurs, l’utilitaire central de toutes les animations. À 30fps, les frames 0 à 30 représentent la première seconde. Le texte apparaît en fondu et glisse vers le haut sur cette durée. Pas d’éditeur de keyframes, pas de timeline, juste des maths et du React.
Composition et timeline
Un projet Remotion est une collection de compositions. Chaque composition définit ses dimensions, son frame rate, sa durée et son composant racine.
import { Composition } from 'remotion';
import { HelloWorld } from './HelloWorld';
import { ProductDemo } from './ProductDemo';
export function RemotionRoot() {
return (
<>
<Composition
id="HelloWorld"
component={HelloWorld}
durationInFrames={90}
fps={30}
width={1920}
height={1080}
/>
<Composition
id="ProductDemo"
component={ProductDemo}
durationInFrames={300}
fps={30}
width={1920}
height={1080}
/>
</>
);
}
Les compositions sont des vidéos indépendantes. Le Remotion Studio permet de prévisualiser chacune dans le navigateur avec une timeline, de scrubber à travers les frames, et de rendre quand on est prêt. C’est un environnement de montage vidéo qui se trouve être un serveur de dev React.
Sequences : structurer les scènes
Les vraies vidéos ont plusieurs scènes. <Sequence> décale un composant dans le temps pour qu’il apparaisse à une frame spécifique et ait son propre compteur de frames interne commençant à 0.
import { AbsoluteFill, Sequence } from 'remotion';
export function ProductDemo() {
return (
<AbsoluteFill style={{ backgroundColor: '#0a0a0a' }}>
<Sequence from={0} durationInFrames={60}>
<TitleCard text="Introducing Acme" />
</Sequence>
<Sequence from={60} durationInFrames={120}>
<FeatureShowcase />
</Sequence>
<Sequence from={180} durationInFrames={90}>
<CallToAction />
</Sequence>
<Sequence from={0} durationInFrames={270}>
<BackgroundMusic />
</Sequence>
</AbsoluteFill>
);
}
Chaque <Sequence> est une scène autonome. Le useCurrentFrame() de TitleCard retourne 0 à la frame 0 de la vidéo, mais celui de FeatureShowcase retourne 0 à la frame 60. Les scènes n’ont pas besoin de connaître leur position absolue dans la timeline. Elles ne se soucient que de leur temps local.
La séquence BackgroundMusic couvre toute la vidéo. Les séquences audio et visuelles se superposent naturellement, comme des éléments dans un arbre React.
Animations spring pour du mouvement naturel
interpolate produit des transitions linéaires par défaut. Pour du mouvement plus naturel, Remotion fournit une fonction spring basée sur la physique qui simule l’amortissement et la masse.
import { useCurrentFrame, useVideoConfig, spring, AbsoluteFill } from 'remotion';
export function AnimatedLogo() {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const scale = spring({
frame,
fps,
config: { damping: 12, stiffness: 200 },
});
const rotation = spring({
frame: frame - 10,
fps,
config: { damping: 15 },
});
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<div
style={{
transform: `scale(${scale}) rotate(${rotation * 360}deg)`,
}}
>
<Logo />
</div>
</AbsoluteFill>
);
}
Le spring part de 0 et se stabilise à 1, avec un overshoot et un rebond déterminés par les valeurs de damping et stiffness. Passer frame - 10 retarde l’animation de 10 frames. Les springs se composent naturellement, et parce qu’ils sont déterministes (pas de temps réel, juste des numéros de frame), chaque rendu produit exactement le même résultat.
Vidéos data-driven
La vraie puissance de Remotion est la génération de vidéos à partir de données. Catalogues produit, vidéos de bienvenue personnalisées, résumés de rapports hebdomadaires, tout ce qui suit un template mais varie en contenu.
import { AbsoluteFill, Sequence, Img } from 'remotion';
interface ReportData {
userName: string;
metrics: { label: string; value: number; change: number }[];
chartUrl: string;
}
export function WeeklyReport({ userName, metrics, chartUrl }: ReportData) {
return (
<AbsoluteFill style={{ backgroundColor: '#0f172a', padding: 80 }}>
<Sequence from={0} durationInFrames={60}>
<FadeIn>
<h1 style={{ color: 'white', fontSize: 48 }}>Weekly Report for {userName}</h1>
</FadeIn>
</Sequence>
<Sequence from={60} durationInFrames={120}>
<MetricsGrid metrics={metrics} />
</Sequence>
<Sequence from={180} durationInFrames={90}>
<Img src={chartUrl} style={{ width: '100%', borderRadius: 16 }} />
</Sequence>
</AbsoluteFill>
);
}
<Composition
id="WeeklyReport"
component={WeeklyReport}
durationInFrames={270}
fps={30}
width={1920}
height={1080}
defaultProps={{
userName: 'Thomas',
metrics: [
{ label: 'Revenue', value: 12400, change: 8.5 },
{ label: 'Users', value: 3200, change: -2.1 },
],
chartUrl: 'https://example.com/chart.png',
}}
/>
Les props coulent dans le composant vidéo comme dans n’importe quel composant React. On change les données, on obtient une vidéo différente. C’est là que Remotion devient une API vidéo : on peut rendre programmatiquement des centaines de vidéos personnalisées en itérant sur un dataset et en changeant les props d’entrée.
Audio et transitions
Remotion gère l’audio de la même façon que le visuel. Les composants <Audio> et <OffthreadVideo> se placent dans l’arbre et suivent le même timing basé sur les frames.
import { Audio, interpolate, useCurrentFrame } from 'remotion';
import bgMusic from './assets/intro.mp3';
export function Intro() {
const frame = useCurrentFrame();
const volume = interpolate(frame, [0, 30, 150, 180], [0, 0.8, 0.8, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
return (
<>
<Audio src={bgMusic} volume={volume} />
<VisualContent />
</>
);
}
Le volume monte pendant la première seconde, reste stable, et redescend pendant la dernière seconde. Le mixage audio, c’est juste de l’interpolation sur la prop volume. Plusieurs composants <Audio> se superposent automatiquement.
Pour les transitions entre scènes, on anime le composant sortant et entrant simultanément en utilisant des séquences qui se chevauchent.
import { AbsoluteFill, Sequence, interpolate, useCurrentFrame } from 'remotion';
export function CrossFade({ children, durationInFrames }: CrossFadeProps) {
const frame = useCurrentFrame();
const overlap = 15;
return (
<AbsoluteFill>
<Sequence from={0} durationInFrames={durationInFrames}>
<div
style={{
opacity: interpolate(frame, [durationInFrames - overlap, durationInFrames], [1, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
}),
}}
>
{children[0]}
</div>
</Sequence>
<Sequence from={durationInFrames - overlap} durationInFrames={durationInFrames}>
{children[1]}
</Sequence>
</AbsoluteFill>
);
}
Pas besoin de logiciel de montage vidéo. Les transitions sont des composants qui contrôlent l’opacité, la position ou n’importe quelle propriété CSS sur des plages temporelles qui se chevauchent.
Rendre en MP4
Le CLI Remotion rend les compositions en fichiers vidéo. Sous le capot, il ouvre un navigateur headless, capture chaque frame comme une image, et les encode en vidéo avec FFmpeg.
npx remotion render src/index.ts HelloWorld out/hello.mp4
Pour le rendu en batch ou les workflows pilotés par API, l’API Node.js donne un contrôle programmatique complet.
import { bundle } from '@remotion/bundler';
import { renderMedia, selectComposition } from '@remotion/renderer';
const bundled = await bundle({ entryPoint: './src/index.ts' });
const composition = await selectComposition({
serveUrl: bundled,
id: 'WeeklyReport',
inputProps: { userName: 'Thomas', metrics: [] },
});
await renderMedia({
composition,
serveUrl: bundled,
codec: 'h264',
outputLocation: 'out/report.mp4',
inputProps: { userName: 'Thomas', metrics: [] },
});
C’est comme ça qu’on construit un pipeline de rendu vidéo. Un serveur reçoit des données, appelle la fonction de rendu avec des props custom, et sort un MP4. Remotion Lambda pousse le concept plus loin en rendant sur AWS Lambda pour une génération vidéo parallèle et scalable.
Conclusion
Remotion transforme la production vidéo en problème d’ingénierie logicielle. Les composants remplacent les calques, les props remplacent les modifications manuelles, et le rendu est une étape de build. Pour tout cas d’usage où les vidéos suivent un template, que ce soit du contenu social, des démos produit, de l’onboarding personnalisé ou des rapports automatisés, écrire du React est plus rapide et plus maintenable que de cliquer dans une timeline. La vidéo entière est du code, ce qui signifie qu’elle est versionnée, testable, et infiniment reproductible.