Project · Live
Gravitational Well 3D
An interactive 3D visualization of General Relativity. Most educational material represents spacetime as a flat 2D rubber sheet — which is wrong. Spacetime is volumetric, and gravity warps it from every angle. This simulation shows that, with a 3D grid deformed in real time by a GLSL vertex shader.

Why I built this
Almost every illustration of gravity you've seen — the bowling ball on a stretched bedsheet, the planet sinking into a funnel — collapses a three-dimensional phenomenon onto a single plane. It biases the intuition toward thinking gravity "pulls down" into a hole.
In reality, spacetime isn't a sheet — it's a volumetric fabric extending in all directions. Mass warps it from every possible angle. I wanted a simulation that shows that honestly, where you can rotate around the well and see the curvature wrap around the body in 3D instead of dipping below it.
Features
- 3D volumetric grid deformed in real time by a custom GLSL vertex shader.
- Up to 8 simultaneous masses — each with independent position, radius, and color.
- Gravity presets from the Moon (0.16 G) to a Neutron Star (extreme), plus a free intensity slider.
- Gravitational waves — animated ripples in the spacetime fabric, à la Einstein 1916.
- Test particles with motion trails that follow geodesics through curved space.
- Scenario presets: Black Hole, Binary System, Triple System, Standard Well.
- Adjustable grid resolution up to 60³ divisions, transparency control, starfield background, orbit camera, frosted-glass UI.
Stack
- Three.js (WebGL) with custom GLSL shaders for the deformable cubic grid.
- React 19 + TypeScript for the UI; Tailwind CSS 4 for styling.
- Vite 6 for dev and build.
- The entire simulation — UI, scene setup, animation loop, shaders — lives in a single self-contained
src/App.tsx.
How the shader works
For each vertex of the grid, the shader computes the displacement caused by every active mass. Roughly:
base = (G · mass²) / max(r, minR)² // inverse-square law base = base / (1 + base) // saturation falloff = 1 / (1 + 0.015·r) // gentle distance falloff wave = sin(r·0.5 − t·5) · e^(−r·0.02) · waveAmp
Each vertex is then pulled radially toward the mass by an amount proportional to base, clamped so it never enters the body's sphere, and projected back inside the cube boundary so the wireframe never escapes its bounding box. Up to MAX_MASSES = 8 bodies are summed per vertex via uniform arrays.
Honest caveats
- This is a visual analogue, not a numerical relativity solver. The math is tuned for legibility, not physical accuracy.
- Very high
Divisions× many active masses can be expensive on integrated GPUs. - The project was scaffolded inside Google AI Studio, so the example env mentions
GEMINI_API_KEY— but the current simulation does not actually call the Gemini API.
Status
Live in Google AI Studio. Source under Apache-2.0 at rafaehlers/Gravitational-Well-3D. First public release: February 2026.