Model or dataset
s0xDk/ghostty-blackhole avatar
s0xDk/ghostty-blackhole

Ghostty Blackhole: A Ray-Traced Black Hole That Tracks Your Claude Code Context

Ghostty Blackhole puts a real, ray-traced black hole inside your terminal. It grows as Claude Code's context window fills up, live. A fresh session is a quiet hole in the corner. A full one swallows half your screen. You'll always see /compact coming.

1,697 stars154 forksGLSLMIT

At a glance

What is it?
Ghostty Blackhole is a custom GLSL shader for the Ghostty terminal that renders a physically accurate black hole. In its default mode, the hole grows in real time as Claude Code's context window fills. A Pomodoro mode drives growth from a wall-clock work cycle instead.
Who is it for?
Ghostty Blackhole is a well-suited tool for engineers who work heavily in Claude Code sessions and want a peripheral warning about context saturation without switching focus to a status bar. The hole grows continuously, so a glance tells you roughly where you are.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 110 days ago.
What is it written in?
Mainly GLSL, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What Ghostty Blackhole Is and Why It Exists

Claude Code limits each session to a context window of fixed size. When the window fills, a `/compact` command is required to summarize the conversation and continue. Developers who do not notice the window filling waste time on a compaction they could have anticipated.

Ghostty Blackhole addresses this through ambient display. A black hole rendered in the Ghostty terminal grows from a small object in the top-right corner toward occupying a significant fraction of the terminal area as the context window fills. The README describes the dynamic: at 0% fill, the hole covers roughly 0.06% of the terminal area (the `TOKEN_AREA_MIN` constant). At 100% fill, the shadow covers roughly 3% of the area (the `TOKEN_AREA_MAX` constant), but the bright accretion disk extends well beyond that, making it read as much larger visually. A new session snaps the hole back to the corner.

The shader is based on Eric Bruneton's black hole shader, which models Schwarzschild geodesics. The README states the author replaced Bruneton's precomputed lookup tables with live per-pixel integration because Ghostty custom shaders have no texture support. A Shadertoy-style fragment pass is all that Ghostty's shader system provides: one full-screen pass, no persistent buffers between frames, no custom uniforms beyond the built-in ones. Every visual element including the accretion disk, photon ring, and lensed starfield has to be computed from scratch each frame from the available shader inputs.

The Physics in the Rendering

Each frame, the shader traces the path of light (null geodesics) through the Schwarzschild metric. The Binet-form acceleration `a = -3/2 h^2 x/r^5` governs exact photon bending. This is not an approximation: the shader integrates the equation for each pixel that passes near the black hole.

The visual outputs that fall out of this physics are documented in the README:

The shadow forms when a ray has an impact parameter below `b_crit = (3 * sqrt(3)/2) * r_s`. Those rays spiral into the horizon and return black. Text near the edge is stretched into the photon ring before it disappears; text behind the hole is genuinely absent from the render.

Gravitational lensing bends escaped rays back onto the terminal background. Text bends and magnifies, and a secondary image of the terminal content appears inside the Einstein ring. Far from the hole, the shader uses the analytic weak-field deflection formula to avoid the cost of full integration for pixels that are only weakly affected.

The accretion disk uses a Shakura-Sunyaev temperature profile rendered as blackbody color. The relativistic Doppler factor `g = sqrt(1 - 1.5 r_s/r) / (1 - beta * k_hat)` shifts the approaching side blue and hot and the receding side dim and red. The photon ring, the bright narrow ring near `1.5 r_s`, emerges from the simulation rather than being drawn explicitly.

Gravitational time dilation is also simulated: the disk pattern at radius `r` advances at `sqrt(1 - 1.5 r_s/r)`, so inner orbits visibly slow as the hole grows heavier.

Three Size Modes: Tokens, Pomodoro, and Demo

The constant `SIZE_MODE` near the top of `blackhole.glsl` selects how the hole grows.

`MODE_TOKENS` is the default. The hole reflects the fill level of Claude Code's context window live. An empty session shows the minimum-size hole in the top-right corner. As the session fills, the hole grows and drifts outward from the corner. When context is reset with `/compact` or a new session starts, the hole snaps back. If no Claude session is running, the hole disappears entirely.

`MODE_POMODORO` ties growth to a 55-minute work period followed by a 5-minute break, derived from the wall clock via `iDate`. The hole starts small at the cycle floor, grows over the work period, collapses in the final minute, and stays small through the break. A typing detector using `iTimeCursorChange` shrinks the hole if the terminal is idle for `IDLE_FADE_SEC` (default 90 seconds). This mode requires no connection to Claude Code and works standalone.

`MODE_DEMO` is a 42-second self-running loop for recording. The hole tours the visual presets (Inferno, Gargantua, M87 donut, Face-on ember, Quasar, Blazar, Pure lens, and back) with crossfades every 5 seconds. Toggling demo mode uses the script `./demo-mode.sh on|off`, which also reloads Ghostty.

How Token Mode Connects to Claude Code

Ghostty custom shaders receive no custom uniform variables. The only runtime input besides time is the cursor color, which any terminal program can set with an OSC 12 escape sequence. Ghostty Blackhole encodes the context fill level in the cursor color.

The script `claude-token.py` reads the context token count from Claude Code and writes the encoded value to the cursor color using a standard terminal escape. The README states this script is wired into Claude Code in three ways: as a hook that runs automatically during sessions.

This design means the token display works without any changes to Claude Code itself. The connection is entirely out-of-band through a protocol terminal emulators have supported for decades. The README notes that because Ghostty's cursor color channel is used, any program that independently changes the cursor color during a Claude session would disrupt the display. This is a consequence of using an existing channel that was designed for a different purpose: the design keeps the connection simple and requires no Ghostty-specific extension, but it means the cursor color is no longer free for other uses while the shader is active.

The Pomodoro iDate Caveat

The Pomodoro schedule anchors the work/break cycle to the wall clock via the shader uniform `iDate`. However, the README includes a notable caveat: stock Ghostty through version 1.3 declares `iDate` but never populates it. The value is always zero.

On current Ghostty releases, this means the wall-clock schedule does not advance: the hole stays at the minimum size set by the cycle floor and only the typing detector works. The full rhythmic cycle (growing over 55 minutes, collapsing for the break) requires a future Ghostty version that wires `iDate` correctly.

The README offers a workaround for previewing the behavior: the `TIME_SCALE` constant runs off `iTime` (elapsed time) instead of the wall clock, which lets you see the full cycle play out at an accelerated rate. Token mode is not affected by the `iDate` issue at all.

Installation, Repository Layout, and Maintenance

The repository contains five primary items at the top level: `blackhole.glsl` (the shader), `claude-token.py` (the token tracking script), `demo.gif` (a preview animation), `presets-grid.png` (a grid showing the visual presets), and a `tuner/` directory for adjusting visual parameters. Installation involves placing `blackhole.glsl` in Ghostty's custom shaders directory and configuring `claude-token.py` as a Claude Code hook so the script runs during sessions. The README's landing page at s13k.dev/blackhole provides complete setup instructions.

The shader requires no compilation step. Ghostty loads GLSL shader files directly from its configuration directory and reloads them automatically when they change. The `tuner/` directory contains tooling for adjusting the shader's visual constants without editing `blackhole.glsl` directly.

The project is licensed under the MIT licence. The last push to the repository was on 2026-06-11. There are no published GitHub releases. The repository has no CI configuration or test suite.

An alternative to this ambient display is using Claude Code's built-in context indicator in the status line, or adding a shell prompt segment that prints the token count as text. The difference in approach is fundamental: text-based indicators require deliberate attention to notice. Ghostty Blackhole occupies peripheral vision continuously and scales physically, so a developer who has been focused on the code for an extended period receives a warning without ever shifting focus to read a number. The trade-off is that the shader consumes GPU cycles for every frame rendered, whereas a text counter costs nothing while idle.

Editorial conclusion

Ghostty Blackhole is a well-suited tool for engineers who work heavily in Claude Code sessions and want a peripheral warning about context saturation without switching focus to a status bar. The hole grows continuously, so a glance tells you roughly where you are. It is not a fit for users of terminals other than Ghostty, or for engineers who prefer compact text-based indicators over ambient visuals. Before installing, verify your Ghostty version: the Pomodoro wall-clock schedule requires `iDate` to be populated, which the README states is not the case in stock Ghostty through 1.3.

Frequently asked questions

How does Ghostty Blackhole know how full Claude Code's context window is?

The bundled script `claude-token.py` reads the context token count from Claude Code and encodes it into the terminal cursor color using an OSC 12 escape sequence. Ghostty custom shaders receive the cursor color as a uniform, so the shader can read the value and scale the hole accordingly.

Does Ghostty Blackhole work with terminals other than Ghostty?

No. The shader is a Ghostty custom shader written in GLSL and uses Ghostty-specific shader uniforms such as `iCurrentCursorColor`, `iTimeCursorChange`, and `iDate`. It will not run in other terminal emulators.

Does the Pomodoro wall-clock schedule work in current Ghostty releases?

Not fully. The README states that stock Ghostty through version 1.3 declares the `iDate` uniform but never populates it, so the wall-clock schedule stays fixed at the cycle floor. The typing detector still works. The full cycle requires a future Ghostty version that correctly provides `iDate`.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. s0xDk/ghostty-blackhole on GitHub
For maintainers

Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/s0xdk-ghostty-blackhole.svg)](https://hysenlabs.com/projects/s0xdk-ghostty-blackhole)
Community notes

Community notes