用 VHS 录制 Gum 交互式 CLI 演示:File / Pager / Table 三则 Tape 脚本实战解析

原创2026-09-30 18:35:081,904 阅读
文章标签:开发工具

用 VHS 录制 Gum 交互式 CLI 演示:File / Pager / Table 三则 Tape 脚本实战解析

Gum 是构建终端 UI 的常用工具(本仓库的 examples/gum 目录专门为其准备了演示场景),而 VHS(本项目,标语为 "Your CLI home video recorder 📼")则负责把这类真实终端交互录制为可复现的 GIF 视频。本文以仓库内 examples/gum/README.md 为骨架,逐行解析三则 .tape 录制脚本——gum file 文件选择器、gum pager 分页器、gum table 表格查看器,并对照源码说明 Sleep、Enter、Down@250ms、Set FontSize 等核心命令的语义。读完本文,你将掌握用 VHS 为任意 TUI 程序编写自动化演示脚本的完整方法。

用 VHS 录制 gum file 文件选择器交互演示

一、场景与背景:为什么 TUI 工具需要"可复现"的演示

终端 UI(TUI)程序天然难以用静态截图表达动态交互——光标移动、键盘输入、滚动、选择高亮这些过程只有在动起来时才有意义。gum 的交互式组件正是如此:gum file 需要用户上下选择文件,gum pager 需要翻页滚动,gum table 需要浏览多行数据。

VHS 的解决思路是把"人工操作终端"的过程脚本化:用 Type 输入命令、用 Enter 触发回车、用 Down@250ms 模拟带速度的方向键滚动,最终由 Output 指令渲染成 GIF。这样生成的演示不仅观感一致,还能精确控制每一帧。

本仓库在 examples/gum 下为 Gum 准备了三个录制脚本与配套素材:

  • file.tape + file.gif:文件选择器演示;
  • pager.tape + pager.gif:分页器演示;
  • table.tape + table.gif:表格查看器演示;
  • superhero.csv:表格演示使用的超级英雄数据集;
  • src/:gum file 浏览的目标目录(内含 lipgloss/ 示例包、id_rsa.pub、super_secret_message.txt 等演示素材)。

二、文件选择器:逐行拆解 gum file 演示脚本

examples/gum/file.tape 是三个脚本中最简短也最典型的一个:

Output examples/gum/file.gif

Type "gum file ./src"
Sleep 0.5s
Enter
Sleep 0.5s
Down@250ms 4
Up@250ms 1
Sleep 0.5s
Enter
Sleep 0.5s
Down@250ms 4
Sleep 0.5s
Up@250ms 2
Sleep 1s

逐条解读:

指令 作用 在本脚本中的含义
Output examples/gum/file.gif 声明最终渲染产物路径 生成 GIF 到 examples/gum 目录
Type "gum file ./src" 在终端中逐字敲入命令 启动 gum 的文件选择器,浏览 ./src 目录
Sleep 0.5s 静置等待,让画面留白 模拟真人阅读屏幕的节奏
Enter 发送回车键 确认启动命令
Down@250ms 4 以每步 250ms 的速度按 4 次方向键 ↓ 逐项下移光标,速度参数让滚动"可读"
Up@250ms 1 以 250ms 间隔按 1 次 ↑ 演示反向移动、高亮切换
Enter 再次回车 选中当前高亮的文件/目录
Down@250ms 4 / Up@250ms 2 继续慢速上下移动 展现选择器在不同条目间切换的状态

值得注意的语法点是 Down@250ms N 与 Down N 的区别:带 @速度 的写法会以指定毫秒间隔逐次按键,视觉效果是光标平滑滚动;不带速度则立即执行。这一点在 examples/commands/arrow.tape、examples/commands/enter.tape 等命令专项示例中也有体现。VHS 的 lexer 与 parser 负责把这些指令解析为内部动作序列(见 lexer/lexer.go 与 parser/parser.go),Sleep、Type、Enter 等在此处被解析为可调度的输入事件。

三、分页器:终端窗口参数与高速滚动

第二个示例 examples/gum/pager.tape 引入了 VHS 最重要的能力之一——在录制前定制终端外观:

Output examples/gum/pager.gif

Set Padding 32
Set FontSize 16
Set Height 600

Type "gum pager < ~/src/gum/README.md --border normal"
Sleep 0.5s
Enter
Sleep 1s
Down@15ms 40
Sleep 0.5s
Up@15ms 30
Sleep 0.5s
Down@15ms 20
Sleep 2s

前三行是"设置"类指令:

  • Set Padding 32:设置终端画面的外边距(像素)。项目 README 中对 Set Padding 的说明是"设置终端框架的 padding(像素)",取值范围可参考 examples/settings/set-padding.tape 中的多种取值演示;
  • Set FontSize 16:设置终端字体大小,Set FontSize 指令的说明位于项目 README.md,示例脚本中给出了 10 / 20 / 40 等不同档位;
  • Set Height 600:设置终端窗口高度,Set Height 同样是一个独立设置指令(见 README.md)。

之后的交互部分利用 Down@15ms 40 以 15ms 的高速连按 40 次方向键——这正是滚动长文本时的标准套路:gum pager < README.md --border normal 将文档喂给分页器,--border normal 控制边框样式,40 次快速下滚配合 30 次上滚、20 次下滚,完整展示分页器在长文档中的流畅滚动与定位。

用 VHS 录制 gum pager 分页器滚动演示

从源码视角看,这些设置指令与 Sleep、Type 一样,属于 VHS 的命令语言一部分;Set Padding / Set FontSize / Set Height 在仓库的 settings 示例集 中都有独立成对的 .tape / .gif 文件用于演示不同参数取值(如 set-font-size-10、set-font-size-20、set-font-size-40),可供参考组合出合适的画面比例。

四、表格查看器:CSV 数据驱动与列宽控制

第三个示例 examples/gum/table.tape 展示了如何演示数据处理类工具:

Output examples/gum/table.gif

Type "gum table < superhero.csv -w 2,12,5,6,6,8,4,20 --height 10"
Enter
Sleep 0.5s
Down 10
Sleep 0.5s
Down 10
Sleep 0.5s
Up 10
Sleep 0.5s
Enter
Sleep 2s

这里的 superhero.csv(examples/gum/superhero.csv)是一份真实可用的超级英雄数据集,含 ID, Name, Gender, Eye color, Race, Hair color, Height, Publisher, Skin color, Alignment, Weight 共 11 列,前 115 行覆盖了 A-Bomb、Batman、Beast Boy、Black Widow 等大量角色。

命令细节:

  • < superhero.csv:shell 重定向,把 CSV 内容作为标准输入喂给 gum table;
  • -w 2,12,5,6,6,8,4,20:按列指定列宽(对应 Name 列 12、Height 列 6、Publisher 列 8 等),保证超长字符串不被截断挤压;
  • --height 10:限制表格可视高度为 10 行,制造出"超出可视区需要滚动"的效果;
  • Down 10 / Up 10:不加速度参数的立即滚动,与第二节 Down@250ms 形成对比——这里刻意用快速跳动来展示表格的翻页感。

(顺带一提:原文档 examples/gum/README.md 的 Table 小节图片误引用了 pager.gif,实际渲染产物应为同目录下的 table.gif,本文按正确路径引用。)

用 VHS 录制 gum table 表格浏览演示

五、Tape 脚本语法速查:从三则示例提炼的通用命令

把三个脚本并排对比,可以提炼出 VHS 录制脚本(.tape)的基础词汇表:

命令 语法示例 说明 出处
Output Output examples/gum/file.gif 声明 GIF/MP4 输出路径,脚本必须包含 三个脚本首行
Type Type "gum file ./src" 逐字输入一段文本(通常是要执行的命令) file/pager/table 均使用
Enter Enter 发送回车 三个脚本均使用
Sleep Sleep 0.5s / Sleep 1s / Sleep 2s 暂停指定时长,控制画面节奏 贯穿全部脚本
Down / Up Down 10 / Up 10 立即按下方向键(可指定次数) table.tape
带速度方向键 Down@250ms 4 / Down@15ms 40 按指定毫秒间隔逐次按键,模拟平滑滚动 file/pager.tape
Set Padding Set Padding 32 设置终端画布外边距(像素) pager.tape
Set FontSize Set FontSize 16 设置字体大小 pager.tape
Set Height Set Height 600 设置终端窗口高度 pager.tape

从实现上看,lexer 负责将 Down@250ms、Sleep 0.5s 这类带单位与速度的 token 切分出来(见 lexer/lexer.go 及 lexer/lexer_test.go),parser 再组合成动作序列(parser/parser.go),最终由 record 模块在真实 TTY 中回放并逐帧截图。因此脚本中的每一个时序与速度参数都会如实反映在最终 GIF 里——这也是"脚本即成品"这一工作流的核心。

六、运行与复现:把脚本变成 GIF

如果你拿到本项目源码,复现这三个演示只需:

vhs examples/gum/file.tape
vhs examples/gum/pager.tape
vhs examples/gum/table.tape

VHS 会按照脚本首行的 Output 指令,在 examples/gum/ 下生成对应的 file.gif、pager.gif、table.gif。录制过程中脚本会真实启动一个终端、真实执行 gum file ./src / gum pager / gum table,因此本机必须安装 gum 与所需命令;gum pager 示例中的 ~/src/gum/README.md 路径属于作者本机路径,实际复现时需替换为你本地存在的文件(例如仓库根目录的 README.md),其余脚本可直接运行。

结语

三则 Gum 演示脚本虽然每份只有十几行,却完整覆盖了 VHS 脚本语言的三大核心要素:输入交互(Type / Enter / 方向键与速度控制)、视觉节奏(Sleep 与 Down@15ms 式的精密时序)、窗口定制(Set FontSize / Set Height / Set Padding)。以此为模板,你可以为任何 TUI 工具编写出观感一致的自动化演示——把"人工操作一次录一次"升级为"写一份脚本永久复现"。更多命令与设置的完整清单,可继续查阅仓库根目录 README.md 以及 examples/commands、examples/settings 下的成对示例。

登录后查看全文
vhs