最近,我把 Lottie 插件的第一个版本 0.1.0 发布到了 Qoder Marketplace,它可以让智能体在 Qoder 中创建、编辑、打包、校验和预览 Lottie 动画。
从功能上看,这很容易被理解成另一个“AI 生成动画”的插件:用户描述一个加载效果,智能体生成一份 Lottie JSON,再通过播放器展示结果。但真正把插件做完以后,我反而觉得,生成可能是其中最不重要的一步,因为一份动画只要进入真实的创作过程, 用户很快就会提出下一轮要求:让这个对象慢一点、让那段轨道提前出现,或者把循环接缝再处理得自然一些。
回头看,这个插件真正想解决的并不是“让智能体多生成一种文件”,而是另一个更接近创作过程的问题:
当动画已经生成以后,智能体怎样重新进入它,找到需要修改的对象,并在不破坏其他部分的前提下继续工作?
换句话说,我们需要的不是一个 Lottie 生成器,而是一套能够让动画被持续观察、定位、修改和验证的创作运行时,也就是:让 Lottie 成为 Agentic Loop 中的工作对象。
这个插件主要受到两方面启发。
一方面,我在使用 Codex 的产物工具时,注意到它处理文档、演示文稿和表格的方式,并不是直接在对话里拼出最终文件,而是先编写一段程序,再由程序生成、检查和修改产物;另一方面,ChatGPT 会把生成后的文件继续留在预览界面中,让人可以直接审阅、标注,再要求智能体完成下一轮修改。文件不再只是对话结束时的附件,而开始成为协作过程的一部分。
但是,当工作对象从静态文档变成带有对象、轨道和时间轴的动画以后,仅仅把文件留在界面里还不够。
Lottie JSON 和 .lottie 很适合播放与分发,dotLottie 还可以在一个压缩容器中封装多份动画、图片、主题与状态机;Lottie Creator
MCP 也已经证明,智能体可以读取动画文件、编辑图层并生成变体。真正没有被自然解决的,是智能体如何在连续多轮修改中继续引用同一个对象、同一条轨道和同一段时间。
当用户说“让左眼在 idle 阶段眨得慢一点”时,智能体需要的不是“画面左边那个眼睛”的屏幕坐标,而是一条能够在工程状态中重新解析的语义地址,以及这次修改所依赖的版本前提:
(source.key, node.key) → track → phase
expectedRevision + stateDigest
地址负责回答“修改什么”,版本前提负责回答“现在面对的,是否仍然是刚才检查过的那一版”。
所以,可编程动画并不是“由代码生成的动画”。它更接近这样一种产物:
对象、轨道和时间状态拥有稳定身份,智能体可以基于明确版本持续修改,并通过验证确认修改范围的动画工程。
如果动画只生成一次,.lottie 可以是终点;但只要它还会被人、另一个智能体或外部工具继续修改,问题就不再是文件能否打开,
而是系统能否重新识别同一对象、确认修改所基于的版本,并证明未触及的部分保持不变。
我把这种能力称为可持续编辑:不是保存所有对话,而是在产物之外保留可恢复的工程状态。MotionProgram 表达期望变化,
MotionProject 保存稳定身份与修订,MotionRuntime 负责计算差异、试运行、校验和提交,.lottie
只是某次提交后的交付结果;即使文件被外部修改,系统也应该先完成对象对账,而不是根据相似性自行猜测。
围绕这个目标,我采用了三个相互衔接的实践:用 Agentic DSL 保留可重放的创作意图,用 CLI over MCP 稳定跨宿主的执行语义,再通过 Canvas 将人的视觉反馈重新转换为可寻址、可验证的工程状态。
设计 MotionProgram 时,我没有重新发明一门动画脚本语言,而是选择把一套受到约束的 JS API 当作 Agentic DSL。
这里其实包含了一个很重要的判断:DSL 不一定需要重新设计语法。对于已经能够熟练编写 JavaScript 的智能体来说,变量、函数、循环、模块和组合能力都是现成的;我们真正需要重新设计的,是它能够表达什么、哪些对象必须拥有稳定身份,以及程序最终怎样被执行和验证。
因此,JavaScript 只是表达层,MotionProgram 的数据结构负责限定领域语义,真正的执行权限与状态变更则由 MotionRuntime 控制:
const program = {
version: 3,
source: {key: 'better-harness-logo'},
timeline: {
phases: {
draw: {durationMs: 1600},
ignite: {durationMs: 1000},
idle: {durationMs: 2200},
},
},
nodes: [
{key: 'ring'},
{key: 'eyeL'},
{key: 'orbit.inner'},
],
tracks: [
{
key: 'ring.draw',
target: 'ring',
property: 'trim.end',
},
{
key: 'eyeL.blink',
target: 'eyeL',
property: 'transform.scale',
},
],
generators: [
{key: 'sparks.burst', seed: 2026},
],
};
这里的关键并不是 JavaScript 本身,而是智能体提交的是一份完整程序,而不是一串散落在对话中的 createLayer、updateTrack 和
exportFile 工具调用。
完整程序可以被检查、比较、试运行和重放;稳定键、随机种子和目标配置也可以成为程序的一部分。下一轮修改时,智能体重新生成完整的
MotionProgram,运行时计算前后差异,并证明除了指定对象、轨道和时间范围之外,其他内容没有被意外修改。
Vercel 在内部文本生成 SQL 智能体 d0 上删去了约 80% 的专用工具,转而让智能体通过文件系统和命令行探索已有语义层;后续实验又说明,Bash
并不适合所有任务。两次实践放在一起,真正值得关注的不是“工具越少越好”,也不是“Bash
可以替代一切”,而是智能体需要一个符合领域语义、可以组合、检查和验证的可编程环境。
对于 Lottie 来说,这个环境不是裸 Bash,也不是几十个原子工具,而是一份可以整体推演的动画程序。
插件 0.1.0 没有一开始就把每一种动画操作包装成 MCP 工具,而是让 JS API 与 qoder-lottie CLI 共享同一套 MotionRuntime。
对象身份、版本冲突、变更计划、验证和错误语义都在运行时中定义,CLI 只是把这些能力稳定地提供给智能体、自动化脚本和持续集成环境:
Skill / Agent
↓
JS API / qoder-lottie CLI
↓
MotionRuntime
↓
MotionProject + .lottie + Evidence
我更愿意把这种设计称为 CLI over MCP。
它并不是说 MCP 不重要,而是一种架构上的先后顺序:先让领域能力成为可以独立运行、调试、组合和复现的命令,再根据跨宿主发现、远程连接、权限控制和结构化工具描述的需要,为它增加 MCP 入口。
在这套分层里,MCP 负责连接,CLI 负责执行,真正的领域语义始终留在运行时。这样,无论能力最终被 Qoder、Codex、Claude Code、持续集成系统还是其他宿主调用,它们面对的都是同一套对象身份、事务边界与错误语义。
一项覆盖七种智能体脚手架、五个模型和一个固定软件任务的对照研究,也给出了一个很有意思的结果:13 组严格配对实验中的 MCP/CLI 成本比从 0.43 倍跨到 29 倍,主导差异的并不是接口形式,而是脚手架如何组织上下文、工具和执行过程。这个实验无法证明 CLI 普遍优于 MCP,却足以提醒我们,不应该在运行时语义还没有稳定之前,就把架构问题简化成协议选择。
如果说运行时解决的是智能体怎样修改动画,那么 Canvas 解决的就是人怎样重新进入这份动画。
当前版本已经打通了从 MotionProgram 生成 .lottie、完成静态校验,再在 Qoder Canvas
中加载和播放的单向流程。验证器还可以进一步检查指定帧、场景状态和循环接缝,因为静态结构正确,并不意味着运动一定自然;一张截图看起来正常,也不意味着整段时序没有问题。
但是,Canvas 真正有价值的下一步,并不是增加更多播放按钮,而是把人的视觉选择重新转换成智能体可以理解的语义地址。
用户在画面中选择左眼,在时间轴上框出 idle 阶段,Canvas 将这次选择转换成对象、轨道、时间范围与当前工程修订,智能体再据此生成新的
MotionProgram,完成试运行、差异检查和重新预览:
Canvas 选择
→ 语义地址 + 版本前提
→ MotionProgram
→ MotionRuntime
→ 新产物 + 验证
→ Canvas
到这一步,Canvas 就不再只是最终结果的预览器,而开始成为人与智能体共同操作产物的界面。人的视觉判断可以落回稳定对象,智能体的结构化修改也可以重新呈现为人能够观察的动画,两者围绕同一份工程状态不断循环。
Lottie 插件 0.1.0 完成的,还只是从语义程序生成动画、完成验证,再把结果交给人观察的单向流程;从 Canvas 反向选择对象、标注时间范围并生成语义地址,仍然属于下一阶段的工作。
但这个版本已经让我更确定一件事:从生成动画走向编程动画,并不是把自然语言换成 JavaScript,也不是为 Lottie 增加更多工具,而是围绕动画建立一套可以持续工作的工程环境——用 JS API 承载 Agentic DSL,用 CLI 建立稳定的执行入口,再让 Canvas 把人的观察重新带回对象、轨道和时间状态。
当一份动画拥有稳定身份、工程状态、版本约束和验证证据,并且人和智能体都可以重新进入同一份工作现场时,它才不再只是 Agent 的一次性输出,而真正成为 Agentic Loop 中可以持续演化的工作对象。
围观我的Github Idea墙, 也许,你会遇到心仪的项目