O que Remotion2.0 faz?
Ao escrever a marcação Remotion de uma maneira específica, o Remotion Studio consegue reconhecer a estrutura do código e a torna interativa:
- Permitindo que itens sejam selecionados clicando neles
- Permitindo arrastar e soltar, redimensionar e rotacionar
- Editando os estilos CSS
- Tornando keyframes e valores de easing editáveis
Se a marcação for muito complexa para o Studio tornar interativa, os valores ficam acinzentados.
Prefira componentes interativos com suas próprias timelines
Use Interactive.withSchema({wrapInSequence: true}) para cenas personalizadas, cartões, títulos e outros componentes visuais cujas props devem ser editáveis por instância.
Exponha controles de conteúdo e aparência significativos em um InteractivitySchema.
Mantenha detalhes decorativos de implementação dentro do componente.
O componente deve aceitar style e repassá-lo a uma raiz visual. Mantenha uma raiz compartilhada quando transformações, corte ou opacidade devem afetar todas as suas camadas.
Achate wrappers internos redundantes quando seus estilos podem ser movidos para um elemento existente sem alterar layout ou animação.
import type React from 'react';
import {Interactive, type InteractivitySchema} from 'remotion';
type LowerThirdProps = {
readonly children: string;
readonly accentColor: string;
readonly style?: React.CSSProperties;
};
const LowerThirdInner: React.FC<LowerThirdProps> = ({
children,
accentColor,
style,
}) => {
return (
<Interactive.Div
style={{
position: 'absolute',
left: 80,
bottom: 80,
display: 'flex',
alignItems: 'center',
gap: 20,
backgroundColor: 'white',
borderRadius: 16,
padding: '20px 32px',
color: 'black',
fontFamily: 'Helvetica, Arial, sans-serif',
fontSize: 48,
fontWeight: 600,
...style,
}}
>
<div
style={{
width: 8,
alignSelf: 'stretch',
borderRadius: 4,
backgroundColor: accentColor,
}}
/>
{children}
</Interactive.Div>
);
};
const lowerThirdSchema = {
children: {type: 'text-content', default: '', description: 'Texto'},
accentColor: {
type: 'color',
default: '#0b84f3',
description: 'Cor de destaque',
},
} as const satisfies InteractivitySchema;
export const LowerThird = Interactive.withSchema({
Component: LowerThirdInner,
componentName: '<LowerThird>',
schema: lowerThirdSchema,
wrapInSequence: true,
});
Reenviar o style injetado dentro do componente é obrigatório; mantenha os estilos editáveis inline no local de chamada do componente.
Escolha campos de schema
Cada chave no schema é uma prop que o Studio pode ler e editar no local de chamada.
Props que não estão no schema ainda funcionam, mas não são editáveis no Studio.
Chaves podem usar notação de ponto, como style.color.
| Tipo | Uso para | Com keyframe |
|---|---|---|
text-content | Texto, como um título | Não |
number | Números, com min, max, step, integer opcionais | Sim |
boolean | Interruptores liga/desliga | Sim (segurar) |
color | Strings de cor CSS | Sim |
enum | Uma escolha entre variants, cada uma com seu próprio schema | Opcional (segurar) |
array | Listas de números, cores, enums e mais | Não |
asset | Fontes de mídia, com assetType opcional | Não |
font-family | Família de fonte CSS | Não |
font-weight | Peso da fonte | Sim |
translate, scale, rotation-css, rotation-degrees, transform-origin | Transformações | Sim |
uv-coordinate | Um ponto normalizado [x, y] no elemento | Sim |
svg-path | Dados de caminho SVG | Sim |
remotion-captions | Dados Caption[] | Não |
hidden | Um valor mantido fora dos controles | — |
Todo campo precisa de um default e deve ter um description, que o Studio mostra como rótulo.
Defina keyframable: false para exibir um controle estático.
Exponha conteúdo e aparência por instância, como o texto e uma cor de destaque.
Não adicione campos para style.translate, style.scale, style.rotate, style.transformOrigin e style.opacity: wrapInSequence: true já os adiciona.
Para tornar propriedades CSS da raiz editáveis por instância, espalhe os fragmentos de schema embutidos:
const cardSchema = {
...Interactive.textSchema, // style.color, style.fontSize, style.fontWeight, ...
...Interactive.backgroundSchema, // style.backgroundColor
...Interactive.borderRadiusSchema, // style.borderRadius, ...
} as const satisfies InteractivitySchema;
Também disponível: Interactive.borderSchema, e Interactive.captionsSchema para componentes que aceitam legendas.
Consulte InteractivitySchema para todas as opções.
Registre componentes reutilizáveis como composições conectadas
Registre cenas substanciais e componentes reutilizáveis com suas próprias camadas ou animação como composições independentes. O Studio chama essas composições conectadas: elas podem ser abertas em sua própria timeline enquanto compartilham a mesma implementação de componente com o vídeo pai.
Defina estilos necessários e carregue fontes dentro do componente para que funcione sem seu pai. Consulte independência do pai.
Registre a mesma referência de componente exportada que o pai renderiza. Para o exemplo acima, use component={LowerThird}, não LowerThirdInner ou um wrapper inline.
Com wrapInSequence: true, nenhum <Sequence> extra é necessário para a conexão.
import {Composition} from 'remotion';
import {LowerThird} from './LowerThird';
export const RemotionRoot = () => (
<Composition
id="LowerThird"
component={LowerThird}
width={1280}
height={720}
fps={30}
durationInFrames={30}
defaultProps={{
children: 'Jane Doe, Product Designer',
accentColor: '#0b84f3',
}}
/>
);
Escolha um ID único, valores padrão inline representativos e dimensões, fps e duração adequados para pré-visualizar o componente. Os padrões de registro não copiam automaticamente props de uma instância pai. Consulte composições conectadas para detalhes de registro e extração.
Coloque o tempo diretamente no componente
Evite um <Sequence> separado em torno de um componente que já aceita props de tempo. Componentes interativos embutidos e componentes personalizados feitos com wrapInSequence: true podem receber name, from, durationInFrames, trimBefore, playbackRate e premountFor diretamente.
<LowerThird
name="Lower third"
from={30}
durationInFrames={90}
accentColor="#0b84f3"
>
Jane Doe, Product Designer
</LowerThird>
Ao remover uma sequência redundante, mova seu tempo e nome para o filho.
Preserve qualquer tempo filho existente; não sobrescreva ou aplique offsets duplicados.
Uma chamada useCurrentFrame() dentro do componente lê seu quadro local, enquanto uma expressão de estilo no local de chamada ainda usa o quadro do chamador. Preserve essa distinção ao mover estilos de animação.
Mantenha um <Sequence> quando ele fornecer tempo compartilhado para vários irmãos, substituir dimensões para useVideoConfig(), ou envolver um componente que não lida com tempo. Mantenha <Series.Sequence> para layout consecutivo e <TransitionSeries.Sequence> para transições; props from diretas não substituem esses comportamentos.
Dê a cada item editável individual seu próprio nó JSX
O Studio edita o nó fonte JSX que criou um item. Se vários itens em tempo de execução vêm do mesmo nó JSX, eles compartilham um alvo de edição de fonte.
Para cada registro de composição, clipe, cena, camada ou sequência que deve ser editável por si só, escreva um nó JSX separado e mantenha suas props editáveis nesse nó. Isso se aplica a <Composition>, <Still>, componentes de mídia embutidos, <Sequence>, <Series.Sequence>, <TransitionSeries.Sequence> e componentes personalizados.
Por exemplo, crie uma timeline editável assim:
<Series>
<Series.Sequence name="Introdução" durationInFrames={90}>
<Introducao />
</Series.Sequence>
<Series.Sequence name="Demonstração" durationInFrames={150}>
<Demonstracao />
</Series.Sequence>
</Series>
Um .map() ou outro loop programático criaria vários itens em tempo de execução a partir de um nó JSX fonte. Isso é apropriado para saída repetida que é intencionalmente controlada como um modelo, como barras de visualização ou partículas. Não é apropriado quando as instâncias precisam de IDs ou nomes, props, metadados, tempo, ordenação, exclusão ou duplicação independentes no Studio.
Torne um elemento HTML interativo usando Interactive
Todo elemento HTML e SVG (exceto <Img>, que já é interativo), como <div>, pode ser tornado interativo usando Interactive:
<Interactive.Div
name="Cartão de saudação"
style={{fontSize: 80, padding: 24}}
>
Olá
</Interactive.Div>
Isso permite que estilos e keyframes sejam definidos no Studio. Seja sensato; se um componente tiver muitos elementos, a timeline pode ficar bagunçada.
Prefira texto inline
Se o texto é fixo e usado apenas uma vez, escreva-o diretamente dentro do elemento interativo em vez de extraí-lo para uma constante.
// 👍 Cópia fixa permanece editável
<Interactive.Div name="Título">
Melhores Práticas Remotion
</Interactive.Div>
Use uma prop ou variável apenas quando o texto é dinâmico ou reutilizado.
Dê nomes descritivos aos elementos interativos
Adicione uma prop name aos elementos para torná-los facilmente identificáveis.
Evite nomes computados; codifique-os.
<>
<Interactive.Div name="Título principal" style={{fontSize: 80}}>
Dia de lançamento
</Interactive.Div>
<Img name="Avatar" src="https://remotion.media/image.jpeg" />
<Video name="Background" src="https://remotion.media/video.mp4" />
<Interactive.Div name="Título">
Dia de lançamento
</Interactive.Div>
</>
Mantenha todos os estilos CSS inline
A melhor maneira é apenas passar um objeto simples para style - sem referência a constantes, sem espalhamento de objetos, sem matemática.
<Interactive.Div
style={{
fontSize: 80,
color: 'red',
}}
>
Olá Mundo!
</Interactive.Div>
const baseStyle = useMemo(() => {
return {
fontSize: 12 // ❌ Estilos não inline não são suportados
}
}, []);
<Interactive.Div
style={{
...baseStyle, // ❌ Espalhamento não é suportado
color: RED, // ❌ Referência a constantes não é suportada
scale: frame * 10 // ❌ Matemática não é suportada
}}
>
Olá Mundo!
</Interactive.Div>
Anime usando interpolate()
Escreva animações como chamadas interpolate() inline na propriedade que muda.
O intervalo de saída, easing, extrapolação e a propriedade output devem usar valores codificados.
O intervalo de entrada pode adicionalmente usar durationInFrames, fps, width e height desestruturados diretamente de useVideoConfig(). Identificadores simples como durationInFrames, multiplicação por um número como 2 * fps ou fps * 2, e subtração de um número como durationInFrames - 1 são suportados.
const {fps, durationInFrames} = useVideoConfig();
// 👍 Valores inline podem ser padronizados e ter keyframes
<Interactive.Div
name="Cartão de produto"
style={{
color: 'white',
fontSize: 80,
scale: interpolate(frame, [0, fps], [0, 1], {
easing: Easing.spring({damping: 200}),
output: 'perceptual-scale',
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}),
rotate: interpolate(frame, [0, 1 * fps], ['0deg', '20deg'], {
easing: Easing.spring({damping: 200}),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}),
translate: interpolate(
frame,
[durationInFrames - 30, durationInFrames],
['0px 0px', '0px 120px'],
{
easing: Easing.spring({damping: 200}),
output: 'perceptual-scale',
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}
),
}}
/>
const translateY = interpolate(frame, [0, 30], [0, 120]); // ❌ Matemática deve estar diretamente na marcação
<Interactive.Div
name="Cartão de produto"
style={{
translate: translateY, // ❌ Apenas chamadas interpolate() inline são suportadas
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Não pode usar matemática com variáveis arbitrárias, não pode usar constantes
scale: interpolate(frame, [0, 1], [0, 1]), // ❌ 'output' deve ser 'perceptual-scale' para transformações de escala ou translate
}}
>
Olá Mundo!
</Interactive.Div>
Prefira keyframes em vez de condições
Evite expressões ternárias e condicionais. Em vez disso, use interpolate() para gerar animações contínuas, mesmo para alternância de visibilidade:
// 👍 Interpolate é editável
<Interactive.Div
style={{
opacity: interpolate(frame, [0, 1], [1, 0], {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'}),
}}
>
Conteúdo
</Interactive.Div>
<Interactive.Div
style={{
opacity: frame > 10 ? 0 : 1, // ❌ Não pode ser editado como keyframe
}}
>
Conteúdo
</Interactive.Div>
Estrutura do componente para editabilidade ideal
Siga este padrão para componentes com props expostas ao usuário no Studio:
- Defina um schema de interatividade tipado com
satisfies InteractivitySchema. - Exporte o componente gerado por
Interactive.withSchema({...}). - (Opcional, para comportamento personalizado) Use
Interactive.useInteractivity(). - Aceite
style?: React.CSSPropertiesno componente interno e aplique-o à raiz visual. - Passe props restantes diretamente para os elementos filho conforme apropriado.
Suporte a layouts complexos
Componentes com layouts complexos ou que usam Suspense ou dados assíncronos podem precisar de manipulação especial para funcionar no Studio.
Consulte as Diretrizes de layout para obter mais orientações.
Lembre-se
Sempre que possível, torne os componentes editáveis no Studio usando as técnicas acima.
