Real-time data engine
Look Up: tonight's rare sky, computed for your exact spot
A live astronomy engine that finds what is worth looking up at from your precise location tonight, down to the exact second the space station crosses the face of the moon. Real orbital mechanics on live data, no API keys, no signup.
- Role
- Author, solo product
- Period
- 2026
- Stack
- Next.js · TypeScript · astronomy-engine · satellite.js · Vercel · Upstash Redis
- Live
- Visit ↗
Look Up computes the rare, beautiful things visible from where you are standing tonight, from the space station’s passes to the exact second it crosses the moon, and the minute to walk outside. Real orbital mechanics on live data, no API keys, no signup. It is live.
Look Up answers one question: what is worth looking up at, from my exact spot, tonight, and when precisely do I look? Point it at a location and it computes the real sky from live data: the space station’s visible passes, the second it crosses the moon or sun, the moon’s phase, bright planets, meteor-shower quality, aurora likelihood from live space weather, close conjunctions, naked-eye comets, and freshly launched Starlink trains. No keys, no signup, anywhere on Earth. This is a non-fintech project, but the engineering underneath is the same discipline as my payments work.
The problem
Sky information online is generic. A site tells you a shower peaks tonight, or that the station is “visible from your city” in a vague window. Whether you can actually see a thing depends on your precise location, the local darkness, and the geometry, and the rarest events have visibility paths only a few kilometres wide. The work is turning raw orbital and ephemeris data into one honest answer for one point on Earth: is this visible from here, and at what second.
Architecture
Each phenomenon is its own module (iss.ts, transits.ts, comets.ts, starlink.ts, aurora.ts, and the rest), pulling its own live source: TLEs from CelesTrak, comet elements from the Minor Planet Center, space weather from NOAA. An assembler (sky.ts) gathers them for a place and moment, ranks what it finds, collapses overlapping sightings, and returns the handful that matter most through a single GET /api/sky endpoint. That same report renders share cards and drives a push loop.
Decisions and tradeoffs
Coarse-to-fine transit detection, with the fine pass as the only arbiter
The hardest thing here is predicting the second the station crosses the moon or sun, a silhouette that lasts about a second on a path a few kilometres wide. Scanning 48 hours at high resolution is far too expensive; scanning coarsely misses a one-second event entirely. So detection runs in three stages: a 30-second scan finds the windows and tracks the closest approach, a 0.5-second scan narrows it, and a 0.02-second pass locates the exact centre and measures how long the station sits inside the disc. The key rule is that the coarse stages never reject a candidate, the station moves about a degree per second, so a coarse sample can sit well off the true minimum. They only decide where to look closely; the 0.02-second refine is the sole arbiter of whether a transit is real.
Rejected: a single-resolution scan. Coarse enough to be fast steps over the event; fine enough to catch it never finishes.
Every phenomenon isolated, so one dead feed never breaks the sky
The engine depends on several third-party data sources that can fail independently. Each phenomenon is wrapped so a failed fetch or a bad payload degrades to “that one is absent tonight” rather than an error page. A missing TLE drops the station and its transits; the moon, planets, and comets still render. This is the same instinct as the money-movement work: never let one dependency take down the whole system.
Compute per observer, never hardcode “visible”
Nothing is marked visible by hand. The comet path is a real Keplerian propagator (elliptical, near-parabolic, and hyperbolic orbits) fed by live orbital elements, run through the standard apparent-magnitude formula for the observer. I validated it against known objects: NEOWISE’s 0.69 AU approach on the real date, and Halley reducing to perihelion distance at perihelion. A curated “currently visible” list would have been simpler and would have started lying the moment the data moved.
Rejected: a hardcoded list of bright objects. It goes stale, and it cannot answer “from here.”
Rank and dedupe down to one clear answer
A location can have a dozen things overhead. The assembler scores each by rarity, how soon it happens, brightness, and altitude, then removes redundancy: a pass that contains a transit shows only the transit, a planet caught in a conjunction defers to the pairing. It returns the top handful and, when the sky is quiet, a forward hook to the next genuinely special night, so a dull evening is never the last word. Near the summer poles, where it never gets dark, it says so plainly instead of showing a blank screen.
What it also does
The same per-location report renders a 1200x630 share card (GET /api/card), so a deep link to tonight’s sky unfurls as an image. A push loop closes the gap between “there is something tonight” and “go outside now”: a cron tick recomputes each subscriber’s sky, finds events that are actually due (a pass beginning within their lead time, a peak while it is dark where they are), and sends one value-carrying alert (“look up in about 8 minutes, the station is rising in the northeast”), deduped so it never nags twice and pruned of dead subscriptions. Subscriptions live in Upstash Redis.
The through-line
Different domain, no money at stake, but the same engineering as the Vida recovery engine: isolate every dependency, compute rather than hardcode, and always return one honest answer. Reliability is reliability, whether the thing that must not break is a repayment or a one-second transit.