---
name: video-render-pipeline
description: Pipeline completo do @web-designer — briefing → composição → preview → render multi-formato → entrega. Inclui presets de export por plataforma, validações, troubleshooting.
owner: "@web-designer"
version: 1.0
tags: [video, render, pipeline, ffmpeg, lambda, export, marketing]
---

# Skill: Video Render Pipeline

## Pipeline canônico (7 etapas)

```
1. RECEIVE  → briefing (TheBoss) + copy (Claudinho) + brandbook (Picasso) + assets
2. PLAN     → storyboard textual (cena 1 = X, cena 2 = Y, transições, duração)
3. BUILD    → composição em Remotion OR HyperFrames
4. PREVIEW  → Studio (Remotion) ou preview (HyperFrames) — iterar
5. RENDER   → MP4 master 1080p H.264
6. DERIVE   → variações por aspect (9:16, 1:1, 16:9) + por plataforma
7. DELIVER  → drop em pasta de entrega + metadata (duração, hash, formato)
```

## Receita por output

### Master MP4 1080p (universal)

```bash
# Remotion
npx remotion render LaunchVideo out/master-1080p.mp4 \
  --codec=h264 \
  --crf=18 \
  --pixel-format=yuv420p \
  --color-space=bt709

# HyperFrames
npx hyperframes render --quality high --width 1920 --height 1080
```

### Reels/TikTok 1080x1920

```bash
npx remotion render Reel out/reel.mp4 \
  --codec=h264 \
  --crf=20 \
  --concurrency=8
```

### Square 1080x1080 (feed)

```bash
npx remotion render Square out/feed.mp4 --codec=h264 --crf=20
```

### GIF preview (email/landing)

```bash
npx remotion render LaunchVideo out/preview.gif \
  --codec=gif \
  --image-format=png \
  --scale=0.5  # 540p pra ficar leve
# Max recomendado: 6s, 720p, 15fps, <5MB
```

### WebM (web autoplay)

```bash
npx remotion render LaunchVideo out/web.webm \
  --codec=vp9 \
  --crf=30
```

## FFmpeg pós-render (otimizações)

```bash
# Comprimir MP4 sem perda visual notável
ffmpeg -i master.mp4 -c:v libx264 -crf 23 -preset slow -c:a aac -b:a 128k out.mp4

# Crop pra reels (de 1920x1080 → 1080x1920 centralizado)
ffmpeg -i landscape.mp4 -vf "crop=ih*9/16:ih,scale=1080:1920" reel.mp4

# Pad pra reels (de 1920x1080 → 1080x1920 com letterbox)
ffmpeg -i landscape.mp4 -vf "scale=1080:608,pad=1080:1920:0:656:black" reel-pad.mp4

# Add áudio externo + sync
ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a aac -shortest final.mp4

# Watermark (logo canto)
ffmpeg -i video.mp4 -i logo.png \
  -filter_complex "[1]scale=120:-1[wm];[0][wm]overlay=W-w-30:30" \
  watermarked.mp4

# Loop seamless (vídeo de fundo)
ffmpeg -stream_loop 3 -i clip.mp4 -c copy loop.mp4

# Thumbnail (frame específico)
ffmpeg -ss 00:00:02 -i video.mp4 -frames:v 1 -q:v 2 thumb.jpg

# Speed up/slow down (sem mudar audio pitch)
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" -filter:a "atempo=2.0" fast.mp4
```

## Lambda render (volume)

Quando @web-designer precisa renderizar **N variações** (ex: 30 ads diferentes):

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

const variations = [
  { headline: "Aprove na Petrobras", color: "blue" },
  { headline: "10.000 já aprovaram", color: "red" },
  // ... mais 28
];

await Promise.all(variations.map(props =>
  renderMediaOnLambda({
    region: "us-east-1",
    functionName: "remotion-render-4-0-XXX",
    serveUrl: SITE_URL,
    composition: "AdVideo",
    inputProps: props,
    codec: "h264",
    framesPerLambda: 80,
  })
));
```

**Custo:** ~$0.02 por render 30s/1080p. 30 vídeos = $0.60.

## Presets por plataforma (entrega final)

| Plataforma | Codec | Container | Bitrate | Audio | Notes |
|---|---|---|---|---|---|
| Meta Ads (Feed) | H.264 | MP4 | 4-8 Mbps | AAC 128k | Max 4GB, max 240s |
| Meta Ads (Reels) | H.264 | MP4 | 5-10 Mbps | AAC 128k | 9:16, max 90s |
| YouTube (Standard) | H.264 high | MP4 | 8-12 Mbps | AAC 192k stereo | 16:9, BT.709 |
| YouTube Shorts | H.264 | MP4 | 5-8 Mbps | AAC 128k | 9:16, max 60s |
| TikTok | H.264 | MP4 | 4-8 Mbps | AAC 128k | 9:16, max 180s |
| Instagram Feed | H.264 | MP4 | 3-5 Mbps | AAC 128k | 1:1 ou 4:5 |
| Instagram Reels | H.264 | MP4 | 5-10 Mbps | AAC 128k | 9:16 |
| LinkedIn | H.264 | MP4 | 8-15 Mbps | AAC 192k | 16:9 ou 1:1 |
| Email embed | H.264 ou GIF | MP4/GIF | <5MB total | none | 6s loop GIF |
| Landing page | WebM VP9 + MP4 fallback | webm+mp4 | 3-5 Mbps | none ou muted | autoplay |

## Estrutura de entrega (drop folder)

```
out/{project}-{date}/
├── master-1080p.mp4        # source de verdade
├── reels-1080x1920.mp4     # IG/TikTok/YT Shorts
├── square-1080.mp4          # Feed IG/FB
├── youtube-1920x1080.mp4    # YouTube
├── preview.gif              # email/landing
├── thumb.png                # capa estática (frame congelado)
├── thumb-1280x720.jpg       # YouTube thumb (delegar pro Picasso pra arte)
└── metadata.json            # {duracao, fps, hash, size, paths}
```

## metadata.json (template)

```json
{
  "project": "qbizu-petro-launch",
  "version": "1.0",
  "rendered_at": "2026-05-17T13:00:00Z",
  "agent": "@web-designer",
  "stack": "remotion@4.0.x",
  "outputs": {
    "master": {
      "path": "out/qbizu-petro-launch/master-1080p.mp4",
      "duration_s": 30,
      "width": 1920,
      "height": 1080,
      "fps": 30,
      "size_mb": 18.4,
      "sha256": "..."
    },
    "reels": { "...": "..." }
  },
  "source": {
    "composition": "LaunchVideo",
    "input_props": {"...": "..."},
    "copy_owner": "@copywriter",
    "brand_owner": "@brand-director"
  }
}
```

## Validações pré-entrega

Antes de avisar TheBoss que terminou:

- [ ] Master 1080p renderizou sem erros
- [ ] Áudio audível e sincronizado (não corta no fim)
- [ ] Texto legível mesmo em 320px (zoom out mobile)
- [ ] Brandbook respeitado (cores, fonte)
- [ ] Hook resolve em ≤3s (revisar frame 0-90)
- [ ] CTA aparece em ≤2s antes do fim
- [ ] Aspect ratio correto pra cada output
- [ ] Filename segue padrão `{slug}-{aspect}-{duration}s.mp4`
- [ ] metadata.json gerado e válido
- [ ] Preview GIF abre em browser sem travar

## Troubleshooting

| Sintoma | Causa provável | Fix |
|---|---|---|
| Render trava em frame X | Asset externo travado (fetch sem `delayRender`) | Adicionar `delayRender()/continueRender()` |
| Áudio fora de sync | `<Audio startFrom>` errado | Validar offset em frames |
| Texto borrado no render | Font não carregada antes do render | `@remotion/google-fonts` + `waitUntilDone()` |
| GIF >50MB | Muitos frames + alta resolução | `--scale=0.5` + `--fps=15` |
| Lambda timeout | `framesPerLambda` muito alto | Baixar pra 40-60 |
| Cor mudou após render | Color space não definido | `--color-space=bt709 --pixel-format=yuv420p` |
| Mobile mostra letterbox preto | Aspect ratio errado | Renderizar 9:16 nativo, não cropar |
| Áudio com clipping | Master volume >1.0 | Usar `volume` function com max 0.95 |
| Render lento | `concurrency` baixo | `--concurrency=8` em CPUs modernas |

## Handoff pro @web-designer/@paid-traffic

Após entrega, @web-designer comunica:
```
Render finalizado.
Master: out/{slug}/master-1080p.mp4
Variações: reels/square/youtube em out/{slug}/
Thumb: out/{slug}/thumb.png (passar pro @brand-director pra arte final se YouTube)
Metadata: out/{slug}/metadata.json
@paid-traffic — está pronto pra rodar em ads
@web-designer — versão WebM em out/{slug}/web.webm pra landing
```

## CI/CD (render automatizado)

```yaml
# .github/workflows/render-video.yml
name: Render marketing video
on:
  push:
    paths: ["src/compositions/**", "props/*.json"]
jobs:
  render:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '22' }
      - run: npm ci
      - run: npx remotion render LaunchVideo out/master.mp4
      - uses: actions/upload-artifact@v4
        with: { name: video, path: out/ }
```

## Backup obrigatório

Após render final:
1. Upload master pro Google Drive da campanha
2. Tag no metadata.json com hash do commit
3. Manter source `src/` versionado em git (composição)
4. NUNCA commitar `out/` (gitignore)

## Referências

- Remotion CLI: https://www.remotion.dev/docs/cli
- FFmpeg cookbook: https://trac.ffmpeg.org/wiki
- Meta video specs: https://www.facebook.com/business/help/video-spec
