mcpField
R
remotion-video

remotion-video

github.com/iart-ai创意与媒体1722.8k 次安装18 周前更新
代码仓库

关于 remotion-video

remotion-video 是使用 React 以代码生成 MP4、GIF 和 WebM 的视频制作技能,面向模板化和数据驱动的动态图形。其动画由帧决定,可精确预览、复现并在 CI 中渲染。

主要功能

  1. 01按帧驱动的确定性动画
  2. 02Sequence 与 Series 时间线编排
  3. 03带类型校验的参数化属性
  4. 04音频与节拍同步
  5. 05浏览器预览及命令行渲染

适用场景

  1. 01批量生成个性化社交视频
  2. 02制作可版本管理的动态图形
  3. 03在 CI 中渲染 MP4 或 GIF

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/iart-ai/motion-design-skills --skill remotion-video

安装后在 Claude Code 中输入/remotion-video确认已加载。

附带文件README.mdreferences/api-and-patterns.md

详细介绍

Remotion(程序化视频)

在 React 中构建真正的 MP4/GIF/WebM 视频。每一帧都是 useCurrentFrame() 的纯函数,因此输出具有确定性、可拖动浏览、可比较差异,并可在 CI 中渲染。这是 After Effects 的代码优先替代方案,适用于模板化和数据驱动的动态图形。

适用场景

  • 通过代码渲染 MP4/GIF/WebM(社交媒体短片、标题卡、解说视频)。
  • 模板化/数据驱动的视频:一个合成,基于 props 生成多个输出(按用户、记录或 CSV/DB 的每一行生成)。
  • 必须进行版本管理、代码审查,并且无需 GUI 即可在 CI 中渲染的动态图形。
  • 程序化音频同步、基于数据制作动画图表,或将着色器/Three.js 嵌入视频。

核心技巧

基于帧的动画

动画由当前帧推导而来,而不是通过 setState 或 requestAnimationFrame 实现。interpolate 将输入范围映射到输出范围;spring 可生成符合物理规律的自然运动。

import {useCurrentFrame, useVideoConfig, interpolate, spring} from 'remotion';

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

  // Fade in over frames 0-30, then stay (clamp prevents over/undershoot).
  const opacity = interpolate(frame, [0, 30], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });

  // Spring entrance; divide by spring duration is unnecessary — drive transforms directly.
  const scale = spring({frame, fps, config: {damping: 200, mass: 1, stiffness: 100}});

  return <h1 style={{opacity, transform: `scale(${scale})`}}>Hello</h1>;
};

除非需要有意产生超出范围的效果,否则请始终对 interpolate 进行钳制——默认情况下,它会在范围之外线性外推,导致不透明度大于 1 或出现负值。

调度:Sequence 和 Series

<Sequence> 会偏移时间:在序列的 from 位置,子元素看到的 frame 会重置为 0。使用它将片段放置到时间轴上。<Series> 可连续排列各个片段,无需手动计算偏移量。

import {Sequence, Series, AbsoluteFill} from 'remotion';

export const Timeline = () => (
  <AbsoluteFill style={{backgroundColor: 'black'}}>
    <Sequence from={0} durationInFrames={60}><Intro /></Sequence>
    <Sequence from={60} durationInFrames={90}><Body /></Sequence>

    {/* Series auto-sequences; offset overlaps the previous segment for crossfades */}
    <Series>
      <Series.Sequence durationInFrames={60}><ShotA /></Series.Sequence>
      <Series.Sequence durationInFrames={60} offset={-15}><ShotB /></Series.Sequence>
    </Series>
  </AbsoluteFill>
);
合成注册 + 参数化 props

<Composition> 声明 id、尺寸、fps、时长和 defaultProps。zod schema 可确保 props 类型安全,并可在 Studio 侧边栏中编辑。

import {Composition} from 'remotion';
import {z} from 'zod';

export const schema = z.object({
  title: z.string(),
  accent: z.string(),
  fps: z.number().default(30),
});

export const Root = () => (
  <Composition
    id="Promo"
    component={Promo}
    durationInFrames={150}
    fps={30}
    width={1080}
    height={1920}
    schema={schema}
    defaultProps={{title: 'Launch', accent: '#5b8cff', fps: 30}}
  />
);

如需让时长依赖数据,可在 Composition 上使用 calculateMetadata,根据 props 计算 durationInFrames(例如行数 × 每行帧数),并在渲染前完成计算。

音频与节拍同步
import {Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';

const BEATS_SEC = [0.5, 1.0, 1.5, 2.0]; // detected offline
export const Music = ({children}) => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();
  const t = frame / fps;
  const onBeat = BEATS_SEC.some((b) => Math.abs(t - b) < 1 / fps);
  return (
    <>
      <Audio src={staticFile('track.mp3')} />
      <div style={{transform: `scale(${onBeat ? 1.06 : 1})`}}>{children}</div>
    </>
  );
};

请离线检测节拍(例如使用 web-audio-beat-detector 或 aubio),并将时间戳写入 props——切勿在渲染时分析音频,因为无头渲染没有实时音频时钟。

渲染

在基于浏览器的 Studio 中预览;通过 CLI 或程序化 API 进行无头渲染。

npx remotion studio                                  # interactive preview
npx remotion render Promo out/promo.mp4 \
  --props='{"title":"Launch","accent":"#f43"}'        # pass parametric props
npx remotion render Promo out.gif --codec=gif         # GIF output

对于批处理/数据驱动的流水线,可在 Node 中使用 @remotion/renderer 渲染(打包一次,渲染多次)——参见参考文件。

交付与验证(渲染静帧 → MP4)

打包的辅助工具(scripts/):使用 scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png 将静帧拼成图集,然后使用 scripts/probe-mp4.sh out.mp4 [WxH] [fps] 验证编码结果。参见 scripts/README.md。

Remotion 从设计上就是逐帧确定性的——每一帧都是 useCurrentFrame() 的纯函数,因此无需寻帧工具,就能在无头模式下渲染任意指定帧(相当于 Web 场景中 ?t=N 的重型版本)。当输出必须是 MP4/GIF、必须包含精确的数字或文本,或者需要根据数据批量生成时,使用此方案;对于轻量级 Web 动画,则交付独立 HTML。

输出约定:

  • 一个已注册合成的 Remotion 项目(<Composition> + zod schema + defaultProps),所有动画均由帧驱动(不使用计时器 / Date.now() / Math.random())。
  • 交付物 = 渲染好的 out/*.mp4(以及项目,以便用户使用新的 props/数据重新渲染)。
  • 时长取决于数据?在 calculateMetadata 中计算,不要手动填写。

验证循环——渲染静帧 → 检查 → 编码。 先渲染单帧(成本低,无需视频编码),检查无误后再完整编码视频。

# 1. Frame-exact stills at start / mid / end (PNG, headless, fast)
npx remotion still Promo out/f-start.png --frame=0
npx remotion still Promo out/f-mid.png   --frame=75
npx remotion still Promo out/f-end.png   --frame=149   # last frame = durationInFrames - 1
#    render with the SAME props you'll ship, not just defaultProps:
#    npx remotion still Promo out/f-mid.png --frame=75 --props='{"title":"Launch"}'

# 2. Inspect each PNG — fidelity (matches brief; numbers/text correct) AND
#    artifacts (text overflow, off-canvas, clipped safe-area, missing font, wrong data binding).

# 3. Only after the stills check out, encode the video:
npx remotion render Promo out/promo.mp4 --props='{"title":"Launch"}'
  • 使用 npx remotion compositions 查看每个合成的 durationInFrames/fps,并确定最后一帧。
  • 数据驱动 / 批量生成:先通过静帧验证一组有代表性的 props,再批量渲染所有行——一次发现布局问题,避免重复出错。
  • 免费生成 README 演示 GIF:npx remotion render Promo out/demo.gif --codec=gif 会生成首屏展示片段(方向 D)。

完成前:

  1. npx remotion still 在第 0 帧、中间帧和最后一帧均可干净渲染——没有错误,也没有缺失资源或字体。
  2. 所有已检查帧中的数字/文本均准确,且位于安全区域内。
  3. 仅使用帧驱动——不使用 Date.now() / Math.random() / 计时器(确保在 CI 中保持确定性)。
  4. Props 使用 zod 类型定义;实际交付的 props 渲染正确(不能只验证 defaultProps)。
  5. 完整 MP4 已编码并可播放;(可选)为 README 渲染 GIF。

快速参考

需求用法
将时间映射为数值interpolate(frame, [a,b], [x,y], {extrapolateRight:'clamp'})
自然缓动spring({frame, fps, config})
在 t 时刻放置片段<Sequence from durationInFrames>
连续播放镜头<Series>
音频<Audio src={staticFile(...)} />
帧 ↔ 秒frame / fps
循环一个数值frame % period,然后插值
可编辑 props在 <Composition> 上定义 zod schema
CI 渲染npx remotion render 或 @remotion/renderer

注意事项

  • 绝不使用 Math.random()、Date.now() 或动画计时器——它们会破坏确定性。使用 Remotion 的 random(seed) 实现稳定的逐帧随机性。
  • 通过 staticFile() 加载字体和资源,并使用 delayRender/continueRender 等待加载完成,否则字体可能会在渲染过程中途突然出现。
  • interpolate 默认会进行外推——请限制范围。
  • <Sequence> 内的 useCurrentFrame 使用局部帧号(从 0 开始);绝对时间请使用 useVideoConfig().durationInFrames。

参考文件

  • references/api-and-patterns.md — interpolate 选项和 Easing、spring 配置示例、Sequence/Series 排程、<Audio> 与节拍同步、使用 zod + calculateMetadata 设置参数化 defaultProps、CLI 标志、通过 @remotion/renderer 以编程方式批量渲染,以及嵌入 GLSL 着色器 / Three.js(@remotion/three)。

评论

支持 Markdown