ccvideo — Claude 风格产品宣传视频
你将制作一段时长 20–45 秒、分辨率 1920×1080 @ 30 fps 的短宣传视频,视觉语言采用 Anthropic Claude 发布视频的风格:暖色调的赤陶色画布、一个运行着 Claude Code 会话的 macOS 终端窗口、逐字键入和流式输出的文本、锁定画面之间的短暂镜头推进、以及衬线标题卡。
前置条件
- 必须存在一个 Remotion 项目。如果没有,请搭建一个:
npx create-video@latest --yes --blank --no-tailwind .然后运行npm i。 - 软件包(使用
npx remotion add <pkg>安装以确保版本匹配):@remotion/google-fonts、@remotion/transitions、zod(需显式声明 zod——库会直接导入它;不要依赖它作为传递依赖项)。 - 组件库必须存在于
src/ccvideo/。如果不存在,请将此技能的templates/目录下的所有文件复制到src/ccvideo/。不要从头重写这些组件。 - 捕获/验证工具必须存在于项目根目录的
scripts/下。如果不存在,请将此技能的scripts/目录(包括scripts/lib/)复制到那里。所有脚本都根据你运行它们的目录解析captures/,因此请始终在项目根目录下运行它们。
真实数据(不可协商的内容规则)
视频内容绝不可以手动写入场景组件。显示的每一条事实——数字、路径、端点、命令输出、行数——都必须来自真正运行过的代码的捕获:
- 每个视频都有一个
captures/<name>/目录,其中存放着原始产物(API 响应、提取的会话事件)以及一个基于它们确定性构建的props.json。props.json是组合渲染的单一数据源。 - 先捕获。 在制作视频之前,运行真实操作:
node scripts/capture-xapi-cli.mjs—— 通过 xapi CLI (npx xapi-to,密钥在~/.xapi/config.json;.agents/skills/xapi/中的xapi技能记录了其所有功能)获取实时 X 数据。node scripts/capture-x-user.mjs—— 官方的 X API 变体(需要X_BEARER_TOKEN;--sample会写入包含raw-meta.json标记为sample: true的占位数据——永远不要发布示例捕获)。node scripts/transcript-to-props.mjs <session.jsonl> --prompt-match <str> --out captures/<name>—— 回放真实的 Claude Code 会话轮次(转录文件位于~/.claude/projects/<project-slug>/*.jsonl)。- 有新的数据源?遵循相同模式编写新的捕获脚本:获取真实数据 → 保存原始数据 → 通过
scripts/lib/中的共享确定性构建器构建 props。
- 发布前验证:
node scripts/verify-props.mjs captures/<name>会根据原始产物重建 props,并且会因任何手动编辑而失败。通过重新捕获来修复,永远不要编辑props.json。 - 诚实回放边界:节奏是一种表演(打字速度、旋转动画时间),但能力必须是真实的——视频只能显示捕获运行中实际执行的操作。这扩展到界面修饰:会话头部事实(Claude Code 版本、当前工作目录)来自捕获(
claude --version、真实 cwd),否则头部将被省略;旋转动画的令牌计数器仅当捕获提供了真实的thinkingTokens值时才渲染(否则仅显示秒数)。示例捕获会直接导致verify-props失败(--allow-sample仅用于管道测试)。 - 捕获旨在保证提交安全性,并具有深度防御机制——但这并非绝对的保证:
transcript-to-props仅持久化视频实际使用的输入(所选事件的显示行 + 计数、一个截断的命令输出、摘要项目符号行),清除形如密钥的字符串(API 密钥、Bearer 令牌、URL 凭据、环境变量/JSON 密码字段、私钥),并将普通路径和扁平化 slug 路径都重写为~——所有这些都在构建 props 之前完成,因此 props、视频和存档的原始文件看到的是相同的脱敏内容。模式列表永远不可能完整:在提交之前始终检查捕获,并将任何脱敏警告视为停止信号。
工作流程
- 先捕获(请参阅“真实数据”):从真实运行中生成
captures/<name>/props.json。 - 从捕获中提取段落表。 展示性文本(卡片标题、思考词)存在于捕获脚本的常量/标志中——选择一个提示、代码段落、运行输出、摘要项目符号。目标是经典弧线:代码 → 创建 → 运行+输出 → 摘要。
- 组合: 在
src/Root.tsx中使用GroundedVideo(来自src/ccvideo)注册一个<Composition>,设置schema={groundedVideoSchema}、defaultProps从捕获的props.json导入,并通过groundedVideoDuration推导calculateMetadata中的时长——时长自动跟随内容。超出标准弧线的自定义场景工作:使用库原语构建,遵循相同规则。 - 在宣布完成前使用静态帧进行验证。 为每个段落渲染一帧静态图像:
npx remotion still <CompId> --frame=<n> --scale=0.5 out.png并检查它们。检查:没有内容被终端窗口裁剪(渲染输出中的[ccvideo]溢出警告意味着需要修剪段落)、节奏感觉不急促、颜色符合调色板。 - 运行
node scripts/verify-props.mjs captures/<name>,然后使用npx remotion studio --no-open预览;使用npx remotion render <CompId> out/<CompId>.mp4进行最终渲染(添加--props=captures/<name>/props.json可以在不修改代码的情况下渲染不同的捕获;添加--scale=2可以获得像官方演示一样的 4K 母版——组合在代码中保持 1920×1080 @ 30 fps)。
两种主题
根据产品选择,两者都共享品牌赤陶色 #D97656/#D97757:
- 赤陶色(Terracotta)(默认)——暖色画布,Claude Code REPL 会话。适用于代理/AI 工作流故事。组件:
GroundedVideo/DataSession。 - 深色(Dark)(
antCLI 演示语法)——近黑色画布#0B0B0B、暖黑色终端#181716(仅通过微妙的边框分隔)、Shell 提示符▶ ~/dir >(箭头#8B92C9、尖括号#5FA97B)、奶油色衬线#D6D4CF。结构是分章节的:像素标志字标卡片 → [每章:插页卡片(单色引导 + 细分割线 + 衬线声明)→ 全新 Shell 段落(输入真实命令、真实输出淡入、空闲提示符返回)] → 字标结尾。适用于 CLI/开发者工具产品。组件:DarkVideo/ShellBeat/InterstitialCard/WordmarkCard,theme.ts中的调色板dark,schemadarkVideoSchema(像浅色主题一样从捕获构建——例如,由capture-xapi-cli.mjs编写、由verify-props.mjs验证的props-dark.json)。
外观(不可协商的风格规则)
- 画布
#CC7D5D,终端#2B2C36,标题栏#3A3634。正文文本#E3E4EB,暗淡#9899A1,注释#6C6E6A,行号#83848C。强调色:长春花色#B8B9F2(路径、内联代码、字符串)、蓝绿色#85BEC5(关键字)、金色#F2C43D(状态箭头)。全部在src/ccvideo/theme.ts中定义——请导入,切勿硬编码。 - 字体:终端内容使用 JetBrains Mono,标题卡使用 Source Serif 4。通过
@remotion/google-fonts在theme.ts中加载,并且已为两种字体栈追加了 Noto Sans SC 作为中日韩(CJK)回退字体——中文提示开箱即用。 - 终端窗口 1560×950 居中(当显示会话
header时为 985;深色主题为 1860×1010),14 px 圆角,深柔阴影,三个交通灯按钮,镜像任务的等宽标题栏文本,例如dev — · Implement X — claude — 106×31。 - Claude Code 会话必须看起来真实:
>输入行上方是金色⏵⏵ auto mode on (shift+tab to cycle) · esc to interrupt状态栏(两者始终可见,固定在底部);输入行正上方固定高度的槽中有一个✻ Cogitating…旋转动画;●工具结果项目符号;一个带有… +N lines (ctrl+o to expand)结尾的编号代码块;一个带有-项目符号的粗体What it does摘要。 - 镜头:终端场景上绝不允许持续的缩放或平移——缓慢的分级缩放会使小的等宽文本明显漂移和晃动。唯一允许的镜头运动是
<CutZoom>:在锁定画面之间进行短暂、强缓动的移动(约 0.6 秒)——推进到密集内容,保持,然后拉回以获得效果。文本只能在有意的快速移动期间处于中等缩放比例,不要持续数秒。在拉出时保持与推进时相同的origin,以免看起来像是横向滑动。DataSession会在run段落周围自动应用此效果。<SlowZoom>仅限标题卡使用。 - 会话真实性界面装饰(全部由 schema 驱动,全部可选):
header(像素标志 +Claude Code vX+ 模型/当前工作目录行,始终可见)、windowTitleIdle→ 提交提示时交换为windowTitle、作为高亮块的提示回显、带有实时(Ns · ↓ N tokens)计数器和可选⎿ Tip:行的旋转动画、仅在工作中获得esc to interrupt的状态栏。额外的段落类型:answer(富散文块)、alert(红色高亮行)、tool段落可能带有⎿子行。 - 无转录漂移。 终端文本只能原地淡入:窗口内无位置入场动画,且永不要安装/卸载会导致其下方行重排的元素——瞬态行(旋转动画、进度)位于固定高度的槽中,因此它们的消失不会移动任何内容。
- 标题卡:在赤陶色上使用近黑色
#1F1508的衬线标题、68% 不透明度的等宽副标题、淡入入场。在 1920 宽时标题 ≥ 132 px,副标题 ≥ 52 px。
组件 API(src/ccvideo)
数据驱动层(推荐用于整个视频):
<GroundedVideo {...props}>—— 介绍卡 → 会话 → 结尾卡,完全来自groundedVideoSchema值(捕获的props.json)。<DataSession {...props.session}>—— 渲染任何sessionSchema值:可选头部、提示打字、旋转动画,然后是beats(判别联合:code、tool、run、summary、answer、alert)。自动应用运行段落的剪切缩放;在渲染时如果内容将溢出则发出警告。sessionTiming(props, fps)/groundedVideoDuration(props, fps)—— 纯时序推导;在calculateMetadata中使用。<Rich segments>—— 渲染 JSON 片段{t: 'plain'|'kw'|'code'|'comment'|'dim'|'bold', s};从 props.json 到样式化文本的桥梁。
展示原语:
<TerminalWindow title width? height? variant?>—— 画布上的窗口(variant="dark"用于深色主题)。子元素是一个 flex 列;给转录区域flex: 1以便<InputBox>+<StatusBar>固定在底部。<TypeText text from cps? cursor?>/<Cursor>—— 打字机效果,35–45 cps。<InputBox typedText? from? cps?>——>行;无typedText= 闪烁光标。<StatusBar mode? hint?>。<Thinking from? until? word? stats? tokens? tip?>—— 旋转动画;stats显示实时(Ns)—— 仅当tokens携带真实的捕获计数时才显示↓ N tokens;tip添加⎿ Tip:行。将其放在转录区域和输入之间的固定高度槽中;until会将其原地淡出。<Line from?>—— 一个输出行,8 帧淡入(仅不透明度)。<ToolLine from>——●项目符号行。<CodeBlock from lines stagger? startLineNo? expandNote?>—— 编号行。- 令牌跨度:
<K>关键字、<C>代码/路径、<Cm>注释、<Dim>、<B>。 <SessionHeader version modelLine>、<PromptEcho>、<AlertLine from?>、<ToolChild from?>—— 会话界面装饰(参见样式规则)。<CutZoom cuts={[{from, scale?, origin?, ease?}]}>—— 锁定画面之间的短暂缓动移动;终端场景上唯一允许的镜头运动。<SlowZoom from? to?>—— 仅限标题卡,绝不在终端周围使用。<TitleCard title subtitle? titleSize?>。
所有动画均为帧驱动(useCurrentFrame + interpolate,已钳位,内联在 style 中)。切勿使用 CSS transition/animation。