Communitygithub.com

zoih6/masafat-watan-video

Estrutura a marcação Remotion para interatividade no Remotion Studio.

O que é masafat-watan-video?

Este skill define as melhores práticas para estruturar marcação Remotion de forma que o Remotion Studio possa reconhecer e tornar o código interativo. Ele permite que desenvolvedores criem componentes que suportam seleção, arrastar e soltar, redimensionamento, rotação e edição de estilos CSS diretamente no Studio. O skill enfatiza o uso de componentes interativos com suas próprias linhas do tempo, utilizando `Track`, composições conectadas e `Interactive.create()`, além de fornecer diretrizes detalhadas sobre esquemas de campo, registro de componentes, e animação inline com `interpolate()`. É útil para qualquer desenvolvedor que queira criar vídeos programáticos com Remotion e maximizar a editabilidade visual no Studio, suportando plataformas como Claude Code, Cursor, e Codex que implementam skills Remotion.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/zoih6/masafat-watan-video/tree/HEAD/skills-docs/remotion-skills/remotion-interactivity

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Prévia

Do README da skill

masafat-watan-video preview

Documentação

Ao escrever a marcação Remotion de uma forma específica, o Remotion Studio é capaz de reconhecer a estrutura do código e torná-lo interativo:

  • Permitindo que itens sejam selecionados clicando neles
  • Permitindo arrastar e soltar, redimensionar e girar
  • Editando os estilos CSS
  • Tornando os valores de keyframes e easing editáveis

Se a marcação for muito complexa para o Studio torná-la interativa, os valores ficarão cinzas.

Prefira componentes interativos com suas próprias linhas do tempo

Construa novas composições com Track, composições conectadas e Interactive.create().

Defina layout explicitamente como 'absolute-fill' para cenas ou 'none' para elementos delimitados. Registre o mesmo componente de cena exportado e componentes de elemento reutilizável com Composition.

Comece com o exemplo completo de Track + composições conectadas. Ele inclui o elemento, a cena, a linha do tempo pai e os registros raiz.

import {Track, useVideoConfig} from 'remotion';
import {Chapter} from './Chapter';

export const MyVideo = () => {
  const {fps} = useVideoConfig();

  return (
    <Track name="Chapters">
      <Chapter
        name="Opening"
        durationInFrames={3 * fps}
        title="Introduction"
      />
      <Chapter
        name="Feature"
        from={3 * fps}
        durationInFrames={4 * fps}
        title="New features"
      />
    </Track>
  );
};

Coloque estilos de fundo e alinhamento em cada instância de cena, conforme mostrado no exemplo completo. Mantenha contêineres apenas de layout como HTML simples.

Escolha campos de esquema

Cada chave no esquema é uma propriedade que o Studio pode ler e editar no local de chamada. Propriedades 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.

TipoUse paraCom keyframe
stringStrings, como um título, prompt ou trecho de códigoNão
numberNúmeros, com min, max, step, integer opcionaisSim
booleanInterruptores liga/desligaSim (hold)
colorStrings de cor CSSSim
enumUma escolha entre variants, cada uma com seu próprio esquema aninhadoOpt-in (hold)
arrayListas de números, cores, enums e maisNão
assetFontes de mídia, com assetType opcionalNão
font-familyFamília de fonte CSSNão
font-weightPeso da fonteSim
translate, scale, rotation-css, rotation-degrees, transform-originTransformaçõesSim
uv-coordinateUm ponto normalizado [x, y] no elementoSim
svg-pathDados de caminho SVGSim
remotion-captionsDados Caption[]Não
hiddenUm valor mantido fora dos controles—

Todo campo precisa de um default e deve ter uma description, que o Studio mostra como rótulo. Defina keyframable: false para mostrar um controle estático.

Exponha o conteúdo e a 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: Interactive.create() os adiciona automaticamente.

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 filhos React.ReactNode, adicione ...Interactive.childrenSchema. Ele fornece controles para conteúdo filho e pode evoluir para suportar conteúdo mais rico. Atualmente, usa um campo de string rotulado como "Text" com um valor padrão de ''. Se um componente exigir filhos apenas de string, declare um campo children explícito com type: 'string' em vez disso. Interactive.textSchema controla estilos de tipografia; childrenSchema controla o conteúdo. O fragmento de filhos não está incluído em baseSchema ou adicionado automaticamente a componentes personalizados. Marcação aninhada e filhos 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 e elementos reutilizáveis como composições independentes. O Studio chama estas de composições conectadas: elas podem ser abertas em sua própria linha do tempo 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={Chapter}, não ChapterInner ou um wrapper inline. Interactive.create() fornece a sequência, portanto nenhum <Sequence> extra é necessário para a conexão.

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: 'A new perspective',
      style: {
        backgroundColor: '#111111',
        justifyContent: 'center',
        alignItems: 'center',
      },
    }}
  />
);

Escolha um ID único, valores padrão inline representativos e dimensões, fps e duração adequados para visualizar o componente. Os padrões de registro não copiam automaticamente as propriedades de uma instância pai. Veja 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 propriedades de tempo. Componentes interativos integrados e componentes personalizados feitos com Interactive.create() podem receber name, from, durationInFrames, trimBefore e playbackRate diretamente.

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

Para tempo de cena compartilhado, agrupe o conteúdo em um componente feito com Interactive.create() e cronometre essa instância. Raízes gerenciadas também aceitam width e height para useVideoConfig().

Use <Track> para colocar itens na mesma linha da linha do tempo do Studio. Use <TransitionSeries> quando as cenas são sequenciais.

Dê a cada item editável independentemente 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 único alvo de edição de origem.

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 propriedades 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 linha do tempo editável assim:

import { Track } from "remotion";

<Track name="Scenes">
  <Introduction name="Introduction" durationInFrames={90} />
  <Demo name="Demo" from={90} durationInFrames={150} />
</Track>

Um .map() ou outro loop programático criaria vários 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 independentes, propriedades, metadados, tempo, ordenação, exclusão ou duplicação 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="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 linha do tempo pode ficar confusa.

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 propriedade ou variável apenas quando o texto for dinâmico ou reutilizado.

Dê aos elementos interativos um nome descritivo

Adicione uma propriedade name aos elementos para torná-los facilmente identificáveis. Evite nomes computados; codifique-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ência 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, // ❌ Referência a constantes não é suportada
    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 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="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}),
        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="Product card"
  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(anyVariable, [0, 30], [0, 1]) // ❌ Só pode interpretar a variável `frame`.
  }}
/>

Mantenha caminhos SVG editáveis com Interactive.Path

Use <Interactive.Path> de remotion em vez de <path> dentro de um SVG para tornar o caminho visualmente editável.

Instale @remotion/paths para interpolação de caminhos e keyframes de caminho no Studio:

bunx remotion add @remotion/paths

Se a geometria for destinada a ser estática, coloque a string do caminho diretamente na propriedade d. Não a extraia para uma constante.

import {Interactive} from 'remotion';

<Interactive.Svg width={300} height={300} viewBox="0 0 300 300">
  <Interactive.Path
    name="Triangle"
    d="M 40 40 L 260 40 L 150 260 Z"
    fill="#0b84f3"
  />
</Interactive.Svg>

Caminhos de morph usando inline

...

[truncado para tradução]

Individual skills in this repo

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

Habilidades Relacionadas