真正够快的视频氛围编程框架
用 Rust 写每一帧,用 SVG 描述画面,Skia 与 ffmpeg 在 GPU 上完成渲染。

让 agent 帮你做视频
fframes 为编程 agent 附带了一个 skill。添加一次,然后像向动态设计师下 brief 一样,描述你想要的视频。
这个 skill 会带着你的 agent 从一个空文件夹走到渲染好的 .mp4:安装 fframes、创建项目、设计动效、置入声音,并在交给你之前检查结果。
fframes 的 API 显式且详尽。编写显式、详尽的代码,正是一个配备了合适 skill 的 agent 擅长的事。skill 的指南是纯 Markdown,作为人类也很值得一读。
为无法观看的作者而打造
编程 agent 无法观看视频,也听不到音轨。每个项目都自带一条命令行,把视频变成 agent 能读的东西:PNG、文本和数字。
你的 agent
不渲染像素也能逐帧检查
inspect 会报告缺失的字体或图片、被画布裁切的文字、无效的 SVG 以及 panic,每一条都带着它的时间和场景。
查看动效
strip 把等间距的帧平铺成一张联络表,onion 混合多帧来展示运动的路径与缓动,frame 写出全尺寸 PNG。
测量声音
audio analyze 按场景报告响度(LUFS)、真实峰值、削波和静音。
你
带声音实时观看
preview 打开一个 GPU 窗口,可以播放、暂停、拖动定位并逐帧步进。
在浏览器里拖着预览
编辑器把视频编译为 WebAssembly 运行,并带一条时间轴。
交付
render 写出最终文件;render --draft 以一半分辨率编码单个场景,约一秒完成。
每条命令都会给出可读的结果
它们把视频变成 agent 能读的东西:PNG、文本和数字,而不是一个需要人眼盯着的播放器。
inspect每 0.25 秒一帧中存在的问题,以及每个场景的首帧和末帧;出错时退出码为 2
timeline各场景及其帧范围、秒范围,以及每条音轨及其混音设置
audio analyze --waveform w.png响度报告,以及一张带有场景线和提示刻度的波形图
strip <scene> -n 12strip.png,一张带标注的联络表
frame <scene>@end,<scene>@50%frames/ 中的全尺寸 PNG
onion "<scene>@0..<scene>@1s" -n 6onion.png,混合后的运动
snapshot与已批准 PNG 的对比,.diff.png 标出变化之处
preview实时窗口,给人类看
render [--draft]视频,或者它的一部分
每条命令都在项目内以 cargo run --release -- <command> 运行。
<scene> 是你的视频中某个场景结构体的名字。时间可以写作 120(帧)、3.2s、50%、<scene>@1.2s,以及 <scene>@0..<scene>@1s 这样的范围。加上 --json 可得到可解析的输出。
为什么这么快
GPU 负责绘制,静态标记在编译期被哈希,编码器直接链接,SVG 不够用时还有着色器可以插进来。
GPU 负责绘制
Skia 后端在 Metal(macOS)或 Vulkan(Linux、Windows)上渲染,比内置的 CPU 后端快约 10 倍。
静态标记被缓存
一帧中没有
{expressions}的部分会在编译期被哈希,并由渲染器复用。ffmpeg 负责编码
fframes 直接链接 ffmpeg 的 libav 库,而不是调用一个独立工具。
SVG 不够用时用着色器
把 SkSL 或粘贴进来的 Shadertoy GLSL 作为任意一帧的一个图层来运行。
- Skia GPU 后端相对内置 CPU 后端的渲染加速
- 10×
- 渲染 128 秒发布视频的耗时
- 36s
- 用氛围式编程写完同一条视频的耗时
- 48min
- render --draft 编码单个场景的耗时
- ~1s
你的 agent 写什么
每一帧都是一个由 Rust 函数返回的 SVG 树,用 svgr! 宏写。下面这段来自 examples/hello-world 的源码,有删节:一个方块沿时间轴运动,一行文字打印当前帧。
impl Video for HelloWorldVideo<'_> {
const FPS: usize = 30;
const WIDTH: usize = 1920;
const HEIGHT: usize = 1080;
fn render_frame(&self, frame: Frame, ctx: &FFramesContext) -> fframes::Svgr<'_> {
fframes::svgr!(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080"
width={ctx.current_video_size.width}
height={ctx.current_video_size.height}>
<rect x="400" y="400" width="200" height="200" fill="blue"
transform={frame.animate(fframes::timeline!(
at 0., animate Transform::translate(0, 0) => Transform::translate(200, 480), Easing::Linear,
at 2. => 6.0, animate Transform::translate(200, 480) => Transform::translate(750, -400), Easing::Linear,
at 6.0 => 10.0, animate Transform::translate(750, -400) => Transform::translate(1310, 480), Easing::Linear,
))}
/>
<text x="100" y="440" font-family="JetBrains Mono" font-size="74" fill="#3b5563">
{format!("This frame index: {}, second: {:.2}", frame.index, frame.seconds())}
</text>
</svg>
)
}
}时间轴就写在 timeline! 里:at 给出秒数,animate 给出起止变换,Easing 给出曲线。不需要打开浏览器去拖关键帧。
完整的 API 参考在 docs.rs/fframes,skill 里的 API 速查表是它的压缩版。
示例项目
仓库 examples/ 下的 15 个目录,每一个都是可以直接 cargo run 的完整项目。在仓库根目录用 just run 或 just render 就能打开或导出其中一个。

fframes-intro那段 128 秒的发布视频,所有内容都对齐它音轨的节拍网格。just run fframes-introjust render fframes-introsignal-lab一段 24 秒的运动研究:产品 UI、数据叙事与技术讲解。motion-graphics弹簧“突入”运动,以及会适配文本框宽度的等宽字体文字。shaders与 SVG 组合的 GPU 着色器图层:一个 SkSL 背景,和一个被裁剪进卡片的 Shadertoy 光线步进器。neon-triangle一段极简着色器短片,便于观察色带和运动伪影。hello-world一个简单的“hello world”视频。beta一个复杂的多场景示例,也就是我们的 beta 发布视频。marketing我们的营销视频。audio-announce一个自动化工作流,生成带自动字幕的音频可视化。podcast一期播客占位视频的音频可视化。teej-podcastteej 的播客,带视频和章节可视化。tiktok一个类 TikTok 的竖屏视频。conference-splash-screen每个会议演讲一张启动屏,批量渲染。low-poly-art渲染器压力测试:大量多边形的动物图形。pixel-memory我狗狗的纪念视频生成器,完全随机。
当前显示 15 个示例。
不用 agent 也行
装上生成器,三条命令就能拿到一个可以预览和渲染的项目。
在 macOS 和 Linux(arm64、x86_64)上,首次构建会下载预编译的 Skia 和 ffmpeg 库,在性能较好的机器上不到一分钟。其他目标与特性组合则需从源码编译,最多约 20 分钟。后续构建只需数秒。
cargo install --locked cargo-fframes
cargo fframes new my-video
cd my-video && cargo run --release -- preview- --template
single-scene / multi-scene模板形态- --format
landscape / portrait / square / uhd画幅- --fps
整数帧率- --title
字符串写入项目标题- --backend
skia / cpucpu 会跳过 Skia,没有预览窗口,渲染更慢- --git
https://github.com/dmtrKovalenko/fframes跟踪 main 分支安装
环境要求
需要 Rust,开发编辑器时还需要 NodeJS。fframes 静态链接 ffmpeg 的 libav 库:macOS 与 Linux(arm64、x86_64)会下载预编译构建,其他目标或设置了 FFMPEG_FORCE_BUILD=1 时则从源码编译。无论哪种情况,它们所链接的系统编码器都必须已安装。
对会被缓存或拿到别的机器上运行的原生构建,示例启用了 build-portable。它在源码构建中省略 -march=native 与 -mtune=native,同时保留匹配的预编译下载,避免换一个 CPU 就撞上 SIGILL。
[target.'cfg(not(any(target_arch = "wasm32", windows)))'.dependencies]
fframes = { workspace = true, features = ["build-portable"] }完整的环境说明见仓库根目录的 README 里。
macOS 会下载预编译的 Skia 与 ffmpeg 构建,你只需要装上 Homebrew 这一层的系统依赖。
brew install pkg-config ffmpeg x264 x265 opus nasm ninja