Communitygithub.com

Remotion Compose

Transforma um briefing de vídeo em linguagem natural em uma composição Remotion completa e pronta para visualização - extrai duração, cenas, cores da marca, proporção de tela e texto real; planeja o orçamento de quadros; e escreve React/TypeScript orientado a dados usando useCurrentFrame, interpolate, spring, AbsoluteFill e Sequence, registrado em Root.tsx.

O que é Remotion Compose?

Remotion Compose é uma habilidade especializada para agentes de IA (como Claude Code, Cursor, Codex) que converte um briefing de vídeo em linguagem natural em uma composição Remotion totalmente funcional. Ela extrai parâmetros essenciais como duração, cenas, cores da marca e texto, planeja o orçamento de quadros e gera código React/TypeScript com animações baseadas em quadros. A habilidade suporta as plataformas Remotion, Studio e remotion-render, e segue um processo estruturado: extração do briefing, construção de um plano de cenas com Sequence, uso da API principal (useCurrentFrame, interpolate, spring, AbsoluteFill) e criação de componentes orientados a dados. Ela garante que todas as animações sejam funções puras de useCurrentFrame(), evitando CSS transitions, setTimeout e Math.random(), para consistência perfeita durante a renderização.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Remotion Compose faz?

Você transforma um briefing em linguagem natural em uma composição Remotion completa e pronta para visualização - React/TypeScript real com animação baseada em quadros. A saída é um arquivo .tsx em src/compositions/, registrado em src/Root.tsx, que o usuário pode imediatamente navegar no Studio ou entregar ao remotion-render.

Ative em qualquer solicitação para criar, gerar, animar ou "escrever o código do vídeo para" uma demonstração de produto, walkthrough, destaque de funcionalidade ou animação de marketing - incluindo "crie um vídeo de 20 segundos mostrando X."

Etapa 1 - Extrair o briefing

Não comece a codificar até ter estes itens. Pergunte em um lote compacto; preencha lacunas óbvias com padrões sensatos em vez de parar:

  1. Duração em segundos e fps (padrão 30 - o padrão para vídeo de produto e marketing, e metade do custo de renderização de 60 fps. Use 60fps apenas ao animar movimento fino de cursor ou UI de rolagem onde 30 trava visivelmente).
  2. Cenas - o que acontece, em ordem. Insista por uma lista de batidas: "logo, depois três funcionalidades, depois um CTA" é melhor que "uma demonstração do meu app."
  3. Marca - cores primária/destaque/fundo em hex, e a fonte (um nome de família @remotion/google-fonts).
  4. Proporção / plataforma - 16:9 paisagem (1920×1080), 9:16 retrato (1080×1920) para redes sociais, ou 1:1 quadrado (1080×1080).
  5. Texto - os títulos/nomes de funcionalidades/texto do CTA reais. Nunca invente alegações de produto; peça as palavras reais.

Converta segundos em quadros em todos os lugares: durationInFrames = seconds * fps. Durações totais típicas: 15-60s para uma demonstração social/de produto, 6-15s para um corte de anúncio.

Etapa 2 - Construir um plano de cenas

Uma <Composition> por vídeo, um componente por cena, costurados na linha do tempo com <Sequence>. Defina o orçamento de quadros antes de escrever código:

Total: 20s @ 30fps = 600 quadros
  Intro (logo)            quadros   0-90    (Sequence from=0   durationInFrames=90)
  Funcionalidade 1        quadros  90-240   (Sequence from=90  durationInFrames=150)
  Funcionalidade 2        quadros 240-390   (Sequence from=240 durationInFrames=150)
  Funcionalidade 3        quadros 390-540   (Sequence from=390 durationInFrames=150)
  CTA final               quadros 540-600   (Sequence from=540 durationInFrames=60)

Limites de ritmo ao orçar:

  • Dê a qualquer batida que carregue texto pelo menos 2 segundos (60 quadros a 30fps) - animação de entrada mais pausa. Um título precisa de aproximadamente 150-200ms de pausa por palavra para ser legível; um título de 6 palavras quer ~1s de pausa após chegar.
  • Animações de entrada: 10-20 quadros. Cross-fades e saídas: 12-15 quadros. Mais longo parece lento, mais curto parece uma falha.
  • Nenhuma cena com menos de ~45 quadros, a menos que seja um corte rápido intencional.

<Sequence from={F}> desloca o relógio local do filho para que dentro desse componente useCurrentFrame() comece em 0. Anime cada cena como se começasse no quadro 0.

Etapa 3 - Referência da API principal

  • useCurrentFrame() - o quadro atual (o relógio). Tudo anima em função disso.
  • useVideoConfig() - { fps, width, height, durationInFrames }.
  • interpolate(frame, [inFrames], [outValues], opts) - mapeamento linear. Sempre passe { extrapolateLeft: "clamp", extrapolateRight: "clamp" } para entrada/saída para que os valores não ultrapassem seu intervalo.
  • spring({ frame, fps, config }) - 0→1 baseado em física (levemente overshoot). Use para qualquer coisa que deva parecer viva (pops, slides, scale-ins).
  • AbsoluteFill - um div posicionado absolutamente em tela cheia; a camada base de cada cena.
  • Sequence - desloca o tempo e limita o tempo dos filhos (o agendador de cenas).
  • Series / Series.Sequence - cenas consecutivas sem calcular deslocamentos from manualmente.
  • Img, staticFile - veja a Etapa 6.

Etapa 4 - spring() vs interpolate()

Use spring() quando…Use interpolate() quando…
O movimento deve parecer físico - pops, saltos, scale-ins, slide-insVocê precisa de controle preciso e linear entre quadros exatos
Você quer um assentamento natural/overshootFades (opacidade 0→1), mudanças de cor, barras de progresso, qualquer coisa sincronizada com o quadro
Entradas de cards, logos, badgesCross-fades e saídas onde overshoot pareceria errado

Padrão - dirija uma transformação com spring, uma opacidade com interpolate:

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

damping: 200 é a configuração de trabalho - um assentamento rápido com overshoot quase imperceptível. Damping menor (~10-20) salta visivelmente; use apenas quando salto for o objetivo.

Etapa 5 - Estrutura padrão de demonstração de produto

Codifique esta forma, a menos que o briefing diga o contrário: intro logo/marca → N destaques de funcionalidades → CTA final. Torne-o orientado a dados (Etapa 6) para que variações sejam 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>
  );
};

Registre em src/Root.tsx, calculando durationInFrames a partir dos mesmos números e fornecendo 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: "Entregue em segundos, não em sprints." },
      { title: "Simples", body: "Um prompt, um vídeo." },
      { title: "Seu", body: "Sua marca, seu texto." },
    ],
    cta: "Comece grátis →",
  }}
/>

Para retrato/redes sociais, defina width={1080} height={1920}; para quadrado, 1080×1080. Mantenha os componentes idênticos - apenas a tela muda.

Etapa 6 - Props orientadas a dados e assets estáticos

A composição acima é totalmente orientada a dados: cada palavra e cor é uma prop. Esse é o ponto - variações (novo texto, nova paleta, texto localizado) não precisam de nova solicitação; apenas passe props diferentes (remotion-render faz isso a partir de um arquivo JSON para lotes).

Assets estáticos (logos, capturas de tela, áudio) ficam em public/assets/ e são referenciados com staticFile() - nunca uma importação ou um caminho bruto:

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

Etapa 7 - Saída

Salve o arquivo final em src/compositions/<NomeDoVideo>.tsx, registre em src/Root.tsx, e diga ao usuário para visualizar com npx remotion studio (http://localhost:3000). Então entregue: "Navegue no Studio. Diga-me o que mudar - muito rápido, cor errada, texto diferente - e eu edito e re-renderizo (remotion-render)."

NÃO FAÇA

  • NÃO anime com transições/animações CSS ou setTimeout/setInterval. O Remotion renderiza quadros de forma independente e em paralelo; qualquer coisa não derivada de useCurrentFrame() é invisível ou inconsistente na renderização final, mesmo que pareça boa na prévia do navegador.
  • NÃO use Math.random() para efeitos de dispersão/partículas - cada worker de renderização obtém valores diferentes e os quadros param de corresponder. Use random(seed) do Remotion para pseudo-aleatoriedade determinística.
  • NÃO busque dados ou espere por trabalho assíncrono sem delayRender() / continueRender() - o renderizador captura o quadro antes dos dados chegarem.
  • NÃO codifique fps, width ou height dentro de componentes de cena - leia-os de useVideoConfig() para que alternar entre 30↔60fps ou paisagem↔retrato não quebre cada temporização e layout.
  • NÃO omita extrapolateLeft/Right: "clamp" em interpolações de entrada/saída - a opacidade sobe além de 1 e elementos saem da tela após seu intervalo terminar.
  • NÃO invente títulos, alegações de funcionalidades ou CTAs - use o texto real do usuário, e peça se estiver faltando.

Padrão de qualidade

  • Cada valor animado é uma função pura de useCurrentFrame() (mais props) - navegar para trás no Studio parece idêntico a avançar.
  • O orçamento de quadros no plano soma exatamente a durationInFrames em Root.tsx, e nenhuma batida de texto segura por menos de seu mínimo legível.
  • Todo texto e cores chegam via props tipadas com defaultProps fornecidos - sem literais enterrados em componentes de cena.
  • Assets carregam via staticFile(); o arquivo registra-se limpo e pré-visualiza no Studio sem erros no console.

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

Habilidades Relacionadas