Ao escrever a marcação Remotion de uma maneira específica, o Remotion Studio é capaz de reconhecer a estrutura do código e torná-la interativa:
- Permitindo que itens sejam selecionados clicando neles
- Permitindo arrastar e soltar, redimensionar e girar
- 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 ficarão acinzentados.
Prefira componentes interativos com suas próprias timelines
Use Interactive.withSchema({wrapInSequence: true, layout: 'absolute-fill'}) para componentes que preenchem seu pai. O wrapper fornece sua raiz visual e item de timeline, e corta o overflow por padrão, para que o componente interno possa retornar um fragmento. Coloque temporização, pré-montagem, dimensões e estilos por instância no componente exportado.
Mantenha visuais que pertencem juntos no mesmo componente, para que se movam e cortem juntos. Um contêiner de layout interno ainda pode fornecer alinhamento, corte dentro de uma área menor ou um grupo animado; um contêiner que apenas preenche a cena geralmente é desnecessário. Cards, caixas de texto e SVGs com seus próprios limites podem manter o layout: 'none' padrão e encaminhar style para sua raiz visual.
import {Video} from '@remotion/media';
import type React from 'react';
import {Interactive, useVideoConfig, type InteractivitySchema} from 'remotion';
type SceneProps = {
readonly title: string;
};
const SceneInner: React.FC<SceneProps> = ({title}) => {
const {fps} = useVideoConfig();
return (
<>
<Video
name="Background footage"
src="https://remotion.media/video.mp4"
premountFor={fps}
objectFit="cover"
style={{width: '100%', height: '100%'}}
/>
<Interactive.Div
name="Scene title"
style={{
position: 'absolute',
left: 80,
bottom: 80,
color: 'white',
fontFamily: 'Helvetica, Arial, sans-serif',
fontSize: 80,
}}
>
{title}
</Interactive.Div>
</>
);
};
const sceneSchema = {
title: {type: 'string', default: '', description: 'Title'},
} as const satisfies InteractivitySchema;
export const Scene = Interactive.withSchema({
Component: SceneInner,
componentName: 'Scene',
schema: sceneSchema,
wrapInSequence: true,
layout: 'absolute-fill',
});
Escolha campos de esquema
Cada chave no esquema é uma prop que o Studio pode ler e editar no local de chamada.
Props que não estão no esquema ainda funcionam, mas não são editáveis no Studio.
Chaves podem usar notação de ponto, como style.color.
| Tipo | Use para | Com keyframe |
|---|---|---|
string | Strings, como um título, prompt ou trecho de código | Não |
number | Números, com min, max, step, integer opcionais | Sim |
boolean | Interruptores liga/desliga | Sim (hold) |
color | Strings de cor CSS | Sim |
enum | Uma escolha entre variants, cada um com seu próprio esquema aninhado | Opt-in (hold) |
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 | — |
Cada campo precisa de um default e deve ter um description, que o Studio mostra como rótulo.
Defina keyframable: false para mostrar 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 as propriedades CSS da raiz editáveis por instância, espalhe os fragmentos de esquema integrados:
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íveis: Interactive.borderSchema e Interactive.captionsSchema para componentes que aceitam legendas.
Para componentes que aceitam children React.ReactNode, adicione ...Interactive.childrenSchema.
Ele fornece controles para o conteúdo dos children e pode evoluir para suportar conteúdo mais rico.
Atualmente, usa um campo string rotulado como "Texto" com um padrão de ''.
Se um componente exigir children apenas de string, declare um campo children explícito com type: 'string'.
Interactive.textSchema controla estilos tipográficos; childrenSchema controla o conteúdo.
O fragmento de children não está incluído em baseSchema ou automaticamente adicionado a componentes personalizados.
Marcação aninhada e children computados são atualmente somente leitura.
text-content é um alias obsoleto para o tipo de campo string.
Veja InteractivitySchema para todas as opções.
Registre componentes reutilizáveis como composições conectadas
Registre cenas significativas e componentes reutilizáveis com suas próprias camadas ou animação como composições independentes. O Studio chama essas de 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. Veja independência do pai.
Registre a mesma referência de componente exportada que o pai renderiza. Para o exemplo acima, use component={Scene}, não SceneInner ou um wrapper inline.
Com wrapInSequence: true, nenhum <Sequence> extra é necessário para a conexão.
import {Composition} from 'remotion';
import {Scene} from './Scene';
export const RemotionRoot = () => (
<Composition
id="Scene"
component={Scene}
width={1280}
height={720}
fps={30}
durationInFrames={30}
defaultProps={{
title: 'A new perspective',
}}
/>
);
Escolha um ID único, defaults inline representativos e dimensões, fps e duração adequados para pré-visualizar o componente. Os defaults de registro não copiam automaticamente props de uma instância pai. Veja composições conectadas para detalhes de registro e extração.
Coloque a temporização diretamente no componente
Evite um <Sequence> separado em torno de um componente que já aceita props de temporização. Componentes interativos integrados e componentes personalizados feitos com wrapInSequence: true podem receber name, from, durationInFrames, trimBefore, playbackRate e premountFor diretamente.
<Scene
name="Opening scene"
from={30}
durationInFrames={90}
premountFor={fps}
style={{opacity: 0.9}}
title="A new perspective"
/>
Ao remover uma sequência redundante, mova sua temporização e nome para o filho. Preserve qualquer temporização existente do filho; não sobrescreva ou aplique offsets duplos. Uma chamada useCurrentFrame() dentro do componente lê seu frame local, enquanto uma expressão de estilo no local de chamada ainda usa o frame do chamador. Preserve essa distinção ao mover estilos de animação.
Mantenha um <Sequence> quando ele fornecer temporização compartilhada para múltiplos irmãos, envolver um componente que não lida com temporização ou fornecer dimensões que o filho não pode aceitar diretamente. Raízes gerenciadas também aceitam width e height para useVideoConfig(). Mantenha <TransitionSeries.Sequence> para layout consecutivo, com ou sem transições; props from diretas não substituem esses comportamentos.
Dê a cada item independentemente editável seu próprio nó JSX
O Studio edita o nó fonte JSX que criou um item. Se múltiplos 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 conta própria, escreva um nó JSX separado e mantenha suas props editáveis nesse nó. Isso se aplica a <Composition>, <Still>, componentes de mídia integrados, <Sequence>, <TransitionSeries.Sequence> e componentes personalizados.
Por exemplo, crie uma timeline editável assim:
import { TransitionSeries } from "@remotion/transitions";
<TransitionSeries>
<TransitionSeries.Sequence name="Introduction" durationInFrames={90}>
<Introduction />
</TransitionSeries.Sequence>
<TransitionSeries.Sequence name="Demo" durationInFrames={150}>
<Demo />
</TransitionSeries.Sequence>
</TransitionSeries>
Um .map() ou outro loop programático criaria múltiplos itens em tempo de execução a partir de um nó fonte JSX. 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, temporização, 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 se tornar interativo usando Interactive:
<Interactive.Div
name="Greeting card"
style={{fontSize: 80, padding: 24}}
>
Hello
</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="Title">
Remotion Best Practices
</Interactive.Div>
Use uma prop ou variável apenas quando o texto for dinâmico ou reutilizado.
Dê aos elementos interativos um nome descritivo
Adicione uma prop name aos elementos para torná-los facilmente identificáveis.
Evite nomes computados; fixe-os.
<>
<Interactive.Div name="Hero title" style={{fontSize: 80}}>
Launch day
</Interactive.Div>
<Img name="Avatar" src="https://remotion.media/image.jpeg" />
<Video name="Background" src="https://remotion.media/video.mp4" />
<Interactive.Div name="Title">
Launch day
</Interactive.Div>
</>
Mantenha todos os estilos CSS inline
A melhor maneira é apenas passar um objeto simples para style - sem referências a constantes, sem espalhamento de objetos, sem matemática.
<Interactive.Div
style={{
fontSize: 80,
color: 'red',
}}
>
Hello World!
</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, // ❌ Referir a constantes não é suportado
scale: frame * 10 // ❌ Matemática não é suportada
}}
>
Hello World!
</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 fixos.
O intervalo de entrada pode usar adicionalmente 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 keyframed
<Interactive.Div
name="Product card"
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}),
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp'
}
)
}}
>
Nova versão chegando!
</Interactive.Div>
Use easing para suavizar as transições. Parâmetros de damping e massa podem ser ajustados para personalizar o efeito de mola.
Use componentes interativos integrados
O Remotion fornece componentes interativos integrados, como <Interactive.Div>, <Interactive.Img>, <Interactive.Video> e <Interactive.Sequence>, que já suportam interatividade pronta para uso. Esses componentes são ideais para elementos que precisam ser editáveis no Studio sem configuração adicional.
<Interactive.Img name="Logo" src="https://remotion.media/logo.png" />
<Interactive.Video name="Background" src="https://remotion.media/video.mp4" />
<Interactive.Sequence name="Intro" durationInFrames={60}>
<Interactive.Div name="Text">
Bem-vindo!
</Interactive.Div>
</Interactive.Sequence>
Esses componentes herdam automaticamente a interatividade e podem ser personalizados com props como name e style.
Evite componentes de ordem superior
Não envolva componentes interativos em funções de ordem superior, como withStyles() ou memo(), pois isso pode quebrar a capacidade do Studio de rastrear a edição. Em vez disso, escreva a interatividade diretamente no componente ou use Interactive.withSchema() para componentes personalizados.
const StyledDiv = withStyles(Interactive.Div); // ❌ Quebra a interatividade
Em vez disso:
<Interactive.Div style={{color: 'blue'}}>
Texto azul
</Interactive.Div>
Resumo das práticas recomendadas
- Use
Interactive.withSchema()para componentes com suas próprias timelines. - Prefira props inline e evite extrair estilos ou valores para constantes.
- Coloque temporização diretamente no componente, evitando
<Sequence>redundantes. - Dê a cada item editável seu próprio nó JSX.
- Use
interpolate()inline para animações, com valores fixos sempre que possível. - Mantenha estilos CSS inline, sem espalhamento ou matemática.
- Nomeie elementos interativos com props
namedescritivas. - Registre componentes reutilizáveis como composições conectadas.
Essas práticas garantem que o Remotion Studio possa reconhecer e editar a marcação de forma eficiente, proporcionando uma experiência interativa suave e intuitiva.
