Remotion 最有价值的能力,不是“可以用 React 做动画”,而是它可以把已有视频导入成底层画面,再让 React 组件按照帧号精准叠加在上面。

这件事很适合真人口播、录屏讲解、产品演示和数据视频:底层是一个已经录好的 MP4,上面再加标题卡、字幕、代码高亮、流程图、进度条和数据图表。

这类任务如果只用一个从零绘制 HTML 的框架,通常要先把真人视频切成画面、再做额外合成;Remotion 则把“视频素材”和“组件画面”放进同一个 React 时间轴里。

本文重点讲 Remotion 的工作模型、项目结构、视频导入、组件叠加、批量生成和验收边界。具体命令和授权条件应以当前 Remotion 文档和项目版本为准。

一、Remotion 把视频当成 React 组件

在 Remotion 中,一条视频可以被理解成一个随帧号变化的 React 画面:

当前帧 0   -> React 组件状态 0
当前帧 1   -> React 组件状态 1
当前帧 2   -> React 组件状态 2
...
当前帧 N   -> React 组件状态 N

组件通过当前帧计算透明度、位置、缩放、字幕和图表状态。渲染器逐帧获得组件结果,再编码为视频。

最小的组件形态类似这样:

import { AbsoluteFill, useCurrentFrame, useVideoConfig } from "remotion";

export const TitleCard = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const opacity = Math.min(1, frame / (fps * 0.5));

  return (
    <AbsoluteFill
      style={{
        backgroundColor: "#f7f7f5",
        justifyContent: "center",
        alignItems: "center",
        opacity
      }}
    >
      <h1>代码做视频</h1>
    </AbsoluteFill>
  );
};

useCurrentFrame() 提供当前帧,useVideoConfig() 提供帧率、宽高和时长等配置。不要把浏览器当前时间当作动画依据,否则逐帧渲染时可能出现状态漂移。

二、视频底层和 React overlay

Remotion 的关键场景是:底层播放一段已有视频,前景叠加 React 组件。

import {
  AbsoluteFill,
  OffthreadVideo,
  useCurrentFrame,
  useVideoConfig
} from "remotion";

export const TalkingHead = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const showTitle = frame >= 0 && frame < fps * 4;

  return (
    <AbsoluteFill>
      <OffthreadVideo src="assets/talking-head.mp4" />

      {showTitle && (
        <div
          style={{
            position: "absolute",
            left: 80,
            bottom: 80,
            padding: "18px 28px",
            background: "rgba(0, 0, 0, 0.72)",
            color: "white"
          }}
        >
          这一段讲清楚一个概念
        </div>
      )}
    </AbsoluteFill>
  );
};

这里的 MP4 是画面底层,标题卡由 React 生成。二者共享同一帧号,所以标题可以精确地在指定帧出现和消失。

三、项目结构应该先固定

一个长期维护的 Remotion 项目不要把所有逻辑塞在 App.tsx

remotion-video/
├── src/
│   ├── Root.tsx
│   ├── compositions/
│   │   ├── TalkingHead.tsx
│   │   ├── ScreenRecording.tsx
│   │   └── DataVideo.tsx
│   ├── components/
│   │   ├── Subtitle.tsx
│   │   ├── LowerThird.tsx
│   │   ├── CodeBlock.tsx
│   │   └── ProgressBar.tsx
│   └── data/
│       └── examples.ts
├── public/
│   ├── video/
│   ├── audio/
│   ├── images/
│   └── fonts/
├── scripts/
└── package.json

Composition 负责一类视频结构,组件负责可复用视觉元素,数据文件负责内容。这样做的好处是:同一个标题卡可以用于真人口播、录屏和产品发布视频,不需要复制整套时间轴。

四、把时间轴变成数据

不要把所有时间点散落在组件代码里。可以统一写成场景数据:

export const scenes = [
  {
    id: "intro",
    startFrame: 0,
    endFrame: 150,
    title: "今天解决一个问题"
  },
  {
    id: "diagram",
    startFrame: 150,
    endFrame: 420,
    title: "把流程拆成三步"
  }
];

组件只负责读取数据和计算画面:

const active = scenes.find(
  scene => frame >= scene.startFrame && frame < scene.endFrame
);

这样当口播稿、场景时长或字幕发生变化时,可以修改数据而不是重写组件。批量视频也可以把同一个 Composition 和不同的输入 JSON 组合起来。

五、字幕和口播怎样同步

字幕同步有三种常见精度:句级、词级和逐字级。

句级字幕实现成本最低,适合信息密度不高的视频;词级字幕更适合口播和教程;逐字级字幕需要更准确的时间戳,也更容易暴露 ASR 错误。

字幕数据可以是:

[
  {"text": "今天讲代码视频", "start": 0.0, "end": 2.1},
  {"text": "重点是逐帧渲染", "start": 2.1, "end": 4.5}
]

转换成帧时:

const startFrame = Math.round(start * fps);
const endFrame = Math.round(end * fps);
const visible = frame >= startFrame && frame < endFrame;

不要让 React 组件自行猜当前句子。字幕的起止时间应该来自统一数据,音频、字幕和画面都引用同一份时间轴。

六、全身出镜和录屏切换

一个常见的视频结构是:

全身出镜:真人视频全屏
录屏讲解:录屏全屏,真人缩成左下角
章节卡:全屏图形动画
回到出镜:真人视频全屏

Remotion 可以把这些段落设计成可组合的组件。关键是提前定义每段的帧范围和层级:

0-180 帧:TalkingHeadFull
180-720 帧:ScreenRecording + TalkingHeadSmall
720-900 帧:ChapterCard

如果切换点来自口播或字幕,不要凭感觉填秒数。先生成时间轴清单,确认每段视频实际长度,再由组件使用帧范围。

七、数据视频和批量生成

Remotion 适合把画面结构和数据分离:

{
  "name": "张三",
  "metric": 82,
  "message": "本周完成了 12 个任务",
  "avatar": "avatars/zhang-san.png"
}

同一个组件可以读取不同 JSON,生成不同版本。适合:

批量渲染前要先处理输入校验:姓名为空、数字格式错误、头像不存在和文本过长,都应该在渲染前被发现,而不是等生成几百条视频后再逐个排查。

八、本地渲染和分布式渲染

本地渲染适合调试和少量成片。它的优点是素材、日志和错误都在当前机器,修改反馈更直接。

当视频数量或时长增加时,可以考虑分布式渲染。Remotion 提供云端渲染相关能力,但并行并不会自动解决所有问题:

云端渲染适合批量生产,但应该先用固定样片验证完整流程,不能第一次就把大批任务提交到远程环境。

九、Remotion 的 AI 使用边界

AI 写 React 比写简单 HTML 更容易遇到错误:

所以给编码 Agent 的任务应该分阶段:

第一轮:只创建 Composition 和静态组件。
第二轮:接入固定数据,不加入视频素材。
第三轮:接入底层 MP4,验证时长和尺寸。
第四轮:加入字幕和 overlay。
第五轮:运行构建、渲染和帧抽查。

每一轮都应该能独立运行。不要让 Agent 一次生成项目、安装依赖、接视频、加字幕、部署和批量渲染,出了问题后很难知道是哪一层失败。

十、字体、素材和视频解码

Remotion 最终还是要在确定的浏览器和编码环境中渲染。正式渲染前检查:

开发预览能播放,不代表逐帧渲染一定成功。尤其是外部视频、远程字体和网络图片,最好在正式渲染前复制到项目可控的素材目录。

十一、授权与成本要单独核对

Remotion 的版本、云渲染能力和商业授权条款可能变化。个人、团队和企业使用时,不能只根据别人文章里的价格或人数限制做判断,应直接查看当前官方授权页面和项目协议。

同样,底层真人视频、音乐、字体、图片和代码截图也有各自的授权边界。框架能把素材合成视频,不代表你自动获得了素材的发布权。

十二、验收 Remotion 视频

至少检查:

结论

Remotion 的核心优势是把已有视频、React 组件、字幕、图表和数据放进同一套帧级渲染模型里。

如果你的底层是一段真人口播或录屏,而前景还要持续叠加动态内容,Remotion 往往比纯 HTML 画面框架更自然。它的代价是 React 构建、依赖、渲染时间和版本维护都更复杂。

它适合做成模板资产,而不是每次从零写一套组件。先把一个真实的视频场景跑通,再抽取字幕、标题卡、数据图表和视频布局,批量生产才会有稳定基础。

参考资料