Remotion Composition 定义实战:从 defaultProps、Folder 分组到 Still 与动态元数据
2026/9/8 22:05:40 网站建设 项目流程

Remotion Composition 定义实战:从 defaultProps、Folder 分组到 Still 与动态元数据

【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion

本文是一份围绕 Remotion 中「Composition(视频合成)」定义与编排的实战指南。基于仓库内 remotion-markup 技能包中的 compositions.md 系统讲解:如何用<Composition>声明可渲染的视频、如何通过defaultProps提供初始参数、如何用<Folder>在 Studio 侧边栏组织场景、用<Still>输出单帧图片,以及如何借助calculateMetadata让时长与尺寸动态化。读完你可以独立搭建一个结构规范、参数可编辑、易被 Remotion Studio 与命令行工具正确识别的根组件(Root)。

一个 Composition 是什么

在 Remotion 中,<Composition>是注册一段「可渲染视频」的声明式入口。它把以下信息绑定在一起:

  • 组件(component):真正被渲染的 React 组件;
  • 画幅(width / height):输出视频的像素尺寸;
  • 帧率(fps):每秒帧数;
  • 时长(durationInFrames):共多少帧;
  • 默认参数(defaultProps):组件渲染前的初始 props。

其类型定义位于 packages/core/src/Composition.tsx:核心 props 除了上述字段外,还支持id、可选的schema(Zod 校验)、calculateMetadatalazyComponent/component二选一的组件声明方式。当组件挂载时,内部会调用registerComposition()将这段配置注册进 CompositionManager(见 Composition.tsx#L191-L237),卸载时自动unregisterComposition(id)

每次渲染器与 Studio 都会以id识别这段合成。例如在 packages/template-helloworld/src/Root.tsx 中:

import { Composition } from "remotion"; import { HelloWorld } from "./HelloWorld"; export const RemotionRoot: React.FC = () => { return ( <> <Composition // 通过该 id 可渲染对应视频: // npx remotion render HelloWorld id="HelloWorld" component={HelloWorld} durationInFrames={150} fps={30} width={1920} height={1080} defaultProps={{ titleText: "Welcome to Remotion", titleColor: "#000000", }} /> </> ); };

也就是说:注册的每个<Composition>都会成为 Studio 侧边栏与 CLI 渲染命令中的一个可选项id同时充当命令参数与预览路由(npx remotion studio启动后访问http://localhost:3000/[id]即可进入对应合成)。

id 的命名约束

id并非任意字符串。运行时通过 packages/core/src/validation/validate-composition-id.ts 校验,错误提示表明:id 只能包含 a-z、A-Z、0-9、CJK(中文)字符与连字符-。因此它天然适配 URL、文件名与命令行参数。

defaultProps:为组件提供初始值

defaultProps用于在渲染之前给组件传入初始参数。这些值会在 Studio 中显示、可编辑,属于「合成级别(composition-wide)」的配置,因此适合存放标题文案、颜色、视频源 URL 这类在成片前希望人工确认或覆盖的输入。

可序列化性要求

技能文档明确:defaultProps的值必须是JSON 可序列化的,同时DateMapSet以及staticFile()生成的引用是受支持的。这背后对应 Composition 注册时的serializeThenDeserializeInStudio()(见 packages/core/src/Composition.tsx#L199-L216):Studio 需要对 props 做序列化往返,以便在编辑器中展示、对比与「保存回代码」。

内联字面量:让 Studio 可以把修改保存回来

面向 Studio 编辑场景,最佳实践是defaultProps以内联对象字面量的形式直接写在<Composition>/<Still>

type Props = { readonly title: string; }; export const MyComposition = ({ title }: Props) => ( <h1>{title}</h1> ); // 👍 内联元数据与默认值:Studio 可读可改,也能写回 <Composition id="MyComposition" component={MyComposition} durationInFrames={100} fps={30} width={1080} height={1080} defaultProps={{ title: "Hello World" }} />; // 👎 隐藏的默认值:Studio 无法把修改后的参数保存回代码 const defaultProps = { title: "Hello World" }; <Composition id="OtherComposition" component={MyComposition} durationInFrames={100} fps={30} width={1080} height={1080} defaultProps={defaultProps} />;

相应地,脚手架阶段还推荐:

  • 组件与<Composition>注册保持在同一个文件,使widthheightfpsdurationInFramesdefaultProps与使用它们的组件代码彼此可见;
  • 不要把它存进变量、从别处 import、用展开运算符、用辅助函数构造或用satisfies包装——这些都会让 Studio 无法精确定位并回写默认值;
  • props 使用type声明而非interface,以保障defaultProps的类型安全校验。

渲染期覆盖

需要说明的是:这些默认值不是写死的。渲染时可以整体覆盖 props,例如在服务端渲染 API 或 CLI 中传入自定义参数;若想在 Studio 中获得结构化的参数面板,还可通过给<Composition>增加 Zodschema让合成可参数化(详见 parameters.md),而calculateMetadata则负责在渲染前对 props 做动态转换。

用 Folder 在侧边栏中组织合成

当一个项目包含大量 Composition(比如营销视频、多平台版本、不同社交尺寸)时,可以用<Folder>在 Studio 侧边栏中做视觉分组,且支持无限层级嵌套:

import { Composition, Folder } from "remotion"; export const RemotionRoot = () => { return ( <> <Folder name="Marketing"> <Composition id="Promo" /* ... */ /> <Composition id="Ad" /* ... */ /> </Folder> <Folder name="Social"> <Folder name="Instagram"> <Composition id="Story" /* ... */ /> <Composition id="Reel" /* ... */ /> </Folder> </Folder> </> ); };

技能文档要求Folder 名称只能包含字母、数字与连字符。对应运行时实现中,<Folder>挂载时通过registerFolder()注册,卸载时注销,并通过 React Context 记录「当前文件夹 + 父文件夹链」,父路径以/连接(见 packages/core/src/Folder.tsx)。名称合法性校验位于 packages/core/src/validation/validate-folder-name.ts,其错误提示为:文件夹名只能包含a-z, A-Z, 0-9-。因此项目目录与侧边栏分组之间可以建立稳定的映射关系,方便大批量合成管理。

Still:单帧静态图合成

<Still>用于输出单帧图片(缩略图、封面、海报等)。它本质是durationInFrames固定为 1 的 Composition——查看 packages/core/src/Still.tsx 可以看到实现:渲染<Composition>时强制写入durationInFrames: 1fps: 1。因此它不需要也不能指定durationInFramesfps,但widthheight仍是必填:

import { Still } from "remotion"; import { Thumbnail } from "./Thumbnail"; export const RemotionRoot = () => { return ( <Still id="Thumbnail" component={Thumbnail} width={1280} height={720} /> ); };

使用时可通过 CLI 输出单帧 PNG,例如npx remotion still Thumbnail;这与普通 Composition 一样受defaultPropsschema等机制支持。

动态时长、宽高与 props:calculateMetadata

静态的时长与尺寸直接内联在<Composition>上即可;但当这些元数据依赖输入 props、远程抓取的数据或素材本身的元信息(例如视频时长、源视频分辨率)时,就需要交给calculateMetadata在渲染前动态计算。技能文档给出完整讲解位于 calculate-metadata.md,其回调类型CalculateMetadataFunction与返回值类型CalcMetadataReturnType均定义于 packages/core/src/Composition.tsx#L43-L64。

典型的声明方式如下:

<Composition id="MyComp" component={MyComponent} durationInFrames={300} fps={30} width={1920} height={1080} defaultProps={{ videoSrc: "https://remotion.media/video.mp4" }} calculateMetadata={calculateMetadata} />

calculateMetadata是一个 async 函数,接收{ defaultProps, props, abortSignal, compositionId, isRendering },返回的可选字段(覆盖<Composition>上对应声明)包括:

  • durationInFrames:总帧数;
  • width/height:画幅像素;
  • fps:帧率;
  • props:转换后真正传给组件的 props;
  • defaultOutName:默认输出文件名(.mp4等扩展名会自动补全);
  • defaultCodecdefaultVideoImageFormatdefaultPixelFormatdefaultProResProfiledefaultSampleRate:渲染相关的默认编码与格式。

例如根据一段视频的真实时长设定合成长度:

import { CalculateMetadataFunction } from "remotion"; import { getVideoDuration } from "./get-video-duration"; const calculateMetadata: CalculateMetadataFunction<Props> = async ({ props }) => { const durationInSeconds = await getVideoDuration(props.videoSrc); return { durationInFrames: Math.ceil(durationInSeconds * 30), }; };

同理,可以用getVideoDimensions让输出画幅与视频一致,或在 Studio 中 props 变化时借助abortSignal取消过期的网络请求、在渲染前 fetch 数据并合并进 props。多素材拼接、按 props 生成默认文件名等进阶场景,请继续阅读 calculate-metadata.md。

在另一个 Composition 中嵌套合成

把一个「子合成」嵌入到另一段合成中,可以使用<Sequence>并传入widthheight来限定该片段的尺寸:

<AbsoluteFill> <Sequence width={COMPOSITION_WIDTH} height={COMPOSITION_HEIGHT}> <CompositionComponent /> </Sequence> </AbsoluteFill>

从实现角度看,<Sequence>是 Remotion 时间轴的编排原语,位于 packages/core/src/Sequence.tsx:其layout属性可选"absolute-fill"(默认,行为类似<AbsoluteFill>)或"none"(无包装元素的 headless 模式),同时提供fromdurationInFramestrimBeforepremountFor等时间控制能力(组合上会校验非法 layout 组合并抛错)。想精细控制各层的出现时机、裁切与时长,可进一步查阅 sequencing.md;若目标是「一个视频包含多个依次衔接的场景」,可参考 multi-scene-video.md。

在 Studio 中验证你的合成结构

定义好根组件后,可以用技能包推荐的方式快速验证:

npx remotion studio --no-open

该命令会启动一个长驻进程并打印 Studio 服务地址;导航到/下的某个 Composition id(例如http://localhost:3000/MapAnimation)即可进入预览。布局、配色或时间轴需要抽查时,还可以做一次性单帧渲染:

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

在 30fps 下--frame=30恰好是第 1 秒(--frame从 0 开始计数)。这套「内联注册 + 侧边栏分组 + 单帧抽查」的工作流能确保每段 Composition 的注册、参数与视觉输出始终处于可被验证的状态。想了解 Composition 之外的场景编排、动效与素材最佳实践,可以继续阅读同目录的 SKILL.md 技能总纲。

【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询