The idea
There are only a few dozen black holes well-characterized enough to be worth showing — famous X-ray binaries, the supermassive black holes at the centers of nearby galaxies, a handful of Gaia astrometric detections, and the LIGO/Virgo gravitational-wave mergers. That's small enough to hardcode, which means the whole "point your phone at the sky" feature can work entirely offline, with no backend and no rate limits.
Point your phone up, and the app tells you something like:
Cygnus X-1 — 40° up, toward NE — 7,000 light-years away, ~21 solar masses
How it works
-
The catalog —
src/data/blackholes.jsonholds 60 entries: RA/Dec (J2000), mass, distance, discovery year, and a short discovery note for each object, researched from SIMBAD, NASA HEASARC, NED, and arXiv/ADS papers. -
Coordinate math —
astronomy-engineconverts each object's fixed RA/Dec into altitude/azimuth for the user's current location and time. This has to account for precession (RA/Dec is anchored to J2000, but the sky has moved since then), which the app handles by rotating into equator-of-date coordinates before computing horizon position. -
Compass + tilt —
DeviceOrientationEventgives the phone's raw alpha/beta/gamma angles. The tricky part: you can't just usealphaas compass heading, because when the phone is held upright (pointing at the sky, not lying flat),alphabecomes unstable. The app instead builds the full device-to-world rotation matrix and rotates the phone's "out the back of the camera" vector through it, which stays well-behaved at any tilt. - Matching — every ~10 seconds the app recomputes alt/az for all 60 objects against the live clock and GPS location, then checks which one is within a few degrees of where the phone is currently pointing.
- Desktop fallback — no compass on a laptop, so there's a Three.js sky dome you drag to look around, plus a searchable/sortable list view. Both work identically to the phone view, just without the orientation sensor.
Honesty about the data
Not every black hole in the catalog has a real, precise sky position. LIGO/Virgo gravitational-wave detections are localized to sky regions ranging from tens to thousands of square degrees — for most of the 12 GW merger events in the catalog, there's no genuine point-source coordinate published, just a probability region.
Rather than quietly picking an arbitrary point and presenting it as fact, the app:
- Uses the best available estimate (published skymap peak, EM-counterpart host galaxy when one exists, or an illustrative point within the credible region otherwise)
- Flags 9 of the 12 GW events with a visible "approx. position" badge in the UI (list view, AR pointer, and sky dome), plus a dashed marker instead of a solid dot
- Documents the actual localization uncertainty (e.g. "90% credible region ~8,284 sq deg") in each entry's note
The 3 GW events with real confidence are GW170817 (pinpointed via its electromagnetic counterpart, host galaxy NGC 4993), GW170814, and GW190521.
Stack
- Vite + vanilla JS (no framework) — the whole app is ~10 small modules
- astronomy-engine — RA/Dec → alt/az conversion
- Three.js — desktop sky dome
- DeviceOrientationEvent / getUserMedia — phone compass + camera passthrough
- No backend, no API keys, no database — the catalog is the data layer
Catalog breakdown (60 objects)
| Category | Count | Examples |
|---|---|---|
| Supermassive black holes | 26 | Sagittarius A*, M87*, TON 618, 3C 273, OJ 287 |
| Stellar-mass / X-ray binaries | 19 | Cygnus X-1, V404 Cygni, GRS 1915+105 |
| Gaia astrometric detections | 3 | Gaia BH1, BH2, BH3 |
| LIGO/Virgo GW mergers | 12 | GW150914, GW170817, GW190521 |
Running it
cd blackhole-sky
npm install
npm run dev -- --host
Compass and camera access require a secure context —
localhost works for local testing, but a phone
on the same network needs HTTPS (e.g. deploy to
Vercel/Netlify) for those permissions to be granted at all.
What's next
- Real skymap files (not secondary-source approximations) for the GW merger positions
- Constellation line overlay in the sky dome
- Offline/PWA install support