Al escribir el marcado de Remotion de una manera específica, el Studio de Remotion puede reconocer la estructura del código y hacerlo interactivo:
- Permitiendo seleccionar elementos haciendo clic sobre ellos
- Permitiendo arrastrar y soltar, redimensionar y rotar
- Editando los estilos CSS
- Haciendo editables los fotogramas clave y los valores de easing
Si el marcado es demasiado complejo para que el Studio lo haga interactivo, los valores se vuelven grises.
Prefiere componentes interactivos con sus propias líneas de tiempo
Construye nuevas composiciones con Track, composiciones conectadas y Interactive.create().
Establece layout explícitamente como 'absolute-fill' para escenas o 'none' para elementos delimitados. Registra los mismos componentes exportados de escena y elementos reutilizables con Composition.
Comienza con el ejemplo completo de Track + composiciones conectadas. Incluye el elemento, la escena, la línea de tiempo padre y los registros raíz.
import {Track, useVideoConfig} from 'remotion';
import {Chapter} from './Chapter';
export const MyVideo = () => {
const {fps} = useVideoConfig();
return (
<Track name="Capítulos">
<Chapter
name="Apertura"
durationInFrames={3 * fps}
title="Introducción"
/>
<Chapter
name="Característica"
from={3 * fps}
durationInFrames={4 * fps}
title="Nuevas funciones"
/>
</Track>
);
};
Pon los estilos de fondo y alineación en cada instancia de escena, como se muestra en el ejemplo completo. Mantén los contenedores solo de diseño como HTML plano.
Elige campos de esquema
Cada clave en el esquema es una prop que el Studio puede leer y editar en el lugar de la llamada. Las props que no están en el esquema siguen funcionando, pero no se pueden editar en el Studio. Las claves pueden usar notación de puntos, como style.color.
| Tipo | Úsalo para | Fotograma clave |
|---|---|---|
string | Cadenas de texto, como un título, aviso o fragmento de código | No |
number | Números, con min, max, step, integer opcionales | Sí |
boolean | Interruptores de encendido/apagado | Sí (mantener) |
color | Cadenas de color CSS | Sí |
enum | Una elección entre variants, cada una con su propio esquema anidado | Opt-in (mantener) |
array | Listas de números, colores, enumeraciones y más | No |
asset | Fuentes de medios, con assetType opcional | No |
font-family | Familia de fuente CSS | No |
font-weight | Peso de fuente | Sí |
translate, scale, rotation-css, rotation-degrees, transform-origin | Transformaciones | Sí |
uv-coordinate | Un punto normalizado [x, y] en el elemento | Sí |
svg-path | Datos de ruta SVG | Sí |
remotion-captions | Datos Caption[] | No |
hidden | Un valor mantenido fuera de los controles | — |
Cada campo necesita un default y debería tener un description, que el Studio muestra como etiqueta. Establece keyframable: false para mostrar un control estático.
Expón el contenido y la apariencia por instancia, como el texto y un color de acento. No agregues campos para style.translate, style.scale, style.rotate, style.transformOrigin y style.opacity: Interactive.create() los agrega automáticamente.
Para hacer editables las propiedades CSS de la raíz por instancia, extiende los 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;
También disponibles: Interactive.borderSchema y Interactive.captionsSchema para componentes que aceptan subtítulos.
Para componentes que aceptan hijos React.ReactNode, agrega ...Interactive.childrenSchema.
Proporciona controles para el contenido de los hijos y puede evolucionar para soportar contenido más rico.
Actualmente, usa un campo de cadena etiquetado como "Texto" con un valor predeterminado de ''.
Si un componente requiere hijos solo de cadena, declara un campo children explícito con type: 'string'.
Interactive.textSchema controla los estilos de tipografía; childrenSchema controla el contenido.
El fragmento de hijos no está incluido en baseSchema ni se agrega automáticamente a componentes personalizados.
El marcado anidado y los hijos calculados son actualmente de solo lectura.
text-content es un alias obsoleto para el tipo de campo string.
Consulta InteractivitySchema para todas las opciones.
Registra componentes reutilizables como composiciones conectadas
Registra escenas y elementos reutilizables como composiciones independientes. El Studio llama a estas composiciones conectadas: se pueden abrir en su propia línea de tiempo mientras comparten la misma implementación de componente con el video padre.
Define estilos requeridos y carga fuentes dentro del componente para que funcione sin su padre. Consulta independencia del padre.
Registra la misma referencia de componente exportada que el padre renderiza. Para el ejemplo anterior, usa component={Chapter}, no ChapterInner o un envoltorio en línea.
Interactive.create() proporciona la secuencia, por lo que no se necesita un <Sequence> adicional para la conexión.
import {Composition} from 'remotion';
import {Chapter} from './Chapter';
export const RemotionRoot = () => (
<Composition
id="Chapter"
component={Chapter}
width={1280}
height={720}
fps={30}
durationInFrames={90}
defaultProps={{
title: 'Una nueva perspectiva',
style: {
backgroundColor: '#111111',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
);
Elige un ID único, valores predeterminados en línea representativos y dimensiones, fps y duración adecuados para previsualizar el componente. Los valores predeterminados del registro no copian automáticamente las props de una instancia padre. Consulta composiciones conectadas para detalles de registro y extracción.
Pon el tiempo directamente en el componente
Evita un <Sequence> separado alrededor de un componente que ya acepta props de tiempo. Los componentes interactivos integrados y los componentes personalizados hechos con Interactive.create() pueden recibir name, from, durationInFrames, trimBefore y playbackRate directamente.
<Chapter
name="Escena de apertura"
from={30}
durationInFrames={90}
style={{opacity: 0.9}}
title="Una nueva perspectiva"
/>
Para el tiempo de escena compartido, agrupa el contenido en un componente hecho con Interactive.create() y temporiza esa instancia. Las raíces administradas también aceptan width y height para useVideoConfig().
Usa <Track> para poner elementos en la misma fila de la línea de tiempo del Studio.
Usa <TransitionSeries> cuando las escenas son secuenciales.
Dale a cada elemento editable individual su propio nodo JSX
El Studio edita el nodo fuente JSX que creó un elemento. Si múltiples elementos en tiempo de ejecución provienen del mismo nodo JSX, comparten un objetivo de edición de fuente.
Para cada registro de composición, clip, escena, capa o secuencia que deba ser editable por sí mismo, escribe un nodo JSX separado y mantén sus props editables en ese nodo. Esto se aplica a <Composition>, <Still>, componentes de medios integrados, <Sequence>, <TransitionSeries.Sequence> y componentes personalizados.
Por ejemplo, escribe una línea de tiempo editable así:
import { Track } from "remotion";
<Track name="Escenas">
<Introduction name="Introducción" durationInFrames={90} />
<Demo name="Demostración" from={90} durationInFrames={150} />
</Track>
Un .map() u otro bucle programático crearía múltiples elementos en tiempo de ejecución desde un nodo fuente JSX. Eso es apropiado para salida repetida que se controla intencionalmente como una plantilla, como barras de visualización o partículas. No es apropiado cuando las instancias necesitan IDs o nombres, props, metadatos, tiempo, orden, eliminación o duplicación independientes en el Studio.
Haz que un elemento HTML sea interactivo usando Interactive
Cada elemento HTML y SVG (excepto <Img>, que ya es interactivo) como <div> se puede hacer interactivo usando Interactive:
<Interactive.Div
name="Tarjeta de saludo"
style={{fontSize: 80, padding: 24}}
>
Hola
</Interactive.Div>
Esto permite que se establezcan estilos y fotogramas clave en el Studio. Sé sensato, si un componente tiene muchos elementos, la línea de tiempo podría volverse desordenada.
Prefiere texto en línea
Si el texto es fijo y solo se usa una vez, escríbelo directamente dentro del elemento interactivo en lugar de extraerlo en una constante.
// 👍 El texto fijo permanece editable
<Interactive.Div name="Título">
Mejores prácticas de Remotion
</Interactive.Div>
Usa una prop o variable solo cuando el texto sea dinámico o se reutilice.
Dale a los elementos interactivos un nombre descriptivo
Agrega una prop name a los elementos para hacerlos fácilmente identificables.
Evita nombres calculados, escríbelos directamente.
<>
<Interactive.Div name="Título heroico" style={{fontSize: 80}}>
Día de lanzamiento
</Interactive.Div>
<Img name="Avatar" src="https://remotion.media/image.jpeg" />
<Video name="Fondo" src="https://remotion.media/video.mp4" />
<Interactive.Div name="Título">
Día de lanzamiento
</Interactive.Div>
</>
Mantén todos los estilos CSS en línea
La mejor manera es simplemente pasar un objeto plano a style - sin referirse a constantes, sin propagación de objetos, sin matemáticas.
<Interactive.Div
style={{
fontSize: 80,
color: 'red',
}}
>
¡Hola Mundo!
</Interactive.Div>
const baseStyle = useMemo(() => {
return {
fontSize: 12 // ❌ Los estilos no en línea no son compatibles
}
}, []);
<Interactive.Div
style={{
...baseStyle, // ❌ La propagación no es compatible
color: RED, // ❌ Referirse a constantes no es compatible
scale: frame * 10 // ❌ Las matemáticas no son compatibles
}}
>
¡Hola Mundo!
</Interactive.Div>
Anima usando interpolate()
Escribe animaciones como llamadas interpolate() en línea sobre la propiedad que cambia.
El rango de salida, el easing, la extrapolación y la propiedad output deben usar valores fijos.
El rango de entrada puede usar adicionalmente durationInFrames, fps, width y height desestructurados directamente de useVideoConfig(). Los identificadores simples como durationInFrames, la multiplicación con un número como 2 * fps o fps * 2, y la resta de un número como durationInFrames - 1 son compatibles.
const {fps, durationInFrames} = useVideoConfig();
// 👍 Los valores en línea se pueden estandarizar y animar por fotogramas clave
<Interactive.Div
name="Tarjeta de producto"
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]); // ❌ Las matemáticas deberían estar directamente en el marcado
<Interactive.Div
name="Tarjeta de producto"
style={{
translate: translateY, // ❌ Solo se admiten llamadas interpolate() en línea
rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ No se pueden usar matemáticas con variables arbitrarias, no se pueden usar constantes
scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Solo puede interpretar la variable `frame`.
}}
/>
Mantén las rutas SVG editables con Interactive.Path
Usa <Interactive.Path> de remotion en lugar de <path> dentro de un SVG para hacer la ruta visualmente editable.
Instala @remotion/paths para interpolación de rutas y fotogramas clave de rutas en Studio:
bunx remotion add @remotion/paths
Si la geometría está destinada a ser estática, coloca la cadena de ruta directamente en la prop d. No la extraigas en una constante.
import {Interactive} from 'remotion';
<Interactive.Svg width={300} height={300} viewBox="0 0 300 300">
<Interactive.Path
name="Triángulo"
d="M 40 40 L 260 40 L 150 260 Z"
fill="#0b84f3"
/>
</Interactive.Svg>
Transforma rutas usando interpolación en línea
… [truncado para traducción]
