1. 这个标题到底在说什么
先把话说在前头:Claude Opus 5.5 本身并不能像文生视频模型那样,直接吐出一个 mp4 文件给你下载。所谓“直出视频”,准确的说法是——它一次性生成了一段用 HTML、CSS、JavaScript 写成的可播放动画,你在浏览器里打开,看到的就是一段会动的画面。这个区别很关键,因为很多人一看到“直出视频”四个字,脑子里浮现的是 Sora、可灵那种视频生成,结果拿到代码一脸懵。
我最早注意到这个玩法,是在一批“鹈鹕骑自行车”的测试提示词刷屏的时候。大家发现,只要提示词写得足够细,模型能直接输出一个完整的 HTML 文件,里面用 CSS 动画或者 Canvas 把一只鹈鹕蹬自行车的循环动作做出来,甚至带背景、带光影、带镜头感。后来提示词越写越狠,从“鹈鹕骑车”进化到“粒子涟漪扩散”“数字加载动画”“屏幕穿出效果”,本质上都是在压榨同一套能力:用前端代码模拟视频。
所以这篇文章要聊的,不是玄学,而是一套可复现的方法论:怎么写出让模型稳定输出“视频级”HTML 动画的提示词,怎么把生成的代码跑起来,怎么调参、怎么排错、怎么把它变成能直接用的东西。适合三类人看:一是想快速做演示动画但不会写前端的产品和运营;二是想拿它当灵感加速器的前端;三是纯粹好奇 AI 编程边界在哪的折腾党。下面全部是我自己反复试出来的经验,能抄的我都给你抄。
2. 为什么是 HTML+CSS,而不是真视频
2.1 模型的能力边界决定了输出形态
大语言模型的核心是文本生成,它的输出天然是 token 序列。视频是像素帧序列,中间隔着一整套编码、渲染管线,模型没法直接“画”出来。但 HTML、CSS、JavaScript 是文本,而且浏览器本身就是个渲染引擎——你把代码给它,它帮你渲染成画面。模型等于把“渲染”这件事外包给了浏览器,自己只负责写“剧本”。
这个思路其实很聪明。它绕开了视频生成最贵的部分(逐帧像素预测),转而在结构化描述上发力。CSS 的@keyframes、transform、animation这些声明式语法,恰好特别适合描述“什么东西在什么时间做什么动作”。模型只要把动作拆解成关键帧,剩下的插值、缓动、合成,浏览器全包了。
2.2 相比真视频,这套方案的优势在哪
我列个表对比一下,你就明白为什么这个玩法值得单独拿出来讲:
| 维度 | AI 直出 HTML 动画 | 传统文生视频 |
|---|---|---|
| 输出体积 | 几 KB 到几十 KB 文本 | 几 MB 到几十 MB |
| 可编辑性 | 直接改代码,精确到像素 | 只能重生成或剪辑 |
| 循环播放 | 天然无缝循环 | 通常需要后期处理 |
| 透明背景 | CSS 直接支持 | 多数模型不支持 |
| 交互能力 | 可加鼠标、点击响应 | 基本没有 |
| 生成速度 | 秒级到十几秒 | 几十秒到几分钟 |
| 分辨率 | 矢量,无限放大不糊 | 固定分辨率 |
最关键的是可编辑性。视频生成出来,你想把鹈鹕的翅膀扇动频率调快一点,只能重新抽卡。但 HTML 动画,你找到那行animation-duration: 0.8s,改成0.5s,刷新,完事。对于需要反复微调的演示场景,这个差距是碾压性的。
2.3 什么场景适合这么干
不是所有视频需求都适合用 HTML 顶。我的判断标准很简单:
- 适合:图标动画、加载动画、数据可视化动效、产品演示循环、网页 banner、教学示意图、UI 交互动效。
- 不适合:真人出镜、复杂实拍质感、需要真实物理模拟的写实场景、长视频叙事。
一句话总结:你要的是“动效”而不是“影像”,就用 HTML;你要的是“影像”,老老实实找视频模型。
3. 提示词怎么写才能稳定出片
3.1 提示词的核心结构:五段式
我试过几十版提示词,最后稳定下来的结构是五段:角色设定 + 画面描述 + 动作拆解 + 技术约束 + 输出格式。缺一段,输出质量就往下掉一档。
先说角色设定。很多人忽略这段,直接上来就描述画面,结果模型给你的代码风格飘忽不定。加一句“你是一名资深前端动画工程师,擅长用纯 CSS 实现流畅动效”,输出的代码规范度会明显提升。这不是玄学,是给模型一个“人格锚点”,让它调用对应的知识分布。
画面描述要具体到主体、背景、配色、视角。比如“一只白色鹈鹕,橙色喙,骑着一辆红色自行车,背景是淡蓝色渐变天空,侧面视角”,比“一只鸟骑车”强太多。模型对颜色和视角的敏感度很高,你给得越细,它脑补得越少,翻车概率越低。
动作拆解是重头戏。你要把循环动作拆成几个关键姿态,用文字描述出来。比如鹈鹕骑车可以拆成:蹬踏板、身体上下起伏、翅膀轻微扇动、头部前后摆动。每个动作给一个大概的节奏,模型就能对应到@keyframes的百分比节点上。
技术约束这段是保证代码能跑的关键。我一般会明确写:使用单个 HTML 文件,内联 CSS 和 JS,不引用外部资源,使用@keyframes实现循环动画,动画时长 X 秒,无限循环。这样模型就不会给你拆成三个文件,也不会去引 CDN 上的库。
输出格式就一句话:直接输出完整 HTML 代码,不要解释,不要 markdown 代码块标记。注意,有些模型会固执地加 ```html 包裹,你得在提示词里明确说“不要用代码块包裹”,否则复制的时候还得手动删。
3.2 一个可以直接抄的提示词模板
下面这个模板我用了很多次,改改主体就能复用:
你是一名资深前端动画工程师,擅长用纯 CSS 实现流畅的循环动效。 请生成一个单文件 HTML 动画,要求如下: 画面内容:一只白色鹈鹕,橙色长喙,骑着一辆红色自行车, 背景是淡蓝色到白色的渐变天空,侧面视角,画面宽 1440px,高 810px。 动作拆解: 1. 鹈鹕双腿交替蹬踏板,周期 1 秒 2. 身体随蹬踏上下起伏,幅度约 5px 3. 翅膀轻微扇动,周期 2 秒 4. 自行车车轮持续旋转,周期 0.5 秒 5. 背景云朵缓慢横向移动,周期 20 秒 技术约束: - 单个 HTML 文件,CSS 和 JS 全部内联 - 不引用任何外部资源、字体、图片 - 使用 @keyframes 实现所有动画 - 所有动画无限循环,衔接自然无跳变 - 使用 transform 和 opacity 做动画,避免触发重排 输出格式:直接输出完整 HTML 代码,不要任何解释文字, 不要用 markdown 代码块包裹。实测下来,这个模板的出片率大概在七成以上。剩下三成翻车,多半是动作拆解写得太抽象,或者主体太复杂(比如让它画一只写实的猫,它就容易糊)。
3.3 提示词里的三个高频坑
第一个坑是动作描述用形容词而不是动词。你写“鹈鹕优雅地骑车”,模型不知道“优雅”对应什么关键帧。你写“鹈鹕身体上下起伏 5px,周期 1 秒”,它立刻懂了。形容词是给人看的,动词和数值才是给模型看的。
第二个坑是忘了约束画布尺寸。不写尺寸,模型可能给你一个100%宽高的自适应布局,结果在某些容器里显示错位。明确写死1440px × 810px或者1920px × 1080px,配合overflow: hidden,画面就稳了。
第三个坑是没说要循环。不写“无限循环”,模型可能给你一个播放一次就停的动画,你还得自己去找animation-iteration-count改。直接在提示词里写死infinite,省事。
提示:如果你的模型总是输出带 markdown 代码块的结果,可以在提示词末尾加一句“第一个字符必须是 <!doctype html>”,强制它从代码开始输出。
4. 拿到代码之后怎么跑起来
4.1 最省事的三种运行方式
代码到手,第一件事是存成.html文件。注意编码选 UTF-8,否则中文注释可能乱码。存好之后有三种跑法:
- 双击直接打开:最简单,浏览器直接渲染。缺点是某些涉及
fetch本地文件的操作会被 CORS 拦,但纯 CSS 动画不受影响。 - VS Code + Live Server:装个 Live Server 插件,右键“Open with Live Server”,改代码自动刷新,调试动效特别爽。
- 本地起个静态服务:
python -m http.server 8000,然后浏览器访问localhost:8000。适合需要加载本地资源的场景。
我日常用第二种,因为调动画参数要反复刷新,Live Server 的热更新能省不少时间。
4.2 代码结构长什么样
模型生成的代码,结构通常是这样:
<!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <title>鹈鹕骑车动画</title> <style> /* 所有动画定义在这里 */ @keyframes pedal { ... } @keyframes bob { ... } @keyframes wheelSpin { ... } </style> </head> <body> <div class="scene"> <div class="pelican">...</div> <div class="bike">...</div> </div> </body> </html>看懂这个骨架,你就能自己改了。.scene是舞台容器,负责裁剪和定位;里面的元素各自挂animation属性,引用对应的@keyframes。想调快慢,改animation-duration;想调幅度,改@keyframes里的transform数值。
4.3 关键参数怎么调
调参这件事,我总结了一个口诀:时长看节奏,缓动看手感,延迟看错位。
animation-duration控制一个循环多久。蹬踏板一般 0.8 到 1.2 秒比较自然,太快像抽搐,太慢像慢动作。车轮旋转可以快一点,0.4 到 0.6 秒。背景云朵要慢,15 到 30 秒,营造纵深感。
animation-timing-function控制速度曲线。linear是匀速,适合车轮旋转;ease-in-out是两头慢中间快,适合身体起伏;cubic-bezier()可以自定义,但新手别碰,容易调出诡异的手感。
animation-delay控制多个动画的相位差。比如左右腿蹬踏,可以给其中一条腿加-0.5s的负延迟,让它和另一条腿错开半个周期,看起来就是交替蹬。负延迟这个技巧很实用,比手动算关键帧省事。
5. 进阶玩法:从“能看”到“好看”
5.1 用 CSS 变量统一管理参数
代码一多,到处找数值改很痛苦。我习惯在:root里定义一组 CSS 变量:
:root { --pedal-duration: 1s; --bob-amplitude: 5px; --wheel-duration: 0.5s; --cloud-duration: 20s; }然后动画里引用var(--pedal-duration)。这样调参只改一处,全局生效。模型生成的代码不一定带这个,但你可以手动重构一下,后期维护成本直线下降。
5.2 加镜头感:缩放和位移
想让画面有“视频感”,光有主体动不够,得有镜头运动。最简单的做法是给舞台容器加一个缓慢的scale或translate动画。比如:
@keyframes cameraPush { 0% { transform: scale(1) translateX(0); } 100% { transform: scale(1.05) translateX(-20px); } }这种缓慢的推镜,能让静态感很强的画面立刻“活”起来。注意幅度要小,5% 以内就够了,大了会晕。
5.3 涟漪光圈扩散效果怎么做
热词里提到的“CSS 涟漪光圈扩散”,原理是多个同心圆依次放大并淡出。核心代码大概是这样:
@keyframes ripple { 0% { transform: scale(0.5); opacity: 0.8; } 100% { transform: scale(2.5); opacity: 0; } } .ripple { animation: ripple 2s ease-out infinite; } .ripple:nth-child(2) { animation-delay: 0.5s; } .ripple:nth-child(3) { animation-delay: 1s; }三个圆错开延迟,就有了连续扩散的感觉。这个效果拿来做加载动画、点击反馈、雷达扫描都很好用。
5.4 数字加载动画和倒计时
数字动画的关键是逐帧切换,用steps()缓动函数最合适:
@keyframes countdown { from { content: "3"; } to { content: "0"; } }不过content属性在@keyframes里的支持度一般,更稳的做法是用 JS 定时改文本,CSS 只负责缩放和淡入淡出。模型有时候会给你纯 CSS 方案,能跑但兼容性一般,遇到问题就换成 JS 驱动。
6. 常见问题与排查实录
6.1 动画不动的排查顺序
动画不动是最常见的问题,按这个顺序查:
- 看
animation-name和@keyframes名字是否一致。大小写敏感,Pedal和pedal是两个东西。 - 看元素有没有被
display: none或者尺寸为 0。动画在跑,但你看不见。 - 看
animation-duration是不是 0。0 秒等于没动画。 - 看有没有被其他样式覆盖。用浏览器开发者工具的 Computed 面板查最终生效值。
6.2 动画跳变的排查
循环动画首尾不衔接,会“跳”一下。原因是0%和100%的关键帧状态不一致。解决办法是让首尾状态完全相同,或者用animation-direction: alternate让它来回播放。我一般选前者,因为来回播放的节奏感不如单向循环自然。
6.3 性能问题
如果动画卡顿,多半是动了不该动的属性。只动transform和opacity,这两个属性走 GPU 合成,不触发重排重绘。动width、height、top、left、margin这些,每一帧都要重新布局,元素一多就卡。
排查方法:Chrome 开发者工具 → Performance → 录制几秒 → 看有没有大块的紫色(重排)或绿色(重绘)。有的话,把对应属性换成transform。
6.4 常见问题速查表
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 动画完全不动 | 名字不匹配 / 时长为 0 | 核对animation-name,检查duration |
| 循环时跳变 | 首尾关键帧不一致 | 统一 0% 和 100% 状态 |
| 动画卡顿 | 动了布局属性 | 改用transform/opacity |
| 元素位置错乱 | 缺少定位上下文 | 给父容器加position: relative |
| 中文乱码 | 编码不是 UTF-8 | 加<meta charset="utf-8"> |
| 代码块包裹 | 模型没听话 | 提示词里强调“不要代码块” |
注意:如果你在 VS Code 里用 Claude Code 之类的工具生成,记得检查它有没有偷偷引用外部字体或图标库。一旦引用了,离线环境就打不开,画面直接崩。
7. 我踩过的几个坑和一点心得
第一个坑是过度信任模型的物理直觉。我让它做“小球弹跳”,它给的关键帧是匀速上下,完全没有重力加速度的感觉。后来我在提示词里明确写“下落用ease-in,上升用ease-out,落地瞬间加挤压变形”,效果立刻对了。模型懂语法,但不懂物理,物理得你喂给它。
第二个坑是元素层级混乱。鹈鹕骑车,结果翅膀画在了身体后面,看起来像穿模。解决办法是在提示词里写清楚 z-index 顺序,或者生成后手动调z-index。我现在的习惯是,提示词里直接写“翅膀在身体上层,自行车在鹈鹕下层”。
第三个坑是颜色搭配翻车。模型对“高级感”的理解和人类不一样,经常给你配出荧光绿配大红。我的做法是提示词里直接指定色值,比如“背景 #E8F4FF,主体 #FFFFFF,点缀 #FF6B35”,不给它自由发挥的空间。
最后分享一个提效技巧:把成功的提示词存成模板库。我现在有一组按场景分类的模板——加载动画、图标动效、数据可视化、场景循环——每次用的时候改主体描述就行。这比每次从零写提示词快得多,出片率也稳定。模型在变,但“角色 + 画面 + 动作 + 约束 + 格式”这个骨架,我用了大半年还没换过。