PRODUCTION NOTE / 001

从网页动画
到一支视频.

这支 98 秒的 Error Trace 动画没有用传统剪辑软件逐镜制作。画面先在浏览器中按时间绘制,再被逐帧截取、编码,最后与程序生成的声音合成 MP4。

探索生成流程
index.html?render FRAME READY

BROWSER CANVAS 1920 × 1080

整体流程

场景 05 / 10 · SYSTEM

FRAME 02400 TIME 00:40.000
window.__seek(40.000) // 拖动试试
10独立场景
98s总时长
60fps默认帧率
5,880总帧数

THE PIPELINE

每一帧,都有来路。

画面和声音分别生成,在最后一步汇合。整个过程由仓库里的脚本串联,无需手动导出几千张图片。

01 / DESIGN

搭建场景

HTML、CSS 和 SVG 构成画面。10 个场景分别定义自己的 GSAP 动画,再接入总时间线。

js/s01–s10 + main.js
02 / SEEK

定位时间

第 f 帧对应 f / FPS 秒。调用 __seek(t),让网页直接呈现那个时刻的画面。

window.__seek(f / FPS)
03 / CAPTURE

逐帧截屏

Playwright 打开渲染页面,按顺序跳到每个时间点,并将浏览器画面截成 PNG。

page.screenshot()
04 / ENCODE

编码视频

PNG 图片流直接送入 ffmpeg,编码为 H.264 视频片段;默认由 6 个浏览器页面并行处理。

PNG → H.264
05 / AUDIO · 并行支路

程序生成声音

Python + NumPy 按场景时间点合成铺底、打字声、转场和提示音,输出同步 WAV。

tools/audio.py → audio.wav
06 / FINAL OUTPUT

合成 MP4

ffmpeg 拼接视频片段,加入 AAC 音轨,输出最终成片。

out/error-trace.mp4

WHO DOES WHAT

工具各司其职。

它们没有在做同一件事:动画、截屏、音频合成和视频编码各有明确的边界。

01 / ANIMATION

GSAP

控制 DOM/SVG 动画与总时间线;seek(t) 让任意时间点的画面可以被重复定位。

02 / BROWSER

Playwright

启动 Chrome、设定 1920 × 1080 视口、调用 __seek(t),然后截取每一帧。

03 / SOUND

Python + NumPy

当前用于生成 WAV。相同的采样、混音和写文件流程也能移植到 Node.js。

04 / VIDEO

ffmpeg

将 PNG 流编码成视频,把各片段与音频汇合,并封装最终的 MP4 文件。

THE RESULT

98 秒,5,880 次精确定位。

网页定义画面,时间决定帧,程序完成余下的制作。

观看 Error Trace 动画