关于 compose
用于将录制素材组装成完整视频的创作技能,面向制作演示和宣传内容的流程。它通过 Remotion 渲染,并提供布局、节奏、效果和画面预设的编排规则。
主要功能
- 01编排单段或并排视频布局
- 02设置播放速度与输出清晰度
- 03添加标题卡、章节和按键叠加
- 04选择画面预设与效果层级
- 05通过渲染脚本生成视频
适用场景
- 01制作功能演示视频
- 02制作前后状态对比视频
- 03为产品页面制作展示视频
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ factory-ai/ factory-plugins --skill compose安装后在 Claude Code 中输入/compose确认已加载。
详细介绍
Compose
此模块负责完整的视频组装流水线。你会收到 capture 阶段的原始输出,并将其制作成一个精良的成品。请按以下步骤完成流水线。
输入
命令或 capture 阶段应已提供包含以下两个部分的交接内容:
机械信息(结构化)
- clips:原始录制文件的路径(
.cast、.mp4、.webm);静帧不是片段——请参阅“仅截图成品” - driver:tuistory | true-input | agent-browser | cua-driver
- layout:
single|side-by-side - labels:每个片段的文字标签(例如,“BEFORE (dev)”、“AFTER (PR)”)
- speed:由组装流程对每个片段应用一次的播放速度倍数(默认为 1x)
- fidelity:
compact|standard|inspect(可选;省略时,side-by-side=inspect,single=standard) - title:标题卡片的文字
- subtitle:一句话摘要
- sections:章节文字横幅
[{t, title}](可选) - keys:按键事件
[{t, label, dur?}](如果请求叠加层) - showcase:预设名称——
macos、minimal、hero、presentation、factory、factory-hero - effects tier:
utilitarian|full|none(请参阅下文“在组装时选择特效”) - output:期望的输出路径
创意指导(自然语言)
以自由文本说明需要强调的内容:哪些时刻需要停留、标题卡片应传达什么、是否需要阶段卡片,以及如何剪掉无用时段。请结合特效等级,根据编辑需求(包括选择具体特效)使用这些指导。
流水线
1. Build props → construct the Showcase JSON props
2. Render → render-showcase.sh (converts .cast, stages clips, probes duration, renders, cleans up)
3. Finalize → verify and output
Remotion 会在单次处理中完成所有合成——标题卡片、转场、窗口边框、背景、按键叠加层、聚光灯、粒子、噪点和调色均会自动完成。你只需构建 props JSON,其余工作由引擎完成。
Remotion 项目和辅助脚本
REMOTION_DIR=${DROID_PLUGIN_ROOT}/remotion
RENDER=${DROID_PLUGIN_ROOT}/scripts/render-showcase.sh
Showcase 模式与 Demo 模式
两者使用相同的 Remotion 流水线,但面向不同的视觉风格。
| Showcase | Demo | |
|---|---|---|
| 目标 | 电影感、高品质的营销素材 | 清晰、实用的演示——单项展示或对比展示,视内容需要而定 |
| 预设 | factory、factory-hero 或 hero | macos、minimal 或 presentation |
| 特效等级 | Full ——聚光灯、缩放、标注、按键叠加层。尽情发挥。 | Utilitarian ——通过缩放提升可读性,通过按键叠加层展示用户操作 |
| 受众 | 外部受众——落地页、社交媒体、营销 | 内部受众——PR 审查、文档、QA |
决策规则:如果视频将面向工程团队以外的观众,请使用 Showcase 模式。如果用于 PR 描述、内部演示或嵌入文档,请使用 Demo 模式。视觉润色层(暖色光晕、粒子、调色、运动模糊)始终存在,但其强度由配色方案决定——Factory 预设会呈现浓郁的电影感暖色调,而 Catppuccin 预设则保持低调、冷峻的风格。
在组装时选择特效
命令阶段已确定 effects tier(utilitarian、full 或 none)。现在你已拿到实际录制内容,可以选择具体特效:
- Utilitarian:对较小或难以辨认的文字添加缩放效果。如果录制了用户操作,则添加按键叠加层。除非屏幕上的内容确实难以找到,否则跳过聚光灯和标注。
- Full:使用完整的特效组合。用聚光灯突出关键证据。放大细节。对于无法通过界面直观理解的内容,添加标注。全程叠加按键层。以电影感为目标——让观众感到有人引导,而不是只能自行浏览。
- None:在 props 中传入
"effects": []。如果已单独确定使用按键叠加层,仍可添加该叠加层。
步骤 1:选择保真度和节奏
未指定 fidelity 时,render-showcase.sh 会为并排布局选择 inspect,为单片段布局选择 standard;可传入 compact、standard 或 inspect(通过 props 或 --fidelity)进行覆盖。保真度仅在此处确定。
| 保真度 | 默认输出尺寸 | Remotion 编码 | 润色叠加效果 | 最适用于 |
|---|---|---|---|---|
compact | 1920x1080 | H.264 CRF 21,JPEG 帧 | 完整颗粒效果 + 调色 | 小型嵌入内容 |
standard | 1920x1080 | H.264 CRF 18,JPEG 帧 | 减弱颗粒效果 + 调色 | 单面板演示 |
inspect | 2560x1440 | H.264 CRF 14,PNG 帧 | 最少颗粒效果 + 调色 | 并排比较/微小文字 |
.cast 转换行为
render-showcase.sh 会在 Remotion 渲染前,通过 agg -> gif -> ffmpeg -> mp4 转换 .cast 输入,并使用 asciicast 自身的 cols/rows 和固定字体度量,确保元素位置在不同保真度配置间保持稳定。转换以 1x 速度运行,并禁用 agg 的空闲时间压缩,因此 mp4 会保留录制时间线(外加 agg 在最后一帧停留的 3s);之后由合成应用 speed,与 .mp4/.webm 片段完全相同。
重要:agg 会用其主题调色板替换全部 16 种 ANSI 颜色。 渲染脚本使用自定义的 Droid CLI 主题。若手动运行 agg,切勿省略 --theme,也切勿使用 monokai 或 dracula 等内置主题。
--theme 标志接受以逗号分隔的十六进制字符串(不带 # 前缀):bg,fg,color0..color7(10 个值),或 bg,fg,color0..color7,color8..color15(包含亮色变体的 18 个值)。
注意:Droid CLI 的 tuistory 录制通常不会输出颜色转义码——该 CLI 使用 Ink 的直接渲染,不会在 cast 输出中生成标准 ANSI SGR 序列。主题中的 bg(第一个值:181818)和 fg(第二个值:e0d0c0,暖白色)是仅有的会影响输出的颜色。暖白色 fg 可避免默认主题带来的冷调蓝灰外观。
对于确实会输出 ANSI 颜色码的其他终端,请根据终端的实际颜色设置构建完整主题字符串。
节奏:以最终视频时长为目标,而不是速度系数。盲目使用倍速,要么会让文字难以辨认,要么会留下空白时段。
| 演示类型 | 目标时长 | 原因 |
|---|---|---|
| 单项功能,3-5 个步骤 | 30-45s | 观众可以一气呵成地看完整个演示 |
| 前后对比、并排展示 | 45-75s | 每个面板都需要时间呈现;静止与动态的对比需要停顿 |
| 多阶段或复杂流程 | 60-120s | 阶段卡片可让观众稍作调整;赶进度会适得其反 |
目标时长针对最终视频,即片段加上 7.5s 的卡片时长(4s 标题、3.5s 片尾;见时长检查点)。设置 speed 属性以达到目标时长:若目标为 60s,片段时长约为 52s,因此 3 分钟的原始录制需要 "speed": 3.5。若原始录制已经是 40s,则使用 "speed": 1,或剪掉无效时段。先剪辑,再加速——使用 asciinema cut 从 .cast 中剪掉大模型思考暂停、构建等待和网络延迟,或通过拆分片段来剪辑;之后若仍超过目标时长,再适度加速。
叠加效果时间边界:props 中的每个叠加效果时间(keys[].t、sections[].t、effects[].t/dur、codeAnnotations[].t/dur)都是相对于内容起始位置的输出时间线秒数。合成只对片段应用 speed,绝不改变叠加效果的时间。捕获日志记录的是原始录制秒数,因此写入 props 前,需将每个时间戳除以速度系数(并减去剪掉的开头时长):在 3 倍速视频中,原始时间 t=6.0s 的按键操作应写为 t=2.0s。
非 .cast 片段
.mp4 和 .webm 片段会原样暂存,并像转换后的 cast 一样按 speed 播放。只有在其像素格式或尺寸无效时,才需手动重新编码。.png 文件不能用作片段;静态图请参见下文“仅截图类素材”。
剪辑宽高比(浏览器录制时必须检查)
在默认 1920×1080 输出和出厂预设边距下,面板大致如下:
| 布局 | 面板宽高比 |
|---|---|
single | ~1760×920(≈16:9 横屏) |
side-by-side | 每个面板 ~872×920(≈8:9,接近正方形/略偏竖屏) |
.cast 转换会自动适配面板宽高比。预录制的 .mp4 / .webm 剪辑不会——如果剪辑宽高比与面板不匹配,剪辑就会出现黑边(默认 objectFit: "contain")或被裁切("cover")。
常见陷阱:浏览器录制通常为 16:9 横屏(例如 1280×720)。放入 side-by-side 布局后,会显示成一条窄带,上下留有大片黑边。
按优先顺序有两种修复方法:
- 以适合面板的视口重新录制——返回录制阶段,将视口设为
side-by-side时约 960×1000,single时约 1280×720。 - 在 props 中传入
"objectFit": "cover"——裁切剪辑边缘以填满面板。相关 UI 居中且边缘内容可以舍弃时,这种做法可以接受。如果被裁切的内容很重要(例如侧边栏 UI 被裁掉),则不可接受。
.cast 剪辑通常不需要这样处理,因为其渲染宽高比由 cols/rows 推导而来;这几乎总是浏览器录制才会遇到的问题。
时长检查点(继续之前必须完成)
检查计划采用的速度系数是否能使最终时长落在节奏表的目标范围内:
final_duration = 4s title + longest_clip_duration / speed_factor + 3.5s outro
这是 remotion/src/lib/duration.ts 为合成计算出的精确时长(帧数会按 30fps 向上取整为整数帧)。内容序列为两个 0.5s 交叉淡化都留有余量:标题交叉淡化在播放前进行;片尾交叉淡化在按帧取整后的播放间隔结束后开始,并显示定格帧。窗口边框自身的 0.5s 入场动画会与播放的前半秒重叠,因此录制时应先停留在稳定状态。任何大于零且有限的 speed 值都有效,即使它会将剪辑缩短至交叉淡化时长以下。
剪辑会持续到最长剪辑结束;较短的剪辑会停留在最后一帧(不会循环),直到序列结束。进行对比时,应让两个剪辑都录制到匹配的结束状态,否则观看者会看到一个面板定格,而另一个仍在继续播放。
| 如果 final_duration... | 操作 |
|---|---|
| 在目标范围内 | 继续 |
| 低于最短时长 | 降低速度系数,直到达到目标。如果即使在 1x 时剪辑也低于最短时长,说明录制时间太短——返回录制阶段并增加交互步骤。 |
| 高于最长时长 | 先剪掉无效时长(asciinema cut),然后提高 speed 属性 |
此检查点不可跳过。时长不在目标范围内的视频无法通过验证。
第 2 步:构建 props
选择布局
默认:single。 一个展示目标/最终状态的剪辑。新功能、Bug 修复证明、操作演示和 README 主视觉都应使用此布局。
只有当内容本质上是在做对比时,才使用 side-by-side:回归对比(损坏 vs 修复)、保持行为不变的重构,或用户明确提出要求。切勿为了适配 side-by-side 布局而虚构“之前”的剪辑。
将 showcaseSchema JSON 保存到临时文件:
DEMO_TMP="$(mktemp -d /tmp/droid-demo-XXXXXX)"
PROPS="${DEMO_TMP}/showcase-props.json"
cat > "$PROPS" << 'EOF'
{
"clips": ["demo.cast"],
"layout": "single",
"labels": [],
"speed": 3,
"title": "PR #11621 — Prevent session freezes",
"subtitle": "Bash Mode blocks interactive commands and supports ESC cancellation",
"preset": "factory",
"keys": [
{"t": 2.0, "label": "vim"},
{"t": 5.5, "label": "sleep 100"},
{"t": 8.0, "label": "Esc"}
],
"sections": [],
"effects": [],
"speedNote": "3x speed",
"windowTitle": "droid demo"
}
EOF
对于对比流程,将 "clips" 替换为两个路径,将 "layout" 设为 "side-by-side",并填写 "labels"(例如 ["BEFORE (main)", "AFTER (PR #11621)"])。
使用针对本次运行的 props 路径,例如 $PROPS;不要在重新渲染或并发演示之间重复使用全局路径 /tmp/showcase-props.json。
clipDuration 由渲染脚本负责设置。 脚本会使用 ffprobe 检查每个剪辑,并写入最长剪辑的源时长(秒);合成时再除以 speed。不要手动设置——若要缩短视频,请裁切源剪辑。
Props 参考
| Prop | Type | Required | Description |
|---|---|---|---|
clips | string[] | 是 | 渲染脚本会按命令行顺序,用暂存路径覆盖此值;位置参数中的片段参数才是唯一可信来源 |
layout | "single" | "side-by-side" | 是 | 合成布局 |
labels | string[] | 是 | 每个片段的标签(并排布局时可见;单画面布局请传入 []) |
fidelity | "compact" | "standard" | "inspect" | 否 | 输出质量/压缩配置。省略时,渲染脚本会根据布局选择。 |
speed | number | 否 | 合成内容会将此播放倍率应用于每个片段(默认值为 1)。叠加元素的时间不会缩放。 |
title | string | 是 | 标题卡片标题 |
subtitle | string | 是 | 标题卡片副标题 |
preset | preset name | 是 | 视觉预设——见下表 |
keys | Keystroke[] | 是 | 击键叠加事件(没有时请传入 []) |
sections | Section[] | 否 | 用于标记章节的分节横幅(没有时请传入 []) |
effects | Effect[] | 是 | 效果时间线(没有时请传入 []) |
clipDuration | number | 否 | 源片段中最长片段的时长(秒)。由渲染脚本设置;请勿手动填写。 |
speedNote | string | 否 | 显示在标题卡片上(例如 "3x speed") |
windowTitle | string | 否 | 窗口标题栏中的文本 |
width | number | 否 | 输出宽度(默认值:inspect 为 2560,否则为 1920) |
height | number | 否 | 输出高度(默认值:inspect 为 1440,否则为 1080) |
objectFit | "contain" | "cover" | "fill" | 否 | 每个片段在其面板中的适配方式。默认值为 "contain"(保留宽高比并添加黑边)。当片段宽高比与面板宽高比不匹配,且你更愿意裁切而不是显示黑边时,请使用 "cover"。参见下文“片段宽高比”。 |
codeAnnotations | CodeAnnotation[] | 否 | 主内容序列播放期间显示的定时语法高亮代码叠加层。参见下文“代码注释”。 |
transitionStyle | "motion-blur" | "flash" | "whip-pan" | "light-leak" | "glitch-lite" | 否 | 标题→内容和内容→结尾过渡的呈现方式。默认值 "motion-blur" 可保留现有风格。参见下文“过渡样式”。 |
预设速查
| Preset | 外观 | 配色 | 适用场景 |
|---|---|---|---|
factory | 暖色黑色背景、红黄绿信号灯、12px 圆角、80px 边距 | Factory(暖色) | Factory 官方内容 |
factory-hero | 与 factory 相同,另加渐变背景 | Factory(暖色) | Factory 落地页、社交媒体 |
hero | 渐变背景、宽裕的边距、醒目的阴影 | Catppuccin(冷色) | 非 Factory 营销内容 |
macos | 深色背景、红黄绿信号灯、简洁边框 | Catppuccin(冷色) | 通用演示 |
presentation | 黑色背景、宽裕的边距 | Catppuccin(冷色) | 幻灯片、演讲 |
minimal | 无窗口栏、极小圆角、紧凑边距 | Catppuccin(冷色) | 文档嵌入、内嵌片段 |
击键结构
{ t: number, label: string, dur?: number }
t:相对于片段起始时间(而非标题卡片)的时间,单位为秒。请根据速度倍率调整。label:显示文本(例如"Ctrl+C"、"vim main.rs")dur:显示时长,单位为秒(默认值:1.2s)。下一次击键开始时会自动切换。
分节结构
{ "t": 2.0, "title": "Testing basic echo" }
t:相对于片段起始时间(而非标题卡片)的时间,单位为秒。请根据速度倍率调整。title:分节标题的显示文本。此文本会持续显示,直到下一节开始。
效果类型
| 效果 | 属性 | 描述 |
|---|---|---|
fade-in | t、dur | 从黑屏淡入(通过架构验证,但 Showcase 尚未渲染此效果——渲染时会发出警告) |
fade-out | t、dur | 淡出至黑屏(通过架构验证,但 Showcase 尚未渲染此效果——渲染时会发出警告) |
zoom | t、dur、to: {x,y,w,h} | 定向缩放至目标区域(30% 放大、40% 停留、30% 缩小) |
spotlight | t、dur、on: {x,y,w,h}、dim? | 将区域以外的部分调暗(dim:0–1,默认值为 0.6) |
callout | t、dur、text、at: {x,y} | 锚定到某个点的文本叠加层 |
区域使用百分比字符串(例如 "25%"),相对于视频尺寸计算。
何时使用效果
| 效果 | 适用场景… | 不适用场景… |
|---|---|---|
spotlight | 突出显示特定区域(错误、状态变化) | 整个画面都与内容相关 |
zoom | 全尺寸下难以看清的小字或细节 | 内容本身已清晰易读 |
callout | 标注观众可能无法识别的内容 | UI 不言自明 |
| 按键叠加层 | 展示用户操作(输入文字、按键) | 片段中没有用户交互 |
少即是多。 一个时机恰当的聚光效果,比五个相互重叠的效果更有冲击力。
代码注释
定时显示的语法高亮代码卡片,叠加在录制的视频上。适用于 PR 演示,让关键源代码变更与运行时证明并排呈现。
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
t | number | 是 | 开始时间,单位为秒,相对于片段起始时间。需根据 speed 倍数调整(规则与 keys[].t 相同)。 |
dur | number | 是 | 卡片显示时长,单位为秒。 |
code | string | 是 | 源代码文本;多行时使用 \n;末尾不加换行符。 |
language | string | 否 | Prism 语言 ID(tsx、ts、py、rust、bash 等)。默认值为 tsx。 |
title | string | 否 | 代码上方的小标题(通常为文件路径)。 |
highlight | [{start,end}] | 否 | 从 1 开始且包含结束行的行范围,带强调色背景和左边框。 |
focus | [{start,end}] | 否 | 从 1 开始且包含结束行的行范围,保持完全不透明;其他行会变暗或模糊。 |
position | "top-right" | "center" | "bottom-left" | 否 | 默认值为 "top-right"。如果录制画面右上角的内容至关重要,则移至 "bottom-left"。 |
保持简短——每张卡片尽量不超过 15 行,显示 3–6 秒。
转场样式
transitionStyle 用于选择标题→内容和内容→片尾的交叉淡化呈现方式。单次渲染中的两次转场使用相同样式。flash 和 light-leak 的色调取自预设调色板。默认的 motion-blur 始终安全;各预设层级的使用指南见 showcase/SKILL.md。
| 样式 | 感受 | 适用场景… |
|---|---|---|
motion-blur | 轻微推轨,模糊与不透明度交叉淡化 | PR 演示、Factory 内容及大多数 Showcase 作品的默认选择 |
flash | 中点处快速闪现预设调色板色调 | 修复 Bug 的证明,其中「修复后」状态应显得突然 |
whip-pan | 水平摇镜与运动模糊 | 节奏较快、充满活力的 Showcase 或营销内容 |
light-leak | 温暖的渐变扫过 | Factory 品牌风格的落地页或社交媒体片段 |
glitch-lite | RGB 通道偏移与水平条带 | 安全或漏洞证明、终端美学;绝不可设为默认值,也不可连续使用两次 |
第 3 步:渲染
使用渲染脚本——它是合成流程(暂存、规范化、时长计算、渲染、清理)的唯一入口:
RENDER=${DROID_PLUGIN_ROOT}/scripts/render-showcase.sh
# Basic render
$RENDER --props "$PROPS" --output "${RUN_DIR}/demo.mp4" \
"${RUN_DIR}/before.cast" "${RUN_DIR}/after.cast"
# Or with inline props (useful for simple cases)
$RENDER --props-inline '{"clips":[],"layout":"single","labels":[],"title":"Demo","subtitle":"Test","preset":"macos","keys":[],"effects":[]}' \
--output "${RUN_DIR}/demo.mp4" "${RUN_DIR}/clip.mp4"
该脚本:
- 仅接受
.cast、.mp4、.webm;将.cast按选定的保真度配置以 1x 转换为.mp4 - 在它为本次渲染专门创建的
${REMOTION_DIR}/public/下的目录中,将片段暂存为clip-<index> - 解析
fidelity、width/height、speed;将clipDuration设为最长片段的时长(ffprobe) - 使用特定配置的编码参数以及
--pixel-format=yuv420p --color-space=bt709运行npx remotion render Showcase(色彩空间设置可确保文件采用有限范围的yuv420p,而非yuvj420p) - 退出或失败时删除自己创建的暂存目录。按 Ctrl-C 或向其进程组发送信号即可取消;仅向脚本的 PID 发送信号,要等
npx remotion子进程退出后才会生效
快速检查帧(在完整渲染前检查布局;规范化和暂存方式与渲染相同):
$RENDER --props "$PROPS" --still 150 --output "${RUN_DIR}/check.png" "${RUN_DIR}/before.cast" "${RUN_DIR}/after.cast"
# frame 150 = 5.0s at 30fps; clips start at frame 120, after the title crossfade
渲染时间:30-60 秒、分辨率为 1920x1080 的视频预计需要约 1-3 分钟。请相应设置工作器超时时间(5 分钟较为稳妥)。
第 4 步:完成
检查结果:
ffprobe -v quiet -print_format json -show_format -show_streams "${RUN_DIR}/demo.mp4"
确认:
- 分辨率与解析后的保真度相符:
compact/standard为 1920x1080,inspect为 2560x1440(side-by-side的默认值),或为 props 中明确指定的width/height - 时长符合
4s title + longest_clip / speed + 3.5s outro(时长检查点公式) - 文件大小适中(GitHub 嵌入要求小于 5 MB,硬性上限为 25 MB)
- 像素格式为
yuv420p,且color_space=bt709(确保通用播放兼容性)
verify 阶段负责解码和证明帧检查;不要仅凭元数据就报告视频可播放。
输出
交给 verify 阶段:
## Compose outputs
- video: /tmp/demo-pr-11621.mp4
- resolution: 1920x1080
- duration: 42s
- size: 3.2 MB
- preset: factory
- keystrokes: 3 events overlaid
- effects: 1 spotlight
- engine: remotion
仅含截图的产物(证明材料、QA)
并非每项交付物都是视频。对于证明材料和 QA 工作流,compose 可能只需整理截图和快照。.png 静帧也在此处理——绝不能将其作为片段传给渲染脚本:
带注释的截图集
ffmpeg -y -i before.png -i after.png \
-filter_complex "
[0:v]scale=960:-1[left];
[1:v]scale=960:-1[right];
[left][right]hstack=inputs=2[out]" \
-map "[out]" comparison.png
嵌入证据的 Markdown 报告
对于基于文本的交付物,应将证据整理成结构化报告,而不是视频。此项由 verify 阶段负责。