Building a NASA Solar System Treks Viewer with Hermes Agent

From 230 catalog entries to 25 verified layers โ€” how an AI agent discovered that most of NASA's planetary data catalog is a ghost town

Case Study ยท June 2026

๐Ÿš€ Interactive viewer โ€” select a body, pick a layer, and toggle auto-rotate. All 25 verified layers are baked in.

The Problem

NASA's Solar System Treks portals host some of the most detailed planetary imagery ever captured โ€” LRO WAC mosaics of the Moon, MOLA hillshades of Mars, MESSENGER color maps of Mercury, and Dawn's imagery of Vesta and Ceres. The data is world-class. The access experience is... not.

Each planetary body has its own Trek portal with a Java-based web viewer that feels like it time-traveled from 2008. The data is exposed via WMTS (Web Map Tile Service), but with a critical limitation: no CORS headers. This means you can't query the catalog or fetch tiles from a modern browser-based application without proxying through a server.

I wanted a unified, multi-body viewer โ€” one page where I could switch between the Moon, Mars, Mercury, Vesta, and Ceres, browse layers by category, and toggle between imagery, topography, mineralogy, and gravity maps. So I enlisted the Hermes Agent to build it.

Phase 1: Discovery

The first challenge was understanding the Trek tile architecture. Through a combination of web research and API probing, the agent uncovered the pattern:

https://trek.nasa.gov/tiles/{Body}/EQ/{LayerID}/
  1.0.0/default/default028mm/{z}/{y}/{x}.jpg

Bodies include Moon, Mars, Mercury, Vesta, Ceres, Titan, and Icy Moons. The EQ path indicates equirectangular projection. The tile matrix is default028mm (roughly 28m/pixel at zoom 0). Tiles are 256ร—256 JPEGs, with zoom levels typically ranging 0โ€“8+.

But which layers actually work? The Trek searchItems API returns hundreds of entries per body โ€” 230+ across just Moon, Mars, Mercury, and Vesta. The naive approach would be to trust the catalog and populate a dropdown. We tried that. Most selections showed... nothing.

Phase 2: The Blank Tile Problem

Here's where it gets interesting. When you request a Trek tile URL, the server often returns HTTP 200 with a valid JPEG response. But the payload is a blank or error tile โ€” sometimes as small as 200 bytes, containing nothing but a gray rectangle or an error message rendered as an image.

HTTP status codes lie. 200 OK doesn't mean "here is your planetary imagery." It means "here is a response." The only way to distinguish real data from placeholders is to check the actual payload size.

The agent wrote a Python discovery script that:

  1. Queried each Trek portal's searchItems API
  2. Constructed tile URLs for every catalog entry at zoom level 0
  3. Fetched headers and verified Content-Length > 500 bytes
  4. Filtered the results to only layers with real imagery

The results were sobering:

BodyCatalog EntriesVerified Real TilesSuccess Rate
Moon11332.7%
Mars8944.5%
Mercury14536%
Vesta141071%
Ceres11100%

Out of 231 catalog entries, only 25 had actual tile imagery. The rest were either raw data products without tile pyramids, special-project datasets, or entries that once had tiles but no longer do.

Phase 3: The Viewer

With the verified layer list in hand, the agent built a CesiumJS-based viewer. Key design decisions:

No Server Required

Since Trek APIs lack CORS, all layer metadata is baked into the HTML at build time. The viewer is a single static file with no backend dependencies. This means it can be deployed to any static host โ€” we used Cloudflare Pages.

Body-Specific Ellipsoids

Each planetary body has a different radius. The viewer creates a custom Cesium.Ellipsoid per body:

This means Mars appears large, Vesta appears tiny โ€” physically accurate scaling.

Equatorial Camera Positioning

The initial view places the camera on the equatorial plane at 0ยฐ longitude, looking toward the center. The camera height above surface is configurable per body (we settled on ~12,000 km for consistent framing).

Verified Layer Categories

Real layers are organized by category:

Moon (3 layers): LRO WAC Global Mosaic v2, LRO WAC Global Mosaic, Chang'e 2 CCD Mosaic

Mars (4 layers): Viking MDIM2.1 Color Mosaic, MOLA Color Hillshade, MOLA+HRSC Color Hillshade Blend, MOLA+HRSC Hillshade Blend

Mercury (5 layers): 4 MESSENGER MDIS mosaics (BDR, LOI, MD3 Color, Enhanced Color), USGS Color Hillshade

Vesta (10 layers): 3 Dawn FC imagery mosaics, 2 topographic hillshades, 4 GRaND mineralogy maps, 1 geologic map

Ceres (1 layer): Dawn FC HAMO Color Hillshade

Auto-Rotate Toggle

A control panel toggle switch enables slow auto-rotation (2ยฐ/second). The spin is implemented using Cesium's clock.onTick with delta-time for frame-rate independence, and properly supports toggle-off via callback removal.

Phase 4: Deployment

The viewer is deployed to Cloudflare Pages at a /treks/ subdirectory, preserving existing content at the root domain.

๐Ÿš€ Launch the Viewer

Lessons Learned

1. HTTP 200 Is Not Enough

When working with tile services, always verify actual payload content, not just status codes. Many services return placeholder tiles with valid HTTP responses.

2. Catalogs Are Not Indexes

A data catalog listing 100+ datasets doesn't mean 100+ are visualizable. Many are raw data, special projections, or deprecated products. Build-time verification is essential.

3. CORS Is a Deployment Constraint

When APIs lack CORS, you can't do runtime discovery. Pre-baking verified data into the client becomes a necessity, not an optimization.

4. Per-Body Configuration Matters

Planetary viewers need per-body ellipsoids, camera distances, and tiling schemes. A one-size-fits-all Earth-centric configuration produces wrong results for small bodies like Vesta.

Try It

๐Ÿ”— Live viewer: hermes-nasa.pages.dev/treks/

Select a body from the dropdown, expand a category, and click a layer to load it. Toggle auto-rotate to watch the planet spin. All 25 verified layers are baked in and ready to view โ€” no server required, no API keys, no CORS proxies.

Technical Stack


Open the Viewer