A black hole, computed rather than drawn
Most black holes on the web are a radial distortion applied to a background image. This one traces photons backwards from the camera and integrates their null geodesics in the Schwarzschild metric, which is why the far side of the accretion disk appears above and below the shadow.
Fig. 1— Schwarzschild black hole with an equatorial accretion disk from 3 to 12 r s, viewed near edge-on. Interactive: drag-free, renders only while on screen.
- Schwarzschild (non-rotating)
- r = rs
- r = 1.5 rs
- 3 – 12 rs (ISCO at 3 rs)
- RK4 in φ, 150–380 steps
- Lensing · Doppler beaming · gravitational redshift
- None — raw WebGL2
What is actually being computed
Light does not travel in straight lines near a black hole, and the usual way to fake that on the web is a screen-space distortion — warp the pixels radially and call it lensing. It looks approximately right and is wrong in every detail that matters, because it has no notion of a photon path.
This renders the real thing. For each pixel a photon is traced backwards from the camera and its null geodesic is integrated in the Schwarzschild metric. Written in terms of u = 1/r, in the plane containing the camera and the singularity, the path obeys d²u/dφ² = −u + (3/2)·rs·u². The first term is ordinary orbital motion; the second is the relativistic correction, and it is the entire reason any of the interesting structure exists.
Why the disk appears above and below the hole
The accretion disk is flat and lies in the equatorial plane. Seen from a shallow angle you would expect a line through the middle and nothing else. Instead there is a bright arc over the top of the shadow and another beneath it.
Those are the same disk. Photons leaving the far side of the disk — behind the black hole, travelling away from you — are bent through more than 90 degrees and arrive at your eye anyway. The arc above the shadow is the top surface of the far side; the arc below is its underside, seen through light that passed beneath. You are looking at an object folded over itself by gravity.
There is a second, much thinner ring hugging the shadow: light that orbited the hole one or more times before escaping. The boundary it traces is the photon sphere at r = 1.5·rs, the radius where light can circle indefinitely.
Why one side is brighter
The disk orbits, and at these radii it orbits fast — a substantial fraction of the speed of light. The side rotating toward the viewer has its emission beamed forward and blue-shifted; the receding side is dimmed and reddened. The asymmetry goes as roughly the cube of the Doppler factor, which is why it is so pronounced rather than subtle.
Layered on top is gravitational redshift: photons climbing out of the well lose energy, so the inner disk is dimmed relative to its temperature. Both effects are computed per intersection rather than approximated with a gradient.
Implementation
One fullscreen quad and one fragment shader in raw WebGL2 — no scene graph, no 3D library, no new dependencies. Integration is RK4 in φ with a fixed step, 150 to 380 steps depending on the device tier.
The disk is intersected by tracking the sign of the photon's y-coordinate between steps and interpolating to the crossing point, which correctly picks up multiple crossings when a ray winds around the hole. Stars are procedural and hash-based, so there is no texture to download.
It renders nothing until you scroll to it, pauses when the tab is hidden or the canvas leaves the viewport, drops resolution if frames run consistently slow, and renders a single settled frame under prefers-reduced-motion. Without WebGL2 you get a static frame and the same links.
The interactive view above lists the whole site. So does this, in plain HTML — nothing on this site is reachable only through a shader.