大家好,我是何三,独立开发者
我第一次看到 OpenTUI 的时候,整个人是懵的。
一个用 Zig 写的终端 UI 框架,竟然支持 React 和 SolidJS 组件,还能在终端里跑 Three.js WebGPU 渲染。
你没看错,终端,命令行那个终端,跑 Three.js。
这不是什么玩具项目。OpenCode(一个 AI 代码编辑器)已经在生产环境用它了,terminal.shop 也在用。一个 Zig 写的底层引擎,加了层 TypeScript 绑定,然后前端框架的组件可以直接扔进终端渲染——这玩意儿说实话,我一开始以为是个整活项目。
结果发现人家是认真的。
为什么说这个项目很"不对劲"
先说底层。
终端 UI 框架其实不少。Node.js 那边有 Ink(用 React 写终端),Python 有 Rich,Go 有 Bubble Tea。但它们都有一个共同问题——性能天花板。
因为都是解释型语言写的,想在终端里搞复杂的布局、动画、异步渲染,很快就会碰到瓶颈。帧率上不去,内存下不来。
OpenTUI 的做法就有点不讲道理了。
它用 Zig 写了一个原生核心,通过 C ABI 暴露接口,上层再封装 TypeScript 绑定。Zig 是什么?它是一门系统级编程语言,比 C 更现代,比 Rust 更简洁,编译出来的二进制小得离谱——但这个语言在国内知道的人真不多。

等等,说到 Zig,我突然想到一个事。
去年有个叫 Ghostty 的终端模拟器,也是 Zig 写的,火得一塌糊涂。当时我还在想,Zig 这语言是不是要起飞了。结果现在又冒出来一个 OpenTUI,还是 Zig 写的。这俩项目要是联个动,一个 Zig 写的终端跑一个 Zig 写的 TUI 框架——画面太美我不敢看。
说回正题。
OpenTUI 最骚的操作是什么?它搞了 React reconciler 和 SolidJS reconciler。
什么意思?
就是你可以用 React 的 JSX 语法直接写终端界面。状态管理、组件化、响应式更新——这些前端概念,全都能用在命令行里。
import { createCliRenderer, Text, Box } from "@opentui/core"
const renderer = await createCliRenderer({
exitOnCtrlC: true,
})
renderer.root.add(
Box({
direction: "col",
children: [
Text({ content: "你好,OpenTUI!", fg: "#00FF00", bold: true }),
Text({ content: "按 Ctrl+C 退出", fg: "#888888" }),
],
})
)
说白了,以前你想写一个好看的终端工具,得用 ncurses 或者直接跟 ANSI 转义码死磕。现在你写终端界面,就跟写网页一样——JSX 拼组件,CSS 类似的属性调样式。
为什么这么设计?别问我,问作者去。反正我个人觉得,这个思路确实让 TUI 开发的门槛降了一大截。
组件多到离谱
OpenTUI 内置的组件阵容,看得我有点想吐槽——一个终端框架,你搞这么多东西干嘛?
- Text / Box — 基础组件
- Input / Textarea — 表单组件
- Select / TabSelect — 选择器
- ScrollBox / ScrollBar — 滚动组件
- Slider — 滑块
- Code — 代码渲染(带语法高亮)
- Markdown — Markdown 渲染
- FrameBuffer — 帧缓冲
- ASCIIFont — ASCII 艺术字生成
- Diff — 代码对比
- QR Code — 二维码生成
对,你没看错,一个终端框架内置了 二维码生成 和 Diff 对比。
这个 QR Code 组件让我想了很多。比如你可以写个终端工具,跑完任务直接输出一个二维码,扫码跳到某个页面。这太适合 DevOps 场景了——部署完 CI/CD,终端里直接蹦个二维码,扫码看结果。
还有那个 FrameBuffer 组件,它其实是 Three.js WebGPU 渲染器的底层支持。OpenTUI 有个叫 @opentui/three 的包,可以在终端里用 Three.js 做 3D 渲染。
这个压缩率——算了先不说这个,你先装上看效果。
一分钟上手
装 OpenTUI 很简单,用 Bun 装就行:
bun create tui
或者手动装:
mkdir my-tui && cd my-tui
bun init -y
bun add @opentui/core
然后写个 index.ts:
import { createCliRenderer, Text } from "@opentui/core"
const renderer = await createCliRenderer({
exitOnCtrlC: true,
})
renderer.root.add(
Text({
content: "Hello, OpenTUI!",
fg: "#00FF00",
})
)
跑起来:
bun run index.ts
终端里就出现了一行绿色的 "Hello, OpenTUI!"。
说实话,这块我也没完全搞懂它的渲染管线是怎么跟 Zig 原生核心交互的。大致流程就是 TypeScript 层把组件树 diff 一下,然后通过 C ABI 把渲染指令发给 Zig 核心,Zig 那边直接用原生方式写终端帧缓冲。细节可能有出入——有懂的大佬欢迎指正。
目前 OpenTUI 是 Bun 独占的,Deno 和 Node 的支持正在开发中。所以想尝鲜的话,得先装个 Bun。
同类项目跟它有什么不一样
终端 UI 框架这块,市面上其实有几条路线:
| 项目 | 语言 | 特点 |
|---|---|---|
| Ink | JavaScript | React 写终端,但性能受限于 Node.js |
| Bubble Tea | Go | 基于 Elm 架构,生态成熟 |
| Rich | Python | 纯文本渲染,不适合复杂交互 |
| Ratatui | Rust | Rust 生态,性能好但上手门槛高 |
| OpenTUI | Zig + TS | 原生性能 + 前端框架绑定,性能与开发的平衡点 |
OpenTUI 的定位其实很特别——它不是跟 Ink 抢饭碗,而是给那些觉得 Ink 性能不够、又不想跳进 Rust 深坑的人一个中间选择。
底层用 Zig 保证性能,上层用 TypeScript 保证开发体验。这个组合拳打得挺聪明。
如果你对 Zig 生态感兴趣,我上次还写过一篇关于 Zig 语言生态的文章(公众号回复「Zig」可以看),里面提到了 Ghostty 和 TigerBeetle 等项目,它们跟 OpenTUI 算是同一个技术浪潮。
几点吐槽和期待
文档写得有点抽象。很多概念对刚从网页开发转过来的人不太友好,比如 "Renderables vs Constructs" 那块,我看了三遍才大概明白区别。
不过好在它们有丰富的 Examples 包,可以直接跑起来看效果:
curl -fsSL https://raw.githubusercontent.com/anomalyco/opentui/main/packages/examples/install.sh | sh
还有一件事我觉得挺酷的——OpenTUI 支持 AI Agent Skill。你可以用 npx skills add anomalyco/opentui 把它的 API 知识库装到你的 AI 编码助手里。说白了,你写代码的时候 AI 可以直接帮你生成 OpenTUI 的组件代码。
这个功能我真的吹爆。
总结
OpenTUI 不是那种"装不装都行"的项目。如果你写 CLI 工具、做 DevOps 面板、搞终端交互式应用,它值得你花半小时折腾一下。
核心就一句话:Zig 保性能,React 保体验,一个让你用前端思维写终端的框架。
装不装都行,看你自己。
项目地址:https://github.com/anomalyco/opentui
本文使用 MGO 编辑并发布
关注"何三笔记",回复"mgo" 免费下载使用