Hyaika Blog

Penguin is all you need

技术

Opus 不做视频生成,它写代码渲染视频——2核VPS复现全过程

Opus 不做视频生成,它写代码渲染视频——2核VPS复现全过程

Opus 5.5 没有视频生成模型。Anthropic 从未发布过类似 Sora 或 Veo 那样的"文字直接出像素"的原生视频模型。但这并不妨碍人们用它做出了大量爆款视频——而且不是什么玩具 demo,是 6 分半钟的奥斯卡最佳影片回顾、完整歌词同步的 MV、43 种电影风格的短片合集。

秘密只有一句话:让模型写动画代码,然后逐帧渲染成 MP4。

这篇文章记录了我在一台 2 核 3.8G 的 VPS 上,把这套"确定性渲染管线"完整跑通的过程。不是教程,是实打实的复现——包括每一个坑、每一次崩溃、最终的 3 秒样片。

核心逻辑:不生成像素,生成代码

普通的 AI 视频生成(Sora、Veo、Kling)走的是 diffusion 路线:输入文字,模型从噪声中"雕刻"出每一帧像素。你无法精确控制某一帧画什么,每次重跑都是赌运气。

Opus 的路线完全不同。整个链路是:

  1. 模型写代码:Opus 5.5 用 p5.js、Canvas、Three.js 写一个完整的"动画工作室"——一个 HTML 页面,所有画面、转场、粒子、3D 场景都是代码
  2. 注入虚拟时钟:渲染器用 __seek(t) 驱动 requestAnimationFrame、timers、Date 和 CSS/WAAPI 动画,让动画变成一个可定位的确定性函数。任意时刻 t 都能精确渲染出那一帧
  3. 无头 Chrome 逐帧截图:Puppeteer 启动 headless Chromium,把 1920×1080 的每一帧截成 JPEG,支持多 worker 并行、断点续渲
  4. ffmpeg 编码:帧序列 + 音轨(如果有),用 libx264 编码成标准 MP4

关键区别在于"确定性"这个词。diffusion 模型每一帧都在赌下一个 seed,而这条管线的每一帧都是写死的代码——第 3 秒第 12 帧有个星星在闪烁,那就是因为代码里 Math.sin(t * 2 + i) 在那个时刻恰好算出了这个值。错了就改代码重渲那一帧,不用从头来。

↑ 这是渲染出来的 3 秒样片。深夜山丘上,一只叫 Clawd 的小兽发现坠落的星星。手绘水彩质感,p5.brush 笔触。1280×720,12fps,36 帧全量渲染。

从 GitHub 找到 ClaudeAnimationBase

社区已经卷疯了。GitHub 上有一个叫 awesome-opus5-5-videos 的仓库收录了 703 个公开 prompt,418 个有在线重制版。但我要的不是 prompt 合集,是一个能直接跑的框架。

找到了 JohnHeibel/ClaudeAnimationBase(★1147)。作者 JohnHeibel 就是用 Opus 5.5 做 I'm Upping My P(doom) 那支完整音乐视频的人,后来把代码提炼成了这个通用脚手架。仓库自带:

  • p5.js + p5.brush:手绘水彩渲染引擎
  • Clawd 角色:一只小兽的完整设计——31 种情绪表情、多个视角
  • 分镜系统:SHOTS 数组注册各场景,按时间轴调用
  • 虚拟时钟渲染器:render.mjs 用 Puppeteer 驱动 headless Chrome,支持 contact sheet(拼贴预览)、单帧截取、并行渲染、断点续渲
  • ffmpeg 编码:帧序列 → MP4,支持音轨混入

它还有一个自带的 demo 场景叫"The fallen star"——11 秒的短片,分两幕:第一幕 Clawd 在山丘上打盹,星星坠落到草丛里;第二幕 Clawd 找到星星,把它扔回天空,星星重新亮起来。我用的就是这个场景。

环境:2 核 3.8G 的挑战

克隆下来 npm install 后,环境清单是这样的:

组件这台机器正常桌面
CPU2 核 Xeon 8255C @ 2.5GHz8+ 核
内存3.8 GB16+ GB
GPUCirrus Logic GD 5446(1996 年的虚拟显卡)独立 GPU
OSUbuntu 22.04 容器桌面 Linux

没有 GPU 是最大的问题。Chrome 的 WebGL 渲染在正常情况下走硬件加速,几毫秒一帧;这里只能被迫走 SwiftShader——用 CPU 纯算力模拟 GPU 的光栅化、着色、像素混合。叠加 p5.brush 的水彩笔触(逐像素做扩散、颗粒、湿边计算),每帧都是一次重计算。

踩坑全记录

坑 1:Google Fonts 网络依赖

第一个报错是 TimeoutError: Timed out after waiting 30000ms。studio.html 引用了 Google Fonts 的 Permanent Marker 字体 CSS,但这台服务器访问不了外网。Puppeteer 的 networkidle0 等待条件永远不满足——网络请求一直 pending,导航超时。

解法:在 openPage() 里加请求拦截,只放行 file:// 本地资源,外部请求一律 abort。

坑 2:字体加载卡死 ready 标志

网络拦了之后页面能加载了,但 window.ready 还是永不置位。读 core.js 发现初始化流程里有一行:

await document.fonts.load('100px "Permanent Marker"');
window.ready = true;

字体被网络拦截了,这个 await 永远 pending,ready 永远 false。而 demo 场景根本没用文字渲染——这行是初始化时的通用预加载。

解法:加超时降级,最多等 1.5 秒就继续,不为了一个不用的字体卡死整个渲染管线。

坑 3:root 权限下 Chrome 拒绝启动

报错 Running as root without --no-sandbox is not supported。render.mjs 的沙箱检测用了 process.platform === 'linux',但我自己的 debug 脚本里犯了个低级 bug——从 node:os import 了 platform 但忘了加括号调用,platform 是个函数不是字符串,platform === 'linux' 永远 false,--no-sandbox 没被加上。

改回 process.platform 后 Chrome 能起了,但完整版 Chrome 在容器里开 WebSocket 1006 断连——GPU 子进程线程创建失败(pthread_create: Resource temporarily unavailable),/tmp 共享内存权限也被宿主占着。

坑 4:headless-shell + TMPDIR 重定向

最终组合解法:

  • 用 chrome-headless-shell(Puppeteer 缓存里的轻量专用版)代替完整 Chrome
  • TMPDIR=/root/tmp 把临时目录从 /tmp 挪到 root 名下,绕过共享内存权限问题
  • --use-angle=swiftshader --enable-unsafe-swiftshader 启用软件 WebGL
  • --disable-dev-shm-usage 禁用 /dev/shm

Chrome 终于稳定启动了,页面加载成功,window.ready = true 到位。渲染管线打通。

渲染:每一帧都是一场战斗

第一帧出来了——89 秒。1920×1080 全分辨率,SwiftShader 软渲 p5.brush 水彩笔触,2 核 CPU。

用 PIL 验证帧内容:25726 种颜色,主导色 #1f244e(深夜蓝),整幅有内容不是黑屏。和 demo 场景"Clawd 深夜在山丘上"的设定完全吻合。

为了提速,把分辨率从 1920×1080 降到 1280×720(改 core.js 的 W/H 常量 + studio.html 的 canvas 属性)。单帧从 89 秒压到 45 秒。3 秒 × 12fps = 36 帧,后台渲染,27 分钟完成,ffmpeg 编码出 MP4。

配置每帧耗时3 秒视频总耗时
1920×1080, 24fps~89 秒~1.5 小时
1280×720, 12fps~45 秒~27 分钟
960×540, 12fps(预估)~15 秒~9 分钟

如果有 GPU 的话呢?p5.js 在正常硬件上渲染一帧通常在毫秒级。全片 11 秒 264 帧大概几分钟就出来了。但这就是在限制条件下的工程价值——用最差的硬件,把整条管线从头到尾跑通,每一环都验证过了。

为什么这条路线成立

社区之所以选择"写代码做视频"而不是等一个原生视频模型,原因很实际:

确定性。一帧渲染错了,改代码重渲那一帧。contact sheet 拼贴图可以在正式渲染前快速预览若干时间点,check_scene 在虚拟时钟下加载页面、报 JS 错误和各时间点的可见文本。你永远知道下一帧会是什么。

成本极低。做一首 3 分钟 MV 大约 30 美元 API credits + 300 万 tokens 的 Opus 5.5 调用。对比视频模型每次抽卡的成本,这是零头。

可控性拉满。每帧都是写死的代码,精确到像素。可以做 6 分半的长片(Lemo-Opuscar 98——98 届奥斯卡最佳影片逐一亮相),可以逐歌词同步,可以做用户交互。Opus 自己写分镜、自己调并行子代理、自己修 bug。

生态已成熟。从 ClaudeAnimationBase 的通用框架,到 lemo-opuscar 的 43 种电影风格 skill,到 makevoid 的音乐 MV 插件,到 shipvideo 的"一句话生成发布视频"产品化。工具链已经覆盖了从创作到部署的全流程。

这不只是"代替视频模型"

值得思考的是,这条路线产生的视觉风格是视频模型很难复现的。p5.brush 的手绘水彩质感、Canvas 2D 的扁平矢量风、Three.js 的低多边形 3D——这些都是"代码原生"的美学,不是从真实视频中"学"来的。代码生成的画面有一种确定性带来的干净和独特。

Lemomo 在 lemo-opuscar 仓库里写了这样一句:"Every film was directed, drawn, scored and mixed by an AI agent writing code: canvas and WebGL pages rendered frame by frame, original music from free sample libraries, text-to-speech narration. No video generation, no stock footage."

没有视频生成,没有素材库。全是代码。

这也许才是最有意思的部分——Opus 做视频不是在"模仿"视频生成模型,它是在定义一种新的视觉创作方式。代码就是画笔,浏览器就是画布,ffmpeg 就是定稿机。而"确定性"这三个字,是这条路线区别于所有 diffusion 模型的根本。

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论