An interactive, real time sandbox for black hole, white hole, and wormhole horizons. horizon is a physically inspired visualization: it uses simple, stable models to show how matter and light behave around a one way boundary in spacetime, and it lets you flip that boundary inside out. The headline feature is time reversal: record a black hole swallowing its accretion disk, then play the recording backwards and watch the same event become a white hole emission.
This is a visualization and teaching tool, not a numerical general relativity solver. See docs/PHYSICS.md for exactly what is real physics intuition and what is artistic license.
| White hole | Wormhole |
|---|---|
![]() |
![]() |
| Time reversal | Causal cones |
|---|---|
![]() |
![]() |
These are real captures from the app. Press
F12while running to save a PNG next to the executable. See screenshots/README.md.
- Three horizon modes that behave differently and are switchable live:
- Black hole: particles orbit and spiral inward and are absorbed at the event horizon; light rays bend in and can be captured.
- White hole: particles are seeded at the horizon and pushed outward with jets; nothing is allowed to fall in; light rays are deflected away.
- Wormhole: a black mouth and a white mouth. Particles that fall into the black mouth are teleported to the white mouth and emerge outward, and a curved bridge connects the two.
- Time reversal recorder: record the full particle state over time, then play it back in reverse. Reversed accretion looks like emission. The trails are reconstructed so the reversed event reads clearly.
- Light ray visualizer: a fan of rays integrated step by step with a selectable lensing strength (None, Weak, Strong, Extreme). Rays bend around the horizons, are captured by black holes, rejected by white holes, and can be re-emitted from the far mouth of a wormhole.
- Causal cone overlay: drop events into the scene and watch their light cones grow as stacked rings. The cones tip toward black holes and away from white holes as an intuition aid.
- Spacetime curvature grid: a rubber sheet grid that dips under black holes and bulges under white holes.
- Procedural accretion / emission disk with differential rotation and a Doppler style brightness asymmetry.
- Rendering: additive HDR scene, a deep starfield, bloom, an ACES tonemap, and an optional screen space lensing distortion around the horizon.
- Dear ImGui control panel for every parameter, plus full keyboard and mouse controls and an orbit camera.
- Screenshot export to PNG (dependency-free encoder), plus an offline
--capturemode that renders one frame of each mode to disk.
| Input | Action |
|---|---|
1 / 2 / 3 |
Black hole / White hole / Wormhole mode |
Space |
Pause and resume the simulation |
T |
Cycle time reversal: idle, record, play reverse, live |
C |
Toggle the causal cone overlay |
G |
Toggle the spacetime grid |
L |
Toggle light rays |
R |
Reset the simulation |
E or click (with cones on) |
Place a causal event under the cursor |
H |
Show or hide the UI panel |
F12 |
Save a screenshot |
Esc |
Quit |
| Left drag | Orbit the camera |
| Right or middle drag | Pan |
| Mouse wheel | Zoom |
W A S D / arrows |
Move the camera target on the plane |
All of the same controls (and more) are available in the ImGui panel.
Requirements:
- A C++17 compiler (GCC, Clang, or MSVC)
- CMake 3.16 or newer
- Git (dependencies are fetched at configure time)
- A GPU and drivers that support OpenGL 3.3 core
GLFW, GLM, and Dear ImGui are downloaded automatically with CMake FetchContent
on the first configure, so the first run needs network access. The OpenGL
function loader is a small hand written one vendored in extern/glloader, so no
GLAD generation step or system GLEW is required.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
./build/horizonThe executable locates shaders/ automatically (it is also copied next to the
binary at build time), so you can run it from anywhere.
GLFW builds from source need the X11 and OpenGL development headers:
sudo apt install build-essential cmake git xorg-dev libglu1-mesa-devIf you already have libglfw3-dev and libglm-dev installed, CMake will use
those instead of fetching them.
Use the Visual Studio generator or MinGW with Ninja. This project was built and verified with MinGW-w64 GCC 14 and Ninja:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
.\build\horizon.exeIf you prefer vcpkg for GLFW and GLM, install them and pass the toolchain file. Dear ImGui is always fetched so its backend include paths stay consistent.
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=<vcpkg>/scripts/buildsystems/vcpkg.cmakeYou can also build without the UI panel (keyboard controls still work):
cmake -S . -B build -DHORIZON_USE_IMGUI=OFFA black hole is a region whose boundary, the event horizon, is a one way membrane: things can fall in but nothing, not even light, can come back out. In this toy model that is exactly what the boundary does. Particles that cross the horizon are removed and light rays that cross it are captured.
A white hole is the time reverse of that idea. The same equations of general relativity that allow a black hole also allow a solution where the horizon is one way in the other direction: nothing can enter, and matter and light stream out. White holes are theoretical. They are valid mathematical solutions but there is no evidence they exist in nature, and forming one looks extremely unnatural, in part because it would require a very special low entropy initial state. horizon leans into the time symmetry: the white hole mode is built as the mirror image of the black hole mode, and the time reversal feature turns one into the other in front of you.
horizon is physically inspired, not a relativistic solver. The simplifications:
- The world is two dimensional (a plane), rendered in a 3D looking scene with an orbit camera. Particles have a small vertical offset so the disk reads as a thin volume.
- Gravity is a softened inverse square attraction, not a metric. Black holes pull, white holes push, and a tangential term fakes frame dragging or spin.
- The event horizon is a hard radius, not a curved null surface.
- Light rays are integrated as 2D polylines that are deflected by the same softened field. This produces a lensing look but is not a geodesic in a Schwarzschild or Kerr metric.
- The lensing of the background is a screen space distortion, not real ray traced lensing.
- The spacetime grid is the classic rubber sheet picture, which is an analogy, not the actual geometry.
Integration is semi implicit Euler at a fixed timestep with a softened force and a velocity clamp, which keeps thousands of particles stable. Full equations and pseudocode are in docs/PHYSICS.md.
The code is modular C++17. Each subsystem is one pair of files.
| Module | Responsibility |
|---|---|
App |
Window, input, the fixed timestep loop, and orchestration |
Renderer |
All OpenGL: the additive multi pass scene, bloom, composite |
Camera |
Orbit, pan, zoom camera and matrices |
Shader |
GLSL program compile, link, and uniform caching |
ParticleSystem |
The 2.5D particle simulation and trail buffers |
HorizonObject |
The force, lensing, and absorption math for one mouth |
RayVisualizer |
Light ray integration and bending |
TimeReversalRecorder |
Snapshot ring buffer and reverse playback |
CausalConeOverlay |
Event light cone geometry |
SimulationParams |
All tunable parameters and the mode enums |
UI |
The Dear ImGui panel (optional at build time) |
Image / Paths |
Dependency-free PNG writer and runtime shader path resolution |
glloader |
A small vendored OpenGL 3.3 core loader |
Rendering is fully additive with no depth test: the scene is composed as glowing
layers into an HDR target, then bloom, a tonemap, and the optional lensing
distortion are applied in a composite pass. Shaders live in shaders/ and are
loaded at runtime so you can edit and rerun without recompiling C++.
- GPU compute shader particle update for very high counts
- A true screen space gravitational lensing pass driven by an impact parameter map
- A Kerr style spin parameter that shears the disk and ray paths
- Redshift and Doppler color shift tied to ray and particle velocity
- Save and load parameter presets
- A 3D camera flythrough path and a deterministic replay export
- A built in GIF or video capture helper
- Built by Ijtihed as a graphics and simulation portfolio project.
- GLFW for windowing and input.
- GLM for math.
- Dear ImGui for the UI.
- The ACES filmic tonemap approximation is from Krzysztof Narkowicz.
Released under the MIT License. See LICENSE.




