Communitygithub.com

Guilhermeslvg/video-portfolio

Melhores práticas para conteúdo, animação e efeitos

O que é video-portfolio?

Este skill fornece orientação completa para escrever marcação Remotion React, com foco em conteúdo, animação e efeitos. Ele cobre desde regras gerais, como preservar alterações do usuário e usar `useCurrentFrame()` e `interpolate()` para animações, até componentes de mídia, ativos e esquemas de interatividade com `Interactive.withSchema()`. O documento também inclui práticas recomendadas para transições, desfoque de movimento, efeitos visuais e de pixel, legendas e anotações de texto, vídeos com múltiplas cenas e composições conectadas. É útil para desenvolvedores que usam Remotion no Claude Code, Cursor e Codex, garantindo que as animações sejam renderizadas corretamente e que a interface Studio possa editar propriedades de forma independente.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Guilhermeslvg/video-portfolio/tree/HEAD/.agents/skills/remotion-markup

Perguntar na sua IA favorita

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

Prévia

Do README da skill

Documentação

Esta é uma orientação para escrever marcação Remotion React. Se isso não for relevante, carregue as Melhores Práticas do Remotion.

Preservar alterações do usuário

Os usuários podem fazer edições no código fora da conversa.

Se você detectar uma alteração surpreendente feita entretanto, não a sobrescreva, assuma que ela foi intencional ou peça confirmação.

Regras gerais

Dentro de uma composição ou componente de cena, obtenha fps de useVideoConfig() para todos os cálculos de segundos para quadros, incluindo propriedades de temporização como from, trimBefore, durationInFrames e premountFor. Manter a expressão no nó JSX, como trimBefore={4 * fps}, permite que o Studio edite a temporização e a mantenha correta se a taxa de quadros da composição mudar.

Dirija animações usando useCurrentFrame() e interpolate(). transition ou animation do CSS não renderizarão corretamente, eles precisam ser refatorados. Classes de animação do Tailwind não renderizarão corretamente, elas precisam ser refatoradas.

Use Easing.bezier() e Easing.spring() para personalizar a temporização.

Estruture sua marcação de acordo com as Melhores Práticas de Interatividade do Remotion. Prefira Interactive.withSchema({wrapInSequence: true, layout: 'absolute-fill'}) para cenas com propriedades editáveis. Sua marcação interna pode retornar um fragmento; o wrapper lida com o layout e estilos de instância. Elementos dimensionados, como barras de título, podem manter o layout padrão e encaminhar style para sua própria raiz. Registre cenas reutilizáveis como composições conectadas. Coloque a temporização diretamente nos componentes que a suportam; evite wrappers <Sequence> redundantes. Dê a cada componente temporizado que suporte premountFor um segundo de pré-montagem: premountFor={fps}, onde fps vem de useVideoConfig(). Aplique isso a mídia, componentes interativos, <Sequence>, <TransitionSeries.Sequence> e <TransitionSeries.Overlay>, incluindo componentes temporizados aninhados dentro de cenas. Pré-monte o item da linha do tempo pai também quando um item aninhado precisar montar antes do pai começar. Um componente sem premountFor, como <TransitionSeries.Transition>, não precisa de substituto.

O Studio edita o nó fonte JSX que criou um item. Crie cada registro de composição, clipe, cena, camada e sequência que devem ser editáveis independentemente como seu próprio nó JSX, com suas propriedades editáveis inline. Loops programáticos são adequados quando as instâncias geradas são intencionalmente controladas como um modelo fonte único, não quando os usuários precisam editar as instâncias separadamente.

import { useCurrentFrame, useVideoConfig, Easing, interpolate, Interactive } from "remotion";

export const FadeIn = () => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();

  return (
    <Interactive.Div
      name="Title"
      premountFor={fps}
      style={{
        opacity: interpolate(frame, [0, 2 * fps], [0, 1], {
          extrapolateRight: "clamp",
          extrapolateLeft: "clamp",
          easing: Easing.bezier(0.16, 1, 0.3, 1),
        }),
      }}
    >
      Hello World!
    </Interactive.Div>
  );
};

Mantenha a chamada interpolate() inline na prop style. Use as propriedades CSS scale, translate, rotate em vez de transform.

// 👍 Quadros-chave inline editáveis e abreviações de transformação
style={{
  scale: interpolate(frame, [0, 100], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.spring({damping: 200}),
    output: 'perceptual-scale' // Para animações `scale`, use "output: 'perceptual-scale'"
  }),
  translate: interpolate(frame, [0, 100], ["0px 0px", "100px 100px"], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.spring({damping: 200}),
  }),
  rotate: interpolate(frame, [0, 100], ["20deg", "90deg"], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.spring({damping: 200}),
  }),
}}

// 👎 Valores não inline e strings de transformação tornam-se mais difíceis de editar no Studio
const scale = interpolate(frame, [0, 100], [0, 1]);

style={{
  transform: `scale(${scale})`,
}}

Ativos

Coloque os ativos na pasta public/ na raiz do seu projeto. Use staticFile() para referenciar arquivos da pasta public/.

Componentes de mídia

Adicione vídeo e áudio usando <Video> e <Audio> de @remotion/media. Adicione imagens usando o componente <CanvasImage>. Adicione GIFs animados, APNG, WebP ou imagens AVIF usando <AnimatedImage>, use @remotion/gif se não estiver usando Chrome. Use staticFile() para arquivos em public/ ou passe uma URL remota diretamente:

import { Audio, Video } from "@remotion/media";
import { staticFile, CanvasImage, AnimatedImage, useVideoConfig } from "remotion";

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

  return (
    <>
      <Video src={staticFile("video.mp4")} premountFor={fps} style={{ opacity: 0.5 }} />
      <Audio src={staticFile("audio.mp3")} premountFor={fps} />
      <CanvasImage
        src={staticFile("logo.png")}
        premountFor={fps}
        style={{ width: 100, height: 100 }}
      />
      <Video src="https://remotion.media/video.mp4" premountFor={fps} />
      <AnimatedImage src={staticFile('nyancat.gif')} premountFor={fps} />
    </>
  );
};

Se a composição for principalmente uma linha do tempo de clipes de vídeo ou áudio, leia video-editing.md antes de escolher sua estrutura fonte.

Exemplo de cena

Um vídeo de fundo com uma barra de título. A barra de título é um componente interativo com sua própria linha do tempo, registrada como uma composição conectada. Seu texto é passado como children e accentColor é uma propriedade editável. O fade-in é animado inline no local da chamada.

// MyScene.tsx
import { Video } from "@remotion/media";
import { Easing, interpolate, useCurrentFrame, useVideoConfig } from "remotion";
import { LowerThird } from "./LowerThird";

export const MyScene = () => {
  const { fps } = useVideoConfig();
  const frame = useCurrentFrame();

  return (
    <>
      <Video
        name="Background"
        src="https://remotion.media/video.mp4"
        premountFor={fps}
        objectFit="cover"
        style={{
          position: "absolute",
          width: "100%",
          height: "100%",
        }}
      />
      <LowerThird
        name="Lower third"
        from={1 * fps}
        premountFor={fps}
        accentColor="#0b84f3"
        style={{
          opacity: interpolate(frame, [1 * fps, 2 * fps], [0, 1], {
            extrapolateRight: "clamp",
            extrapolateLeft: "clamp",
            easing: Easing.bezier(0.16, 1, 0.3, 1),
          }),
        }}
      >
        Jane Doe, Product Designer
      </LowerThird>
    </>
  );
};
// LowerThird.tsx
import type React from "react";
import { Interactive, type InteractivitySchema } from "remotion";

type LowerThirdProps = {
  readonly children: React.ReactNode;
  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 = {
  ...Interactive.childrenSchema,
  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,
});
import { Composition } from "remotion";
import { LowerThird } from "./LowerThird";
import { MyScene } from "./MyScene";

export const RemotionRoot: React.FC = () => {
  return (
    <>
      <Composition
        id="MyScene"
        component={MyScene}
        durationInFrames={60}
        fps={30}
        width={1280}
        height={720}
      />
      <Composition
        id="LowerThird"
        component={LowerThird}
        durationInFrames={30}
        fps={30}
        width={1280}
        height={720}
        defaultProps={{
          children: "Jane Doe, Product Designer",
          accentColor: "#0b84f3",
        }}
      />
    </>
  );
};

Atraso, corte

Coloque a temporização diretamente nos componentes que a suportam. Veja Propriedades de temporização para as props suportadas, exemplos e ordem de operações.

Mapas

Veja Remotion Maps se quiser incluir mapas no vídeo.

Destaques e anotações de texto

Veja text-highlights.md para destaques de texto (marcadores de destaque), círculos, sublinhados, tachados, texto riscado, caixas.

Vídeos com múltiplas cenas

Veja multi-scene-video.md se planeja fazer um vídeo com várias cenas subsequentes.

Composições conectadas

Quando uma cena ou grupo de camadas merece sua própria linha do tempo editável, siga connected-compositions.md. Prefira esta estrutura para cenas substanciais em um vídeo de múltiplas cenas.

Ação de pré-composição

Para uma solicitação do Studio como Pré-compor Brilho ambiente (src/BarChart.tsx:134), encontre a marcação da sequência selecionada no local fornecido. Crie uma composição conectada, seguindo connected-compositions.md: extraia a marcação em um componente nomeado, de preferência torne-o interativo com Interactive.withSchema({wrapInSequence: true}), e registre a mesma referência de componente exportada com uma <Composition> única na raiz. Renderize o componente interativo diretamente com suas props de temporização, ou como o único filho de uma sequência quando esse wrapper tiver um propósito. Se o nó selecionado já for uma sequência, mantenha suas props e extraia seus filhos. O registro precisa de dimensões, fps, duração e defaultProps equivalentes ao uso pai. Uma extração de componente sem uma composição registrada não completa uma solicitação de pré-composição.

Leve estilos herdados como fontFamily e carregamento de fonte para o componente extraído; veja independência do pai.

Narração

Veja voiceover.md para adicionar uma narração gerada por IA a composições Remotion usando ElevenLabs TTS.

Incorporação de vídeos

Veja embedding-videos.md para conhecimento avançado sobre incorporação de vídeos - corte, volume, velocidade, loop, pitch.

Incorporação de áudio

Veja audio.md para recursos avançados de áudio como corte, volume, velocidade, pitch.

Corte de imagem

Veja cropping.md se precisar cortar o retângulo visível de um componente.

Transições

Veja transitions.md para padrões de transição de cena.

Desfoque de movimento

Ao adicionar desfoque de movimento ou um rastro de movimento, leia motion-blur.md para a abordagem preferida HTML-em-canvas, requisitos de preview e alternativas.

Efeitos visuais e de pixel

Ao adicionar um efeito visual, primeiro identifique o elemento ou grupo que ele deve afetar. Se o componente alvo suportar effects e um efeito interno abaixo corresponder à solicitação, prefira esse efeito em vez de uma aproximação CSS. Por exemplo, aplique vignette() diretamente na prop effects de um <Video> quando o vinheta deve afetar aquele vídeo.

Estes componentes aceitam effects diretamente:

Importar deComponentes
remotion<Img>, <CanvasImage>, <AnimatedImage>, <Solid>, <HtmlInCanvas>
@remotion/media<Video>
@remotion/gif<Gif>
@remotion/rive<RemotionRiveCanvas>
@remotion/shapes<Arrow>, <Callout>, <Circle>, <Ellipse>, <Heart>, <Pie>, <Polygon>, <Rect>, <Spark>, <Star>, <Triangle>

Elementos HTML comuns, wrappers DOM <Interactive.*>, <AbsoluteFill> e <Sequence> não aceitam effects diretamente. Para aplicar efeitos ao seu conteúdo, envolva-os em <HtmlInCanvas> e coloque a prop effects no wrapper.

Para outros elementos, prefira HTML regular e CSS onde adequado. Considere envolver um grupo em <HtmlInCanvas> quando o pós-processamento de todo o grupo for apropriado e o ambiente suportá-lo.

Leia effects.md antes de aplicar um efeito para importações, parâmetros e configuração. Também cobre efeitos personalizados reutilizáveis com createEffect() quando nenhum efeito interno corresponder.

Efeitos disponíveis

Efeitos internos de @remotion/effects:

  • Cor e tom: brightness(), colorCorrection(), colorKey(), contrast(), duotone(), exposure(), grayscale(), hue(), invert(), levels(), linearGradient(), linearGradientTint(), lut(), saturation(), shadowsHighlights(), thermalVision(), tint(), vibrance(), whiteBalance().
  • Desfoque e rastros: blur(), lightTrail(), linearProgressiveBlur(), radialProgressiveBlur(), regionBlur().
  • Distorção: displacementMap(), mirror(), pixelate(), pixelateRegion().
  • Efeitos de iluminação e brilho: glow(), shimmer().
  • Mascaramento e composição: matte(), overlay(), remapAlpha().
  • Efeitos especiais: vignette().

Não complique demais a escolha: para um desfoque de fundo, blur() é suficiente. Não alcance linearProgressiveBlur() a menos que uma transição de desfoque progressiva seja explícita.

Consulte a documentação de cada efeito para parâmetros e exemplos.

Individual skills in this repo

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

Habilidades Relacionadas