Communitygithub.com

anaydhawan/openvidstudio

内容、动画与效果的最佳实践指南

openvidstudio 是什么?

该技能为使用 Remotion 进行 React 标记编写提供全面指导,涵盖驱动动画的核心概念,如 `useCurrentFrame()` 和 `interpolate()`。它强调保留用户编辑、避免覆盖意外更改,并推荐在 `style` 属性内联使用 interpolate,同时利用 `scale`、`translate` 和 `rotate` 等 CSS 简写属性替代 `transform`。技能支持多种平台(包括 Remotion Studio 和 CLI),并详细说明资产应放置于 `public/` 文件夹,使用 `staticFile()` 引用,同时介绍 `<Video>`、`<Audio>`、`<CanvasImage>` 和 `<AnimatedImage>` 等媒体组件的正确用法。此外,它还深入提供关于延迟、裁剪、转场、字幕、3D 内容、音效可视化、地图集成、Google 字体加载以及通过 FFmpeg 进行音视频操作的专门指南,帮助开发者构建高质量的动态视频。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/anaydhawan/openvidstudio/tree/HEAD/.agents/skills/remotion-markup

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

预览

来自技能 README

文档

这是为编写 Remotion React 标记提供的指南。 如果当前任务不相关,请改用 Remotion 最佳实践。

保留用户更改

用户可能会在对话之外对代码进行编辑。

如果你发现代码中出现了意外的更改,不要覆盖它,请假定这是有意为之,或请求用户确认。

通用规则

使用 useCurrentFrame() 和 interpolate() 驱动动画。
CSS transition 或 animation 无法正确渲染,需要重构。
Tailwind 动画类也无法正确渲染,需要重构。

使用 Easing.bezier() 和 Easing.spring() 自定义时序。

根据 Remotion 交互性最佳实践来组织标记。

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

export const FadeIn = () => {
  const frame = useCurrentFrame();

  return (
    <Interactive.Div
      name="Title"
      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>
  );
};

将 interpolate() 调用内联在 style 属性中。

使用 scale、translate、rotate 等 CSS 属性,而非 transform。

// 👍 内联可编辑的关键帧和变换简写
style={{
  scale: interpolate(frame, [0, 100], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
    easing: Easing.spring({damping: 200}),
    output: 'perceptual-scale' // 对于 `scale` 动画,请使用 "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}),
  }),
}}

// 👎 非内联的值和变换字符串在 Studio 中更难编辑
const scale = interpolate(frame, [0, 100], [0, 1]);

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

资源

将资源放置在项目根目录的 public/ 文件夹中。
使用 staticFile() 引用 public/ 文件夹中的文件。

媒体组件

使用 @remotion/media 中的 <Video> 和 <Audio> 添加视频和音频。
使用 <CanvasImage> 组件添加图片。
使用 <AnimatedImage> 添加动画 GIF、APNG、WebP 或 AVIF 图像;若未使用 Chrome,请使用 @remotion/gif。
对 public/ 中的文件使用 staticFile(),或直接传入远程 URL:

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

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

示例场景

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

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

  return (
    <AbsoluteFill
      name="Scene"
      style={{
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'white'
      }}
    >
      <Interactive.Div
        name="Title"
        style={{
          opacity: interpolate(frame, [1 * fps, 2 * fps], [0, 1], {
            extrapolateRight: "clamp",
            extrapolateLeft: "clamp",
            easing: Easing.bezier(0.16, 1, 0.3, 1),
          }),
          fontSize: 88
        }}
      >
        Title
      </Interactive.Div>
      <Interactive.Div
        name="Subtitle"
        style={{
          opacity: interpolate(frame, [2 * fps, 3 * fps, 8 * fps, 10 * fps], [0, 1, 1, 0], {
            extrapolateRight: "clamp",
            extrapolateLeft: "clamp",
            easing: [Easing.bezier(0.16, 1, 0.3, 1), Easing.linear, Easing.bezier(0.16, 1, 0.3, 1)],
          }),
          fontSize: 32
        }}
      >
        Subtitle
      </Interactive.Div>
    </AbsoluteFill>
  );
};

延迟与裁剪

大多数组件(<AbsoluteFill>、<Interactive.*>、<Img>、<AnimatedImage>、<CanvasImage>、<HtmlInCanvas>、<Solid>、来自 remotion 的 <Sequence>、来自 @remotion/media 的 <Video> 和 <Audio>、<Gif> 等)支持以下属性:

from

<Img from={1 * fps} {/* ... */}/>
<Video from={1 * fps} {/* ... */}/>
<Interactive.Div from={1 * fps} {/* ... */}/>

表示元素在时间轴上开始出现的时间。

durationInFrames

<Img durationInFrames={20 * fps} {/* ... */}/>
<Interactive.Div durationInFrames={20 * fps} {/* ... */}/>

表示图层在时间轴上播放的持续时间。
对于媒体,请传入媒体的自然时长:<Video durationInFrames={29.322 * fps}/>

trimBefore

对于其内部时钟应稍后启动的组件很有用:

// 裁剪掉素材的前 2 秒
<Video trimBefore={2 * fps} {/* ... */} />

// 子组件的 `useCurrentFrame()` 从 `10 * fps` 开始
<Sequence trimBefore={10 * fps} {/* ... */} />

回退方案

如果组件不支持这些属性,请将其包裹在来自 remotion 的 <Sequence> 中,后者支持这些属性。

  • layout="absolute-fill" 使 Sequence 的行为类似于 AbsoluteFill
  • layout="none" 是“无头”模式,不会使用包装元素。

地图

如果需要在视频中包含地图,请参阅 Remotion 地图。

文本高亮与注释

关于文本高亮(标记高亮)、圆圈、下划线、删除线、划掉的文本、方框等,请参阅 text-highlights.md。

多场景视频

如果计划制作包含多个连续场景的视频,请参阅 multi-scene-video.md。

画外音

关于使用 ElevenLabs TTS 为 Remotion 合成添加 AI 生成的画外音,请参阅 voiceover.md。

嵌入视频

关于嵌入视频的高级知识——裁剪、音量、速度、循环、音调,请参阅 embedding-videos.md。

嵌入音频

关于高级音频功能,如裁剪、音量、速度、音调,请参阅 audio.md。

视频编辑

关于在 Remotion Studio 中构建可编辑的视频时间线,请参阅 video-editing.md。

裁剪

如果需要裁剪组件的可视矩形区域,请参阅 cropping.md。

转场

关于场景转场模式,请参阅 transitions.md。

视觉与像素效果

在创建视觉效果时,考虑是使用 CSS 和 HTML 实现,还是需要着色器。
优先级顺序:

  1. 常规 HTML + CSS 或其他 Web 技术

  2. 直接应用于元素(<Video>、<Img>)的效果,或通过将内容包裹在 <HtmlInCanvas> 中,后者也接受 effects:

    • 通过 effects.md 列出的预设效果
    • 当没有预设可用时,通过 effects.md 使用自定义 createEffect()。

3D 内容

关于使用 Three.js 和 React Three Fiber 在 Remotion 中创建 3D 内容,请参阅 ./3d.md。

音效

当需要使用音效时,请加载 ./sfx.md 文件以获取更多信息。

音频可视化

当需要可视化音频(频谱条、波形、低音响应效果)时,请加载 ./audio-visualization.md 文件以获取更多信息。

地图

对于静态地图、动画路线和标记、地理说明、Mapbox、MapLibre、MapTiler、GeoJSON 或 3D 地理飞越,请加载 Remotion 地图。

字幕

当处理字幕或副标题时,请加载 Remotion 字幕技能以获取更多信息。

Google 字体

这是在 Remotion 中加载字体的推荐方式。关于如何加载 Google 字体,请参阅 google-fonts.md。

本地字体

关于如何加载本地字体,请参阅 local-fonts.md。

GIF

关于如何显示与 Remotion 时间线同步的 GIF,请参阅 gifs.md。

高级图像

关于调整和定位图像、动态图像路径以及获取图像尺寸,请参阅 images.md。

Lottie 动画

关于在 Remotion 中嵌入 Lottie 动画,请参阅 lottie.md。

时序

关于 interpolate() 的更多时序技巧,请参阅 timing.md。

参数化视频

关于通过添加 Zod 模式使合成参数化,请参阅 parameters.md。

测量 DOM 节点

关于在 Remotion 中测量 DOM 元素尺寸,请参阅 measuring-dom-nodes.md。

测量文本

关于测量文本尺寸、将文本适配到容器以及检查溢出,请参阅 measuring-text.md。

使用 FFmpeg

对于某些视频操作,例如裁剪视频或检测静音,应使用 FFmpeg。请加载 ./ffmpeg.md 文件以获取更多信息。

静音检测

当需要检测并从视频或音频文件中裁剪静音片段时,请加载 ./silence-detection.md 文件。

动态时长、尺寸和数据

关于动态设置合成的时长、尺寸和属性,请参阅 calculate-metadata.md。

高级合成

关于如何定义静态图片、文件夹、默认属性以及如何嵌套合成,请参阅 compositions.md。

高级排序

关于更多排序模式——延迟、裁剪、限制项目时长,请参阅 sequencing.md。

安装模块

使用 npx remotion add 添加正确版本的新包:

npx remotion add @remotion/media

这适用于 @remotion/* 包、mediabunny、@mediabunny/* 和 zod。

预览标记

npx remotion studio --no-open

这将启动一个长时间运行的进程,并打印预览的服务器 URL。
如果服务器已启动,它将打印 URL。
您可以通过导航到 /[composition-id] 来访问特定合成,例如 http://localhost:3000/MapAnimation。

可选:单帧渲染检查

您可以使用 CLI 渲染单帧,以快速检查布局、颜色或时序。
对于简单编辑、纯重构或当您已经从 Studio 或之前的渲染中获得足够信心时,请跳过此步骤。

npx remotion still [composition-id] --scale=0.25 --frame=30

在 30 fps 下,--frame=30 表示一秒标记(--frame 从零开始)。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能