Communitygithub.com

Remotion Compose

Convierte un resumen de video en lenguaje natural en una composición completa de Remotion, lista para previsualizar: extrae duración, escenas, colores de marca, relación de aspecto y texto real; planifica el presupuesto de fotogramas; y escribe código React/TypeScript con useCurrentFrame, interpolate, spring, AbsoluteFill y Sequence, registrado en Root.tsx. Úsalo cuando alguien pida crear un video animado a partir de una descripción.

¿Qué es Remotion Compose?

Remotion Compose es una habilidad especializada para agentes de IA (como Claude Code, Cursor o Codex) que transforma un resumen simple en lenguaje natural en un componente de Remotion completamente funcional. Extrae automáticamente los parámetros clave del video: duración en segundos, fotogramas por segundo (por defecto 30 fps), lista de escenas, colores de marca, relación de aspecto (16:9, 9:16 o 1:1) y el texto real (títulos, características, llamada a la acción). Luego planifica el presupuesto de fotogramas dividiendo el tiempo total entre las escenas, escribiendo componentes React/TypeScript que usan las APIs de Remotion para animación cuadro a cuadro (useCurrentFrame, interpolate, spring, Sequence, AbsoluteFill). El resultado es un archivo .tsx en src/compositions/ registrado en src/Root.tsx, listo para previsualizar en Remotion Studio o renderizar con remotion-render. La habilidad es útil para desarrolladores que quieren crear rápidamente demos de productos, tutoriales, anuncios o videos de marketing sin escribir código manualmente, asegurando animaciones suaves, tiempos precisos y datos configurables a través de props tipadas. Soporta cualquier plataforma: video horizontal (1920×1080), vertical (1080×1920) o cuadrado (1080×1080).

Compatible con~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/SkillMedev/tutorial-video-studio/tree/main/skills/remotion-compose

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace Remotion Compose?

Conviertes un resumen en lenguaje natural en una composición completa de Remotion, lista para previsualizar - React/TypeScript real con animación basada en fotogramas. El resultado es un archivo .tsx en src/compositions/, registrado en src/Root.tsx, que el usuario puede examinar inmediatamente en Studio o pasar a remotion-render.

Actívalo ante cualquier solicitud de crear, generar, animar o "escribir el código de video para" una demo de producto, tutorial, presentación de funcionalidad o animación de marketing - incluyendo "construye un video de 20 segundos que muestre X".

Paso 1 - Extraer el resumen

No empieces a codificar hasta que tengas estos datos. Pregunta en un lote compacto; llena los vacíos obvios con valores predeterminados sensatos en lugar de detenerte:

  1. Duración en segundos, y fps (por defecto 30 - el estándar para video de producto y marketing, y la mitad del costo de renderizado que 60. Usa 60fps solo cuando animes movimiento fino del cursor o UI de scroll donde 30 tartamudea visiblemente).
  2. Escenas - qué sucede, en orden. Presiona por una lista de tiempos: "logo, luego tres funciones, luego un CTA" es mejor que "una demo de mi app".
  3. Marca - colores primario/de acento/fondo en hex, y la fuente (un nombre de familia de @remotion/google-fonts).
  4. Relación de aspecto / plataforma - 16:9 horizontal (1920×1080), 9:16 vertical (1080×1920) para redes sociales, o 1:1 cuadrado (1080×1080).
  5. Texto - los titulares/nombres de funciones/texto de CTA reales. Nunca inventes afirmaciones sobre el producto; pide las palabras reales.

Convierte segundos a fotogramas en todas partes: durationInFrames = seconds * fps. Las longitudes totales típicas: 15-60s para un demo social/de producto, 6-15s para un corte publicitario.

Paso 2 - Construir un plan de escenas

Una <Composition> por video, un componente por escena, unidos en la línea de tiempo con <Sequence>. Planifica el presupuesto de fotogramas antes de escribir código:

Total: 20s @ 30fps = 600 fotogramas
  Intro (logo)          fotogramas   0-90    (Sequence from=0   durationInFrames=90)
  Función 1             fotogramas  90-240   (Sequence from=90  durationInFrames=150)
  Función 2             fotogramas 240-390   (Sequence from=240 durationInFrames=150)
  Función 3             fotogramas 390-540   (Sequence from=390 durationInFrames=150)
  CTA outro             fotogramas 540-600   (Sequence from=540 durationInFrames=60)

Umbrales de ritmo al presupuestar:

  • Dale a cualquier tiempo que lleve texto al menos 2 segundos (60 fotogramas a 30fps) - animación de entrada más pausa. Un titular necesita aproximadamente 150-200ms de pausa por palabra para ser legible; un titular de 6 palabras quiere ~1s de pausa después de que aterrice.
  • Animaciones de entrada: 10-20 fotogramas. Fundidos y salidas: 12-15 fotogramas. Más largos se sienten lentos, más cortos como un parpadeo.
  • Ninguna escena de menos de ~45 fotogramas a menos que sea un corte rápido intencional.

<Sequence from={F}> desplaza el reloj local del hijo para que dentro de ese componente useCurrentFrame() comience en 0. Anima cada escena como si comenzara en el fotograma 0.

Paso 3 - Referencia de la API principal

  • useCurrentFrame() - el fotograma actual (el reloj). Todo se anima como una función de esto.
  • useVideoConfig() - { fps, width, height, durationInFrames }.
  • interpolate(frame, [inFrames], [outValues], opts) - mapeo lineal. Siempre pasa { extrapolateLeft: "clamp", extrapolateRight: "clamp" } para entradas/salidas para que los valores no se salgan de su rango.
  • spring({ frame, fps, config }) - 0→1 basado en física (sobrepasa ligeramente). Úsalo para cualquier cosa que deba sentirse viva (pops, deslizamientos, escalados).
  • AbsoluteFill - un div con posición absoluta de fotograma completo; la capa base de cada escena.
  • Sequence - desplaza y limita temporalmente a los hijos (el programador de escenas).
  • Series / Series.Sequence - escenas consecutivas sin calcular los desplazamientos from manualmente.
  • Img, staticFile - ver Paso 6.

Paso 4 - spring() vs interpolate()

Usa spring() cuando…Usa interpolate() cuando…
El movimiento debe sentirse físico - pops, rebotes, escalados, deslizamientosNecesitas control preciso y lineal entre fotogramas exactos
Quieres un asentamiento natural/sobrepasoFundidos (opacidad 0→1), cambios de color, barras de progreso, cualquier cosa sincronizada al fotograma
Entradas de tarjetas, logos, insigniasFundidos y salidas donde el sobrepaso se vería mal

Patrón - impulsa una transformación con un spring, una opacidad con interpolate:

const { fps } = useVideoConfig();
const frame = useCurrentFrame();
const pop = spring({ frame, fps, config: { damping: 200 } });   // 0 → 1, vivaz
const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
const scale = interpolate(pop, [0, 1], [0.8, 1]);

damping: 200 es la configuración de trabajo: un asentamiento rápido con un sobrepaso apenas perceptible. Un damping más bajo (~10-20) rebota visiblemente; úsalo solo cuando el rebote sea el objetivo.

Paso 5 - Estructura estándar de demo de producto

Codifica esta forma a menos que el resumen diga lo contrario: intro de logo/marca → N llamados de función → CTA de outro. Hazlo basado en datos (Paso 6) para que las variantes sean gratuitas.

// src/compositions/ProductDemo.tsx
import {
  AbsoluteFill, Sequence, useCurrentFrame, useVideoConfig,
  interpolate, spring,
} from "remotion";
import { loadFont } from "@remotion/google-fonts/Inter";

const { fontFamily } = loadFont();

export type Feature = { title: string; body: string };
export type ProductDemoProps = {
  brand: string;
  colors: { bg: string; fg: string; accent: string };
  logoText: string;
  features: Feature[];
  cta: string;
};

const Intro: React.FC<{ text: string; colors: ProductDemoProps["colors"] }> = ({ text, colors }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const s = spring({ frame, fps, config: { damping: 200 } });
  const scale = interpolate(s, [0, 1], [0.7, 1]);
  const opacity = interpolate(frame, [0, 12], [0, 1], { extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ backgroundColor: colors.bg, justifyContent: "center", alignItems: "center" }}>
      <h1 style={{ fontFamily, fontSize: 120, color: colors.fg, transform: `scale(${scale})`, opacity }}>
        {text}
      </h1>
    </AbsoluteFill>
  );
};

const FeatureCallout: React.FC<{ feature: Feature; colors: ProductDemoProps["colors"] }> = ({ feature, colors }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const slide = spring({ frame, fps, config: { damping: 200 } });
  const x = interpolate(slide, [0, 1], [-60, 0]);
  const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ backgroundColor: colors.bg, justifyContent: "center", paddingLeft: 160 }}>
      <div style={{ transform: `translateX(${x}px)`, opacity }}>
        <div style={{ fontFamily, fontSize: 32, color: colors.accent, fontWeight: 700, letterSpacing: 2 }}>
          {feature.title.toUpperCase()}
        </div>
        <div style={{ fontFamily, fontSize: 64, color: colors.fg, maxWidth: 1100, marginTop: 16 }}>
          {feature.body}
        </div>
      </div>
    </AbsoluteFill>
  );
};

const Outro: React.FC<{ cta: string; colors: ProductDemoProps["colors"] }> = ({ cta, colors }) => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 18], [0, 1], { extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ backgroundColor: colors.accent, justifyContent: "center", alignItems: "center" }}>
      <h2 style={{ fontFamily, fontSize: 84, color: colors.bg, opacity }}>{cta}</h2>
    </AbsoluteFill>
  );
};

export const ProductDemo: React.FC<ProductDemoProps> = ({ colors, logoText, features, cta }) => {
  const intro = 90;
  const per = 150;
  const outro = 60;
  return (
    <AbsoluteFill>
      <Sequence durationInFrames={intro}>
        <Intro text={logoText} colors={colors} />
      </Sequence>
      {features.map((f, i) => (
        <Sequence key={i} from={intro + i * per} durationInFrames={per}>
          <FeatureCallout feature={f} colors={colors} />
        </Sequence>
      ))}
      <Sequence from={intro + features.length * per} durationInFrames={outro}>
        <Outro cta={cta} colors={colors} />
      </Sequence>
    </AbsoluteFill>
  );
};

Regístralo en src/Root.tsx, calculando durationInFrames a partir de los mismos números y proporcionando defaultProps:

<Composition
  id="ProductDemo"
  component={ProductDemo}
  durationInFrames={90 + 3 * 150 + 60}
  fps={30}
  width={1920}
  height={1080}
  defaultProps={{
    brand: "Acme",
    colors: { bg: "#0B0B0F", fg: "#FFFFFF", accent: "#6C5CE7" },
    logoText: "Acme",
    features: [
      { title: "Rápido", body: "Entrega en segundos, no en sprints." },
      { title: "Simple", body: "Un prompt, un video." },
      { title: "Tuyo", body: "Tu marca, tu texto." },
    ],
    cta: "Empieza gratis →",
  }}
/>

Para vertical/redes sociales, establece width={1080} height={1920}; para cuadrado, 1080×1080. Mantén los componentes idénticos - solo cambia el lienzo.

Paso 6 - Props basados en datos y activos estáticos

La composición anterior es totalmente basada en datos: cada palabra y color es una prop. Ese es el objetivo: las variantes (nuevo texto, nueva paleta, texto localizado) no necesitan ninguna re-solicitud; solo pasa diferentes props (remotion-render lo hace desde un archivo JSON para lotes).

Los activos estáticos (logos, capturas de pantalla, audio) viven en public/assets/ y se referencian con staticFile() - nunca un import o una ruta cruda:

import { Img, staticFile } from "remotion";
<Img src={staticFile("assets/logo.png")} />

Paso 7 - Salida

Guarda el archivo terminado en src/compositions/<VideoName>.tsx, regístralo en src/Root.tsx, y dile al usuario que lo previsualice con npx remotion studio (http://localhost:3000). Luego entrega: "Examínalo en Studio. Dime qué cambiar - demasiado rápido, color incorrecto, texto diferente - y lo editaré y re-renderizaré (remotion-render)."

NO HAGAS

  • NO animes con transiciones/animaciones CSS o setTimeout/setInterval. Remotion renderiza fotogramas de forma independiente y en paralelo; cualquier cosa que no derive de useCurrentFrame() es invisible o inconsistente en el render final, aunque se vea bien en la previsualización del navegador.
  • NO uses Math.random() para efectos dispersos/de partículas - cada worker de renderizado obtiene valores diferentes y los fotogramas dejan de coincidir. Usa random(seed) de Remotion para pseudo-aleatoriedad determinista.
  • NO obtengas datos ni esperes trabajo asíncrono sin delayRender() / continueRender() - el renderizador captura el fotograma antes de que lleguen los datos.
  • NO codifiques fps, width o height dentro de los componentes de escena - léelos de useVideoConfig() para que cambiar 30↔60fps o horizontal↔vertical no rompa cada temporización y diseño.
  • NO omitas extrapolateLeft/Right: "clamp" en interpolaciones de entrada/salida - la opacidad sube más allá de 1 y los elementos se desplazan fuera del lienzo después de que su rango termina.
  • NO inventes titulares, afirmaciones de funciones o CTAs - usa el texto real del usuario, y pregúntalo si falta.

Barra de calidad

  • Cada valor animado es una función pura de useCurrentFrame() (más props) - rebobinar hacia atrás en Studio se ve idéntico a avanzar.
  • El presupuesto de fotogramas en el plan suma exactamente a durationInFrames en Root.tsx, y ningún tiempo de texto dura menos de su mínimo legible.
  • Todo el texto y los colores llegan a través de props tipadas con defaultProps proporcionados - sin literales enterrados en componentes de escena.
  • Los activos cargan a través de staticFile(); el archivo se registra limpiamente y se previsualiza en Studio sin errores de consola.

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Captions From Transcript

Produce an accurate, properly timed caption track (SRT or WebVTT) from a video

Kinetic Typography

Put text in motion the right way - title cards, animated captions, lower-thirds, callouts, and word-by-word reveals - with a reading-time-per-word budget so copy holds long enough to read, plus enter/exit timing, weight and size transitions, and type hierarchy in motion. Use when someone asks to

Motion Design Principles

The craft layer for motion: pick the right easing (ease-in / ease-out / ease-in-out / spring), get timing and spacing right, build the anticipation→action→follow-through arc, and apply Disney

Narration Script

Write the spoken voiceover for a tutorial or demo - the actual words, phrased for the ear and synced one-instruction-per-action to what is on screen, with a pacing budget and a confident, jargon-checked tone. Use when someone says

Product Demo Director

Direct the craft of putting a real software UI on screen - cursor choreography, zoom/pan/callout language, screen-recording vs recreated-UI, and making state changes legible with highlights, focus pulls, and slow-downs. Use when filming or recreating an app for a product demo, feature walkthrough, onboarding clip, or release reel and asking

Remotion Render

Renders a Remotion composition to MP4 and runs the edit-and-re-render loop - CLI render commands, 1080p/4K/9:16 presets, concurrency tuning, codec selection, batch variants from a JSON data file, and Lambda for cloud rendering. Use when someone says

Remotion Setup

Scaffolds a new Remotion video project wired for Claude Code Agent Skills - Node check, create-video scaffold, skills install, folder conventions, Google Fonts, and a smoke-test render. Use whenever someone wants to start making videos with Remotion and Claude, even just

Screencast Capture

Capture clean raw screen and camera footage for a tutorial or product demo - choosing the recorder (macOS Screenshot toolbar, QuickTime, OBS, Windows Game Bar), setting resolution / frame-rate / cursor / microphone, prepping a distraction-free stage, and recording in retakeable segments. Use when someone says

SkillMedev/tutorial-video-studio

Plan a product demo, feature announcement, or launch video as a beat sheet and shot list BEFORE animating - hook in the first 3s, problem, reveal, proof, CTA - with target duration and pacing per scene type, output as a JSON scene plan that remotion-compose consumes directly. Use when someone says

Social Video Formatter

Reframe and export a finished video for social platforms - 9:16 ↔ 16:9 cropping, burned-in captions, a platform-native first frame, loop design, and per-platform specs (aspect, length, safe areas) for TikTok, Reels, Shorts, X, and LinkedIn. Use when someone says

Sound and Music Sync

Score a video like an editor: beat-match cuts to the music, land SFX on transitions, pace the voiceover so it breathes, source royalty-free tracks safely, and duck the music so the VO sits clearly on top. Use when adding music, sound effects, or voiceover to a video, when asked to

Skills relacionados