終端機渲染
一個終端機畫面是一個 cols × rows 的儲存格網格。正確性來自於 VT;「好看」來自於度量 + 繪圖。相同的模擬器 ≠ 相同的外觀。
四個層次
| 層次 | 職責 | 如果出錯 |
|---|---|---|
| 1. VT | 位元組 → 儲存格網格(游標、模式、回滾、替代畫面) | 亂碼 / 尺寸錯誤 / 游標卡住 |
| 2. 度量 | 從字型取得儲存格寬/高;使用 cols/rows 和 儲存格像素調整 PTY 大小 | 欄位搖晃、邊緣模糊 |
| 3. 繪圖 | 繪製儲存格:背景區塊、字形、圖形、對比度 | 間隙、文字太細、TUI 邊框斷裂 |
| 4. 會話(選用) | 持久化 / 遠端:守護行程擁有 VT,客戶端鏡像畫面 | 回滾隨著視窗關閉而消失 |
一句話: VT 負責正確性;字型 + 度量 + 每個儲存格放置 + 幾何方塊繪圖負責外觀;髒列快取負責速度。
1. VT(網格必須正確)
- 對於代理程式 TUI,建議使用真正的模擬器(例如 libghostty-vt),而不是自己實作的 ANSI 子集。
- 每個儲存格:文字(字素簇)、前景/背景色、粗體/斜體/淺色、底線/刪除線、寬度標記。
- 處理:寬字元 / emoji 寬度、替代畫面、同步輸出(模式 2026)、在下一次 PTY 讀取之前寫回查詢回覆。
- UI 讀取網格的快照;不要在繪圖路徑中重新解析位元組串流。
2. 度量
- 欄寬 ≈
'M'的前進寬度(可選CellWidth乘數)。 - 行高 ≈ 上升 + 下降,然後 × 約 1.15–1.2;對齊到裝置像素。
- 保持寬度為字型前進寬度;將框線/背景邊緣對齊到像素,使相鄰區塊之間沒有縫隙(不要以導致字形搖晃的方式四捨五入儲存格寬度)。
- 調整大小時,將
cols、rows、cell_width_px、cell_height_px發送給 PTY(程式會使用像素尺寸處理滑鼠 / 圖片)。
3. 繪圖(外觀成敗的關鍵)
改進現有終端機時的優先順序:
- 內建固定寬度字型 + Nerd 符號(例如 JetBrains Mono + Symbols Nerd Font)。系統預設的等寬字型 / 缺少 Powerline 圖示會毀掉代理程式 TUI。
- 將框線 / 區塊 / 點字 / Powerline 繪製為幾何圖形,而不是字型字形——字型會在行之間留下間隙;全螢幕邊框必須連接。
- 將字形放置在網格上:相同樣式的文字區塊使用強制寬度 shaping,或每個儲存格置中。縮小超出窄儲存格的後備字形(emoji)。
- 將缺少的 PUA / Nerd 圖示路由到符號字型(或將它們輪廓適配到儲存格內)。
- 選用的潤色:
minimum-contrast(跳過精靈圖 / 刻意圖形)、macOS 字型加粗、多樣式底線、填補顏色延伸。
繪圖管線(每幀)
- 用終端機背景填滿窗格。
- 原點 = 填補 + 垂直剩餘空間/2;將原點對齊到裝置像素。
- 僅在行
Arc/id 變更(或字型/儲存格尺寸變更 / 全部髒掉)時重建行操作。 - 先繪製所有背景區塊,然後是精靈圖,然後是文字區塊,然後是游標 / IME / 覆蓋層。
行操作
- 合併連續相同背景的儲存格為一個四邊形。
- 一個精靈圖儲存格 → 幾何繪製(參見 herdr / Ghostty 中的精靈圖方法)。
- 否則,塑造一個相同樣式的文字區塊;對窄儲存格強制前進寬度為
cell_w,以便欄位保持鎖定。
不應歸咎於 VT 的情況
如果邊框有間隙、圖示是 tofu(方塊)、或文字看起來細薄/不均勻,但網格內容是正確的——請修正繪圖/字型,不要更換模擬器。
4. 會話拓撲
同程序(簡單): PTY → VT → 快照 → UI 繪圖。
守護行程 + 用戶端(kero 風格): 守護行程無頭 VT + PTY;Mirror 編碼目前畫面的 VT 幀;用戶端 VT 與 Conn 逐格繪製;回滾在視窗關閉 / 遠端連線後仍然存在。
參考實作
| 專案 | 技術棧 | 備註 |
|---|---|---|
| Ghostty | Zig + libghostty-vt | VT + 精靈圖語義的來源 |
| herdr-app | GPUI + libghostty-vt | 儲存格繪圖、精靈圖、對比度、內建字型 |
| kero | MyGo + libghostty-vt | 鏡像幀、Ghostty 主題、GPU UI |
| kumu | GPUI-kit + libghostty-vt | 相同的繪圖概念:精靈圖 + JetBrains + Nerd |
檢查清單
在新增或修正終端機渲染時:
- VT 擁有網格;UI 僅繪製快照
- 儲存格度量來自等寬字型;調整大小包含像素儲存格尺寸
- 內建(或保證有)等寬字型 + Nerd 符號
- 框線 / Powerline / 點字以形狀繪製
- 髒列繪圖快取以列識別碼為鍵值
- 游標、IME 和選取範圍位於儲存格座標上
- 將已知的 TUI(htop、Claude Code、狀態列)與 Ghostty 進行比較
其他細節
- 精靈圖 / 幾何圖形範圍和對比度規則:paint.md