---
name: remotion-advanced
description: Remotion v4 completo (React for Video) — Compositions, Sequences, Transitions, Lambda cloud render, Captions, Audio, Spring/Interpolate APIs. Production-grade programmatic video.
owner: "@web-designer"
shared_with: ["@brand-director", "@web-designer"]
version: 1.2
tags: [video, remotion, motion-design, programmatic-video, react]
---

# Skill: Remotion Advanced (v4)

## Versões verificadas (2026-05-29)

| Pacote | Latest | Runtime |
|---|---|---|
| `remotion` | **4.0.469** | Node v26.0.0 |
| `@remotion/cli` | 4.0.469 | — |
| `@remotion/captions` | 4.0.469 | — |
| `@remotion/lottie` | 4.0.469 | — |
| `@remotion/transitions` | 4.0.469 | — |
| `@remotion/google-fonts` | 4.0.469 | — |
| `@remotion/zod-types` | 4.0.469 | — |
| **Node mínimo** | >= 22 (Anthony tem v26) | ✓ |

## Quando usar (por agent owner)

- **@web-designer** (owner) — vídeo programático completo: launch videos, reels, ads, demos, intros.
- **@brand-director** (shared) — motion de logo, transição entre páginas do brandbook, mockup animado de identidade visual.
- **@web-designer** (shared) — hero video em landing page, micro-interactions complexas que precisam de timing programático.

## Stack & instalação

```bash
# Projeto novo
npm create video@latest
# Skills oficiais (LLM context)
npx skills add remotion-dev/skills
# Pacotes-chave (todos 4.0.469 em 2026-05-29)
npm i remotion@latest @remotion/cli@latest \
      @remotion/transitions@latest @remotion/captions@latest @remotion/lambda@latest \
      @remotion/google-fonts@latest @remotion/shapes@latest @remotion/media-parser@latest \
      @remotion/lottie@latest @remotion/three@latest @remotion/skia@latest @remotion/zod-types@latest
```

## APIs nucleares (decoreba)

| API | Uso | Exemplo |
|---|---|---|
| `useCurrentFrame()` | Frame atual da composição | `const frame = useCurrentFrame();` |
| `useVideoConfig()` | `{fps, durationInFrames, width, height}` | `const { fps, width } = useVideoConfig();` |
| `interpolate(input, [a,b], [x,y], opts)` | Mapeamento linear | `interpolate(frame, [0,30], [0,1], {extrapolateRight:"clamp"})` |
| `spring({fps, frame, config})` | Física natural | `spring({fps, frame, config:{damping:200}})` |
| `Easing.bezier(a,b,c,d)` | Custom easing | `easing: Easing.bezier(.4,0,.2,1)` |
| `random(seed)` | Determinístico | `const x = random("particle-1") * width;` |
| `delayRender()/continueRender()` | Async assets | Para imagens externas, fontes, fetch |
| `<Sequence from={f} durationInFrames={n}>` | Timeline temporal | Compor cenas em série |
| `<Series>` / `<Series.Sequence>` | Encadeamento sequencial | Sem precisar calcular offsets |
| `<Audio src=>` / `<Video src=>` / `<OffthreadVideo>` | Mídia | `OffthreadVideo` é o padrão moderno |
| `<Img src=>` | Imagem com pré-carregamento | Substitui `<img>` |
| `staticFile("/path")` | Public folder | `staticFile("/logo.png")` |

## Transitions (`@remotion/transitions` v4.0.53+)

```tsx
import { TransitionSeries, linearTiming, springTiming } from "@remotion/transitions";
import { fade, slide, wipe, flip, clockWipe, none } from "@remotion/transitions/fade"; // import por preset

<TransitionSeries>
  <TransitionSeries.Sequence durationInFrames={60}>
    <SceneIntro />
  </TransitionSeries.Sequence>
  <TransitionSeries.Transition
    presentation={fade()}
    timing={linearTiming({ durationInFrames: 15 })}
  />
  <TransitionSeries.Sequence durationInFrames={120}>
    <SceneFeatures />
  </TransitionSeries.Sequence>
  <TransitionSeries.Transition
    presentation={slide({ direction: "from-right" })}
    timing={springTiming({ config: { damping: 200 } })}
  />
  <TransitionSeries.Sequence durationInFrames={90}>
    <SceneCTA />
  </TransitionSeries.Sequence>
</TransitionSeries>
```

**6 presets:** `fade`, `slide`, `wipe`, `flip`, `clockWipe`, `none` (corte seco).
**2 timings:** `linearTiming` (controle exato), `springTiming` (físico).

## Spring (movimento físico)

```tsx
const scale = spring({
  fps,
  frame,
  config: { damping: 200, mass: 1, stiffness: 100, overshootClamping: false }
});
// damping ↑ = menos bounce | stiffness ↑ = mais rápido | mass ↑ = mais lento
```

**Presets que uso:**
- **Snap-in agressivo:** `{damping: 12, stiffness: 200}` — entrada de logo
- **Suave premium:** `{damping: 30, stiffness: 80}` — texto headline
- **Bounce dramático:** `{damping: 8, stiffness: 150}` — CTA chamativo
- **Clamped (sem overshoot):** `{damping: 200, overshootClamping: true}` — corporate

## Interpolate (mapeamento linear)

```tsx
// Fade in 0-15f, hold 15-75f, fade out 75-90f
const opacity = interpolate(frame, [0, 15, 75, 90], [0, 1, 1, 0]);

// Slide up com clamp
const y = interpolate(frame, [0, 20], [100, 0], {
  extrapolateLeft: "clamp",
  extrapolateRight: "clamp",
  easing: Easing.out(Easing.cubic),
});
```

**Easing comuns:**
- `Easing.linear` — robótico
- `Easing.ease` — default suave
- `Easing.bezier(.4,0,.2,1)` — material design (uso em 80% dos casos)
- `Easing.bezier(.68,-0.55,.27,1.55)` — bounce
- `Easing.out(Easing.cubic)` — desaceleração natural
- `Easing.inOut(Easing.quad)` — entrada+saída balanceada

## Audio (`<Audio>` + `<Video>`)

```tsx
<Audio
  src={staticFile("/music/track.mp3")}
  volume={(f) => interpolate(f, [0, 30, 270, 300], [0, 1, 1, 0])}
  startFrom={0}        // skip primeiros N frames do source
  endAt={300}           // termina em frame N
/>
<OffthreadVideo
  src={staticFile("/footage/hero.mp4")}
  muted               // pra usar audio separado
  playbackRate={1.0}
/>
```

**Audio reactive:** use `@remotion/media-utils` (`visualizeAudio`, `getAudioData`) para waveforms e barras de frequência sincronizadas.

## Captions (`@remotion/captions`)

```bash
npx remotion install whisper-cpp  # transcrição local grátis
```

```tsx
import { parseSrt, serializeSrt } from "@remotion/captions";
import { TikTokStyleCaption } from "./TikTokStyleCaption";

const captions = parseSrt({ input: srtContent });

<Sequence from={c.startInSeconds * fps} durationInFrames={(c.endInSeconds - c.startInSeconds) * fps}>
  <TikTokStyleCaption text={c.text} />
</Sequence>
```

**Estilo TikTok (palavra-por-palavra com pop):**
- Font weight 900, size 60-80px
- Stroke preto 8px + shadow
- Cada palavra com `spring` scale 0→1 + slight rotation
- Highlight word atual em cor de marca

## Lambda cloud render

```bash
npx remotion lambda functions deploy
npx remotion lambda sites create src/index.ts --site-name=launch-video
```

```ts
import { renderMediaOnLambda } from "@remotion/lambda/client";

const { bucketName, renderId } = await renderMediaOnLambda({
  region: "us-east-1",
  functionName: "remotion-render-4-0-XXX",
  serveUrl: "https://remotionlambda-...s3.amazonaws.com/sites/launch-video/index.html",
  composition: "LaunchVideo",
  inputProps: { product: "QBizu", headline: "..." },
  codec: "h264",
  framesPerLambda: 80,  // chunks paralelos
  maxRetries: 3,
});
```

**Performance:** vídeo 1080p/30fps/60s em ~20s usando 8 Lambdas em paralelo. Custo ~$0.02 por render.

## Composition root (template padrão MSE)

```tsx
// src/Root.tsx
import { Composition } from "remotion";
import { LaunchVideo, launchVideoSchema } from "./compositions/LaunchVideo";

export const RemotionRoot = () => (
  <>
    <Composition
      id="LaunchVideo"
      component={LaunchVideo}
      durationInFrames={450}  // 15s @ 30fps
      fps={30}
      width={1920}
      height={1080}
      schema={launchVideoSchema}  // Zod → editável no Studio
      defaultProps={{ product: "QBizu", headline: "Aprove na Petrobras com IA" }}
    />
    <Composition id="Reel" component={Reel} durationInFrames={900} fps={30} width={1080} height={1920} />
    <Composition id="Square" component={Square} durationInFrames={450} fps={30} width={1080} height={1080} />
  </>
);
```

## Receitas prontas pra marketing

### Hook visual nos 3 primeiros segundos (0-90 frames @ 30fps)

```tsx
const frame = useCurrentFrame();
const punchIn = spring({fps, frame, config:{damping:10, stiffness:200}});
const blurAmount = interpolate(frame, [0, 15], [20, 0], {extrapolateRight:"clamp"});

<div style={{
  transform: `scale(${punchIn})`,
  filter: `blur(${blurAmount}px)`,
  fontSize: 120,
  fontWeight: 900,
}}>
  PARE
</div>
```

### Stagger automático (cascata sem calcular delays)

```tsx
{items.map((item, i) => {
  const localFrame = frame - i * 6;  // 6 frames entre cada
  const y = interpolate(localFrame, [0, 20], [50, 0], {extrapolateLeft:"clamp", extrapolateRight:"clamp"});
  const opacity = interpolate(localFrame, [0, 20], [0, 1], {extrapolateLeft:"clamp", extrapolateRight:"clamp"});
  return <div key={i} style={{transform:`translateY(${y}px)`, opacity}}>{item}</div>;
})}
```

### Counter animado (social proof)

```tsx
const value = Math.floor(spring({fps, frame, config:{damping:30}}) * 50000);
// formata como "50.000+"
```

### Ken Burns (zoom + pan lento em foto)

```tsx
const scale = interpolate(frame, [0, durationInFrames], [1, 1.2]);
const x = interpolate(frame, [0, durationInFrames], [0, -50]);
<Img src={photo} style={{transform:`scale(${scale}) translateX(${x}px)`, width:"100%", height:"100%", objectFit:"cover"}} />
```

## CLI essencial

```bash
npm run dev                                  # Remotion Studio (preview)
npx remotion render LaunchVideo out/v.mp4    # render local
npx remotion render LaunchVideo out/v.gif --codec=gif --image-format=png
npx remotion render LaunchVideo out/v.webm --codec=vp8
npx remotion still LaunchVideo out/thumb.png --frame=45  # thumbnail
npx remotion compositions                    # listar todas
npx remotion benchmark                       # perf profiling
```

## Regras inegociáveis (@web-designer)

1. **Sempre `useCurrentFrame()` — NUNCA CSS transitions** (rendering quebra)
2. **Sempre `OffthreadVideo` em vez de `<Video>`** quando possível (menos memória)
3. **Sempre `<Img>` em vez de `<img>`** (pre-load garantido)
4. **Sempre `Zod schema`** em props pra ter editor visual no Studio
5. **Sempre testar em mobile via Remotion Studio antes de render final**
6. **Sempre `framesPerLambda: 80`** em Lambda (sweet spot custo/tempo)
7. **Nunca random sem seed** — quebra determinismo
8. **Nunca fontes do sistema** — usar `@remotion/google-fonts` ou load explícito

## Output canônico

- **MP4 H.264** — padrão universal (Meta Ads, YouTube)
- **MP4 H.265** — só se cliente pediu (40% menor mas menos compatível)
- **WebM VP9** — web otimizado (autoplay sem barulho)
- **GIF** — preview/email (max 6s, 720p, 15fps)
- **PNG sequence** — handoff pra after effects

## Anti-patterns (NÃO faça)

❌ `setTimeout`/`setInterval` — não existe runtime em render
❌ `requestAnimationFrame` — mesma coisa
❌ `useState` pra animação — use `useCurrentFrame`
❌ CSS `transition`/`animation` — rendering pulará frames
❌ Fonts via `<link>` HTML — use `loadFont()` do `@remotion/google-fonts`
❌ `fetch` direto sem `delayRender` — frame renderiza antes da resposta

## Referências

- Docs: https://www.remotion.dev/docs
- Skills oficiais: `npx skills add remotion-dev/skills`
- Templates: https://www.remotion.dev/templates
- Recipes: https://www.remotion.dev/docs/recipes
