- Rust 93.5%
- Shell 4.4%
- PowerShell 2.1%
| assets | ||
| examples | ||
| scripts | ||
| src | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
termcast
把"脚本"渲染成终端操作演示视频(GIF / MP4)。
写一个描述"你想让观众看到什么"的 DSL 脚本,termcast 在真实 PTY 里逐字执行这些命令、 录制带时间戳的输出流,再把空闲时间钳制、把超长命令压缩到目标时长,最终渲染成 带字幕标题的演示视频。因为走的是真实终端仿真,输出、颜色、进度条、交互式回显 都和真机一模一样——不是事后伪造的字幕动画。
command "更新", "5s" do
ping -n 11 127.0.0.1 # 真实运行约 10 秒
end
command "say hello" do
echo "hello"
end
上面这段脚本会生成一个约 7 秒的视频:第一条命令实际跑 10 秒,被
压缩到 5 秒播完;第二条按实际节奏原速播放。每个 command 块的
标题(如"更新")会作为字幕显示在画面顶部。
特性
- 真实执行:命令在 ConPTY/PTY 驱动的真实 shell 中运行,输出流被原样录制。
- 精确切段:段边界由 OSC 133 语义标记(
D;exit/A/B)检测——由注入的 shell 集成或 fish 原生提供——不靠提示符正则猜测。 - 时间重映射:段内空闲钳制(
idle)+ 目标时长压缩(只压缩、不放慢), 段间事件顺序有回归测试保证不交错。 - asciinema 兼容:录制格式为 asciinema v2(
.castJSONL),可用--keep-cast保留并用自带replay示例单独回放检查。 - 渲染与内容解耦:字体、字号是渲染期参数,默认 Cascadia Mono + 微软雅黑 作为 CJK 回退(缩放到双格宽),网格尺寸由录制决定。
- GIF + MP4 双输出:MP4 依赖 ffmpeg,找不到时自动跳过并提示。
快速开始
cargo run --release -- build examples/hello.dsl -o out/hello.gif
默认同时输出 out/hello.gif 和 out/hello.mp4。examples/ 下还有
hello-bash.dsl(bash + 中文输出的例子)。
工作原理
script.dsl ─解析─► 段列表 ─PTY驱动─► 带时间戳的输出事件流(.cast)
│ 段边界由 OSC 133 语义标记检测
▼
时间重映射(空闲钳制 + 目标时长压缩)
▼
avt 终端仿真 → 字体渲染 → RGBA 帧 → GIF / ffmpeg → MP4
- 解析(
dsl.rs):脚本解析为set设置 +command段列表。 - 录制(
session.rs):在 ConPTY/PTY 里起一个持久 shell,逐字"打字"执行 每段命令。注入的集成配置(assets/prompt.ps1、assets/bashrc、assets/zshrc)发出 OSC 133 标记,驱动器由此精确知道每条命令何时结束。 fish ≥ 4.0 则零注入:它原生就发这些标记,只用--no-config -C起隔离会话 并统一提示符样式。 - 重映射(
retimer.rs):钳制段内空闲停顿,把超过目标时长的段线性加速 到目标;有回归测试保证段事件不溢出、不交错。 - 渲染(
render.rs):avt 终端仿真逐帧推进,双字体光栅化为 RGBA。 - 编码(
encode.rs):写 GIF,若找到 ffmpeg 再写 MP4。
DSL 参考
set fps = 30 # 帧率
set font-size = 18 # 字号(px)
set geometry = "80x24" # 终端尺寸
set typing = "40ms" # 打字间隔
set idle = "800ms" # 无目标时长的段内最大停顿
set gap = "300ms" # 段间停顿
set shell = "powershell" # 或 "pwsh" / "bash" / "zsh" / "fish"
command "标题", "5s" do # 时长可省略 = 原速;支持 5s / 500ms / 5(秒)
多行命令...
end
时长语义:只会压缩,不会放慢。真实时长超过目标则线性加速到目标; 不足目标则以原速播完后停顿补齐。
CLI 参考
termcast build <script.dsl> [选项]
| 选项 | 说明 |
|---|---|
-o, --out <PATH> |
输出 GIF 路径(MP4 写在同名 .mp4) |
--fps <N> |
覆盖脚本中的帧率 |
--font-size <PX> |
覆盖脚本中的字号 |
--geometry <WxH> |
覆盖脚本中的终端尺寸,如 80x24 |
--main-font <PATH> |
主字体路径(默认 Cascadia Mono) |
--cjk-font <PATH> |
CJK 回退字体;传空串 "" 禁用 |
--dump-frames <DIR> |
把每帧 RGBA 转储为 PNG,便于排查渲染问题 |
--keep-cast |
保留中间产物 .cast 和 .segments.json |
CLI 选项优先于脚本里的 set 值。默认输出名取脚本文件名主干(如
hello.dsl → hello.gif)。
回放与调试
cargo run --release -- build examples/hello.dsl --keep-cast -o out/hello.gif
cargo run --example replay -- out/hello.cast # 直接回放录制,检查分段是否正确
TERMCAST_DEBUG=1:输出 PTY 数据块、各阶段耗时、逐帧屏幕转储。TERMCAST_FFMPEG:显式指定 ffmpeg 路径(默认先找 PATH,再找 WinGet 包目录)。
Shell 支持
| Shell | 方式 | 备注 |
|---|---|---|
| PowerShell / pwsh | 注入 assets/prompt.ps1 |
经实测 ConPTY 透传 OSC 133 |
| bash | 注入 assets/bashrc |
Windows 上必须是 Git Bash——裸 bash 会解析到 WSL,读不了 Windows 路径的 rcfile;仅装了 WSL 的主机会自动把路径翻译成 /mnt/c/... |
| zsh | 注入 assets/zshrc |
需要 MSYS2/WSL,或在 Linux/macOS 上使用 |
| fish ≥ 4.0 | 零注入 | 原生 OSC 133 标记,--no-config -C 起隔离会话;fish < 4.0 不支持 |
构建(Windows / GNU 工具链)
本仓库在 Windows 上用 rustup 的 stable-x86_64-pc-windows-gnu 工具链构建
(rust-toolchain.toml 已 gitignore,因为它只适用于本机;Linux/macOS 直接
cargo build 即可)。GNU 目标需要真实的 mingw-w64 binutils(rustup 自带的
dlltool 缺 as,无法生成导入库):
winget install BrechtSanders.WinLibs.POSIX.UCRT # 一次性
sh scripts/cargo.sh build # 包装脚本把 WinLibs 的 bin 挂进 PATH
sh scripts/cargo.sh test # 13 单测 + 2 个真实 PTY 端到端测试
MP4 需要 ffmpeg(winget install Gyan.FFmpeg)。
测试
dsl解析器、retimer(含"目标段事件不得溢出到下一段"回归)、OSC 133 扫描器:纯单元测试。tests/session_e2e.rs:真实 ConPTY 会话,验证 133 标记往返、切段、cast 落盘(Windows only;未安装 zsh/fish 时软跳过)。
项目结构
| 模块 | 职责 |
|---|---|
src/dsl.rs |
脚本解析(set / command ... do ... end) |
src/session.rs |
PTY 驱动、shell 集成、asciinema v2 事件录制 |
src/retimer.rs |
时间重映射:空闲钳制 + 目标时长压缩 |
src/render.rs |
avt 终端仿真 + 双字体(拉丁/CJK)光栅化 |
src/encode.rs |
GIF / ffmpeg MP4 / PNG dump 输出 |
src/main.rs |
CLI(clap) |
assets/ |
各 shell 的注入式集成配置 |
examples/ |
示例脚本 + replay 回放工具 |
模块按 dsl → session → retimer → render → encode 单向分层。
已知限制 / 后续方向
- GIF 体积偏大(逐帧独立调色板);可做全局调色板 + 帧差分。
- 段内打字回显依赖 PSReadLine / readline 的定位重绘,段落间事件顺序已由 retimer 保证不交错;极端 ConPTY 重绘差异未穷尽测试。
- Windows 上 zsh/fish 未经实测(本机未装,e2e 测试会软跳过;Linux/macOS CI 可覆盖)。
- 计划:主题可配、
--speed全局倍速、avt dump 快照加速 seek(生成器是 离线的,暂不需要)。
许可证
Apache-2.0