# Black Hole Observatory v2 preview — light & detail

An interactive image of a stationary, opaque equatorial disk around a Kerr black
hole. This is an original numerical implementation, not a simulation of a
specific source or an evolving solution of the Einstein field equations.

## Geometry and observer

Set G=c=M=1. Radii are in GM/c², **half the Schwarzschild-radius unit used in v0**.
The dimensionless spin a ranges from 0 to 0.98. The horizon is
r₊ = 1 + √(1−a²). The observer is stationary at infinity, at inclination i=10°–85°
from the spin axis. Framing is the horizontal coverage of the asymptotic image
plane in M; it is not distance from the black hole.

For horizontal and vertical image coordinates α and β, the future-directed
photon constants divided by its energy are

    λ = −α sin i
    Q = β² + (α² − a²) cos² i

The calculation follows the ray backward from the observer. Let u=1/r and
μ=cos θ, and use a positive backward Mino parameter τ. The radial and polar
potentials are

    (du/dτ)² = 1 + (a² − λ² − Q)u² + 2[(λ−a)²+Q]u³ − a²Q u⁴
    (dμ/dτ)² = Q + (a² − λ² − Q)μ² − a² μ⁴

We differentiate these potentials to integrate second-order equations. This
passes radial and polar turning points without manual sign flips:

    u″ = (a²−λ²−Q)u + 3[(λ−a)²+Q]u² − 2a²Q u³
    μ″ = (a²−λ²−Q)μ − 2a² μ³

Initial conditions at infinity are u=0, u′=1, μ=cos i, μ′=β sin i.
The v2 GPU shader lifts polar motion to a smooth unit vector **n**, plus a
frame-dragging phase χ. This avoids dividing by sin²θ at the polar axis:

    n″ = −(Q+λ²+2a² n_z²)n + (0,0,a² n_z)
    n(0) = (sin i,0,cos i)
    n′(0) = (−β cos i, α, β sin i)
    χ′ = −a(2u−aλu²)/(1−2u+a²u²),  χ(0)=0
    φ_em = atan2(n_y,n_x) + χ

Here n_z=μ, |n|=1, |n′|²=Q+λ²+a²μ², and (n×n′)_z=−λ.
The z equation reduces to the polar equation above. The base azimuth obeys
ψ′=−λ/(1−μ²); adding χ recovers the past-directed Kerr azimuth equation.
The emitting longitude is periodic; comparisons use wrapped angle differences.

Only the stationary surface pattern uses φ. Coordinate time is **not** integrated:
this release has no rotating texture, animated gas, or retarded emission model.
The texture is a prescribed stationary brightness pattern, not a material pattern
advected with the circular emitter velocities. All lensed views sample that same
pattern at their emission coordinates. Camera motion changes inclination at
infinity; it is not a finite-distance flyby.

## Disk and light

The disk occupies r_ISCO ≤ r ≤ 25 M, with prograde circular geodesic emitters.
The standard Kerr prograde ISCO expression is

    Z₁ = 1 + (1−a²)^(1/3) [(1+a)^(1/3) + (1−a)^(1/3)]
    Z₂ = √(3a² + Z₁²)
    r_ISCO = 3 + Z₂ − √[(3−Z₁)(3+Z₁+2Z₂)]

The first equatorial crossing inside this interval hits the opaque disk.
Crossings through its central gap or outside its outer edge continue tracing.
The two disk faces emit identically. There is no light in the background sky.
Thus a dark pixel may mean capture, a disk miss, negligible emissivity, or an
unresolved ray; it should not automatically be called the event horizon.

For angular velocity Ω=1/(r^(3/2)+a), the observed/emitted frequency ratio is

    g = 1/[uᵗ (1−Ωλ)]
      = √(1−3/r+2a/r^(3/2)) / [1+(a−λ)/r^(3/2)]

Bolometric intensity transfers as I_obs = g⁴ I_em. This combines gravitational
and orbital frequency shifts. Switching frequency shifts off sets g=1 for
presentation while preserving the geodesics. The straight-light comparison
uses a flat disk with neither capture nor frequency shifts.

## Deliberate presentation choices

The illustrative local emissivity is proportional to
(r/r_ISCO)^−3 [1−√(r_ISCO/r)], normalized to its peak and smoothly tapered to
zero between 20 and 25 M. It is **not** the relativistic Novikov–Thorne flux.
Optional deterministic multiscale noise in (cos(φ+2 ln r), sin(φ+2 ln r), ln r)
adds illustrative spiral detail. This is surface emission, not a plasma volume. A warm display palette,
exposure, ACES-like tone curve, sRGB encoding, and optional screen-space glow
make structure visible. They are not a calibrated thermal spectrum or a
prediction of visible-light colors. Spin comparisons normalize each local
emissivity profile separately; they do not hold accretion rate or luminosity
fixed. The disk has no animated turbulence, hydrodynamics, or magnetic fields.
There are no jets, finite thickness, returning radiation, or evolving spacetime.

## Numerical implementation and limits

A GLSL3 fragment shader integrates each ray with RK4, step
h=0.025/max(1,√(α²+β²)), up to 1024 steps. Equatorial intersections are refined
with 12 bisections, each using an RK4 substep. Infinity is u<0; capture occurs
at u≥1/r₊. Nonfinite states, unit-vector norm drift above 0.002, and exhausted
step budgets are labeled **unresolved**, never silently treated as capture.
Unresolved rays render dark. Infinitely narrow higher-order images and
critical rays are not resolved by a finite step/pixel budget.

The image is averaged in linear half-float HDR targets using deterministic
subpixel Halton offsets (first sample at pixel center). Balanced refines to 8
samples with a 1536-pixel long-edge cap; Sharp uses 32 and a 2560-pixel cap.
Actual dimensions also depend on CSS size and devicePixelRatio. Interaction
uses a 480-pixel cap, then refines 220 ms after input stops. A GL fence bounds
queued GPU work; the animation loop stops after refinement. Every view, preset,
exposure, quality, and size change discards old samples. No temporal reprojection
or averaging across different camera poses is used.

Highlights are extracted before tone mapping and blurred at half/eighth resolution.
Bloom is optional, followed by one ACES-like tone map and one sRGB encoding.
Seven targets require about 28.25 bytes per full-resolution pixel (plus renderer,
canvas, and driver overhead): ~58.6 MB at 1080p or ~234.3 MB at 4K. Dimensions
are bounded by the device texture limit and a 3840×2160 area cap. If float color
buffers are unavailable, a labeled LDR fallback averages tone-mapped samples
and disables bloom; it is not equivalent to HDR. This preview uses explicit
quality presets, not a measured adaptive quality controller.

Scientific presentation enables curved light and physical g⁴ transfer, with
texture and bloom off. Cinematic presentation keeps curved light but disables
frequency shifts, enabling texture and bloom. Both reset exposure to 1 and
**keep spin, inclination, and framing unchanged**. All presets retain illustrative
emissivity and RGB colors. Neither is a calibrated spectrum. These are
Interstellar-inspired choices, not a claim of DNGR/film-quality equivalence.

## Reproducible checks

- `scripts/reference.py` independently integrates inverse radius and **polar
  angle θ and azimuth φ**, using SciPy DOP853 (rtol 2e−11, atol 2e−12). It does not import the
  renderer's JS or GLSL. 224 rays cover four spins, four inclinations, both image
  sides, disk hits, escape, and capture.
- The reference solver ends capture at u=(1−10⁻⁷)/r₊ to avoid the azimuth
  coordinate singularity at the horizon; all emitting intersections lie outside
  the ISCO.
- `scripts/test-physics.mjs` compares the separate CPU u/μ RK4 inspector against those
  references and checks analytic ISCO/redshift limits. Results are published in
  [data/validation.json](data/validation.json).
- The web browser suite runs the actual GLSL integration into a float render
  target and reads it back for comparison with the independent references.
  Azimuth is checked against the independent θ/φ solver modulo 2π.
  It also checks controls, straight-light comparison, image export, mobile
  layout/touch, errors, and teardown. GPU sample errors are attached to CI as
  `kerr-gpu-reference-check` in the browser test report.

These are sampled numerical checks, not global error bounds or a proof that
all pixels are accurate. CPU double precision and GPU float arithmetic differ.
The automated mobile tests emulate Chromium touch/layout; physical iPhone/Safari
performance is not established. Reported `cpuSubmitMs` measures JavaScript
submission only, **not GPU frame time**.

## Visual references and release status

The [ScienceClic transcript](https://gist.github.com/mdashjames/a24db191e7960e6951ae31664e2d657d)
informed physical versus cinematic presets. The
[Alaskan FX transcript](https://gist.github.com/mdashjames/3fc40b91c092ca4684715bf9deaad78e)
informed multiscale emission and compositing. No transcript text, film imagery,
or tutorial assets are incorporated. Refraction shells and a painted halo are
not used as substitutes for Kerr paths.

This is a quality checkpoint, pending physical device review and the 4K film
in [release tracker #18](https://github.com/midkernel/experiments/issues/18).
The short comparison uses the same spin, inclination, framing, exposure,
frequency-shift and glow switches. Texture implementation, sampling, and
compositing intentionally differ, so it is an overall comparison, not an
isolated antialiasing experiment. v1 has one sample at 1280×720; v2 has eight.

## Primary sources

- James et al., *Gravitational lensing by spinning black holes in astrophysics,
  and in the movie Interstellar* (2015), https://arxiv.org/abs/1502.03808.
- Gralla & Lupsasca, *The Null Geodesics of the Kerr Exterior* (2020),
  https://arxiv.org/abs/1910.12881 — separated null-geodesic potentials.
- Li, Zimmerman, Narayan & McClintock, *Multi-Temperature Blackbody Spectrum of a
  Thin Accretion Disk around a Kerr Black Hole* (2005),
  https://arxiv.org/abs/astro-ph/0411583 — relativistic disk transfer and the
  distinction from a full disk-spectrum model. This experiment does not
  implement KERRBB or its self-irradiation treatment.

Three.js is MIT-licensed; its license is included in `licenses/three.txt`.
All scene code and visual assets here are generated by Midkernel's experiment.
