/remotion-best-practices
Use este skill sempre que estiver escrevendo uma composição Remotion — vídeos de demonstração animados, walkthroughs de produtos, submissões para hackathons, apresentações narradas — qualquer coisa renderizada em MP4 via npx remotion render.
O skill agrupa duas camadas de conhecimento:
- Fundamentos do Remotion — os arquivos de regras upstream mantidos pela equipe Remotion em
github.com/remotion-dev/skills(composições, animações, fontes, áudio, transições, FFmpeg, legendas, etc.). - Regras de produção de vídeos de demonstração — lições capturadas de um longo ciclo de iteração construindo o demo do hackathon vskill / Skill Studio. Estas são as regras que, quando quebradas, produzem uma "apresentação de slides" em vez de um walkthrough de produto convincente.
Leia ambas as camadas antes de criar.
Escopo e aplicabilidade
As regras da Camada 2 abaixo foram derivadas de um projeto específico: o demo do hackathon vskill / Skill Studio (hackathon Anthropic / Claude Code "Built with Opus", abril de 2026). Elas refletem a aparência daquele produto — cromo do Studio com cabeçalho de breadcrumb, árvore da barra lateral, páginas escuras do verified-skill.com com fontes mono, cenas de terminal, uma tese editorial "Inter é porcaria de IA, serifa distinta é excelência".
Não aplique estas regras literalmente em demos não relacionados. Um aplicativo móvel de consumo, um painel financeiro, um jogo ou uma apresentação B2B SaaS terá sua própria linguagem visual, seu próprio ritmo e suas próprias expectativas de público. Um fluxo Salvar-depois-Publicar, uma página
verified-skill.com/queue, ou uma barra lateral do Studio com contagens PROJETO/PESSOAL/PLUGINS é conteúdo, não ofício.Use esta camada como referência para a técnica subjacente: o padrão de zoom de câmera, a disciplina de direcionamento do cursor, o retângulo de realce ajustado ao conteúdo, as transições de estado no local, o acoplamento voz/script.ts, o pipeline de renderização+reforço de áudio — aqueles generalizam. As constantes exatas (zoom de 1,72×, centro do botão x=1488, pílula de versão v1.0.0 → v1.0.1, atribuição "Padrões Tier-1 · LLM Tier-2 · Socket") são específicas do Skill Studio — traduza, não copie.
Camada 1 — Fundamentos do Remotion
Espelha o skill upstream remotion-best-practices em https://github.com/remotion-dev/skills/blob/HEAD/skills/remotion/SKILL.md.
Configuração de novo projeto
Quando estiver em uma pasta vazia ou espaço de trabalho sem um projeto Remotion existente, crie um usando:
npx create-video@latest --yes --blank --no-tailwind my-video
Iniciando a pré-visualização
Inicie o Remotion Studio para pré-visualizar um vídeo. O HMR do Studio recarrega ao vivo conforme os arquivos mudam — você NÃO precisa de um mecanismo preview_start separado, e Bash run_in_background é a maneira correta de mantê-lo ativo entre edições.
npx remotion studio --port=3030
Renderização
# O ponto de entrada deve ser o arquivo que chama registerRoot() (geralmente src/remotion/index.ts)
npx remotion render src/remotion/index.ts <CompositionId> out/video.mp4 --concurrency=8 --log=info
Pegadinhas comuns:
- Passar
Root.tsxcomo entrada → erro: "este arquivo não contém registerRoot". Useindex.ts. TransitionSeriesfaz introspecção de props em filhos diretos; não envolva filhos em<React.Fragment>. UseflatMapretornando um array plano de elementos<TransitionSeries.Sequence>e<TransitionSeries.Transition>.interpolate(frame, [a, b], …)requera < bestritamente. Se você derivarbde constantes, verifique a sanidade no momento do design do orçamento da cena — o Remotion lança "inputRange must be strictly monotonically increasing" no primeiro quadro avaliado e toda a composição falha ao carregar.
Verificação de renderização de um quadro
npx remotion still <composition-id> --scale=0.25 --frame=30
Tópicos cobertos pelos arquivos de regras upstream
(Carregue sob demanda do repositório de skills upstream — github.com/remotion-dev/skills/tree/HEAD/skills/remotion/rules/.)
compositions.md— Definindo composições, stills, pastas, props padrão, metadados dinâmicosanimations.md—interpolate,spring, easing, matemática baseada em quadrostransitions.md—@remotion/transitions(fade, slide, wipe), como encadeá-los dentro deTransitionSeriesassets.md—staticFile(),Img,Audio,Video, carregamento de fontesfonts.md—@remotion/google-fontse registro de fontes locaisaudio.md— Importando, cortando, volume, velocidade, pitchcaptions.md,subtitles.md— Trilhas de legenda e sincroniaffmpeg.md— Corte, concat, operações de áudio via shell-out FFmpegsilence-detection.md,extract-frames.md,get-audio-duration.md,get-video-duration.md— Utilitários do Mediabunnycharts.md,gifs.md,light-leaks.md,3d.md— Receitas de renderização especializadas
Camada 2 — Regras de produção de vídeos de demonstração
Estas são as regras conquistadas ao longo de um longo ciclo de iteração. Trate-as como padrões, não como polimento opcional — a maioria delas veio de feedback "isto parece estranho, corrija" que levou várias rodadas para ser resolvido.
A. Fidelidade à referência
A1. Sempre puxe a referência real
Se o usuário disser "faça parecer com 2:43 deste vídeo do YouTube," extraia o quadro e estude-o. Não aproxime de memória.
SOURCE="/Users/antonabyzov/Movies/.../Source.mov"
DEST_DIR=".specweave/.../assets/keyframes"
for t in 102 105 108 110 112; do
ffmpeg -y -ss "$t" -i "$SOURCE" -frames:v 1 -q:v 2 "$DEST_DIR/at-${t}s.jpg" -loglevel error
done
Em seguida, Leia cada JPG e projete a partir do que está realmente na tela — tipografia, rótulos de botões exatos, cores de selos, layout da árvore da barra lateral, posicionamento da entrada de pesquisa, valores de contagem (por exemplo, PROJETO (1), PESSOAL (0 de 12), PLUGINS (0 de 50), DISPONÍVEL (62)).
A2. Use logotipos e ícones reais, não aproximações
- Selo-sino
skill-studio-logo.png— copie em cada cena do Studio como<Img src={staticFile("...")} />. Não renderize um glifo✷e chame-o de logotipo. - Ícones de provedores — busque o SVG/PNG real para Claude, Anthropic, OpenAI, OpenRouter, Ollama, LM Studio (por exemplo, de
lobehub/static-png). Não substitua por emoji. - Mascotes — desenhe com divs estilizadas para corresponder à forma exatamente. O mascote do Claude Code é um corpo pêssego
#e08160com dois olhos quadrados, duas protuberâncias laterais a meio do corpo e dois pares de pernas embaixo (▪ ▪ ▪ ▪). Não é arte ASCII. - Cromo da janela do aplicativo — ao mostrar um site em um "navegador Chrome", renderize um quadro de navegador Chrome real: cantos arredondados, pontos de sinalização, nav ‹ › ↻, barra de URL com cadeado bloqueado e uma URL real (
localhost:3000/hero, sem espaços extras, sem ponto médio).
A3. Corresponda aos layouts de referência do YouTube pixel por pixel
Antes de redesenhar uma cena a partir da imaginação, liste os elementos visíveis no quadro de referência e verifique cada um em relação à sua saída:
- Texto do banner — redação exata (
Enviar habilidades para verificação, nãoEnviar uma Habilidade) - Ordem das abas —
Visão Geral · Editar · Testes · Executar · Gatilho · Versões - Selos de confiança —
T1 NÃO VARRIDO,Varredura de Segurança —,Editor Confiável - Entrada de filtro — sempre acima de
DISPONÍVELna barra lateral - Contagens — mantenha-as consistentes entre os slides (
PESSOAL (0 de 12)em todos os lugares, não(11)em um slide e(0 de 12)em outro) - Controles do lado direito do cabeçalho (nesta ordem):
🔍 Encontrar habilidades [⌘K]·+ Nova Habilidade·● Seletor de modelo·🔔 sino
B. Zoom de câmera
B1. O zoom de câmera é em tela cheia, não em escala de seção
Não dimensione um único painel dentro do cromo. Envolva o cromo inteiro (barra superior + corpo) em uma div de transformação e dimensione + traduza isso:
<div
style={{
width: "100%",
height: "100%",
transform: `translate(${cameraTx}px, ${cameraTy}px) scale(${cameraScale})`,
transformOrigin: "50% 50%",
willChange: "transform",
}}
>
{/* BARRA SUPERIOR + CORPO */}
</div>
Os SVGs de cursor + ondulação de clique vão dentro deste wrapper para que eles sejam dimensionados com o cromo e permaneçam colados ao seu alvo.
B2. Clique primeiro, depois aplique o zoom
O visualizador precisa ver o alvo do clique no contexto, então ser transportado para a consequência. Ordenação:
quadro 130 cursor se aproxima do botão
quadro 174 ondulação de clique
quadro 184 botão mostra "Executando…"
quadro 188 zoom de câmera começa (1.0 → 1.55+ em ~30 quadros)
quadro 220+ zoom mantido — cascata / resultados / revelação de rolagem acontece aqui
Aplicar zoom primeiro e depois clicar parece um slide de apresentação. Clicar primeiro e depois aplicar zoom parece que o usuário realizou a ação e a câmera seguiu.
B3. Escolha uma escala que realmente empurre o cromo para fora da tela
Um modesto 1,1× mal muda alguma coisa. Para "a barra superior sair do topo da tela," você precisa de ≥ 1,5× combinado com uma tradução que traga o ponto focal para o centro da tela. Calcule o alvo ≥ (metadeAlturaTela) / (distância do ponto focal à barra superior) — para uma linha em y=540 e uma barra superior de 64 px, isso é ≥ ~1,5×. Use 1,55–1,85× como padrões para "preencher a viewport."
C. Alvos de clique do cursor
C1. Acerte o elemento real
Quando o cursor pousa no botão errado (+ Nova Habilidade vs a pílula do seletor de modelo), o visualizador pensa que a demonstração está quebrada. Re-derive o alvo do layout cada vez — não adivinhe valores de pixel.
Para uma faixa de controles alinhada à direita com padding: "0 22px":
// Borda direita → 22 pad → sino (32) → 14 → modelo (~290) → 14 → Nova Habilidade (~120) → 14 → Encontrar habilidades (~150)
NOVA_HABILIDADE_PILL_X = 1920 - 22 - 32 - 14 - 290 - 14 - 60 // = 1488 (centro do botão)
ENCONTRAR_PILL_X = 1920 - 22 - 32 - 14 - 290 - 14 - 120 - 14 - 75 // = 1339
Depois de ter a constante, use-a tanto na interpolação de aproximação do cursor quanto na interpolação de saída do cursor para que a ondulação do clique caia exatamente na pílula, não 200 px à direita dela.
C2. Destaque o alvo à medida que o cursor se aproxima
Adicione uma prop *Ativo em componentes de cabeçalho compartilhados (por exemplo, findAtivo, novaHabilidadeAtivo em StudioHeader) que a cena do cursor ativa durante a janela de aproximação + clique. O botão recebe:
- Escala de 1,08×
- Anel índigo ou roxo suave via
box-shadow: 0 0 0 4px rgba(99,102,241,0.30) transition: all 0.15s ease
D. Realces e retângulos
D1. Retângulos de realce são da largura do conteúdo, não da linha inteira
Quando o usuário quiser um retângulo vermelho em torno de duas linhas do terminal, não envolva a coluna flex pai — isso se estende pela linha. Use:
<div
style={{
display: "inline-flex",
flexDirection: "column",
alignSelf: "flex-start",
width: "fit-content",
border: "2px solid #dc2626",
borderRadius: 6,
padding: "10px 16px",
backgroundColor: "transparent",
}}
>
{/* as duas linhas, nada mais */}
</div>
Qualquer coisa que deva estar fora do retângulo (por exemplo, a terceira linha "Gerando componente…") deve ser um irmão, não um filho.
D2. Anotações: prefira retângulos a elipses
Um traço de retângulo estilo desenhado à mão em torno de uma linha parece "marca-texto na tela", que é o que a maioria dos usuários quer dizer com "destacar isto". Uma elipse pode parecer decorativa.
<svg viewBox="0 0 1000 100" preserveAspectRatio="none">
<rect
x="6" y="6" width="988" height="88" rx="6" ry="6"
fill="none"
stroke="#ea580c"
strokeWidth="3.6"
strokeDasharray="2160"
strokeDashoffset={2160 * (1 - progress)}
/>
</svg>
D3. Use laranja (#ea580c) para "isto é o que há de novo" e vermelho (#dc2626) para "isto é o bug"
A mesma demonstração pode carregar ambos. Não misture.
E. Padrões de layout para cromo de produto
E1. O cabeçalho do Studio é um único componente compartilhado
Use um StudioHeader.tsx com este layout canônico, chamado de cada cena do Studio:
- Esquerda: imagem do logotipo (PNG 40 × 40) + marca "Skill Studio" + breadcrumb
[Criação|Disponível] / [escopo] / [pasta] / [habilidade] - Direita: 🔍 Encontrar habilidades
[⌘K]· ✦ + Nova Habilidade · ● Seletor de modelo · 🔔 Sino
Passe breadcrumb, bellBadge, findAtivo, novaHabilidadeAtivo como props. O cabeçalho de cada cena é então estável em pixels.
E2. A barra lateral tem uma entrada de filtro constante acima de DISPONÍVEL
Toda barra lateral do Studio — Navegar, Atualizar, AuthorEvals, ConsumeInstall, AuthorEditAndPublish — recebe a mesma entrada Filtrar habilidades… acima da árvore DISPONÍVEL. Pré-preencha com a consulta do contexto (frontend-design) em slides onde o usuário já pesquisou.
E3. Larguras e tipografia da barra lateral
- Largura: 400 px (ou 460 px em slides com árvores profundamente aninhadas)
- Preenchimento externo: 24–30 px
- Cabeçalhos de grupos (
DISPONÍVEL,CRIAÇÃO): 18–19 pt, espaçamento entre letras 1.6, peso 700 - Sub-cabeçalhos (
HABILIDADES,.CLAUDE): 15–16 pt, espaçamento entre letras 1.4 - Texto da linha: 17–19 pt
- Pílula de versão: 13–14 pt mono com borda de 1 px, preenchimento 3/10
- Lacunas verticais: 12–14 px entre seções, 22–36 px acima dos cabeçalhos de seção
Barras laterais estreitas e densas parecem painéis de Configurações. Barras laterais amplas e abertas parecem UI de produto real.
F. Transições de estado no local
F1. Não deslize para a esquerda entre cenas que devem parecer uma única tela
Se "clicar em Instalar → árvore atualiza com nova habilidade" deve ser lido como uma interação contínua:
- Defina
transitionType: nullna próxima cena ou mescle as duas cenas em uma - Mantenha o cromo idêntico entre as cenas
- Anime o elemento que muda (virada de contador, rotação de chevron, deslize de linha) — não faça um fade completo
F2. Destaque novos itens fortemente
Um fundo pêssego + anel laranja sólido de 2 px + sombra projetada + pílula de chamada ✓ Acabou de instalar é a intensidade certa para "isto acabou de chegar". Uma tonalidade de fundo sutil parece estado padrão e o visualizador não percebe.
backgroundColor: "#fff5ee",
boxShadow: `0 0 0 2px ${LARANJA}, 0 8px 22px rgba(234,88,12,0.22)`,
F3. Viradas de contador: halo pulsante + rotação de chevron
Quando uma contagem muda (PROJETO (0) → (1)):
- Gire o chevron
▸ → ▼(transição de 200 ms) - Renderize um halo laranja breve atrás da contagem: opacidade
0,45 → 0, escala0,4 → 2,2ao longo de 18 quadros - Deslize as novas linhas filhas de
translateY: -12 → 0ao longo de 24 quadros
G. Padrões de edição do Editor / SKILL.md
G1. Substitua, nunca remova, campos obrigatórios
Uma habilidade deve sempre ter uma description. Para atualizar a descrição: risque a linha primitiva em vermelho, deslize a nova descrição para dentro em um momento natural (por exemplo, depois que o usuário clicar em "Salvar").
descriçãoAntiga = (exibido como texto riscado por ~24 quadros, depois deslizado para fora)
descriçãoNova = (deslizado de translateX(30) → 0, virado com fade em 0.7 de opacidade inicial)
G2. O painel de arquivos mostra a árvore aplicada vs. encenada
O editor real do Studio lista apenas SKILL.md (e talvez icon.png, meta.json). Para a demonstração, adicione algumas linhas de teste que serão removidas da cena de renderização final, ou use uma prop de cena que controla a exibição da árvore de arquivos. Um visualizador que já usa o Studio sabe como é uma árvore de arquivos real — se a demonstração mostrar 5 arquivos quando o produto real mostra 3, a demonstração perde credibilidade.
H. Áudio e locução
H1. Regeneração de locução substitui, não duplica
O script é a única fonte da verdade. Quando a locução for regenerada, não mantenha o áudio antigo. Versione o áudio como src/remotion/audio/generated/v1-clean.mp3 (não v1.mp3 + v1-bg-removed.mp3, que se deteriora em referências obsoletas).
Após a regeneração, limpe manualmente a pasta de áudio para arquivos de locução órfãos. O Remotion não falha em arquivos não referenciados, mas eles poluem a árvore de assets e confundem o agente.
H2. Normalização, não reforço duplo
Um loop comum de feedback: "o áudio está baixo, aumente o volume" → "o áudio está muito baixo, execute ganho FFmpeg".
Reforço duplo é quando o áudio é normalizado duas vezes — primeiro pelo volume da faixa do Remotion, depois por um filtro FFmpeg volume=2.0. O resultado é distorção e picos cortados.
Fluxo correto:
- Normalize o arquivo de áudio:
ffmpeg -i in.mp3 -filter:a loudnorm -c:a libmp3lame -b:a 192k out.mp3 - Use os parâmetros de volume do Remotion (
volume) apenas para esmaecimentos de entrada/saída, não para ganho de corpo - Se o arquivo normalizado ainda estiver muito baixo, re-normalize para um LUFS alvo mais alto ou substitua o arquivo fonte
Regra: um arquivo de áudio, uma passagem de normalização.
H3. Sincronização voz-ação por cena
Cada cena que tem locução precisa de seus próprios marcadores de tempo. *Não compartilhe tempos entre cenas.
// Ruim — o mesmo script usado em cenas diferentes sem compensação de deslocamento
const SCRIPT_A = [início: 0, duração: 4000] // cena X
const SCRIPT_B = [início: 0, duração: 4000] // cena Y (erro: a cena Y começa mais tarde)
// Bom — matemática em script temporizado por cena
const CENA_A = { duração: 100 } // quadros
const CENA_B = { duração: 90 } // quadros
O agente pode pular a verificação manual se você aplicar a regra: cada cena com áudio calcula seus próprios início DO ÁUDIO e início da CENA em vez de copiar de cenas adjacentes.
H4. Pular silêncio em clipes de áudio futuros (ferramenta de edição)
Se você tiver um clipe de áudio de voz onde o locutor faz uma longa pausa no meio, pule o silêncio para manter o ritmo do vídeo:
ffmpeg -i input.wav -filter:a silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-30dB output.wav
Apenas faça isso uma vez. Refazer em um arquivo já processado produz artefatos.
I. Kit de publicação no YouTube
Quando o vídeo estiver renderizado, prepare estes assets para que o usuário possa publicar imediatamente.
I1. Capítulos
Um arquivo de descrição com timestamps da forma:
0:00 O que construímos
0:15 Criando sua primeira habilidade
0:37 Testando com Claude Code
1:04 O padrão de publicação
1:28 Conclusão e próximos passos
Os capítulos devem corresponder a marcos reais no script/quadros.
I2. Descrição
Um parágrafo de 3-5 linhas resumindo o que o vídeo mostra e por que é interessante. Inclua um CTA para baixar/experimentar. Mantenha-o limpo — descrições do YouTube com 3 quebras de linha e uma linha de link são mais escaneáveis do que parágrafos densos.
I3. Miniatura
Uma miniatura personalizada (1280×720 PNG) que mostra o produto em ação com um título em negrito sobreposto. Carregue-a separadamente no YouTube Studio — o YouTube prefere arquivos PNG para miniaturas.
I4. Hashtags
#Remotion #ReactJS #VideoGeneration #DevTools #Hackathon
Use 3-5 hashtags. A primeira (#Remotion) é a mais importante para descoberta.
Como usar este skill
- Leia ambas as camadas antes de criar — especialmente as regras de produção (Camada 2). Pule a leitura por sua conta e risco.
- Use a Camada 1 para mecânica — scaffolding, API de composição, guias de renderização.
- Use a Camada 2 para qualidade — posicionamento de câmera, realces, correção de áudio, consistência de layout, prontidão para publicação.
- Adapte as regras da Camada 2 ao seu projeto — as constantes e nomes de componentes acima são do Skill Studio; substitua-os pelos seus.
- Use como lista de verificação, não como dogma — se o seu vídeo não tem locução (H), pule essa seção. Se você não está publicando no YouTube (I), pule.
Resolução de problemas
| Sintoma | Causa provável | Correção |
|---|---|---|
| "inputRange deve ser estritamente monotônico" | interpolate com intervalo a ≥ b | Verifique as constantes; certifique-se de que a < b |
| Cursor erra o alvo em 200px | O layout mudou, a constante não | Recalcule a partir do layout renderizado; teste com uma still |
| Cena congelada / zoom colado | zoomState nunca sai de true | Verifique a lógica de temporização no componente da cena |
| Áudio distorcido | Reforço duplo (normalizado duas vezes) | Use um arquivo fonte; normalize uma vez |
| Vídeo parece uma apresentação de slides | Sem zoom de câmera, sem animação de estado | Adicione zoom de câmera (B) e transições no local (F) |
| Miniatura do YouTube rejeitada | Formato ou tamanho incorreto | Use 1280×720 PNG, < 2 MB |