1. 从写代码到做视频这条路线到底在解决什么问题先说结论用 Claude Opus 5.5 这类强推理模型写代码来做视频本质上是把视频制作这件事从剪辑软件里拖时间轴迁移到用代码描述画面与运动。你不再需要逐帧拖拽而是写一段可复现、可参数化、可版本管理的程序让浏览器或渲染器把画面算出来。这条路线的核心关键词就是Canvas、WebGL、Three.js、提示词工程而 Claude Opus 5.5 在其中扮演的角色是一个能听懂自然语言、又能吐出可运行代码的技术合伙人。我做这套东西的起点其实很朴素早期用传统剪辑软件做数据可视化短片改一个数字就要重新导出一次一条 30 秒的片子改十几版是常态。后来换成代码驱动同样的片子改参数只要刷新浏览器导出交给录制或离屏渲染就行。再后来接入 Claude Opus 5.5连写代码这一步都能用自然语言描述需求来推进效率提升是数量级的。这篇文章适合三类人看一是会一点前端、想用代码做视频但不知道从哪下手的开发者二是做数据可视化、产品演示、教学动画的内容创作者三是已经在用 AI 写代码、但发现提示词写不好就出一堆废代码的实践者。我会把 7 类技术路线讲清楚用 5 个案例拆开揉碎最后给一套我自己反复打磨、可以直接抄的提示词框架。全程不聊虚的只讲能跑起来的东西。需要提前说明的是下面涉及的具体 API、参数、库版本都是基于当前主流实践的合理方案不同环境可能有差异你落地时以自己项目的实际依赖为准。我尽量把为什么这么选讲透这样即使工具迭代了思路也不会过时。2. 七类技术路线全景拆解先选对赛道再动手很多人一上来就问用 Three.js 还是 Canvas这其实是个伪问题。选路线的前提是搞清楚你的画面到底要什么。我把代码做视频拆成 7 类路线从轻到重排一遍你对号入座。2.1 路线一纯 Canvas 2D 绘图适合图表与扁平动画Canvas 2D 是最容易上手的一类。它的心智模型就是一块画布 一支笔你调用fillRect、arc、bezierCurveTo这些方法把图形画上去再用requestAnimationFrame逐帧更新。适合做柱状图动画、进度条、文字逐字出现、粒子飘散这类扁平风格的内容。它的优势是零依赖、调试直观、性能对简单场景完全够用。劣势也明显没有真正的三维空间做不了光照和透视复杂场景下每帧重绘全部内容会掉帧。我的经验是只要画面元素在几百个以内、没有 3D 需求Canvas 2D 就是性价比最高的选择别为了炫技上 WebGL。2.2 路线二Canvas 离屏渲染适合批量导出与高分辨率输出普通 Canvas 是画在屏幕上的但你可以用OffscreenCanvas或者创建一个不挂载到 DOM 的 canvas 元素在内存里逐帧绘制再用toBlob或convertToBlob把每一帧存成图片最后用 FFmpeg 合成视频。这条路线的价值在于你可以渲染 4K 甚至更高分辨率不受屏幕尺寸限制还能在后台批量跑。关键点是帧率与时间戳的对应关系。假设你要 30fps、时长 10 秒那就是 300 帧第 n 帧对应的时间是n / 30秒。所有动画逻辑都必须基于这个虚拟时间来算而不是依赖requestAnimationFrame的真实时间否则导出会抖动。这一点后面案例里会再展开。2.3 路线三WebGL 原生着色器适合流体、光效与像素级控制WebGL 让你直接操作 GPU。你写顶点着色器和片元着色器片元着色器里每个像素的最终颜色由你决定。做流体、噪声、光晕、扭曲、故障风这些效果WebGL 是天花板最高的路线。代价是学习曲线陡。你得理解 GLSL 语法、uniform 传参、纹理采样、坐标系转换。但一旦跨过这道坎你会发现很多看起来很贵的视觉效果其实就是一个片元着色器加一个时间变量。比如经典的云间列车那种流动云雾本质就是多层噪声函数叠加时间偏移。2.4 路线四Three.js 场景化适合三维空间与镜头运动Three.js 把 WebGL 的复杂度封装成了场景图Scene、Camera、Mesh、Light、Material。你描述有一个立方体、一盏平行光、相机从 A 点移动到 B 点它帮你翻译成 GPU 指令。做产品 3D 展示、空间穿梭、粒子星系、镜头推拉Three.js 是首选。它的核心价值在于镜头语言。代码做视频最缺的就是运镜而 Three.js 的 Camera 可以精确控制位置、朝向、视场角配合缓动函数就能做出电影感的推拉摇移。这也是为什么热词里three.js 快速创建项目一直很火——大家都想快速搭一个能运镜的三维舞台。2.5 路线五Three.js 后期处理适合电影感调色与辉光Three.js 自带 EffectComposer 后期处理管线可以叠加 Bloom辉光、景深、色彩校正、胶片颗粒等 Pass。这一步是把能看变成好看的关键。很多新手做出来的三维画面灰扑扑的就是因为少了后期。我的习惯是基础场景搭完后先加一层 Bloom 让高光溢出再加一层轻微的色彩查找表调色最后叠一点噪点模拟胶片质感。这三步下来画面质感立刻上一个台阶。注意 Bloom 参数别开太大否则整个画面糊成一团。2.6 路线六代码生成 视频合成流水线适合规模化生产当你需要批量产出几十上百条视频时单条手写就不划算了。这时候要把流程拆成模板 数据 渲染 合成四段模板是参数化的代码数据是 JSON 或表格渲染是离屏逐帧合成交给 FFmpeg。Claude Opus 5.5 在这里的价值是帮你快速生成模板代码和 FFmpeg 命令省去查文档的时间。2.7 路线七AI 生成素材 代码编排适合混合工作流最后一类是把 AI 生成的图片、视频片段作为素材用代码来编排它们的出现时机、转场和叠加效果。比如用文生图模型生成背景用代码控制它随音乐节奏缩放。这条路线的难点在于素材的尺寸、帧率、色彩空间要统一否则合成时会出各种诡异问题。下面这张表帮你快速定位路线核心技术适合场景上手难度性能上限纯 Canvas 2DCanvas API图表、扁平动画低中Canvas 离屏渲染OffscreenCanvas批量导出、高分辨率中中WebGL 着色器GLSL流体、光效、像素控制高极高Three.js 场景Three.js三维展示、运镜中高Three.js 后期EffectComposer电影感调色中高代码生成流水线模板FFmpeg规模化生产中高高AI 素材代码编排混合创意短片中中3. 五个案例拆解从需求到可运行代码的完整链路光讲路线太抽象我拿 5 个真实做过的案例把需求描述 → 提示词 → 代码 → 调优整条链路走一遍。每个案例我都会说清楚踩过的坑。3.1 案例一Canvas 绘制动态数据看板需求是做一个 15 秒的销售数据看板动画柱状图从 0 长到目标值数字同步滚动背景有轻微网格呼吸效果。提示词我这样写用原生 JavaScript 和 Canvas 2D创建一个 1920x1080 的画布。绘制 6 根柱状图高度从 0 缓动到目标值缓动函数用 easeOutCubic时长 1.5 秒。每根柱子上方显示对应数字数字从 0 滚动到目标值与柱子同步。背景绘制淡灰色网格网格透明度随时间做正弦波动。所有动画基于传入的时间参数 t 计算不要用 Date.now()。这里最关键的一句是基于传入的时间参数 t 计算。为什么因为导出时要逐帧渲染如果动画依赖真实时间导出就会乱。把时间作为参数传进去渲染函数就变成了纯函数给定 t输出确定的画面。这是代码做视频的第一原则。代码骨架大概是这样function renderFrame(ctx, t) { const duration 1.5; const progress Math.min(t / duration, 1); const eased 1 - Math.pow(1 - progress, 3); // easeOutCubic ctx.clearRect(0, 0, 1920, 1080); drawGrid(ctx, t); data.forEach((item, i) { const h item.value * eased; drawBar(ctx, i, h); drawNumber(ctx, i, item.value * eased); }); }导出时循环for (let f 0; f 450; f) renderFrame(ctx, f / 30)每帧存图。450 帧就是 15 秒 30fps。坑点数字滚动如果直接用Math.round会出现跳变不自然。我后来改成对数字也做缓动并且用toFixed(0)保证是整数显示。另外网格呼吸的透明度别超过 0.15否则抢主体。3.2 案例二WebGL 片元着色器做流体背景需求是一段 20 秒的抽象流体背景颜色在蓝紫之间流动有类似墨水滴入水中的扩散感。这类效果用 Canvas 2D 做会很吃力直接上 WebGL。提示词写一个全屏 WebGL 片元着色器用 simplex noise 生成流动纹理。使用三层不同频率和速度的噪声叠加通过时间变量驱动偏移。颜色在深蓝 #0a1a3a 和紫色 #6a3a9a 之间根据噪声值混合。输出带轻微暗角。片元着色器核心逻辑float n1 snoise(vec3(uv * 2.0, time * 0.15)); float n2 snoise(vec3(uv * 4.0 n1, time * 0.25)); float n3 snoise(vec3(uv * 8.0 n2, time * 0.4)); float v (n1 n2 * 0.5 n3 * 0.25) * 0.5 0.5; vec3 col mix(vec3(0.04, 0.10, 0.23), vec3(0.42, 0.23, 0.60), v);坑点simplex noise 函数很长直接让模型写容易出错。我的做法是让模型用现成的噪声库或者先让它生成一个经过验证的 noise 实现再在此基础上改。另外time的推进速度要慢0.15 这种量级比较合适太快就像沸腾的水而不是流体。3.3 案例三Three.js 云间列车运镜这个对应热词里的webgl 云间列车。需求是一列低多边形列车在云层中穿行相机跟随列车侧后方云层用粒子或半透明平面模拟。提示词用 Three.js 创建一个场景。一列由多个 BoxGeometry 组成的低多边形列车沿 Z 轴负方向匀速前进。相机位于列车侧后方位置随列车移动朝向略微偏向列车前方。云层用 200 个半透明 PlaneGeometry 随机分布在列车路径两侧材质用 MeshBasicMaterial 带透明度贴图。添加平行光和环境光。背景色用渐变天空。这里有个关键决策云层用粒子还是平面粒子性能好但缺乏体积感平面有体积感但容易穿帮。我最后选了平面 随机旋转 透明度贴图因为列车速度不快平面穿帮不明显而体积感对云间这个氛围很重要。相机跟随的代码const camOffset new THREE.Vector3(8, 4, 12); function updateCamera() { const target train.position.clone().add(camOffset); camera.position.lerp(target, 0.1); camera.lookAt(train.position.x, train.position.y 1, train.position.z - 5); }坑点lerp的系数 0.1 决定了跟随的软硬。太大相机会抖太小会滞后。我试了 0.05 到 0.2最后 0.1 最稳。另外lookAt的目标点要比列车位置稍微靠前否则相机像在盯着车尾看没有向前的感觉。3.4 案例四Three.js 后期处理做电影感接上个案例画面能看但不够高级。加后期Bloom 让云层边缘发光色彩校正压暗部提亮部加轻微噪点。提示词在 Three.js 场景中加入 EffectComposer依次添加 RenderPass、UnrealBloomPass、自定义 ShaderPass 做色彩校正、FilmPass 做胶片颗粒。Bloom 强度 0.8半径 0.4阈值 0.85。色彩校正用 lift-gamma-gain 模型。后期管线的顺序很重要先渲染再 Bloom再调色最后颗粒。如果颗粒加在 Bloom 前面颗粒也会被发光放大画面会脏。阈值 0.85 意味着只有亮度超过 0.85 的部分才发光这样云层的高光会溢出暗部保持干净。坑点加了后期之后帧率会掉导出时如果逐帧渲染一帧可能要几百毫秒。20 秒 30fps 就是 600 帧可能要跑好几分钟。建议导出时把分辨率降到 1280x720 先预览确认没问题再上 1080p 或 4K。3.5 案例五代码流水线批量生成短视频最后一个案例是规模化的。需求是根据一份 CSV 数据批量生成 50 条结构相同、数据不同的短视频。流程拆成四步第一步把 CSV 读成 JSON 数组第二步每条数据套进模板生成一个 HTML 页面或直接调用渲染函数第三步用 Puppeteer 或 Playwright 打开页面逐帧截图第四步用 FFmpeg 把图片序列合成 MP4。FFmpeg 命令ffmpeg -framerate 30 -i frame_%04d.png -c:v libx264 -pix_fmt yuv420p -crf 18 output.mp4-framerate 30要和渲染帧率一致-crf 18是质量参数数字越小质量越高体积越大18 到 23 是常用区间。-pix_fmt yuv420p保证兼容性不加的话某些播放器打不开。坑点Puppeteer 截图默认是异步的如果不等上一帧渲染完就截下一帧会出现重复帧或跳帧。我的做法是在页面里暴露一个window.renderFrame(t)函数Puppeteer 调用它并等待返回再截图。这样时序完全可控。4. 可复用提示词框架让 Claude Opus 5.5 一次吐对代码前面案例里我反复提到提示词怎么写。这一节把方法沉淀成框架。核心思路是把模型当成一个需要明确约束的工程师而不是一个会读心的魔法师。4.1 提示词的四段式结构我总结的框架是四段环境约束 目标描述 技术选型 输出规范。环境约束告诉模型运行环境比如原生 JavaScript不引入任何外部库或使用 Three.js r160通过 CDN 引入。这一步能避免模型给你一堆需要构建工具的代码。目标描述说清楚画面要什么越具体越好。别说做一个好看的动画要说1920x1080深色背景6 根蓝色柱状图从底部生长时长 1.5 秒缓动为 easeOutCubic。技术选型明确指定用 Canvas 还是 WebGL 还是 Three.js以及关键 API。这一步是防止模型自作主张。输出规范规定代码结构比如所有动画逻辑封装在 renderFrame(ctx, t) 函数中t 为秒数不要使用 Date.now() 或 requestAnimationFrame。4.2 时间参数化代码做视频的第一原则这一条我要单独拎出来讲因为它太重要了。凡是涉及导出的项目动画必须由外部传入的时间参数驱动而不是自己读系统时间。原因有三一是导出时逐帧渲染系统时间不可控二是参数化后可以任意跳帧、倒放、变速三是便于测试给定 t 就能复现画面。提示词里我会明确写所有动画状态必须是时间 t 的纯函数禁止在渲染函数内部调用 Date.now()、performance.now() 或依赖 requestAnimationFrame 的时间戳。4.3 分步生成先骨架后细节一次性让模型生成几百行代码出错概率很高。我的做法是分步第一步让它生成骨架和主循环确认结构对了第二步让它填充具体绘制逻辑第三步让它加缓动和细节。每一步都要求它输出完整可运行代码而不是片段。这样做的另一个好处是如果某一步出错你能快速定位是哪一层的问题而不是面对一坨代码无从下手。4.4 提示词模板可直接抄下面是我常用的模板你替换方括号内容即可环境原生 JavaScript[是否使用库]运行在浏览器。 目标创建一个 [宽]x[高] 的画布实现 [具体画面描述]。 时间动画总时长 [X] 秒帧率 [Y] fps。 技术使用 [Canvas 2D / WebGL / Three.js]关键 API 为 [列出]。 约束 1. 所有动画逻辑封装在 renderFrame(ctx, t) 中t 为秒数。 2. 禁止使用 Date.now()、performance.now()、requestAnimationFrame 的时间戳。 3. 缓动函数使用 [easeOutCubic 等]。 4. 代码需完整可运行包含必要的初始化。 输出完整 HTML 文件包含 canvas 和 script。4.5 迭代与纠错模型出错时怎么救模型出错是常态关键是怎么救。我的经验是不要笼统地说不对要指出具体现象和期望。比如柱子生长到一半就停了比动画有问题有用得多。如果模型连续两次改不对就换思路把问题拆得更小或者自己写关键部分让它补全。还有一个技巧让模型解释它的代码。问它你这行progress t / duration在 t 大于 duration 时会怎样它往往会自己发现没做 clamp然后修正。这比直接指出错误更能让它理解意图。5. 常见问题与排查技巧实录做这类项目问题集中在几个地方。我整理成速查表再补充几个独家避坑经验。问题现象可能原因排查方向解决思路导出视频抖动动画依赖真实时间检查是否有 Date.now改为时间参数化画面模糊画布尺寸与 CSS 尺寸不符检查 canvas.width设置 devicePixelRatio帧率骤降每帧重绘全部元素看渲染函数复杂度分层缓存或上 WebGL颜色发灰色彩空间未处理检查输出编码设置 sRGB 或调色视频打不开像素格式不兼容检查 FFmpeg 参数加 -pix_fmt yuv420p截图重复帧异步时序问题检查截图时机用同步渲染函数内存溢出帧图片未释放检查图片缓存逐帧写入磁盘5.1 画布模糊的根因与修复新手最常遇到的就是画布模糊。根因是 canvas 有两个尺寸一个是 CSS 显示尺寸一个是实际像素尺寸。如果只设 CSS 不设像素尺寸浏览器会拉伸就糊了。正确做法const dpr window.devicePixelRatio || 1; canvas.width 1920 * dpr; canvas.height 1080 * dpr; canvas.style.width 1920px; canvas.style.height 1080px; ctx.scale(dpr, dpr);但导出时要注意如果你要 1920x1080 的输出就别乘 dpr直接用 1920x1080否则导出尺寸会翻倍。5.2 导出速度优化的三个手段导出慢是常态三个手段能明显提速。第一降低预览分辨率确认无误再上高分辨率。第二关闭不必要的后期处理导出时用简化管线。第三用离屏渲染避免屏幕刷新开销。我实测下来同样的场景离屏渲染比屏幕渲染快 30% 到 50%。5.3 提示词失效时的降级策略有时候模型就是理解不了你的意图反复出错。这时候降级把复杂需求拆成多个简单需求逐个生成再拼装。或者干脆自己写核心逻辑让模型只做辅助。别跟模型死磕时间成本不划算。5.4 素材统一混合工作流的隐形杀手如果你用 AI 生成的图片做素材务必统一尺寸、帧率、色彩空间。我踩过的坑是生成的图片是 sRGB渲染管线是线性空间合成后颜色偏暗。解决办法是在加载纹理时设置texture.colorSpace THREE.SRGBColorSpace让 Three.js 帮你转换。6. 工具链与项目搭建从零到能跑这一节讲具体怎么把环境搭起来让代码真的能跑。6.1 Three.js 项目的两种引入方式第一种是 CDN适合快速验证script typeimportmap { imports: { three: https://unpkg.com/three0.160.0/build/three.module.js, three/addons/: https://unpkg.com/three0.160.0/examples/jsm/ } } /script script typemodule import * as THREE from three; import { EffectComposer } from three/addons/postprocessing/EffectComposer.js; /script第二种是 npm 安装适合正式项目。npm install three之后用打包工具引入。CDN 的好处是零配置坏处是依赖网络。正式项目我建议 npm版本可控。6.2 导出流水线的目录结构我习惯的目录结构project/ src/ render.js // 渲染函数 scene.js // 场景搭建 data/ input.csv // 数据源 output/ frames/ // 帧图片 videos/ // 成品视频 export.js // 导出脚本export.js负责读数据、循环渲染、存帧、调 FFmpeg。这样数据和逻辑分离换数据不用改代码。6.3 帧率与时长的心算导出前先算清楚时长 X 秒帧率 Y fps总帧数就是 X 乘 Y。30 秒 30fps 是 900 帧60fps 是 1800 帧。帧数直接决定导出时间一帧如果 200 毫秒900 帧就是 3 分钟。心里有数就不会被导出时间吓到。6.4 版本管理代码做视频的隐藏优势这是代码路线相比剪辑软件最大的优势之一你的视频工程是一个代码仓库可以 git 管理。改了什么、什么时候改的、为什么改全都有记录。我现在的习惯是每条视频一个分支改版就提交回滚就是 checkout。这在传统剪辑里是不可想象的。7. 提示词工程的底层逻辑为什么有的提示词好用最后聊聊提示词这件事的底层逻辑因为热词里提示词工程ai 编程提示词一直很热但很多人只是抄模板不理解为什么。7.1 提示词的本质是约束搜索空间模型生成代码时理论上可能的输出是无限的。提示词的作用是缩小这个空间让模型往你要的方向走。所以提示词越具体输出越可控。做一个动画和1920x1080、6 根柱子、easeOutCubic、1.5 秒后者把搜索空间压缩了几个数量级。7.2 为什么鹈鹕骑自行车这类测试提示词有效你可能见过鹈鹕骑自行车这种看似无厘头的测试提示词。它的价值在于这是一个模型训练数据里罕见的具体场景能快速暴露模型在空间关系、物体组合、细节一致性上的能力边界。做代码视频时你也可以用类似的压力测试提示词来评估模型比如画一个正在融化的钟表挂在树枝上看它能不能处理好形变和空间关系。7.3 从描述结果到描述过程新手提示词往往只描述结果画一个好看的星空。老手会描述过程用 500 个随机分布的点每个点大小随机亮度随时间正弦闪烁颜色在白色和淡蓝之间插值。描述过程的好处是模型不需要猜你的审美只需要执行你的算法。这也是代码做视频和纯 AI 生成视频的根本区别前者你控制过程后者你只能祈祷结果。7.4 提示词的复用与参数化好的提示词是可以复用的。把变化的部分抽成变量固定的部分做成模板。比如画一个 [形状]颜色 [色值]位置 [坐标]这样一个模板能生成无数变体。这也是批量生产的基础。8. 我踩过的坑与实操心得写到这里把几个印象最深的坑分享一下都是文档里不会写的。第一个坑别在渲染函数里做异步操作。我早期在渲染函数里加载图片结果导出时图片还没加载完就截图了出来一堆空白帧。正确做法是先把所有资源加载完再开始渲染循环。第二个坑缓动函数别乱用。easeInOut 看起来优雅但用在数据展示上会让人看不清中间值。数据类动画用 easeOut 更合适快速到达再缓慢稳定。第三个坑颜色别凭感觉调。我一开始手动调 RGB调了半天不满意。后来改用 HSL只调色相和明度效率高很多。深色背景配高饱和主体浅色背景配低饱和主体这个规律基本不会错。第四个坑导出前先做 3 秒预览。完整导出可能要几分钟如果方向错了就是浪费。先导 3 秒看看效果确认了再全量导出。第五个坑模型生成的代码一定要读。不是不信任模型而是它有时会用一些你环境里没有的 API或者写出性能很差的循环。读一遍改一改比出了 bug 再查快得多。这套东西我做了大半年从最初的手忙脚乱到现在能比较顺畅地批量产出最大的体会是代码做视频的门槛不在代码而在把画面翻译成算法的思维。一旦你习惯了用参数、时间、缓动、噪声这些概念去描述画面剩下的就是熟练度问题。Claude Opus 5.5 这类模型能帮你跨过语法和 API 的门槛但画面的设计思路还是得你自己想。这也是为什么我一直强调提示词要描述过程而不是结果——过程是你的结果才是模型的。