OfficialVideo y animacióngithub.com

remotion-interactivity

Estructura el marcado de Remotion para hacerlo interactivo en el estudio.

¿Qué es remotion-interactivity?

Este skill guía a los desarrolladores sobre cómo estructurar el marcado de Remotion para que el Remotion Studio pueda reconocerlo y hacerlo interactivo. Permite seleccionar elementos con clics, arrastrar y soltar, redimensionar y rotar, editar estilos CSS, y modificar keyframes y valores de easing. Se recomienda usar `Interactive.withSchema()` para componentes que llenan su contenedor padre, lo que proporciona una línea de tiempo y un elemento visual raíz, y facilita la edición por instancia. Es crucial registrar componentes reutilizables como 'connected compositions' para que tengan su propia línea de tiempo y compartan la implementación con el video padre. El skill también detalla cómo definir esquemas de props (usando tipos como `string`, `number`, `boolean`, `color`, `enum`, etc.), cómo poner el timing directamente en el componente (evitando `<Sequence>` redundantes), cómo nombrar elementos interactivos de forma descriptiva, mantener los estilos CSS en línea, y animar usando `interpolate()`. Siguiendo estas prácticas, los desarrolladores pueden crear componentes altamente editables y personalizables dentro del ecosistema de Remotion Studio.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/remotion-dev/skills/tree/main/skills/remotion-interactivity

Installed? Explore more Video y animación skills: steipete/video-frames, steipete/summarize, openclaw/openclaw · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Vista previa

Del README del skill

remotion-interactivity preview

Documentación

Al escribir el marcado de Remotion de una manera específica, el Remotion Studio 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 keyframes y valores de easing

Si el marcado es demasiado complejo para que el Studio lo haga interactivo, los valores se mostrarán atenuados.

Preferir componentes interactivos con sus propias líneas de tiempo

Usa Interactive.withSchema({wrapInSequence: true, layout: 'absolute-fill'}) para componentes que llenan su elemento padre. El wrapper proporciona su raíz visual y elemento de línea de tiempo, y recorta el desbordamiento por defecto, por lo que el componente interno puede devolver un fragment. Pon el timing, premontaje, dimensiones y estilos por instancia en el componente exportado.

Mantén juntos los elementos visuales que pertenecen al mismo componente, para que se muevan y recorten juntos. Un contenedor de diseño interno aún puede proporcionar alineación, recorte dentro de un área más pequeña o un grupo animado; un contenedor que solo llena la escena generalmente es innecesario. Las tarjetas, los cuadros de texto y los SVG con sus propios límites pueden mantener el layout por defecto 'none' y pasar style a su raíz 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',
});

Elegir campos del esquema

Cada clave en el esquema es una prop que el Studio puede leer y editar en el punto de llamada. Las props que no están en el esquema aún funcionan, pero no son editables en el Studio. Las claves pueden usar notación de puntos, como style.color.

TipoUsar paraKeyframable
stringCadenas de texto, como un título, prompt o fragmento de códigoNo
numberNúmeros, con min, max, step e integer opcionalesSí
booleanInterruptores de encendido/apagadoSí (hold)
colorCadenas de color CSSSí
enumUna elección entre variants, cada una con su propio esquema anidadoOpt-in (hold)
arrayListas de números, colores, enums y másNo
assetFuentes de medios, con assetType opcionalNo
font-familyFamilia de fuente CSSNo
font-weightPeso de la fuenteSí
translate, scale, rotation-css, rotation-degrees, transform-originTransformacionesSí
uv-coordinateUn punto [x, y] normalizado en el elementoSí
svg-pathDatos de ruta SVGSí
remotion-captionsDatos Caption[]No
hiddenUn valor mantenido fuera de los controles—

Cada campo necesita un default y debería tener un description, que el Studio muestra como la 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: wrapInSequence: true ya los añade.

Para hacer que las propiedades CSS de la raíz sean editables 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 e 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 admitir contenido más enriquecido. Actualmente, usa un campo de cadena etiquetado como "Text" con un valor por defecto de ''. Si un componente requiere hijos solo de cadena, declara un campo children explícito con type: 'string' en su lugar. Interactive.textSchema controla los estilos tipográficos; 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.

Registrar componentes reutilizables como composiciones conectadas

Registra escenas sustanciales y componentes reutilizables con sus propias capas o animación como composiciones independientes. El Studio las llama composiciones conectadas: se pueden abrir en su propia línea de tiempo mientras comparten la misma implementación del componente con el video padre.

Define los estilos requeridos y carga las fuentes dentro del componente para que funcione sin su padre. Consulta independencia del padre.

Registra la misma referencia de componente exportado que renderiza el padre. Para el ejemplo anterior, usa component={Scene}, no SceneInner ni un wrapper en línea. Con wrapInSequence: true, no se necesita un <Sequence> extra para la conexión.

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',
    }}
  />
);

Elige un ID único, valores predeterminados representativos en línea, y dimensiones, fps y duración adecuados para previsualizar el componente. Los valores predeterminados de registro no copian automáticamente las props de una instancia padre. Consulta composiciones conectadas para detalles de registro y extracción.

Poner el timing directamente en el componente

Evita un <Sequence> separado alrededor de un componente que ya acepta props de timing. Los componentes interactivos integrados y los componentes personalizados creados con wrapInSequence: true pueden recibir name, from, durationInFrames, trimBefore, playbackRate y premountFor directamente.

<Scene
  name="Opening scene"
  from={30}
  durationInFrames={90}
  premountFor={fps}
  style={{opacity: 0.9}}
  title="A new perspective"
/>

Al eliminar una secuencia redundante, mueve su timing y nombre al hijo. Conserva cualquier timing existente del hijo; no sobrescribas ni apliques dos veces los desplazamientos. Una llamada a useCurrentFrame() dentro del componente lee su fotograma local, mientras que una expresión de estilo en el punto de llamada aún usa el fotograma de la función llamante. Preserva esa distinción al mover estilos de animación.

Mantén un <Sequence> cuando proporciona timing compartido para múltiples hermanos, envuelve un componente que no maneja timing, o suministra dimensiones que el hijo no puede aceptar directamente. Las raíces administradas también aceptan width y height para useVideoConfig(). Mantén <TransitionSeries.Sequence> para diseño consecutivo, con o sin transiciones; las props from directas no reemplazan esos comportamientos.

Dar a cada elemento editable de forma independiente su propio nodo JSX

El Studio edita el nodo fuente JSX que creó un elemento. Si varios elementos en tiempo de ejecución provienen del mismo nodo JSX, comparten un único 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, crea una línea de tiempo editable así:

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>

Un .map() u otro bucle programático crearía múltiples elementos en tiempo de ejecución a partir de 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, timing, ordenamiento, eliminación o duplicación independientes en el Studio.

Hacer un elemento HTML interactivo usando Interactive

Cada elemento HTML y SVG (excepto <Img>, que ya es interactivo) como <div> se puede convertir en interactivo usando Interactive:

<Interactive.Div
  name="Greeting card"
  style={{fontSize: 80, padding: 24}}
>
  Hello
</Interactive.Div>

Esto permite establecer estilos y keyframes en el Studio. Sé sensato; si un componente tiene muchos elementos, la línea de tiempo podría volverse desordenada.

Preferir texto en línea

Si el texto es fijo y se usa solo una vez, escríbelo directamente dentro del elemento interactivo en lugar de extraerlo en una constante.

// 👍 El texto fijo permanece editable
<Interactive.Div name="Title">
  Remotion Best Practices
</Interactive.Div>

Usa una prop o variable solo cuando el texto es dinámico o se reutiliza.

Dar a los elementos interactivos un nombre descriptivo

Agrega una prop name a los elementos para hacerlos fácilmente identificables. Evita nombres calculados; escríbelos manualmente.

<>
  <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>
</>

Mantener todos los estilos CSS en línea

La mejor manera es pasar un objeto plano a style, sin referencias a constantes, sin propagación de objetos y sin matemáticas.

<Interactive.Div
  style={{
    fontSize: 80,
    color: 'red',
  }}
>
  Hello World!
</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, // ❌ La referencia a constantes no es compatible
    scale: frame * 10 // ❌ Las matemáticas no son compatibles
  }}
>
  Hello World!
</Interactive.Div>

Animar usando interpolate()

Escribe las 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 hardcodeados.

El rango de entrada puede usar adicionalmente durationInFrames, fps, width y height desestructurados directamente de useVideoConfig(). Se admiten identificadores simples como durationInFrames, multiplicación por un número como 2 * fps o fps * 2, y resta de un número como durationInFrames - 1.

const {fps, durationInFrames} = useVideoConfig();

// 👍 Los valores en línea se pueden estandarizar y animar con keyframes
<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'
      }
    ),
    backgroundColor: 'blue',
  }}
>
  Hello World!
</Interactive.Div>

Tipos de salida compatibles

Los siguientes tipos de salida son compatibles:

  • rotate: '0deg', '20deg', etc.
  • scale: Especifica output: 'perceptual-scale' para que la relación entre valores lineales y percepción visual sea suave. Para animaciones que deben coincidir con la sintaxis CSS scale(), usa output: 'css-scale'.
  • translate: '10px 20px' o '10px'.
  • Colores: '#ff0000', 'rgba(255, 0, 0, 0.5)', 'red', etc.
  • Opacidad: 0 a 1.
  • Números: cualquier número.

Easing

Pasar una función de easing (de remotion o @remotion/easing) es la forma preferida de definir una animación. Studio almacena la función para que puedas elegir entre las funciones de easing disponibles y personalizar sus parámetros.

Si pasas un array de puntos de easing, Studio muestra un editor de curvas de Bézier que permite al usuario ajustar visualmente la curva de easing.

import {Easing} from 'remotion';

interpolate(frame, [0, fps], [0, 1], {
  easing: Easing.bezier(0.25, 0.1, 0.25, 1),
  extrapolateLeft: 'clamp',
  extrapolateRight: 'clamp'
})

La interpolación en línea produce representaciones fáciles de actualizar que el Studio puede volver a cargar en caliente.

Para animar propiedades que no están en línea ("No se admite el tipo de salida"), aún puedes usar interpolate() pero el Studio lo representará como un bloque gris: el valor seguirá animándose, pero no se podrá editar.

El uso de interpolate() en una expresión JSX ({interpolate(...)}) o en variables como const opacity = interpolate(...) no es compatible. Pasa todos los valores de propiedades animadas directamente en el objeto style.

Además de las animaciones, ocultar elementos con un fragmento

Para ocultar un componente, envuélvelo en <Fragment name="My component" /> con un nombre. La propiedad name se usa para la identificación. El elemento se puede ocultar en Studio haciendo clic en el ícono del ojo.

<Fragment name="My component">
  <MyComponent />
</Fragment>

Esto permite a los usuarios ocultar y mostrar componentes de forma interactiva en Studio.

Soporte del editor de Studio

Studio admite la edición visual de keyframes, valores de easing, dimensiones, colores y temporización cuando el marcado sigue estas pautas. Líneas de tiempo largas y planas o anidadas anónimas pueden hacer que ciertas características de Studio no estén disponibles.: Sección de línea de tiempo oculta, los valores se atenúan o no aparecen controles de animación.

Para un componente personalizado, el esquema define qué props son editables en el panel de props de Studio. Los componentes interactivos y las composiciones conectadas se pueden abrir en líneas de tiempo secundarias para una edición enfocada.

Individual skills in this repo

This repo contains 19 individual skills — each has its own dedicated page.

Skills relacionados