Perigee
An asteroid gets found, and then it can get lost. The confirmation page holds dozens of unconfirmed objects. A survey found them. Someone with a telescope still has to get another night of positions before the patch of sky to search outgrows the camera. That patch grows with the square of the uncertainty radius:
[ A \propto r^{2} ]
JPL Scout already publishes the radius tonight and again tomorrow. It does not know that the camera is 15 arcminutes wide, or that the observer is at Angell Hall and the Sun is about to come up. Perigee is that last decision: point, or leave it alone.
What inspired this
I started with a page that explained close approaches, flares, and papers. It looked finished, and it did not tell anyone what to do. The people who lose these objects are university telescopes and club observers, including a telescope on this campus. The question that mattered was narrower. From this site, with this chip, which object is worth the night?
How I built it
Perigee is a Next.js app. One request reads the live Scout confirmation page. For the objects that might fit the chip, a second request pulls a one-orbit ephemeris over the next 16 hours. Altitude at the chosen site, and whether the Sun is more than 15° down, are computed locally. The sites are Angell Hall, Mt. Lemmon, Teide, and Mauna Kea. The chip, the limiting magnitude, and the fastest rate the mount will track are choices, because those are the instrument someone actually has.
The square on the page is the field of view. Scout's published figure is a 1σ radius. The dot is the 2σ patch tonight, twice that radius, which is the patch a follow-up usually tries to cover. The dashed circle is the same patch tomorrow. Field count is how many chips tile that circle. It is a covering estimate, not a scheduled mosaic.
Coordinates are geocentric. A close pass can shift the pointing by about a degree between the geocenter and the observatory, and the page says so.
Grok 4.7 writes the observing handoff from that row only. Grok Imagine paints a finder plate of the same chip. Grok Voice reads the handoff. The decision is already on the page before the model speaks. If a value is missing, the brief says it is missing. Scout's impact rating, when it is present, runs from 0 to 4 and is not a probability.
Objects that already have designations sit below the sheet. For those, the orbit condition code and the length of the data arc matter more than the nominal miss distance. A diameter inferred from absolute magnitude is an albedo range, not a measurement. The papers are live OpenAlex results on follow-up astrometry.
What I learned
Waiting feels safe, and it is the expensive choice. A radius that grows by ten becomes a search area that grows by a hundred. A bright, slow object that still fits the chip tomorrow is not the target. The target is the one that is one field tonight and will not be one field tomorrow.
JPL computed the positions and the uncertainty. The sheet computes whether that uncertainty fits a specific camera at a specific site. Those are different jobs, and mixing them up would make the demo a lie.
Challenges
Scout's ephemeris wants to sample a thousand orbits unless you ask for one, which is too slow for a page that has to answer while the object is still up. The 2σ circle had to be labeled as a choice, because the column Scout publishes is 1σ. Objects that are too fast, too faint, in the glare, under the horizon, or already held by the surveys had to stay off the telescope even when the story was exciting. A one-hour window was rendering as "from 07:00 to 07:00." And a dashboard of every NASA feed kept trying to take the first screen. The chip had to stay the thing a judge sees first.
Run it
npm install, then npm run dev, then open the local page. Public JPL, NASA, and OpenAlex data load with no key. An xAI key in .env.local turns on the handoff, the plate, and the voice.
Built With
- cursor
- grok-imagine
- grokvoice
- jpl-scout-api
- nasa-apis
- next.js
- node.js
- openalex
- react
- shadcn/ui
- tailwind-css
- typescript
- xai-grok
Log in or sign up for Devpost to join the conversation.