最近 Twitter 上有个项目刷了我的屏。
一个开发者,因为太沉迷写代码、经常忘记休息,于是在自己的终端里塞了一个真正的黑洞。
不是比喻,不是 ASCII 艺术。是一个用 GLSL 着色器实时渲染的、符合广义相对论的、带吸积盘和光子环的史瓦西黑洞。
项目叫Ghostty Blackhole,作者 s13k。开源不到一个月,GitHub 已经 1000+ stars。
我在自己的终端里跑起来之后,只能说——这大概是我今年见过最炫酷又最实用的终端 hack。
它到底做了什么
一句话:把你的 Ghostty 终端变成一个黑洞观景窗。
它本质上是 Ghostty 终端的一个自定义着色器(custom shader)。Ghostty 1.3 开始支持 GLSL 着色器,跟 Shadertoy 一样,每个像素执行一段片段着色器代码。作者利用这个机制,把 Eric Bruneton 的经典黑洞渲染算法搬进了终端。
区别在于:Bruneton 的原始实现依赖预计算的查找纹理,而 Ghostty 的自定义着色器不能带自定义纹理——只有一个终端画面的"屏幕纹理"。
作者的选择是:不做近似,直接上物理。
你的代码,就是被透镜弯曲的星空
先说说它渲染了什么。
黑洞阴影:光子如果距离太近(小于临界碰撞参数b_crit = (3√3/2) r_s),就会螺旋坠入视界,回来的只有黑色。你终端里靠近黑洞的文字,会被拉伸成光子环然后消失——是真的消失,不是遮罩。
引力透镜:逃逸出来的光线被弯曲后投影回终端"天空平面"。文字被放大、翻转、镜像——黑洞背后会出现一个倒立的二次成像。远处的文字也会被轻微弯曲,模拟弱场偏转。
吸积盘:一个薄薄的开普勒盘,采用 Shakura-Sunyaev 温度分布,渲染成真实的黑体颜色。重点是相对论多普勒效应——朝你转过来的那一侧蓝热明亮,远离的那一侧暗红黯淡。这个视觉效果跟《星际穿越》里的 Gargantua 是一个原理。
光子环:光线在1.5 r_s光子球附近反复缠绕——这不是画上去的环,是物理上光线绕了黑洞好几圈之后自然产生的结果。每绕一圈就捕捉一次吸积盘,光子环的亮度是这些层层叠叠的盘图像的叠加。
引力时间膨胀:越靠近视界,时间流逝越慢。吸积盘内圈的花纹会肉眼可见地"冻住"——这是真实的√(1 − 1.5 r_s/r)时间因子。
最妙的是:这些都是每像素独立积分出来的,没有任何预计算表格。
每像素都在算一条光子的路
核心计算是这样工作的:
对于黑洞附近的每个像素,着色器发射一条平行光线,然后用数值方法积分它的零测地线——也就是光子在 Schwarzschild 时空中的路径。
加速度方程是 Binet 形式的:
a = -(3/2) h² x / r⁵其中h = |x × v|是角动量守恒量,一次计算全程复用。光线要么落入视界(黑色),要么逃逸并被投影回终端画面(弯曲的文字和吸积盘)。
这里有一个性能巧思:只有黑洞附近的像素才走完整的数值积分。远离黑洞的区域,直接切换到解析的弱场偏转近似α = 2r_s/b,几乎不花计算。所以小黑洞的时候对帧率几乎没有影响——只有当它长大(上下文快满了),计算量才会上升。
N_STEPS是主要的性能旋钮,控制每像素的积分步数。作者还很诚实地在 README 里写了:"A big hole on a big high-DPI display is where frames go to die."
但这个项目真正牛逼的地方,不是物理
物理很酷,但让我真正哇出声的,是 Token 模式的数据通道设计。
这个着色器需要知道Claude Code 的上下文窗口填充率——你用了多少 token,还剩多少。上下文的多少决定了黑洞的大小:0% 时黑洞缩在屏幕右上角不起眼,100% 时它大到吞掉半个屏幕。
问题是:Ghostty 的自定义着色器没有自定义 uniform 变量。你没法从外部传一个数字进去。
着色器能拿到什么?它只能拿到 Ghostty 内置的 uniform——分辨率、时间、鼠标位置、光标颜色……等等,光标颜色?
把上下文填充率编码进光标颜色
这就是整个设计最精妙的地方。
Ghostty 的着色器可以读取iCurrentCursorColor,而任何程序都可以用标准的 OSC 12 转义序列设置终端光标颜色。
于是作者写了一个 Python 脚本claude-token.py,用三种方式挂到 Claude Code 里:
挂载点 | 触发时机 | 做什么 |
|---|---|---|
statusLine | 每次 assistant 对话轮次 | 把上下文填充率编码到光标颜色的低 4 位,琥珀色从 |
SessionStarthook | 启动 / 恢复 / | 重置为角落小点(0%) |
SessionEndhook | 退出 / Ctrl+D | 清除光标颜色——没有签名信号 = 没有黑洞 |
关键细节:颜色编码的高位固定 + 4 位校验和组成一个 16 位签名。你主题里自带的琥珀色光标不会意外触发黑洞,只有claude-token.py发出的特定编码才会被识别。
而且 Ghostty 在被 OSC 12 改变光标颜色时,会把旧颜色存入iPreviousCursorColor,同时触发iTimeCursorChange。着色器拿到两帧之间的颜色差,就能平滑过渡黑洞大小——1% 的变化花 0.3 秒,10% 的变化花 1 秒,最多 1.5 秒。你能看到黑洞在变大,而不是在跳。
整个数据流是:
Claude Code 上下文状态 → claude-token.py 编码到光标颜色 → OSC 12 转义序列 → Ghostty 渲染光标 + 更新 iCurrentCursorColor → blackhole.glsl 解码 → 黑洞大小实时更新零文件写入、零重载、零卡顿。更新就在下一帧。
这大概是「用现有 API 搭出设计者没想过的用法」的教科书级别案例。
三种模式,一个着色器
着色器顶部有一个SIZE_MODE开关:
Token 模式(默认):实时追踪 Claude Code 的上下文填充。刚刚/clear时黑洞缩在右上角,大小只占终端面积的 0.006%。随着对话深入,黑洞逐渐长大、漂移速度加快、活动范围扩展到整个屏幕上方。接近满的时候黑洞的影子覆盖终端 ~3% 的面积——但视觉上吸积盘要大 3 倍,看着就是半个屏幕被吞掉了。这时候你就知道:该/compact了。
番茄钟模式:不依赖 Claude Code,纯靠壁钟。55 分钟工作期间黑洞从角落慢慢长大,最后 5 分钟塌缩回小点,然后保持 5 分钟休息。还带打字检测——连续 90 秒没操作,黑洞自动缩小消失。
Demo 模式:42 秒自动循环,黑洞从小到大,吸积盘在 Inferno → Gargantua → M87* donut → Quasar → Blazar → Pure lens 等 8 种预设之间自动切换。没有任何文件重载——全部在一个编译的着色器里跑完。
一分钟装好
需要 Ghostty 1.3+。两行配置:
# ~/.config/ghostty/config custom-shader = /path/to/ghostty-blackhole/blackhole.glsl custom-shader-animation = true然后配置 Claude Code 的 hooks:
// ~/.claude/settings.json{"statusLine": {"type":"command","command":"/path/to/ghostty-blackhole/claude-token.py"},"hooks": {"SessionStart": [{"hooks": [{"type":"command","command":"/path/to/ghostty-blackhole/claude-token.py"}] }],"SessionEnd": [{"hooks": [{"type":"command","command":"/path/to/ghostty-blackhole/claude-token.py"}] }] } }启动一个新的 Claude Code 会话,右上角就会出现一个小黑洞。没有会话时自动消失,回到干净的终端。
如果你用 macOS,项目里还带了一个原生 SwiftUI 调参应用——滑块调节吸积盘温度、倾角、多普勒强度、透镜深度、漂移速度等等,每个参数都实时热重载。cd 进tuner/目录,swift run就起来了。
我的一些想法
说实话,这种项目让我想起一个现象:最好的工具设计,往往来自于开发者对自己工作习惯的深刻不满。
作者 s13k 显然是一个「写代码忘了时间」的人。他没有下载一个番茄钟 App,也没有设置系统提醒——他在自己的终端里造了一个黑洞,然后让它监控自己的 AI 编程助手,用一种你根本不可能忽略的方式告诉你:"该休息了"。
而且他做得很彻底。不是贴一张黑洞 PNG,不是用 CSS 动画伪造一个漩涡——他是完整实现了 Schwarzschild 度规下的光子路径积分。在终端里。在一个着色器里。每一个像素都是真实解出来的。
这是一种很纯粹的技术浪漫。
另外,这个项目也让我重新审视了 Ghostty 的着色器系统。Ghostty 给自定义着色器提供的 uniform 不算多,但作者硬是找到了「光标颜色」这个奇怪但完美的数据通道。这种创造力不是凭空产生的——它是「深入了解你的平台限制」和「不满足于官方提供的功能边界」碰撞出来的东西。
适合谁?
如果你同时满足以下条件,这个项目你一定会喜欢:
用 Ghostty 作为主力终端
重度 Claude Code 用户,经常上线忘了时间
对物理渲染 / 着色器编程有兴趣
喜欢把工具折腾成别人看着会过来问"你屏幕上这是什么"的样子
如果你不满足上面任何一条……也可以装上 Demo 模式当屏保看。反正它确实好看。
项目地址:github.com/s0xDk/ghostty-blackhole
主页:s13k.dev/blackhole
你用什么工具提醒自己休息?或者你有没有那种「一写就忘了时间」的时刻?评论区聊聊。
我是顾北,关注我,获取更多好玩有趣的开源仓库!
谢谢你阅读我的文章~
我们下期再见!
PS:本文部分内容由AI辅助创作