Every number traces to NASA. Where the record had a gap, the site marks the gap instead of quietly filling it.
No backend, no build step, one dependency. Choices that survive real users and reshare with no server to babysit.
The MoonKAM classroom archive is gone. Rather than pad the gap with lookalikes, the site publishes only frames whose origin it can state, and says plainly which ones were rescued and what is still missing.
The whole site is static HTML, CSS, and vanilla JavaScript with one library, three.js. There is no backend, no database, no API keys, and no tracking. Every page is a file. That is a deliberate constraint: a tribute that might be reshared by NASA social or education teams should keep working with no server to maintain and nothing that can quietly break or leak.
The second rule was harder than the first: nothing invented. Every number traces to NASA or the mission record, every image is NASA public domain and credited, and the site states plainly that it is an independent tribute, not affiliated with NASA. Where I could not stand behind a precise claim, I described the category instead of faking the specifics.
The centerpiece is a WebGL globe built with three.js. A sphere is textured with GRAIL's actual free-air gravity map, the exact cylindrical image NASA's Goddard visualization studio publishes for this purpose. The globe carries four of their maps on the same sphere: free-air gravity, Bouguer gravity with the terrain’s own pull removed, crustal thickness derived from the difference, and the photographic surface for comparison. Only free-air is fetched on load; the others arrive the first time someone asks for them, because 13 MB of textures nobody selected is 13 MB wasted. The color scale is theirs, not mine: red is a mass excess and blue a mass deficit, exactly as SVS publishes it. Rainbow scales are rightly criticized in scientific visualization, but recoloring a dataset I did not compute would be inventing something, so the published artefact ships as it is. The word "cylindrical" is load-bearing: only an equirectangular (2:1) projection wraps cleanly onto a sphere, so the common orthographic globe render could not be used as the texture.
I drive rotation by hand rather than pulling in a camera-controls library. On pointer drag I compose small quaternion rotations around the world axes, and a click on a pin slerps the sphere toward a target orientation. Quaternions avoid the gimbal and axis-order surprises you hit when you accumulate Euler angles, which matters the moment you let a pin fly to a specific latitude and longitude.
file:// for security reasons. The globe renders perfectly over https but falls back to a flat image when you open the file locally. The fix was to test on the deployed URL, not the local file, and to self-host both three.js and the textures so nothing depends on a third party staying online or on cross-origin permissions.Nineteen real basins, craters, and landmarks sit on the globe. The hard part is not drawing them, it is making a marker at a real latitude and longitude land on the exact spot the texture paints. That means reproducing the precise way three.js maps the image onto its sphere, then projecting each marker from 3D back to a 2D screen position every frame so an HTML label can ride along and hide when it rotates to the far side.
Two limits made the site better rather than worse. The MoonKAM classroom archive is gone: images.moonkam.ucsd.edu went dark years ago and thousands of student frames went with it. The easy fix was to fill the space with lunar imagery that looks close enough. Instead the site publishes only frames whose origin it can state, two from NASA's public library and a further set rescued from Wikimedia Commons, where someone had saved them off the gallery before it closed. They survive at 640 pixels wide, so they are shown at 640 pixels wide, labelled as rescued frames rather than as the archive, with the hunt for the rest described in the open. And the gravity pins describe a feature by what its gravity means, a mass excess or a low, instead of claiming a crater-exact precision I cannot defend by eye.
Even the mission patch is handled with care. It is public domain, but NASA emblems carry usage rules, so it sits as a faint watermark under an explicit non-affiliation line rather than as a header badge that could imply endorsement.
Three faces do three jobs. IBM Plex Mono carries the telemetry bar, coordinates, labels, and readouts, the instrument voice. Fraunces, a high-contrast display serif, carries the headlines. Newsreader, a screen-tuned serif, carries the reading.
The convention for space sites is a clean sans plus a mono for data. NASA's own system pairs Inter and Public Sans with a monospace for numbers. This site matches on the mono exactly and diverges on the serifs on purpose: it is a personal tribute, not an agency page, so leaning editorial makes it feel hand-made and keeps it from reading as an official NASA product. A hidden ?font=sans preview swaps in the NASA-style Inter and Public Sans so the two directions can be compared on the real globe.
The accent colors are not decoration, they are GRAIL's real encoding: warm red is a mass excess that pulls harder, cool blue is a gravity low. Markers reuse those exact meanings, which is why they had to read on top of the same-colored map. The fix was a white core with a dark outline and a colored ring, so a pin stays visible on red, blue, or grey.
Restraint did most of the work. An early hero stacked a starfield, a faded spacecraft render, and the mission patch behind the headline at once, and it read as noise. Dropping those to near-invisible whispers and adding breathing room was the difference between busy and classy. There are two full themes, a deep-space dark and a warm paper light, built by flipping CSS variables, with the one catch that anything sitting on a fixed-dark surface (the image cards, the camera frame, the pin tooltips) is pinned to light text so it never vanishes when the theme changes.
prefers-reduced-motion and holds still for anyone who asks it to.Fonts for the sans preview load only when it is requested, so default visitors never download them. Textures are self-hosted and sized for the web. The site is a git-connected static deploy on Vercel with clean URLs, and when the separate gravity page was merged into the landing page, the old route was kept alive with a redirect so any shared link still works.
| Decision | Why | What it cost |
|---|---|---|
| No backend | Nothing to maintain or leak; reshareable | No shared state, no live features |
| Hand-rolled globe controls | Fewer dependencies, no axis-flip bugs | More code to own than a library |
| HTML overlay pins | Crisp labels, easy clicks, cheap | A layer to keep in sync each frame |
| Only frames with a traceable origin | Honesty over a fuller-looking gallery | Small, uneven imagery |
| Serif type | Feels like a tribute, not a clone | Off the NASA sans convention |
| Theme via variable flip | One system, two looks | Fixed-dark surfaces need manual pinning |
| Self-hosted three.js and textures | No CDN or CORS dependency | Larger repo, manual updates |
Vanilla HTML, CSS, and JavaScript. three.js for the globe. Fraunces, Newsreader, and IBM Plex Mono for type. Real imagery from NASA, JPL-Caltech, MIT, and Goddard, with a Moon surface texture from Solar System Scope under CC BY 4.0. Deployed as a static site on Vercel from a private GitHub repository, on a custom domain via Route 53.
The globe takes keyboard focus. Arrow keys rotate it, plus and minus zoom, and the square-bracket keys or the Prev and Next controls step through all nineteen features, so exploring the Moon never requires a mouse. A blend slider fades the gravity field into the real surface for anyone who wants to compare the two directly. Every animation respects prefers-reduced-motion and holds still when asked, images carry real descriptions, the interactive globe announces itself to screen readers, and text is pinned to legible contrast in both the dark and the light theme.