Wrap seventeen moons and dwarf planets in the missions' own maps, grey where no probe looked

Audit #40. Io, Titan and Pluto had square disc photographs (40.5, 42.6 and
42.9% black sky) that PR #33 unlisted, and every other moon or dwarf planet
fell through to the derived surface. Seventeen of them are now wrapped in
public-domain global mosaics from USGS Astrogeology and the NASA PDS: Phobos
(Viking), Io, Europa, Ganymede, Callisto (Galileo and Voyager), Mimas,
Enceladus, Tethys, Dione, Rhea, Titan, Iapetus, Phoebe (Cassini), Triton
(Voyager 2), Ceres (Dawn), Pluto and Charon (New Horizons). io.jpg, titan.jpg
and pluto.jpg are replaced by maps under the same names.

Every file is simple cylindrical over 360 by 180 degrees, with longitude 0 in
the middle and east to the right, the frame MAP_TO_BODY puts on the IAU body
frame. Processing: the source's no-data pixels (0 in every band) become one
flat grey, the mean of the mapped surface, never invented terrain; area
downsampling to 2048x1024 for bodies over 1 000 km in radius and 1024x512
for the rest; half a turn where the source is centred on 180; JPEG q85
(Europa q82). Largest file 386 KB (Europa); 3.5 MB for all seventeen.

The centre was read from each GeoTIFF's central meridian and left-edge tie
point, not from its label: Rhea's and Enceladus's labels say CENTER_LONGITUDE
= 180 over images centred on 0. Taken from the label, Rhea came out half a
turn round, which the seam it left down the middle of the map gave away.
Each map was then checked by eye against the IAU Gazetteer: Pele and Loki on
Io, Pwyll on Europa, Osiris and Tros on Ganymede, Valhalla and Asgard on
Callisto, Herschel on Mimas, Ali Baba and Aladdin on Enceladus, Odysseus on
Tethys, Creusa on Dione, Inktomi on Rhea, Xanadu, Shangri-La and Belet on
Titan, Cassini Regio on Iapetus, Jason on Phoebe, Occator and Haulani on
Ceres, Stickney on Phobos, Sputnik Planitia and Cthulhu on Pluto, Mordor
Macula on Charon, Leviathan Patera on Triton.

Unmapped share, now grey: Triton 38.6%, Charon 34.0%, Pluto 31.9%, Phoebe
20.4%, the Galilean polar gaps 3.6-4.3%, Ceres's south pole 3.6%, the rest
under 0.2%. Pixels darker than 8 of 255: at most 0.55% (Charon's Mordor
Macula, Pluto's Cthulhu), against the 20-43% black sky of the photographs
PR #33 dropped.

Left out, and said so in src/assets/textures/README.md: Deimos, whose only
cylindrical map (Stooke, Viking) has no label for its longitude direction and
on which neither Voltaire nor Swift could be found to settle it; the five
Uranian moons, whose only maps (Schenk 2020, USRA) carry no licence; Hyperion,
Nereid, Proteus, Eris, Haumea and Makemake, which have no photographic
simple-cylindrical map.

Source URLs, credits, licences, processing and each measurement are in the new
src/assets/textures/README.md; the root README now points there and counts
twenty-seven bodies in real photography. texture-catalog.spec.ts checks that
the seventeen are registered and that Deimos, the Uranian moons, Hyperion and
Eris are not. Unit suite 790 -> 792 tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-24 23:41:28 +02:00
co-authored by Claude Opus 5.5
parent 76fb38665f
commit 302fa963ad
21 changed files with 131 additions and 10 deletions
+6 -4
View File
@@ -134,9 +134,11 @@ its own readout, so a stale image is visible as one.
### On surfaces that were never photographed
Fifteen bodies here have a real photograph. Everything else does not, and never will on current
instruments: no exoplanet's surface has ever been imaged, and a few of the solar system's own
moons have no usable map in this asset set either.
Twenty-seven bodies here are wrapped in real photography: the Sun, the eight planets and the Moon,
and seventeen moons and dwarf planets in mission mosaics, grey where no probe has seen them
(`src/assets/textures/README.md`). Everything else is not, and no exoplanet ever will be on
current instruments: none has had its surface imaged. Deimos, the five large moons of Uranus and
a few small bodies have no map in this asset set either.
Those bodies get a surface reasoned from what *has* been measured, in a chain that is worth
following because every link is standard:
@@ -327,4 +329,4 @@ Star catalogue: [HYG database](https://github.com/astronexus/HYG-Database) (Hipp
Bright Star, Gliese) — 68 388 stars within 250 pc. Solar-system ephemerides: NASA/JPL Horizons. Exoplanets: NASA Exoplanet
Archive. Deep-sky objects: [OpenNGC](https://github.com/mattiaverga/OpenNGC). Body and skybox
imagery: NASA/JPL/USGS public domain and Solar System Scope (CC BY 4.0) — per-file provenance
is recorded in `src/app/shared/rendering/texture-catalog.ts`.
is recorded in `src/assets/textures/README.md`.
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { bodyTexturePath } from './texture-catalog';
describe('bodyTexturePath', () => {
it('wraps the moons and dwarf planets that have a mission mosaic in it', () => {
const mapped = ['phobos', 'io', 'europa', 'ganymede', 'callisto', 'mimas', 'enceladus', 'tethys', 'dione', 'rhea', 'titan', 'iapetus', 'phoebe', 'triton', 'ceres', 'pluto', 'charon'];
for (const id of mapped) {
expect(bodyTexturePath(id)).toBe(`assets/textures/bodies/${id}.jpg`);
}
});
it('leaves the bodies with no map it could check to their derived surface', () => {
for (const id of ['deimos', 'miranda', 'ariel', 'umbriel', 'titania', 'oberon', 'hyperion', 'eris']) {
expect(bodyTexturePath(id)).toBeUndefined();
}
});
});
+28 -6
View File
@@ -10,15 +10,20 @@ import * as THREE from 'three/webgpu';
* `procedural-planet-texture.ts`, which derives a surface from the body's own measured size,
* mass, orbit and host star instead.
*
* Io, Pluto, Titan and Deimos used to be listed with the square photographs of them in
* `assets/textures/bodies/`: pictures of a lit disc against black sky, not maps. Wrapped round a
* sphere they put black sky on a fifth to a third of the surface, in a band up to 57 degrees wide
* across the equator that the spin then swept past the camera. They are left out until a real map
* of each is added.
* Io, Pluto, Titan and Deimos used to be listed with square photographs of them: pictures of a
* lit disc against black sky, not maps, which wrapped round a sphere put black sky on a fifth to a
* third of the surface. Io's, Pluto's and Titan's are now the global mosaics the moons below are
* drawn from; Deimos's photograph is still in the folder, unlisted, for want of a map whose
* longitudes could be checked.
*
* Provenance (CC BY 4.0 Solar System Scope, via Wikimedia Commons — see each file's Commons page
* for the original credit line): mercury/venus/earth/mars/saturn/uranus/neptune/moon/sun/
* saturn-ring/skybox — Solar System Scope texture pack; jupiter — Solar System Scope 8k pack.
*
* The moons', Ceres's and Pluto's are public-domain mission mosaics from USGS Astrogeology and the
* PDS, each put in the same frame — longitude 0 in the middle, east to the right — and each
* measured, in `assets/textures/README.md`. Where a probe saw only part of a body (Pluto, Charon,
* Triton, Phoebe, the Galilean poles), the rest is a flat grey, never invented terrain.
*/
const BODY_TEXTURE_PATHS: Record<string, string> = {
mercury: 'assets/textures/bodies/mercury.jpg',
@@ -29,7 +34,24 @@ const BODY_TEXTURE_PATHS: Record<string, string> = {
saturn: 'assets/textures/bodies/saturn.jpg',
uranus: 'assets/textures/bodies/uranus.jpg',
neptune: 'assets/textures/bodies/neptune.jpg',
moon: 'assets/textures/bodies/moon.jpg'
moon: 'assets/textures/bodies/moon.jpg',
phobos: 'assets/textures/bodies/phobos.jpg',
io: 'assets/textures/bodies/io.jpg',
europa: 'assets/textures/bodies/europa.jpg',
ganymede: 'assets/textures/bodies/ganymede.jpg',
callisto: 'assets/textures/bodies/callisto.jpg',
mimas: 'assets/textures/bodies/mimas.jpg',
enceladus: 'assets/textures/bodies/enceladus.jpg',
tethys: 'assets/textures/bodies/tethys.jpg',
dione: 'assets/textures/bodies/dione.jpg',
rhea: 'assets/textures/bodies/rhea.jpg',
titan: 'assets/textures/bodies/titan.jpg',
iapetus: 'assets/textures/bodies/iapetus.jpg',
phoebe: 'assets/textures/bodies/phoebe.jpg',
triton: 'assets/textures/bodies/triton.jpg',
ceres: 'assets/textures/bodies/ceres.jpg',
pluto: 'assets/textures/bodies/pluto.jpg',
charon: 'assets/textures/bodies/charon.jpg'
};
/** The Sun isn't a `BodyRecord` (it's the system's star marker), so it's looked up separately. */
+79
View File
@@ -0,0 +1,79 @@
# Body textures
`bodies/` holds the surface maps `src/app/shared/rendering/texture-catalog.ts` wraps round the
bodies, keyed by their ids in `bodies.json`. Every map is simple cylindrical (equirectangular),
360 by 180 degrees, twice as wide as tall, with **longitude 0 in the middle and east to the right**,
which is the frame `MAP_TO_BODY` in `body-orientation.ts` puts onto the IAU body frame. The IAU
prime meridian (W) then turns longitude 0 to where it belongs at any date.
## Solar System Scope (CC BY 4.0)
`mercury`, `venus`, `earth`, `mars`, `saturn`, `uranus`, `neptune`, `moon`, `sun`, `saturn_ring`
and the skybox come from the Solar System Scope texture pack, and `jupiter` from its 8k pack, via
Wikimedia Commons. See each file's Commons page for the original credit line.
## Mission mosaics (public domain)
Each was downloaded from the URL below and processed the same way (script:
`build_maps.py`, kept with the measurements outside the repository):
1. Pixels the source leaves unmapped (value 0 in every band, its no-data value) are set to one
flat grey: the mean of the mapped surface. They are never filled with invented terrain.
2. Downsampled by area averaging (PIL `BOX`) to 2 048 by 1 024 for bodies over 1 000 km in radius
and 1 024 by 512 for the rest.
3. Rolled half a turn where the source is centred on longitude 180, so longitude 0 is in the
middle. Every source already has east to the right. The centre was read from each file's
GeoTIFF tags (central meridian plus the tie point of its left edge), not from its label: Rhea's
and Enceladus's labels say `CENTER_LONGITUDE = 180` over an image centred on 0.
4. Saved as JPEG at quality 85 (Europa 82, to stay under 400 KB), greyscale where the source is.
Each was then checked by eye against the IAU Gazetteer: the named feature lies where its
coordinates put it on the processed map. "Black" is the share of pixels darker than 8 of 255 after
processing; the disc photographs dropped in PR #33 were 20-43% black sky.
| Map | Source | Mission, credit | Checked against | Unmapped (grey) | Black | Size |
| --- | --- | --- | --- | --- | --- | --- |
| `phobos.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Phobos_Viking_Mosaic_40ppd_DLRcontrol.tif) Phobos Viking Mosaic 40ppd (DLR controlled) | Viking Orbiter, with Mars Express images; P. Stooke after Simonelli et al. 1993, PDS Stooke Small Bodies Maps | Stickney (1 N, 49 W) | 0.03% | 0.008% | 1024x512, 119 KB |
| `io.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Io_GalileoSSI-Voyager_Global_Mosaic_ClrMerge_1km.tif) Io Galileo SSI-Voyager Global Mosaic, colour merge, 1 km | Galileo SSI and Voyager; USGS Astrogeology | Pele, Loki, Prometheus | 0.02% | 0% | 2048x1024, 283 KB |
| `europa.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Europa_Voyager_GalileoSSI_global_mosaic_500m.tif) Europa Voyager-Galileo SSI Global Mosaic 500 m | Voyager and Galileo SSI; Archinal et al., USGS | Pwyll (25 S, 271 W) | 4.33% (polar gaps) | 0% | 2048x1024, 386 KB |
| `ganymede.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Ganymede_Voyager_GalileoSSI_Global_ClrMosaic_1435m.tif) Ganymede Voyager-Galileo SSI Colour Global Mosaic 1.4 km | Voyager and Galileo SSI; USGS | Osiris, Tros, Galileo Regio | 3.63% (polar gaps) | 0% | 2048x1024, 363 KB |
| `callisto.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Callisto_Voyager_GalileoSSI_global_mosaic_1km.tif) Callisto Voyager-Galileo SSI Global Mosaic 1 km | Voyager and Galileo SSI; USGS | Valhalla, Asgard | 3.90% (polar gaps) | 0% | 2048x1024, 344 KB |
| `mimas.jpg` | [PDS](https://planetarydata.jpl.nasa.gov/img/data/carto/coiss_3006/extras/full/images/SM_1M_0_0_SIMP.IMG.png) COISS_3006, Cassini ISS cartographic map of Mimas | Cassini ISS; DLR and FU Berlin (Roatsch et al.), NASA PDS | Herschel (1 N, 112 W) | 0.01% | 0.042% | 1024x512, 155 KB |
| `enceladus.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Enceladus_Cassini_mosaic_global_110m.tif) Enceladus Cassini Global Mosaic 110 m | Cassini ISS; NASA/JPL/Space Science Institute | Ali Baba, Aladdin, Salih | 0.06% | 0.020% | 1024x512, 168 KB |
| `tethys.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Tethys_Cassini_mosaic_global_293m.tif) Tethys Cassini Global Mosaic 293 m | Cassini ISS; NASA/JPL/Space Science Institute | Odysseus, Penelope | 0.04% | 0.009% | 1024x512, 182 KB |
| `dione.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Dione_Cassini_Voyager_mosaic_global_154m.tif) Dione Cassini-Voyager Global Mosaic 154 m | Cassini ISS and Voyager; NASA/JPL/Space Science Institute | Creusa, Evander | 0.18% | 0.011% | 1024x512, 195 KB |
| `rhea.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Rhea_Cassini_Voyager_mosaic_global_417m.tif) Rhea Cassini-Voyager Global Mosaic 417 m | Cassini ISS and Voyager; NASA/JPL/Space Science Institute | Inktomi, Tirawa | 0% | 0.003% | 1024x512, 128 KB |
| `titan.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Titan_ISS_P19658_Mosaic_Global_4km.tif) Titan Cassini ISS Global Mosaic 4 km (938 nm, through the haze) | Cassini ISS; NASA/JPL-Caltech/SSI | Xanadu, Shangri-La, Belet | 0.02% | 0.078% | 2048x1024, 294 KB |
| `iapetus.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Iapetus_Cassini_Voyager_mosaic_global_783m.tif) Iapetus Cassini-Voyager Global Mosaic 783 m | Cassini ISS and Voyager; NASA/JPL/Space Science Institute | Cassini Regio (leading side, 90 W), Engelier | 0% | 0.019% | 1024x512, 159 KB |
| `phoebe.jpg` | [PDS](https://planetarydata.jpl.nasa.gov/img/data/carto/coiss_3001/extras/full/images/SP_1M_0_0_SIMP.IMG.png) COISS_3001, Cassini ISS cartographic map of Phoebe | Cassini ISS; DLR and FU Berlin (Roatsch et al.), NASA PDS | Jason (16 N, 318 W) | 20.41% (the north) | 0.344% (shadows) | 1024x512, 78 KB |
| `triton.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Triton_Voyager2_ClrMosaic_GlobalFill_600m.tif) Triton Voyager 2 Global Colour Mosaic 600 m (PIA18668) | Voyager 2; P. Schenk, NASA/JPL/LPI | Leviathan Patera; southern cap | 38.59% (the north Voyager 2 never saw) | 0% | 2048x1024, 205 KB |
| `ceres.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Ceres_Dawn_FC_DLR_global_20ppd_Oct2015.tif) Ceres Dawn FC Global Mosaic, HAMO, Oct 2015 | Dawn Framing Camera; DLR, NASA/JPL | Occator (20 N, 239 E), Haulani (6 N, 11 E) | 3.60% (south pole) | 0.049% | 1024x512, 165 KB |
| `pluto.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Pluto_NewHorizons_Global_Mosaic_300m_Jul2017_8bit.tif) Pluto New Horizons LORRI-MVIC Global Mosaic 300 m | New Horizons; NASA/JHUAPL/SwRI/LPI | Sputnik Planitia (175 E, across 180), Cthulhu, Burney | 31.92% (the south, in winter dark in 2015) | 0.501% (Cthulhu) | 2048x1024, 297 KB |
| `charon.jpg` | [USGS](https://asc-pds-services.s3.us-west-2.amazonaws.com/mosaic/Charon_NewHorizons_Global_Mosaic_300m_Jul2017_8bit.tif) Charon New Horizons LORRI-MVIC Global Mosaic 300 m | New Horizons; NASA/JHUAPL/SwRI/LPI | Mordor Macula (north pole), Organa | 34.02% (the south) | 0.549% (Mordor) | 1024x512, 72 KB |
Licence: every source above is NASA mission imagery, published by USGS Astrogeology or the NASA
PDS. The USGS metadata gives access constraints of "public domain" (Io, Triton, Enceladus,
Tethys, Dione, Rhea, Iapetus, Ganymede, Phobos) or "none" (the rest), with the use constraint
"please cite authors", which the credits column does. Io's colour is Galileo's violet, green and 756 nm
filters, which USGS says the eye would see "similar but much more muted"; Ganymede's is the
Galileo and Voyager colour mosaic; Triton's is orange, violet and ultraviolet shown as red, green
and blue (Smith et al. 1989). Phoebe is irregular (a 106.6 km sphere here), and its map keeps the
deep shadows of a single flyby. Phobos's source notes that where images lit
from opposite sides meet, the seam was blended for appearance, not geometry.
Longitudes follow each body's IAU prime meridian, which the checks above confirm on the maps. For
Pluto and Charon that is the right-hand-rule pole of the WGCCRE 2015 report, which New Horizons'
maps also use: the Charon-facing hemisphere is centred on longitude 0 and Sputnik Planitia sits on
the far side, near 180.
## Left out
- **Deimos.** `deimos.jpg` is a square disc photograph (32.6% black sky), not a map, and is not
listed. The only cylindrical map found, `wms_basemaps/Deimos/deimoscyl4.jpg` (Stooke, Viking), has
no label giving its longitude direction, and neither Voltaire nor Swift, the craters near its
prime meridian, could be found on it to settle it.
- **Miranda, Ariel, Umbriel, Titania, Oberon.** Voyager 2 saw only their southern hemispheres,
and no public-domain map of them exists at USGS or the PDS. The best maps (P. Schenk 2020, USRA
repository, hdl.handle.net/20.500.11753/1687) carry no licence.
- **Hyperion, Nereid, Proteus, Eris, Haumea, Makemake.** No public-domain photographic map in
simple cylindrical projection (Hyperion's USGS basemap is a relief rendering, not a mosaic).
Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB