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

ghostty-blackhole is one shader, a cursor colour side channel, and a clock that reads zero

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,710 stars158 forksGLSLMIT

At a glance

What is it?
This repository is a single fragment shader plus a single Python script. The black hole is genuinely ray-traced near its edge and approximated analytically further out, the context window percentage arrives through the terminal cursor colour, and the pomodoro mode is documented as not working on current terminal releases.
Who is it for?
This is a good weekend project with an unusually honest README, and the honesty is the reason it is worth reading. It tells you that a headline feature does not work on current releases, that the idle tracking is a workaround for stateless shaders rather than a real timer, and that the stated look is modelled on someone else's shader with the lookup tables replaced by live integration.
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 155 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 November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • s0xDk/ghostty-blackhole1,710 ★ · +17
Star history
Repository2026-09-212026-11-13
s0xDk/ghostty-blackhole1.7k1.7k

17 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The whole product is one shader file and one script

The repository root is short enough to read as the entire architecture. A shader file, a Python script, a tuner directory, a licence file, a README, an ignore file, an animated image and a grid image.

There is no package, no manifest, no build system, no continuous integration and no releases. The primary language is recorded as the shading language, because essentially all of the code is the fragment shader.

That shape follows from the host. The project targets a custom shader slot in a terminal emulator, so installation is a matter of placing the shader file where that terminal looks for it, and there is nothing to compile and nothing to version. The Python script exists only to feed it data, which is the subject of a separate mechanism here.

The project also has a landing page hosted outside the repository, so the repository is the artefact and the site is the presentation. The licence is MIT and the most recent push is dated in June, with no newer release to look for.

The state channel is the terminal cursor colour

The page explains that custom shaders in this terminal accept no custom uniforms. That sounds like a dead end for a project whose entire purpose is to react to something outside itself, and the README treats it as the central constraint rather than a limitation to work around quietly.

The way out is the cursor colour. Shaders do receive that value, and any program can set it with a standard terminal escape sequence. So the context window percentage is encoded into the colour, and a bundled script does the encoding and is wired into the coding agent three different ways. The page names the script and says it is wired in three ways; the list of those three ways is where the visible text ends.

Using a colour as a data channel is the clever part and also the fragile part. The channel exists only for as long as the terminal passes the value through, it shares its bandwidth with whatever else in the session decides to set a cursor colour, and it carries no more than a colour's worth of range. None of that is the shader author's fault, since it is what the host provides, but it does mean the token mode's reliability is bounded by the terminal rather than by the shader.

Pomodoro mode does not advance on current releases

The break reminder is computed entirely inside the shader, with no daemon and no shell hooks, and the page is explicit that this is why the schedule is approximate rather than exact.

The reason is platform behaviour. Shaders are stateless: no buffers persist between frames, and the terminal offers no custom uniforms, so a shader cannot remember when your own work streak began. Rather than working around that with an external process, the schedule is anchored to the wall clock through a built-in uniform.

And then the caveat. Stock terminal releases, through a stated version, declare that wall clock uniform but never populate it, so it is always zero. On those versions the wall-clock schedule does not advance: the hole sits at its smallest cycle size and only the typing detector works. The page says the full cycle comes alive once the terminal wires the uniform up, and suggests a time-scaling override that runs off a different clock so the effect can be previewed today.

Token mode, which is the default, is unaffected. So the honest summary is that a headline feature is inert on current releases, and the README says so in its own words.

Two idle signals with different meanings

The cycle has two components and they answer different questions.

The first is the typing detector, driven by a built-in uniform that reports when the cursor last changed. Leave the terminal alone for a configured interval, ninety seconds by default, and the hole shrinks live, disappearing entirely after a few minutes of quiet. The page frames this as the anti-nag feature: it does not press you while you are not working.

The second is the wall clock, which sets the shape of the cycle itself. The hole is always present while you work, starting small, growing across a configurable work period of fifty five minutes by default, collapsing back to small in the final minute and staying small through a break of five minutes. At those defaults the peak lands five minutes before the hour, which the page presents as a fixed, predictable rhythm rather than a random one.

What the page does not claim is flexibility. Because the cycle is anchored to the clock rather than to your activity, taking a break at an odd hour does not restart it, and the README describes the result as an hourly bell rather than a per-streak stopwatch. That is a real difference from a pomodoro timer, and it is stated rather than implied.

Far from the hole the physics is analytic, not integrated

The rendering claim is specific: near the hole, every pixel integrates its own null geodesic through the Schwarzschild metric using a Binet-form acceleration, which is stated to give exact photon bending. The terminal contents are sampled as the lensed background sky.

That is expensive, and the page says where the cost is avoided. Far from the hole the shader hands off to the analytic weak-field deflection, so only pixels near the hole pay for the integration. Everything else follows from that split.

The visual features named in the README are consequences of the ray tracing rather than drawn effects. Text near the edge is stretched into the photon ring before it disappears. Escaped rays project back onto the terminal plane, bending and magnifying the text and showing a mirrored secondary image inside the Einstein ring. The thin bright ring is described as emergent rather than drawn, since rays winding near the photon sphere pick up every crossing of the disk.

The disk colouring is physical too: a standard accretion temperature profile rendered as blackbody colour, shifted and beamed by a relativistic factor so the approaching side runs blue-hot and the receding side dim and red. A procedural starfield is sampled along the bent ray direction, and it is off by default behind a gain setting.

The README credits another author's shader as the model, noting that it used precomputed lookup tables where this one does the physics live.

The documented demo toggle is not in the repository

The third size mode is a showcase built for recording. It runs a fixed loop of forty two seconds in which the hole grows from a corner seed to full size exactly as the token mode would, while the disk appearance tours a list of presets, crossfading at roughly five second boundaries.

Two details make it usable for capture. Everything runs off the shader's own elapsed time inside a single compiled program, so there are no reloads and a recording does not hitch. And the cursor channel is ignored in that mode, so a live coding session running alongside cannot disturb a recording.

The mode is toggled by a shell script taking an on or off argument, which the page says also reloads the terminal.

That script is not in the repository. The root listing contains the shader, the Python script, a tuner directory, the licence, the README, an ignore file and two images. Everything else the README names is present, including the bundled script and the tuner directory the preset tour references, so the missing piece is specific rather than a directory-level omission.

A reader following the documentation will hit that command and find nothing to run.

Sizes are percentages of the window, and the prompt area is spared

The sizing scheme is expressed as fractions of the terminal area rather than pixels, which is why the page claims the same apparent size on any window shape.

At an empty context the hole is a small disc in the top right corner covering a fraction of six hundredths of a percent of the terminal area. As the context fills it grows toward a maximum of roughly three percent at full context, which the page is careful to say is the shadow alone, since the bright disk extends several times further and reads much bigger. It also moves faster, and its permitted roaming box expands left and down until it covers the playable area above the work region.

Two details protect the animation. The orbit is scaled to that box and is never clipped, because clipping would park the hole motionless against the boundary. Margins keep the shadow and the bright inner disk on screen while it is still small.

The bottom fraction of the screen, named as the work area and holding your prompt, is never distorted, and the hole drifts on a slow Lissajous path confined above it. Time dilation is rendered rather than simulated in the page's terms: the disk pattern at a given radius advances at its proper rate, so inner orbits visibly freeze, and the whole disk winds down as the hole grows heavier, controlled by a separate minimum setting.

Editorial conclusion

This is a good weekend project with an unusually honest README, and the honesty is the reason it is worth reading. It tells you that a headline feature does not work on current releases, that the idle tracking is a workaround for stateless shaders rather than a real timer, and that the stated look is modelled on someone else's shader with the lookup tables replaced by live integration. Use token mode, which is the default and is unaffected by the clock problem. Expect the shader to be the only thing you install, since there is no package and no release, and treat the pomodoro as a preview until the terminal populates the uniform it needs.

Frequently asked questions

What is Ghostty Blackhole?

It is a custom terminal shader that renders a ray-traced black hole, growing with either a pomodoro schedule or with a coding agent's context window fill. It is a single fragment pass with no custom textures, so the terminal contents act as the lensed background sky and the physics is computed live rather than sampled from lookup tables.

Does the pomodoro mode in Ghostty Blackhole work right now?

Not on current terminal releases. The README states that stock releases through 1.3 declare the wall clock uniform but never populate it, leaving it always zero, so the cycle does not advance and only the typing based fade responds. Token mode, which is the default, is unaffected.

How does the shader know how full the context window is?

Through the cursor colour. Custom shaders accept no custom uniforms but do receive the cursor colour, and any program can set it with a standard escape sequence, so a bundled script encodes the context fill into that colour and is wired into the coding agent three ways.

What does the black hole do to the text in my terminal?

Text near the edge is stretched into the photon ring before it disappears, and text behind the hole is gone, since the terminal contents are sampled as the lensed background. Further out the text bends and magnifies and shows a mirrored secondary image. A bottom fraction of the screen is reserved as a work area and is never distorted.

What are the three size modes in Ghostty Blackhole?

A pomodoro mode driven by a wall clock schedule, a token mode that tracks the coding agent's context window and is the default, and a demo mode running a fixed forty two second preset tour for recordings, with the cursor channel ignored so a live session cannot disturb a capture.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. s0xDk/ghostty-blackhole on GitHub
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)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/s0xdk-ghostty-blackhole.svg)](https://hysenlabs.com/projects/s0xdk-ghostty-blackhole)

Was this useful?