Community编程与开发github.com

终端渲染

设计并实现嵌入式终端渲染(单元格网格、VT、字体、精灵图、绘制缓存)。用于构建或改进终端面板、PTY 查看器、Agent TUI 宿主、libghostty-vt / Ghostty 风格的绘制、框线绘制、Powerline 字形、Nerd Font 图标,或当终端输出与 Ghostty / kero / herdr 相比显示错误、模糊或不对齐时。

终端渲染 是什么?

本技能详细阐述了嵌入式终端渲染的完整架构与实现要点,这是一个面向开发者工具和 AI agent 用户的专业技能。它基于四层模型(VT、度量、绘制、会话),强调 VT 在处理字节流和光标控制方面的正确性,以及字体度量和几何绘制带来的视觉“好看”。技能明确指出,同样终端模拟器的不同实现,外观也可能存在差异(Same emulator ≠ same look)。该技能支持在 GPUI、Zig、MyGo 等多种技术栈中构建 TUI 界面,并推荐使用 libghostty-vt 等成熟的 VT 引擎和 JetBrains Mono 等字体。其核心思想是:VT 保证功能正确性,字体和基于度量、逐像素对齐的几何绘制决定美观度,而脏行缓存则负责性能优化。通过学习本技能,开发者可以避免常见的 TUI 边框断裂、字体图标显示为空格(tofu)、或文本渲染模糊等问题。

兼容平台✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/yankewei/skills/tree/HEAD/terminal-rendering

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

终端渲染 是做什么的?

一个终端屏幕是一个 cols × rows 的单元格网格。正确性源于 VT; “好看” 则来源于度量和绘制。相同的模拟器 ≠ 相同的外观。

四个层次

层次职责如果出错
1. VT字节 → 单元格网格(光标、模式、回滚、alt 屏幕)乱码 / 尺寸错误 / 光标卡死
2. 度量根据字体确定单元格宽度/高度;根据行列 和 单元格像素调整 PTY 大小列抖动、边缘模糊
3. 绘制绘制单元格:背景区域、字形、精灵图、对比度间隙、文字变细、TUI 边框断裂
4. 会话(可选)持久化/远程:守护进程拥有 VT,客户端镜像帧窗口关闭时回滚丢失

一句话总结: VT 保证正确性;字体 + 度量 + 逐单元格放置 + 几何框线绘制保证美观;脏行缓存保证速度。

1. VT(网格必须正确)

  • 对于 Agent TUI,优先使用真实的模拟器(例如 libghostty-vt),而不是手写的 ANSI 子集。
  • 每个单元格:文本(字素簇)、前景色/背景色、粗体/斜体/细体、下划线/删除线、宽字符标志。
  • 处理:宽字符/emoji 宽度、alt 屏幕、同步输出(模式 2026)、在下次 PTY 读取前写回查询响应。
  • UI 读取网格的 快照;不要在绘制路径中重新解析字节流。

2. 度量

  • 列宽 ≈ 字符 'M' 的步进宽度(可选 CellWidth 乘数)。
  • 行高 ≈ 上升量 + 下降量,然后乘以约 1.15–1.2;对齐到设备像素。
  • 保持宽度为字体步进宽度;将 框/背景边缘 对齐到像素,使相邻单元格无缝连接(不要以导致字形抖动的方式舍入单元格宽度)。
  • 调整大小时,向 PTY 发送 cols、rows、cell_width_px、cell_height_px(程序使用像素尺寸进行鼠标/图像操作)。

3. 绘制(美观成败的关键)

改进现有终端时的优先级顺序:

  1. 提供一套固定的等宽 + Nerd 符号字体(例如 JetBrains Mono + Symbols Nerd Font)。系统默认等宽字体/缺少 Powerline 图标会破坏 Agent TUI。
  2. 将框/块/盲文/Powerline 作为几何图形绘制,而不是使用字体字形 —— 字体在行之间留有间隙;全屏边框必须无缝连接。
  3. 在网格上放置字形:使用强制宽度塑形的相同样式区域,或逐单元格居中。缩小溢出的后备字形(emoji),使其适合狭窄的单元格。
  4. 将缺失的 PUA / Nerd 图标路由到符号字体(或将它们按轮廓适配到单元格中)。
  5. 可选优化:minimum-contrast(跳过精灵图/有意图形)、macOS 字体加粗、多样式下划线、填充颜色扩展。

绘制管线(每帧)

  1. 用终端背景色填充面板。
  2. 原点 = 内边距 + 垂直剩余空间/2;将原点对齐到设备像素。
  3. 仅当行的 Arc/id 发生变化(或字体/单元格大小改变/整屏脏)时,重建行操作。
  4. 先绘制所有 背景范围,然后是 精灵图,接着是 文本运行,最后是光标 / IME / 覆盖层。

行操作

  • 合并连续具有相同背景色的单元格为一个四边形。
  • 一个精灵图单元格 → 几何绘制(参见 herdr / Ghostty 中精灵图的方法)。
  • 否则,创建一个相同样式的文本运行;对于窄单元格,强制步进宽度为 cell_w,以使列保持锁定。

不要归咎于 VT 的情况

如果边框有间隙、图标显示为空格(tofu)或文本看起来变细/不均匀,但网格内容正确 —— 修复 绘制/字体,不要更换模拟器。

4. 会话拓扑

进程内(简单): PTY → VT → 快照 → UI 绘制。

守护进程 + 客户端(kero 风格): 守护进程无头 VT + PTY;Mirror 编码当前屏幕的 VT 帧;客户端使用 Conn 的 VT 逐单元格绘制;回滚在窗口关闭 / 远程连接后依然存在。

参考实现

项目技术栈备注
GhosttyZig + libghostty-vtVT + 精灵图语义的来源
herdr-appGPUI + libghostty-vt单元格绘制、精灵图、对比度、打包字体
keroMyGo + libghostty-vt镜像帧、Ghostty 主题、GPU UI
kumuGPUI-kit + libghostty-vt相同的绘制思路:精灵图 + JetBrains + Nerd

检查清单

添加或修复终端渲染时:

  • VT 拥有网格;UI 仅绘制快照
  • 从等宽字体计算单元格度量;调整大小时包含像素单元格尺寸
  • 打包(或保证)等宽 + Nerd 符号字体
  • 框 / Powerline / 盲文绘制为形状
  • 脏行绘制缓存以行标识为键
  • 光标、IME 和选择区域位于单元格坐标上
  • 对照 Ghostty 比较已知的 TUI(htop、Claude Code、状态行)

附加细节

  • 精灵图 / 几何范围及对比度规则:paint.md

相关技能