1. 这个标题到底在说什么:先拆概念再动手
先把话说在前头,标题里说的“直出视频”,并不是指模型真的吐出一个 mp4 文件让你下载。我实测下来,它的真实含义是:用一段结构化的提示词,让模型一次性生成一套可运行的 HTML + CSS + JavaScript 代码,这套代码在浏览器里跑起来之后,呈现的是一个会动的、带时间轴的、可以逐帧播放的动画页面。你打开这个页面,看到的就是一段“视频”,只不过它的底层不是视频编码,而是 DOM 元素加 CSS 动画加 JS 定时器。
这个区别非常关键,因为它决定了你后面所有的操作方向。如果你以为它能直接导出 mp4,那你会在第一步就卡住,然后觉得“这标题是骗人的”。但如果你理解了它输出的是“可播放的动画页面”,那你会发现这条路子其实非常实用:体积小、可交互、可二次编辑、能直接嵌到网页里,比传统视频在某些场景下更灵活。
我为什么会关注这个点?因为过去一年里,用 AI 写前端代码这件事已经从“玩具”变成了“生产力”。尤其是 Claude 系列在代码生成上的稳定性,让很多原本需要手写几百行 CSS 动画的活儿,变成了一次对话就能搞定。而“直出视频”这个说法之所以能成为热词,本质上是因为它触碰到了一个真实需求:普通人想快速做一个带动画的视觉内容,但不想学 AE,也不想学剪辑软件。
这篇文章适合谁看?三类人。第一类是有一定 HTML/CSS 基础,想用 AI 加速动画开发的前端或设计岗;第二类是完全不懂代码,但想通过提示词“骗”出一个能跑的动画页面的内容创作者;第三类是已经在用 Claude Code 或类似工具,想搞清楚提示词该怎么写才能稳定出活的效率玩家。三类人的基础不同,但目标一致:让模型把“视频”这件事用代码的方式做出来。
在往下走之前,我需要先把这个项目的核心逻辑讲清楚。所谓“直出视频”,拆开来看是三个层次的能力叠加:代码生成能力、动画编排能力、以及提示词对输出结构的约束能力。缺任何一个,你都得不到一个能看的成品。很多人失败不是因为模型不行,而是因为提示词只写了“做一个视频”,没有告诉模型“用什么技术做、做成什么样、时间怎么分配”。
2. 核心思路拆解:为什么是 HTML + CSS + JS 这条路
2.1 模型输出“视频”的三种可能路径与取舍
当你让一个语言模型“生成视频”时,它理论上可以走三条路。第一条是生成视频文件,比如通过某种编码接口输出 mp4 或 webm。这条路在纯对话场景下基本走不通,因为模型本身不携带视频编码器,也没有文件输出通道。第二条是生成一系列图片帧,然后让你自己去合成。这条路可行但很笨,因为你要额外做帧合成,而且图片质量不可控。第三条就是生成 HTML + CSS + JS 代码,让浏览器在运行时把动画渲染出来。
我选第三条,理由很直接:它是唯一一条“模型能完整控制、用户能零成本运行、结果能直接分享”的路径。模型擅长写结构化文本,HTML 和 CSS 本身就是结构化文本,天然契合。浏览器是每个人都有的运行环境,不需要装任何东西。生成的页面可以直接发给别人,对方双击就能看。这三点加起来,让这条路成为当前最务实的方案。
提示:不要试图让模型输出视频文件,也不要让它输出 GIF。前者它做不到,后者体积大且质量差。把目标锁定在“可运行的动画页面”上,成功率会高很多。
2.2 为什么提示词必须约束技术栈
我踩过的最大一个坑,就是早期提示词写得太随意,只说“做一个鹈鹕骑自行车的动画”。结果模型给我的东西五花八门:有时候用 Canvas 画,有时候用 SVG,有时候甚至用纯 CSS 但结构混乱到没法改。后来我学乖了,提示词里必须明确三件事:用什么技术、画布多大、动画怎么驱动。
技术栈锁定为 HTML + CSS + JS,是因为这三者的分工非常清晰。HTML 负责结构,把画面里的元素(鹈鹕、自行车、背景、地面)都定义成独立的 DOM 节点。CSS 负责样式和动画,用@keyframes控制元素的位移、旋转、缩放。JS 负责时间轴和交互,比如播放、暂停、进度条、循环。这个分工让代码可读、可改、可扩展。
画布尺寸我一般锁定为 1440×810,也就是 16:9 的比例。这个尺寸的好处是:在大多数笔记本屏幕上能完整显示,同时分辨率足够高,截图或录屏之后画质不会糊。如果你要做竖屏内容,改成 810×1440 就行,但要注意元素的布局逻辑要跟着调整。
动画驱动方式我强烈建议用 CSS 的@keyframes加animation属性,而不是用 JS 逐帧改样式。原因很简单:CSS 动画由浏览器合成线程处理,性能好、代码短、容易调试。JS 只在需要做时间轴控制的时候介入,比如暂停和恢复。
2.3 提示词的结构化模板长什么样
经过多次迭代,我总结出一个比较稳的提示词骨架,分成五个部分。第一部分是角色设定,告诉模型“你是一个前端动画工程师”。第二部分是任务描述,明确“生成一个单文件 HTML,包含内联 CSS 和 JS”。第三部分是画面描述,把场景里的元素、位置、颜色、动作都写清楚。第四部分是技术要求,锁定画布尺寸、动画时长、循环方式。第五部分是输出约束,要求“只输出代码,不要解释”。
这个骨架的核心价值在于:它把模糊的“做个视频”翻译成了模型能精确执行的工程指令。模型不需要猜你想要什么,它只需要按部就班地把每个元素翻译成代码。我实测下来,用这个骨架生成的代码,第一次就能跑的比例大概在七成以上,剩下的三成通常是细节需要微调。
3. 提示词工程细节:把“视频”翻译成代码的关键
3.1 场景描述要写到“元素级”
很多人写提示词失败,是因为描述停留在“画面级”。比如“一只鹈鹕骑着自行车在夕阳下前进”,这句话对人来说很有画面感,但对模型来说信息量不够。它不知道鹈鹕在画面左边还是右边,不知道自行车有几个轮子,不知道夕阳是什么颜色,不知道前进是原地踩踏还是整体位移。
我的做法是把描述拆到“元素级”。每一个可见的东西都单独列出来,并且给它三个属性:位置、外观、动作。比如鹈鹕:位置在画面中央偏左,外观是白色身体加橙色喙,动作是身体随踩踏节奏上下起伏。自行车:位置在鹈鹕下方,外观是两个黑色圆形轮子加一个三角形车架,动作是轮子持续旋转。背景:位置铺满整个画布,外观是橙红色渐变加一个圆形太阳,动作是太阳缓慢下沉。
这样写的好处是,模型在生成代码时,每个元素都能对应到一个独立的 DOM 节点和一组独立的 CSS 规则。后面你要改任何一个元素,都能在代码里精确定位,不会牵一发而动全身。
3.2 时间轴与节奏的量化表达
“视频”和静态图的区别在于时间。所以提示词里必须包含时间信息。我通常用两种方式表达:总时长加关键帧百分比。比如总时长设为 6 秒,循环播放。然后描述每个动作在时间轴上的分布:0% 到 100% 轮子持续旋转,0% 到 50% 鹈鹕身体上升,50% 到 100% 身体下降,0% 到 100% 背景整体向左缓慢平移模拟前进。
这种量化表达让模型能直接把它翻译成@keyframes里的百分比节点。如果你只说“鹈鹕上下起伏”,模型可能会给你一个随机的时长和节奏,看起来就很别扭。而当你明确“每 0.5 秒一个起伏周期”,模型就能算出对应的动画时长和缓动函数。
注意:时间参数不要写得太复杂。我建议一个页面里的动画周期不超过三种,否则代码会变得很难维护,而且模型也容易出错。简单就是稳。
3.3 输出格式约束:为什么必须要求“只输出代码”
这一点看起来是小事,但实际影响很大。如果你不约束输出格式,模型会在代码前后加一堆解释文字,比如“这是为您生成的代码”“您可以根据需要修改”。这些文字本身没错,但当你想要直接复制代码去运行时,它们就是干扰。更麻烦的是,有些模型会把代码拆成好几段,中间穿插说明,导致你复制的时候容易漏掉部分。
所以我在提示词最后一定会加一句:只输出一个完整的 HTML 文件代码,从<!DOCTYPE html>开始到</html>结束,不要有任何额外文字。这句话能显著提高输出的可用性。我实测下来,加了这句之后,直接复制粘贴就能跑的比例从五成提升到了八成以上。
另外,我还会要求代码里的 CSS 和 JS 都内联在 HTML 里,不要拆成外部文件。原因是单文件更方便分享和运行,你发给别人一个文件就行,不用附带一堆依赖。对于这种演示性质的动画页面来说,单文件是最优解。
4. 完整实操流程:从提示词到可播放页面
4.1 环境准备:你其实不需要装任何东西
先说一个反直觉的事实:做这件事,你不需要装 Node.js,不需要装构建工具,不需要配任何开发环境。你只需要两样东西:一个能打开网页的浏览器,和一个能写代码的文本编辑器。浏览器推荐 Chrome 或 Edge,文本编辑器推荐 VS Code,但其实记事本也能用。
如果你已经在用 Claude Code 或者类似的命令行工具,那流程会更顺,因为你可以直接在终端里让模型生成文件。但如果你只是用网页版的对话界面,也完全没问题,复制粘贴代码到本地文件就行。我两种方式都试过,结论是:对于这种单文件动画,网页版对话反而更直观,因为你能立刻看到代码长什么样。
具体操作是这样的:新建一个文件夹,在里面新建一个文件,命名为index.html。然后用文本编辑器打开它,把模型生成的代码粘贴进去,保存。最后双击这个文件,浏览器就会打开它,你就能看到动画了。整个过程不超过两分钟。
4.2 提示词实战:一个可直接复用的完整示例
下面是我实际用过的一个提示词,你可以直接拿去改。它的结构就是我前面说的五段式。
你是一个资深前端动画工程师,擅长用 HTML、CSS 和 JavaScript 制作流畅的网页动画。 任务:生成一个单文件 HTML 页面,页面内包含一段循环播放的动画,动画内容是一只鹈鹕骑着自行车在夕阳下的公路上前进。 画面元素与要求: 1. 画布尺寸固定为 1440×810 像素,背景铺满整个画布。 2. 背景为橙红色到紫色的渐变,右上角有一个圆形太阳,太阳在动画过程中缓慢下沉。 3. 公路位于画面下方三分之一处,深灰色,带白色虚线,虚线向左移动模拟前进。 4. 鹈鹕位于画面中央偏左,白色身体,橙色喙,黑色眼睛,身体随踩踏节奏上下起伏。 5. 自行车位于鹈鹕下方,两个黑色圆形轮子,轮子持续顺时针旋转,车架为深灰色三角形结构。 技术要求: 1. 所有动画使用 CSS @keyframes 实现,不要用 JavaScript 逐帧修改样式。 2. 动画总时长为 6 秒,无限循环。 3. 轮子旋转周期为 0.5 秒,鹈鹕身体起伏周期为 0.5 秒,太阳下沉和虚线移动贯穿整个 6 秒。 4. 使用 transform 和 opacity 做动画,避免触发重排。 输出要求: 只输出一个完整的 HTML 文件代码,从 <!DOCTYPE html> 开始到 </html> 结束。CSS 和 JavaScript 都内联在 HTML 中。不要有任何额外文字说明。这个提示词的关键在于:每个元素都有明确的位置、外观和动作,时间参数具体到秒,技术约束清晰。我用它生成的代码,基本一次就能跑,偶尔需要调一下元素的具体坐标。
4.3 代码到手后的三步检查法
拿到代码之后,不要急着欣赏,先做三步检查。第一步,看结构是否完整。确认代码从<!DOCTYPE html>开始,到</html>结束,中间有<head>和<body>,CSS 在<style>标签里,JS 在<script>标签里。如果缺了任何一块,直接让模型补。
第二步,看动画是否真的在动。打开页面后,观察三个地方:轮子有没有转,鹈鹕有没有起伏,背景有没有移动。如果某个元素不动,大概率是@keyframes的名字和animation属性引用的名字不一致,或者动画时长写成了 0。
第三步,看性能是否流畅。打开浏览器的开发者工具,切到 Performance 面板,录几秒看看帧率。如果帧率稳定在 60 帧左右,说明没问题。如果掉到 30 帧以下,通常是动画属性用错了,比如用了left或top而不是transform。
提示:如果你发现动画卡顿,优先检查是不是有元素在动画过程中改变了宽高。改变宽高会触发重排,非常耗性能。把所有动画都改成
transform: translate()和transform: rotate(),流畅度会立刻提升。
4.4 参数微调:让画面从“能看”到“好看”
模型生成的代码,通常能达到“能看”的水平,但离“好看”还差一点。这时候需要你手动微调几个参数。我一般调三个地方:颜色、速度、缓动函数。
颜色方面,模型给的渐变往往比较保守。你可以把背景渐变的色值改成更饱和的,比如把#ff6b6b改成#ff4757,对比度会更强。速度方面,如果动画看起来太快或太慢,直接改animation-duration的值就行,6 秒改成 8 秒,整体节奏就慢下来了。缓动函数方面,默认的linear看起来很机械,改成ease-in-out会让动作更自然。
我个人的经验是:先调速度,再调颜色,最后调缓动。因为速度对观感的影响最大,颜色次之,缓动最小。而且速度调整最简单,改一个数字就行,不会引入新的问题。
5. 常见问题与排查技巧实录
5.1 模型输出不完整或格式错乱怎么办
这是最常见的问题。表现是:代码只输出了一半,或者中间夹杂了中文说明,或者 CSS 和 JS 混在一起。原因通常是提示词里的输出约束不够强,或者对话上下文太长导致模型“忘了”要求。
解决办法有三个。第一,在提示词里把输出约束放在最后,并且用加粗或重复的方式强调。第二,如果模型还是输出不完整,直接回复“继续”,让它接着写。第三,如果格式错乱,回复“请重新输出,只输出完整代码,不要任何解释”,通常第二次就会好。
我实测下来,Claude 系列在代码生成上的稳定性是比较好的,出现不完整的情况大多是因为提示词本身太模糊。把要求写清楚,问题基本能解决。
5.2 动画不播放或只播放一次
如果页面打开后动画不动,先检查@keyframes的定义和引用是否匹配。CSS 里定义的是@keyframes rotate { ... },那animation属性里必须写animation: rotate 0.5s linear infinite;。名字对不上,动画就不会执行。
如果动画只播放一次就停了,检查animation-iteration-count是不是写成了1。要循环播放,必须写infinite。有时候模型会漏掉这个属性,手动补上就行。
还有一种情况是动画播放了但看不到效果,原因是元素的初始状态和结束状态一样。比如你让一个元素从translateX(0)移动到translateX(0),那它当然不动。检查关键帧里的起止值是否有差异。
5.3 元素位置错乱或重叠
这个问题通常出在定位方式上。如果所有元素都用position: absolute,但没有给父容器设置position: relative,那它们会相对于整个页面定位,位置就会乱。解决办法是给画布容器加position: relative,所有子元素用absolute相对于它定位。
另一个常见原因是z-index没设置好,导致该在上面的元素被盖住了。比如鹈鹕应该骑在自行车上,但如果自行车的z-index比鹈鹕高,鹈鹕就会被挡住。给每个元素明确指定z-index,从背景到前景依次递增,就能解决。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 动画完全不动 | @keyframes名称与animation引用不一致 | 检查两处名称是否完全相同 |
| 动画只播一次 | 缺少infinite属性 | 在animation简写里加上infinite |
| 元素位置错乱 | 父容器没有position: relative | 给画布容器加上相对定位 |
| 元素被遮挡 | z-index顺序错误 | 按背景到前景递增设置z-index |
| 动画卡顿 | 使用了left/top/width做动画 | 改用transform和opacity |
| 代码不完整 | 提示词输出约束不够强 | 强调“只输出完整代码”,必要时回复“继续” |
| 画面比例不对 | 画布尺寸与元素坐标不匹配 | 统一按 1440×810 设计,元素坐标按此计算 |
5.5 几个我踩过的坑
第一个坑是过度追求复杂场景。我一开始想让模型做一个“鹈鹕骑自行车穿过城市街道,背景有建筑、行人、车辆”的动画,结果代码量爆炸,模型输出到一半就断了,而且出来的效果很乱。后来我学乖了,场景越简单,成品越稳。一个鹈鹕、一辆车、一条路、一个太阳,足够了。
第二个坑是忽略了移动端适配。1440×810 在电脑上没问题,但在手机上打开会被压缩得很小。如果你需要手机上看,要么改成竖屏尺寸,要么在 CSS 里加transform: scale()做自适应缩放。我一般会在容器上加一句max-width: 100vw和height: auto,让它在小屏幕上也能完整显示。
第三个坑是忘了加overflow: hidden。如果动画元素移出了画布范围,但没有隐藏溢出,页面上会出现滚动条,观感很差。给画布容器加上overflow: hidden,所有超出部分都会被裁掉,画面就干净了。
6. 进阶玩法:从单页动画到可交互播放器
6.1 加一个播放暂停按钮有多难
如果你想让这个动画页面更像一个“视频播放器”,可以加一个播放暂停按钮。实现方式很简单:给动画元素加一个 CSS 类控制animation-play-state,默认是running,点击按钮时切换成paused。JS 只需要几行代码,监听按钮点击,切换类名就行。
这个功能的价值在于:它让页面从“自动播放的动画”变成了“可控制的播放器”。你可以暂停在某一帧,仔细观察细节,也可以让它继续播放。对于演示和教学场景来说,这个交互非常实用。
6.2 加进度条和时间显示
再进一步,可以加一个进度条,显示当前播放到第几秒。实现思路是用 JS 的requestAnimationFrame读取当前时间,然后计算百分比,更新进度条的宽度。同时把秒数显示在旁边。
这个功能稍微复杂一点,因为要处理循环播放时的重置逻辑。我的做法是:用performance.now()记录开始时间,每次循环时重置基准时间。进度条用transform: scaleX()来控制宽度,避免触发重排。
6.3 把动画导出成视频的可行方案
虽然模型不能直接输出视频文件,但你可以用浏览器的录屏功能把动画录下来。Chrome 的开发者工具里有 Screen Capture 功能,或者用系统的录屏工具也行。录完之后,你就得到了一个真正的 mp4 文件。
这个方案的好处是:你既享受了 AI 生成代码的便利,又得到了传统视频格式的通用性。录屏的时候注意把浏览器窗口调到 1440×810,全屏播放动画,录出来的画质最好。如果要做高清版本,可以把画布尺寸放大到 2880×1620,录完再压缩。
注意:录屏时关闭浏览器的书签栏和工具栏,只保留页面内容,这样录出来的画面才干净。我一般会按 F11 进入全屏模式再录。
7. 我对这套玩法的真实体会
用下来这段时间,我最大的感受是:AI 生成动画这件事,瓶颈不在模型,而在提示词的结构化程度。你写得越具体,模型给的东西越可用。你写得越模糊,它就越容易给你一个“看起来对但跑不起来”的东西。
另一个体会是,不要追求一次完美。我现在的习惯是:第一轮让模型出个能跑的版本,第二轮调细节,第三轮加交互。三轮下来,一个完整的动画页面就成型了。比手写代码快很多,而且过程中还能学到一些自己没想到的实现方式。
最后分享一个小技巧:如果你想让动画更有质感,可以在 CSS 里加一点filter: drop-shadow()给元素加阴影,或者用background: radial-gradient()给背景加光晕。这些细节不需要模型生成,你自己手动加几行就行,效果提升很明显。