让编程助手把网页渲染成产品讲解视频
作者通过 HTML/CSS 编排场景、无头 Chrome 渲染帧,再用 ffmpeg 合成产品讲解视频,并提供交给编程助手执行的提示词。流程需要 Node、Chrome 和 ffmpeg,配音与音效可接入 ElevenLabs,也支持生成无声视频。
AI 深度解读
作者为 Pageree 做了一支 52 秒的讲解视频,没有录屏,也没打开视频编辑器:画面用 HTML 和 CSS 搭建,Chrome 逐帧截图,ffmpeg 合成声音与视频,AI 编程助手负责写代码。它把前端熟悉的网页开发,变成了一条视频生产流水线。
最有价值的不是「五分钟出片」,而是三个设计:动画能跳到任意时刻、场景跟着配音调整长度、修改后只重新生成受影响的音频。理解这套结构,比直接复制提示词更有用。
网页为什么能拿来做讲解视频
这种方法适合卡片、标题、流程和界面示意组成的短片。作者要求每个场景只讲一个意思,用粗边框、硬阴影、大标题和留白统一风格,不依赖真人或素材照片。
提示词给出的默认规格是约 45 秒、16:9、1920×1080、30 fps,强调色为 #693bda。故事拆成 5 到 7 个场景,每场 4 到 9 秒:先点出观众的问题,再用三四场解释工作方式,最后展示产品名和 URL。每场标题最多 8 个词,旁白最多约每秒 2 个词。这些是英文语境下的写作约束,中文不能机械照搬词数。
工程放进 video/,职责分得很清楚:
video.json保存场景、旁白、音效、触发位置和音乐提示词。index.html用 HTML 和 CSS 排版,画布为 1600×900 CSS 像素。timeline.js计算动画状态,timing.js提供场景起止时间。make.mjs用原生 Node 22 实现音频生成、静帧检查和渲染,不装额外依赖。
环境需要 Node 22 或更新版本、Google Chrome 和 ffmpeg,Mac 可用 brew install ffmpeg。声音来自 ElevenLabs,需要 ELEVENLABS_API_KEY;没有密钥仍能输出静音视频。原文还明确要求,ElevenLabs 商用需要付费方案。
作者说的五分钟,是用户填提示词、确认分镜和检查静帧的参与时间。助手写代码、调用服务、渲染另算;「笔记本上几分钟」也只是作者给出的估计,没有机器配置和耗时记录。
动画能跳到任意一秒,才适合逐帧输出
浏览器播放动画时,时间会自然向前走。但生成视频需要反复问一个确定的问题:第 12.4 秒,所有元素应该在哪里?
渲染器需要的是可计算的画面状态。
因此作者禁止 CSS animations 和 transitions,把动画记录成轨道:at(selector, start, duration, {prop: [from, to]}, easing)。再由 seek(t) 根据时间计算透明度、位移、缩放等属性。下面这段代码展示了核心算法:
function seek(t) {
const state = new Map();
for (const tr of tracks) { // 按开始时间排序
const s = state.get(tr.el) ?? {};
state.set(tr.el, s);
for (const [p, [from, to]] of Object.entries(tr.props)) {
if (t < tr.start) { if (!(p in s)) s[p] = from; continue; }
const k = tr.dur ? Math.min(1, (t - tr.start) / tr.dur) : 1;
s[p] = from + (to - from) * tr.ease(k);
}
}
for (const [el, s] of state) {
if ('o' in s) el.style.opacity = s.o;
el.style.transform = `translate(${s.x ?? 0}px, ${s.y ?? 0}px) scale(${s.s ?? 1})`;
}
}
要留意 t < tr.start 的分支:轨道尚未开始时,也要给元素设置起始值,否则直接跳时间检查画面可能出错。示例只展示透明度、平移和缩放;提示词要求的旋转、百分比宽度、读取 data-text 的打字效果,还需要助手补全。
场景内部通过 t(scene, offset) 和 end(scene, offset) 定位,避免把整片时间写死。index.html?t=12.5 查看某一刻,index.html?play 连续预览,stills 2,8,14 则导出指定秒数的 PNG。
动效节奏也有明确约束:每 0.5 到 1 秒有变化,入场用 0.3 到 0.6 秒,错峰间隔 0.12 秒,弹出稍微过冲,完成后停留一秒。它们提供制作起点,但不能代替观看检查。
先量配音,再决定场景什么时候结束
作者实际踩过的坑是:先写死场景时长,生成出来的配音却比预想长。
解决方法是先生成声音,测出真正的说话长度,再计算场景时长:
max(最短时长, 旁白开始时间 + 语音长度 + 0.5 秒)。
生成语音末尾可能有 0.2 到 0.6 秒静音,不能直接拿 MP3 文件时长当说话时长。原文用这条命令找静音:
ffmpeg -i line.mp3 -af silencedetect=noise=-45dB:d=0.1 -f null -
关键是 noise=-45dB:d=0.1,它决定静音检测的阈值和持续时间。旁白可以比画面提前最多半秒,不能落后画面。
语音调用 POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id},模型为 eleven_multilingual_v2,用 previous_text、next_text 传入相邻台词。音效走 POST /v1/sound-generation,传 duration_seconds;音乐走 POST /v1/music,传 music_length_ms 和 force_instrumental: true。文件按生成输入的哈希命名,输入未变就复用缓存。
执行 node make.mjs audio 后,再运行 node make.mjs render。Chrome 使用 --remote-debugging-port=0 启动,从配置目录的 DevToolsActivePort 读取端口,通过 Node 内置 WebSocket 驱动 DevTools 协议。
视口为 1600×900,deviceScaleFactor 为 1.2,对应目标 1920×1080。每帧执行 seek(frame / 30),等待两次 requestAnimationFrame,保存 JPEG。作者报告 52 秒视频生成了 1,557 帧,原文没有解释帧数与取整后的时长如何对应。
最后由 ffmpeg 按 30 fps 合成:adelay 放置旁白和音效,amix 使用 normalize=0,sidechaincompress 在人声出现时压低背景音乐,结尾淡出,再用 loudnorm 调到 -14 LUFS。输出采用 H.264、AAC 和 faststart,另生成 .srt 字幕。
其中 normalize=0 是作者特别提醒的坑:漏掉它,混音会压低输入音量,人声容易变轻。
我的判断
这套方案最值得借鉴的是修改成本的控制。分镜先确认、静帧先检查、声音独立缓存、场景相对计时,都是为了让一句文案的改动不至于牵动整条时间线。
但它更适合以文字和图形为主的讲解片。需要真实操作演示时,录屏仍有直接展示行为的价值;需要复杂剪辑时,原文没有证明网页方案更省事。相比手写绝对时间,它给出了清楚的改进理由;相比其他视频工具,则没有对照数据。
作者认为声音比任何视觉修改都更能提升完成度,这是制作感受。原文没有观众测试,也没有转化数据,不能据此断言它更能卖产品。
另一个边界是交付完整度:原文提供了详细提示词和核心算法,没有给出完整工程。五分钟能否复现,仍取决于助手是否正确实现音频解析、时间线和混音,以及用户愿意改几轮。
能拿来做什么
- 给新功能制作短讲解时,先让助手输出分镜表,确认观众问题、操作逻辑和结束信息,再开始生成代码,避免画面做好后重写故事。
- 用前端实现卡片式说明视频时,优先做出
seek(t)和?t=检查入口,再增加动效;每场都导出静帧,检查文字截断、重叠和边缘留白。 - 使用 AI 配音时,先生成音频再排场景,并缓存生成输入。修改台词后重新测量语音长度,让对应场景自动伸缩。
- 最终检查要同时覆盖静帧、连续播放和声音。布局正确只能说明画面能看,旁白节奏、音乐音量和转场是否合拍,还得完整听一遍。