工程现场

让 Codex 用 Remotion 做视频:方向对了,审美还是差得不行

记录一次用 Remotion 和 Codex 制作 Mira 产品介绍片的完整施工过程:从电子相册、动态 PPT,到建立视觉契约、逐帧整改和最终停止。

让 Codex 用 Remotion 做视频:方向对了,审美还是差得不行

事情开始得很朴素。

我想给 UIChat Mira 做一条二十多秒的产品介绍视频。

不需要复杂剧情,也不准备拍真人。只要能简单说明 Mira 是什么,展示一点产品界面和工作流,再配上几个自然的转场,最后落到品牌上就够了。

最初的想法大概是:

AI 都已经会写完整项目了,做条产品视频应该不难吧。

事实证明,生成一个 MP4 确实不难。

难的是让这个 MP4 不像玩具、不像作业,也不像一套被强行加上动画的 PPT。

而即便到了最终版本,我也不能说 Codex 的审美突然变好了。

更准确地说,是我们通过大量约束,把它从完全错误的方向上拖了回来。

最终成片已经不再是纯粹的 PPT 动画,产品叙事和镜头方向基本成立,但细看仍然谈不上多漂亮。

我最后决定停下来,也不是因为它已经完美了。

只是我不想再继续花时间和 Token,陪 Codex 为几像素、几个转场和几个字体问题来回扯皮。

第一版:技术上是视频,精神上是电子相册

最开始,我们没有使用专业的视频工程工具,而是用 Python 生成画面,再通过 FFmpeg 拼接。

它有标题、有卡片、有淡入淡出,也能正常播放。

但那东西本质上不是产品视频,而是:

几张静态海报被依次放进时间线,再配上一些转场。

它满足了视频文件的技术定义,却没有形成真正的镜头语言。

没有视觉对象的连续变化,没有产品状态的推进,也没有注意力从一个区域自然转移到另一个区域。

画面只是在不断告诉观众:

好了,下一张 PPT 来了。

这次失败很有价值,因为它让我确认了一件事:

视频不是“图片加动画”,而是信息如何沿着时间发生变化。

也是在这之后,我们决定使用 Remotion。

Remotion 是什么

Remotion 可以简单理解为一套使用 React 和 TypeScript 编写视频的工具。

在普通前端项目里,组件最终渲染成网页;在 Remotion 里,组件会根据当前帧计算状态,最后被渲染成视频。

一个 Composition 通常会定义:

  • 视频尺寸;
  • 帧率;
  • 总帧数;
  • 渲染入口。

Sequence 用来安排不同内容在时间线上的出现区间,Remotion Studio 则可以预览画面、拖动时间轴并逐帧检查。

整个开发过程大致是:

React 组件
    ↓
根据当前帧计算画面状态
    ↓
在 Remotion Studio 中预览
    ↓
通过 CLI 渲染成 MP4

对开发者来说,这种方式很顺手。

视频不再只是一个只能在剪辑软件里打开的工程,而是变成了:

  • 目录;
  • 组件;
  • Props;
  • TypeScript;
  • Git diff;
  • 设计 token;
  • 检查脚本;
  • 渲染命令。

我们这次也给 Codex 安装了 Remotion 相关的创建、渲染和最佳实践 Skills,让它能够直接在工程里搭建 Composition、修改时间线并输出视频。

Remotion 比较适合:

  • 产品介绍片;
  • 功能演示;
  • 技术架构解读;
  • 数据可视化;
  • 批量模板视频;
  • 需要长期维护和多语言适配的视频。

它不一定能取代 DaVinci Resolve、Premiere 或剪映。

它更像是把一部分视频生产,从“剪辑工程”变成了“软件工程”。

这也正是它适合 Codex 的地方。

Codex 很熟悉代码工程。

问题是,它熟悉代码,不代表它熟悉审美。

Codex 会写动画,但不等于会做视频

Remotion 环境创建得很顺利。

我们选择了 Blank 模板,安装了相关 Skills,然后让 Codex 制作第一条 18 秒 Mira 片头。

它很快交付了:

  • 大标题;
  • 能力卡片;
  • 运行时架构;
  • Agent Loop;
  • 章节编号;
  • 橙色转场线;
  • 五个完整场景。

从代码施工角度看,它完成得很快。

从画面上看,它像一套会动的技术汇报 PPT。

粗黑无衬线大字、左侧装饰线、01 / 05 页码、等距卡片和流程节点,一个都没少。

我们让它做的是 Mira 产品视频,它理解成了:

请生成一套会动的咨询公司汇报模板。

这也是和 Codex 扯皮的真正开始。

Codex 的问题并不是完全不会动。

相反,它特别爱动。

标题要飞进来,卡片要一个个出现,线条要从左边扫过去,流程节点要轮流高亮。

但这些运动经常没有叙事意义。

它们只是为了证明:

这里有动画。

视频最终看起来更热闹了,却没有更像产品。

“使用 Claude 风格”不是一条足够有效的指令

我手里原本有一份比较完整的 Claude 视觉分析文档。

里面定义了:

  • 暖米白画布;
  • 珊瑚色强调;
  • 深色产品界面;
  • 衬线展示标题;
  • 无衬线正文;
  • 卡片、圆角、间距和边框;
  • 哪些设计模式应该使用;
  • 哪些模式应当避免。

最初的想法很简单:

让 Codex 每次都遵守这份提示词。

但很快就发现,这也不够。

第一,完整设计分析文档太长。

每次生成一个小镜头都重新读取,不但浪费上下文,还容易把与视频无关的网站导航、价格卡片和 CTA 规则带进来。

第二,静态设计规范不能自动变成视频规范。

它能告诉 Codex:

标题应该用什么字体。

却不会告诉它:

上一个镜头中的产品窗口,应该怎样继承到下一个镜头。

第三,“遵守风格”仍然属于软约束。

Codex 可能读过,然后在某个场景里顺手又写一个新的颜色、一个新的阴影,或者一组完全不同的 spring 参数。

它不是不知道你给了规范。

它只是总觉得自己可以临场发挥一下。

而它的临场发挥,通常正是画面变丑的起点。

于是我们没有继续改视频,而是先暂停下来,给这个工程建立了一套“宪法”。

在做视频之前,我们先做了视频设计系统

最后形成了几层约束。

AGENTS.md

它负责告诉 Codex:

  • 普通视觉任务必须读取哪份规范;
  • 动画任务还需要读取哪份运动规范;
  • 什么情况下才能修改现有 Composition;
  • 不得复制第三方商标和品牌身份;
  • 不得绕开项目中的 token 和组件。

MIRA_STYLE_CONTRACT.md

这是一份精简后的 Mira 视觉契约。

它不再试图完整描述某个网站,而是只保留 Mira 真正需要的视觉语言:

  • 暖色、克制、编辑型;
  • cream、card 和 dark surface 形成节奏;
  • coral 只承担少量关键强调;
  • 中文展示标题使用衬线字体;
  • 产品 UI 使用无衬线字体;
  • 深色区域必须承载产品、代码或运行时内容;
  • 禁止左侧贯穿装饰线;
  • 禁止固定页码;
  • 禁止把每个镜头都做成相同的卡片阵列;
  • 禁止用大量卡片代替真实产品工作流。

MIRA_MOTION_SYSTEM.md

这是静态设计规范里原本没有的部分。

它定义了几种允许使用的运动方式:

  • fade
  • maskedReveal
  • surfaceExpand
  • cameraPush
  • sharedElement
  • traceLoop

更重要的是,它规定了几条非常朴素的原则:

每个运动都应该说明内容发生了什么变化。

场景之间优先继承已有元素,而不是整页清空。

转场应当服务内容连续性,不能自己成为表演节目。

theme.ts

颜色、字体、圆角、阴影、间距、缓动曲线和 spring preset 被写进了 TypeScript。

场景不能再随手写:

color: "#cc785c"

而要使用:

colors.accent

Codex 也不能在每个场景里重新创造一套动画手感,而只能从有限的 motion preset 中选择。

Token Policy

最后,我们还写了一个轻量检查脚本,扫描场景和 Composition 里有没有:

  • 内联十六进制颜色;
  • rgb()rgba()
  • 任意 boxShadow
  • 内联的 spring 参数。

这个检查器后来真的抓出了旧场景里的几项视觉技术债。

那一刻我突然意识到,我们已经不是在“给 Codex 一份审美建议”了。

我们是在给一个 AI 施工队建立代码规范、设计规范和质检规则。

当然,这些规范只能减少它胡来的范围。

它们不能把 Codex 变成一个真正有审美判断的设计师。

先做五秒,不要急着做完整片

设计系统建立后,我们没有马上重做完整视频。

只让 Codex 创建了一条五秒的 MiraOpeningStudy

画面极其简单:

UIChat Mira

它不是
一个聊天壳。

而是一套被真实问题塑造的个人 AI 工作台。

没有卡片,没有流程图,没有页码,没有装饰线。

只有暖色画布、衬线标题、大面积留白,以及一个被珊瑚色强调的“不”字。

这一次,方向终于基本对了。

虽然中文宋体的效果依然丑得令人发笑,但至少它不再像工作总结 PPT。

这一步形成了一个很实用的经验:

不要让 Agent 一开始就生成完整成片。先用三到五秒验证字体、留白、构图和运动气质。

如果这些基础变量都不对,直接生成二十多秒,只是在批量制造返工。

而且短样片更容易判断问题究竟来自:

  • 字体;
  • 配色;
  • 构图;
  • 动画;
  • 还是 Codex 根本理解错了风格。

完整产品片:最大的错误是窗口停在那里,标题不断更换

开头方向确认后,我们开始制作一条 26 秒的完整 Mira 产品介绍视频。

叙事结构是:

  1. 它不是一个聊天壳;
  2. Mira 是本地优先的个人 AI 工作台;
  3. 模型、知识、MCP 和工具围绕一个任务协同;
  4. 它不仅返回答案,还保留过程、证据和上下文;
  5. AI 进入真实工作流;
  6. 回到 Mira 的品牌句——“接住你”。

第一版已经摆脱了最明显的 PPT 模板感,品牌气质也比之前正常得多。

但中间四到二十三秒,几乎始终是同一个深色产品窗口停在那里,左上角标题轮流变化。

技术上,界面内部确实出现了:

  • 模型状态;
  • 知识库;
  • MCP;
  • 工具执行;
  • 证据引用;
  • 执行轨迹。

可产品窗口太小,普通观看尺寸下根本读不清。

连续播放时,它仍然像一张产品截图停了十九秒。

于是我们又做了一轮整改:不再更换页面,而是让同一个 ProductWindow 经历不同的观察尺度。

Wide
完整工作区

Medium
知识、MCP 和工具协同

Close
答案、证据和执行过程

Pull back
回到完整桌面工作空间

这次改动非常关键。

产品介绍不再只靠标题宣称“这里有证据”,而是让镜头真正推近证据区域。

也不再为每项能力生成一张独立卡片,而是让这些能力围绕同一个用户任务依次发生。

产品片最重要的不是把功能名称全部念一遍,而是让观众看到一个任务怎样流经产品。

到了这里,视频的方向才算真正成立。

但“方向成立”和“画面好看”仍然是两回事。

最终成片:不是玩具了,但也没有突然变高级

经过几轮修改后,最终版本至少解决了几个关键问题:

  • 不再是一页一页切换的动态 PPT;
  • ProductWindow 成为了持续存在的视觉对象;
  • 镜头有 wide、medium、close 和 pull back;
  • 模型、知识、工具和证据围绕同一个任务展开;
  • 开场、产品工作区和品牌结尾之间有了基本的连续性;
  • 中间不再只是放着一张缩得很小的产品截图。

从这个意义上说,改动方向是对的。

它已经不是一个纯玩具式的 PPT 动画,而是一条拥有基本产品叙事和镜头结构的介绍片。

但我要诚实一点:

Codex 的审美还是差得不行。

字体、比例、换行、细节留白、元素之间的呼吸感,仍然有很多地方只能算勉强。

一些转场需要反复指定到具体秒数和具体问题,它才能修掉:

  • 旧标题残留在产品窗口后方;
  • 近景裁切过度,看不出仍在同一个窗口;
  • 产品状态字太小;
  • 收尾出现灰色半透明矩形;
  • 右侧残留窄窄的深色切片。

其中不少问题,人看一眼就能发现。

Codex 却需要一条几百上千字的提示词,明确告诉它:

  • 哪几秒;
  • 哪个元素;
  • 为什么不好;
  • 允许怎么改;
  • 禁止怎么改;
  • 改完检查哪些帧。

即便如此,修完也只是从“明显不对”变成“勉强通过”。

所以最后停止修改,并不是因为我认为它已经达到了理想效果。

只是继续打磨的边际收益越来越低。

为了修掉一个只有几帧的小尾巴,可能要重新写一大段提示词,消耗一轮上下文和 Token,然后再承担它改坏别处的风险。

到这个阶段,停止并不是对成片质量的高度认可。

只是一次现实的成本判断:

方向已经正确,能发,也不再丢人。剩下的问题,不值得继续陪 Codex 折腾。

和 Codex 扯皮时,长提示词不是重点,边界才是

整个过程中,我们写了很多很长的提示词。

但回头看,真正有效的并不是文字数量,而是其中越来越明确的边界。

例如:

只允许修改 MiraProductIntro

不得修改已经验收的中文 Composition。

不得重构成多语言系统。

不得修改设计契约和 theme。

这一轮只处理 3.8 到 4.6 秒的标题残影。

不要提出下一版方案,完成后停止。

这类约束看起来很啰唆,但对 Agent 施工非常重要。

因为 Codex 有一种程序员特有的热情:

既然这里有一点重复,不如顺便抽象一下。

而在视频工程里,“顺便抽象一下”很可能意味着:

  • 已经完成的中文版被改坏;
  • 英文版换行影响中文布局;
  • 共享组件为了兼容两个版本变得更复杂;
  • 一个局部修复扩大成整个工程重构。

最终我们甚至明确要求:

英文版宁可复制一套场景,也不要以国际化为名重构已经收工的中文版。

这并不优雅。

但很安全。

在面向 AI 的工程实践里,局部重复有时比不可控的全局重构更便宜。

尤其是已经通过验收的部分,必须明确冻结。

否则 Codex 很容易一边解决新问题,一边重新制造旧问题。

对付 Codex 视频施工,逐帧截图比代码审查更重要

代码检查通过,并不意味着视频好看。

pnpm check 可以发现类型错误。

Token Policy 可以发现内联颜色和非法 spring。

但它们发现不了:

  • 字号小得像网页脚注;
  • 产品窗口压住了标题;
  • 转场中残留了一条黑色竖条;
  • 近景裁得太狠,看不出仍在同一个窗口;
  • 结尾灰色透明块像渲染故障;
  • 十九秒里虽然代码一直在变,但视觉上什么都没发生。

所以每一轮,我们都会要求检查固定时间点:

3.8 秒
4.4 秒
10.5 秒
16 秒
22.5 秒
25.5 秒

静帧负责检查构图、可读性和遮挡。

连续播放负责检查节奏、继承关系和镜头运动。

这和普通前端开发很不一样。

网页可以等用户滚动和点击;视频不会等人。

每一帧出现多久、上一帧留下了什么、观众此刻应该看哪里,都是产品的一部分。

而对于 Codex 来说,要求它“整体再高级一点”通常没有意义。

必须把问题描述为:

  • 某个时间点;
  • 某个视觉对象;
  • 某种错误关系;
  • 一个有限的修复范围。

否则它很可能用更多装饰来解决装饰过多的问题。

Remotion 适合 AI 做视频吗

我的结论是:

适合,但不是因为 AI 自动拥有了导演能力。

它适合,是因为 Remotion 把视频变成了 Agent 熟悉的工作对象:

  • 目录;
  • 组件;
  • Props;
  • 类型;
  • 时间参数;
  • 设计 token;
  • lint;
  • diff;
  • render 命令。

Codex 很擅长处理这些。

它可以快速:

  • 搭建场景;
  • 编排时间线;
  • 复用产品窗口;
  • 替换英文文案;
  • 调整镜头缩放;
  • 按照指定帧数修改局部动画;
  • 渲染中英文成片。

但它仍然不擅长:

  • 判断画面是不是有 PPT 味;
  • 判断留白是高级还是空;
  • 判断字体是真的合适,还是仅仅“符合衬线字体要求”;
  • 判断一个转场是连续还是脏;
  • 判断某段虽然一直在动,实际上却没有信息变化;
  • 判断细节是不是已经廉价;
  • 判断什么时候应该停止修改。

所以 Remotion 并不是:

输入一段提示词,自动得到专业视频。

更准确地说,它是:

把视频变成一套 AI 能参与施工、但仍需要人类导演和验收的软件工程。

至于最终画面能不能真正好看,决定因素仍然是:

  • 谁来定义风格;
  • 谁来控制边界;
  • 谁来逐帧验收;
  • 谁知道什么时候该推翻;
  • 谁知道什么时候该停止。

这次形成的工作流

经过几轮折腾后,我认为更合理的流程应该是:

一、先明确视频到底要讲什么

不要从动画开始。

先写清楚:

  • 观众是谁;
  • 二十多秒后应该记住什么;
  • 产品能力通过哪个任务被展示;
  • 哪些内容不能声称。

二、先建立设计约束,再让 Agent 做镜头

至少需要:

  • 项目级 Agent 规则;
  • 视觉契约;
  • Motion System;
  • TypeScript token;
  • 基础 policy 检查。

否则每个镜头都是一次新的审美抽奖。

需要注意的是,设计系统只能让输出不那么失控。

它不能自动补齐 Codex 缺失的审美判断。

三、先做三到五秒视觉样片

只验证:

  • 字体;
  • 颜色;
  • 构图;
  • 留白;
  • 基本运动。

样片不过,不进入完整视频。

四、用持续存在的视觉对象组织整片

我们这次使用的是 ProductWindow

它从深色 surface 展开,随后被推近、聚焦、拉远,最终收拢回品牌画面。

比起每个场景新建一张页面,这种方式更容易形成真正的视频连续性。

五、用任务流展示产品,而不是罗列功能

不要做:

模型
知识库
MCP
工具
证据

五张卡片依次出现。

应该展示:

用户提出任务
    ↓
模型理解
    ↓
知识与工具介入
    ↓
返回答案与证据

功能应该出现在任务过程中,而不是出现在功能清单里。

六、每轮只解决一个层级的问题

先解决整体风格。

再解决产品叙事。

再解决镜头尺度。

最后才修标题残影、裁切和转场碎片。

不要在同一轮同时要求:

  • 重写文案;
  • 重做设计;
  • 添加声音;
  • 国际化;
  • 重构组件;
  • 输出最终成片。

Codex 会很积极,工程会很危险。

七、已验收的内容必须冻结

提示词里要明确:

  • 哪些 Composition 不得修改;
  • 哪些场景已经通过;
  • 哪些文件只能只读复用;
  • 是否允许抽象和重构;
  • 最终输出文件不得覆盖什么。

八、准备好为视觉问题写非常具体的提示词

不要只说:

这里不好看。

要说:

3.8 到 4.6 秒之间,旧标题残留在 ProductWindow 后面。将旧标题退出提前 6 到 10 帧,并确保窗口覆盖该区域之前标题透明度已经接近 0。

这很累,但目前仍然比期待 Codex 自己理解“脏”是什么意思可靠。

九、知道什么时候停

最后一版仍然存在一些我并不完全满意的地方。

中文字体不好看,英文版也只是相对更适合这套拉丁衬线视觉系统。

某些动画还能继续精修,界面细节也能继续提高。

但继续修改需要更多时间、上下文和 Token,还会不断引入新的回归风险。

所以最后我说:

够了,不想动了。

这不是“作品已经完美”的另一种表达。

而是:

它已经从错误方向回到正确方向,也已经不再是一个玩具。剩余提升不值得当前成本。

这同样是产品开发里很重要的一种判断。

最后的感受

我们原本只是想做一条二十多秒的视频。

最后却经历了:

  • 一版电子相册;
  • 一版动态 PPT;
  • 一套设计分析;
  • 三份项目契约;
  • 一个 TypeScript 主题系统;
  • 一个 token policy;
  • 一个五秒视觉实验;
  • 三轮完整产品片整改;
  • 一套独立英文版;
  • 一条背景音乐;
  • 以及无数次“不要顺便重构”。

听起来很荒唐。

但这件事和 Mira 自己的开发过程其实很像。

复杂度不应该因为我们见过一张漂亮架构图,就被一次性设计出来。

它应该被真实问题一点一点逼出来。

视频也是如此。

我们不是先拥有了一套完整的视频生产体系,再开始做片子。

我们先做出一个很烂的东西,然后才知道为什么需要 Remotion;先得到一套动态 PPT,才知道为什么需要视觉契约;先让 Codex 随意发挥,才知道为什么需要 Motion System 和 Token Policy;先差点为了英文版重构中文工程,才知道为什么必须冻结已经完成的内容。

AI 可以在几分钟内写出 780 帧的视频代码。

但它不会自动知道哪一帧看起来很丢人。

即使被指出来了,它也可能需要几百字的施工要求,才能勉强把问题改对。

所以最终的结论并不是:

Codex 已经可以独立做出很漂亮的视频。

而是:

Remotion 让 Codex 有能力参与视频施工,但审美、导演、验收和停止权,暂时仍然必须掌握在人手里。

最终成片并不完美。

它只是终于不再是一个纯玩具。

至于剩下的那点不甘心,我决定留给以后。

不是每个像素,都值得继续烧 Token。