Motion Canvas
Verificado 2026-10: @motion-canvas/core, /2d, /ffmpeg 3.17. Necesita Node 16+.
Remotion vs Motion Canvas: Remotion = React, fotograma → interfaz, se escala a vídeos basados en datos/plantillas y renderizado en servidor. Motion Canvas = línea de tiempo imperativa (yield* un paso tras otro) con un editor para sincronizar con una locución. Elige uno por vídeo; no los mezcles.
Configuración
npm init @motion-canvas@latest # nombre, TypeScript, elegir exportador "Video (FFmpeg)"
npm install
npm run serve # editor en http://localhost:9000
src/project.ts # makeProject({ scenes: [...] })
src/scenes/*.tsx # una escena por archivo
// src/project.ts
import {makeProject} from '@motion-canvas/core';
import intro from './scenes/intro?scene'; // el sufijo ?scene es obligatorio
export default makeProject({scenes: [intro]});
Escena
import {Circle, Rect, Txt, makeScene2D} from '@motion-canvas/2d';
import {all, chain, createRef, easeInOutCubic, sequence, waitFor, waitUntil} from '@motion-canvas/core';
export default makeScene2D(function* (view) {
const circle = createRef<Circle>();
view.add(<Circle ref={circle} x={-300} size={240} fill="#e13238" />);
yield* all( // en paralelo, espera a que todas terminen
circle().position.x(300, 1).to(-300, 1), // interpolación: propiedad(valor, segundos), encadena con .to()
circle().fill('#e6a700', 1).to('#e13238', 1),
);
yield* waitUntil('title'); // evento temporal nombrado, se arrastra en la línea de tiempo del editor
yield* circle().scale(2, 0.6, easeInOutCubic);
});
- Coordenadas: origen en el centro de la vista;
x,y,size,width,height,rotation,scale,opacity,fill,stroke,lineWidth. - Componentes:
Rect(radiuspara esquinas redondeadas),Circle,Line/Spline(points,endpara dibujado progresivo),Txt,Img,Video,Layout(flexbox:layout direction gap),Code,Latex. - Una propiedad llamada con un valor lo asigna; con
(valor, segundos[, ease])interpola y debe usarse conyield*; sin argumentos la lee.
Flujo
| Llamada | Efecto |
|---|---|
all(...t) | Ejecuta todo junto, espera a que terminen todas |
any(...t) | Ejecuta todo junto, espera a la primera en terminar |
chain(...t) | Una tras otra |
sequence(0.2, ...t) | Inicia cada una 0.2 s después de la anterior (sin esperar) |
delay(0.5, t) | Inicia tras 0.5 s |
loop(3, () => t) | Repite |
waitFor(1.5) | Pausa 1.5 s |
waitUntil('event') | Pausa hasta el evento nombrado del editor — úsalo para sincronizar con la locución |
useDuration('event') | Duración de un evento nombrado, como duración de interpolación |
Renderizado
- Editor → Panel de renderizado: resolución, fotogramas por segundo (24/30/60), rango, exportador. Haz clic en RENDER.
- La salida se guarda en
/output. El exportador por defecto escribe una secuencia de imágenes; para MP4 con audio añade el exportador FFmpeg:
npm install --save @motion-canvas/ffmpeg
// vite.config.ts
import {defineConfig} from 'vite';
import motionCanvas from '@motion-canvas/vite-plugin';
import ffmpeg from '@motion-canvas/ffmpeg';
export default defineConfig({plugins: [motionCanvas(), ffmpeg()]});
Luego elige Video (FFmpeg) en Configuración de Vídeo.
- Los cambios de resolución no escalan el diseño; decide el tamaño final (ej. 1920×1080 o 1080×1920) antes de diseñar.