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 校验)、calculateMetadata与lazyComponent/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 可序列化的,同时Date、Map、Set以及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>注册保持在同一个文件,使width、height、fps、durationInFrames、defaultProps与使用它们的组件代码彼此可见; - 不要把它存进变量、从别处 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: 1与fps: 1。因此它不需要也不能指定durationInFrames或fps,但width、height仍是必填:
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 一样受defaultProps、schema等机制支持。
动态时长、宽高与 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等扩展名会自动补全);defaultCodec、defaultVideoImageFormat、defaultPixelFormat、defaultProResProfile、defaultSampleRate:渲染相关的默认编码与格式。
例如根据一段视频的真实时长设定合成长度:
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>并传入width、height来限定该片段的尺寸:
<AbsoluteFill> <Sequence width={COMPOSITION_WIDTH} height={COMPOSITION_HEIGHT}> <CompositionComponent /> </Sequence> </AbsoluteFill>从实现角度看,<Sequence>是 Remotion 时间轴的编排原语,位于 packages/core/src/Sequence.tsx:其layout属性可选"absolute-fill"(默认,行为类似<AbsoluteFill>)或"none"(无包装元素的 headless 模式),同时提供from、durationInFrames、trimBefore、premountFor等时间控制能力(组合上会校验非法 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),仅供参考