diff --git a/assets/textures/1k_callisto.jpg b/assets/textures/1k_callisto.jpg new file mode 100644 index 0000000..739456d Binary files /dev/null and b/assets/textures/1k_callisto.jpg differ diff --git a/assets/textures/1k_charon.jpg b/assets/textures/1k_charon.jpg new file mode 100644 index 0000000..0dab91b Binary files /dev/null and b/assets/textures/1k_charon.jpg differ diff --git a/assets/textures/1k_europa.jpg b/assets/textures/1k_europa.jpg new file mode 100644 index 0000000..808e70e Binary files /dev/null and b/assets/textures/1k_europa.jpg differ diff --git a/assets/textures/1k_ganymede.jpg b/assets/textures/1k_ganymede.jpg new file mode 100644 index 0000000..71a2171 Binary files /dev/null and b/assets/textures/1k_ganymede.jpg differ diff --git a/assets/textures/1k_io.jpg b/assets/textures/1k_io.jpg new file mode 100644 index 0000000..817c70e Binary files /dev/null and b/assets/textures/1k_io.jpg differ diff --git a/assets/textures/1k_phobos.jpg b/assets/textures/1k_phobos.jpg new file mode 100644 index 0000000..2ead78e Binary files /dev/null and b/assets/textures/1k_phobos.jpg differ diff --git a/assets/textures/1k_titan.jpg b/assets/textures/1k_titan.jpg new file mode 100644 index 0000000..f556fb7 Binary files /dev/null and b/assets/textures/1k_titan.jpg differ diff --git a/assets/textures/1k_triton.jpg b/assets/textures/1k_triton.jpg new file mode 100644 index 0000000..67c8be0 Binary files /dev/null and b/assets/textures/1k_triton.jpg differ diff --git a/assets/textures/CREDITS.md b/assets/textures/CREDITS.md index 89c4ae6..cdc2d30 100644 --- a/assets/textures/CREDITS.md +++ b/assets/textures/CREDITS.md @@ -1,7 +1,9 @@ # Texture credits -All planet, moon, Sun, ring and starfield maps in this directory are from the -**Solar System Scope** texture pack and are used under **CC BY 4.0**. +## `2k_*` planet, Sun, ring & starfield maps — Solar System Scope (CC BY 4.0) + +The **`2k_`** planet, Moon, Sun, ring and starfield maps in this directory are from +the **Solar System Scope** texture pack and are used under **CC BY 4.0**. - Source: https://www.solarsystemscope.com/textures/ - License: Creative Commons Attribution 4.0 International (CC BY 4.0) @@ -28,6 +30,29 @@ Downloaded 2026-07-16 at 2k resolution: Attribution also appears in the app's HUD footer, as CC BY requires. +## `1k_*` moon maps — USGS Astrogeology / NASA (public domain) + +Added wave 2 (PERIHELION · SELENE). Global equirectangular (simple-cylindrical) +mosaics from the **USGS Astrogeology Science Center** (`planetarymaps.usgs.gov`), +built from NASA mission imagery. USGS/NASA-produced planetary data are in the +**U.S. public domain** (no copyright asserted). Each was downloaded as a GeoTIFF +and downscaled to 1024×512 JPEG with `sips` (Europa re-encoded at q70 to stay +under budget). Downloaded 2026-07-16. + +| File | Body | Mission / instrument | Source (USGS Astrogeology) | License | +|------|------|----------------------|----------------------------|---------| +| 1k_io.jpg | Io | Galileo SSI + Voyager, color-merge | `.../mosaic/Io_Galileo_SSI_Global_Mosaic_ClrMerge_1km.tif` | Public domain | +| 1k_europa.jpg | Europa | Voyager + Galileo SSI, global 500 m | `.../mosaic/Europa_Voyager_GalileoSSI_global_mosaic_500m.tif` | Public domain | +| 1k_ganymede.jpg | Ganymede | Voyager + Galileo SSI, global color 1435 m | `.../mosaic/Ganymede_Voyager_GalileoSSI_Global_ClrMosaic_1435m.tif` | Public domain | +| 1k_callisto.jpg | Callisto | Voyager + Galileo SSI, global 1 km | `.../mosaic/Callisto_Voyager_GalileoSSI_global_mosaic_1km.tif` | Public domain | +| 1k_titan.jpg | Titan | Cassini ISS, global mosaic (PIA19658), 4 km | `.../mosaic/Titan_ISS_P19658_Mosaic_Global_4km.tif` | Public domain | +| 1k_triton.jpg | Triton | Voyager 2, global color mosaic (gap-filled) 600 m | `.../mosaic/Triton_Voyager2_ClrMosaic_GlobalFill_600m.tif` | Public domain | +| 1k_charon.jpg | Charon | New Horizons LORRI/MVIC, global mosaic 300 m (Jul 2017) | `.../mosaic/Charon_NewHorizons_Global_Mosaic_300m_Jul2017_8bit.tif` | Public domain | +| 1k_phobos.jpg | Phobos | Mars Express HRSC-SRC, global mosaic 16 ppd | `.../mosaic/Phobos_ME_SRC_Mosaic_Global_16ppd.tif` | Public domain | + +Host base URL: `https://planetarymaps.usgs.gov/mosaic/` (served from the USGS +`asc-pds-services` bucket). USGS terms: . + **Truth boundary (brief §7b):** these are the *real data* textures — real worlds get real maps. The stylized grimoire portraits in `../art/grimoire/` are the *aesthetic* layer (generated art), kept visually and directorially separate. diff --git a/js/bodies.js b/js/bodies.js index c34ff36..94593aa 100644 --- a/js/bodies.js +++ b/js/bodies.js @@ -62,18 +62,18 @@ export const BODIES = { parent: 'earth', moonOrbit: { aKm: 384400, periodDays: 27.322 } }, phobos: { name: 'Phobos', type: 'moon', radiusKm: 11.27, color: '#8a7c6e', - texture: null, parent: 'mars', moonOrbit: { aKm: 9378, periodDays: 0.319 } }, + texture: '1k_phobos.jpg', parent: 'mars', moonOrbit: { aKm: 9378, periodDays: 0.319 } }, deimos: { name: 'Deimos', type: 'moon', radiusKm: 6.2, color: '#9a8c7a', texture: null, parent: 'mars', moonOrbit: { aKm: 23459, periodDays: 1.262 } }, io: { name: 'Io', type: 'moon', radiusKm: 1821.6, color: '#e8d24b', - texture: null, parent: 'jupiter', moonOrbit: { aKm: 421700, periodDays: 1.769 } }, + texture: '1k_io.jpg', parent: 'jupiter', moonOrbit: { aKm: 421700, periodDays: 1.769 } }, europa: { name: 'Europa', type: 'moon', radiusKm: 1560.8, color: '#c9b79c', - texture: null, parent: 'jupiter', moonOrbit: { aKm: 671034, periodDays: 3.551 } }, + texture: '1k_europa.jpg', parent: 'jupiter', moonOrbit: { aKm: 671034, periodDays: 3.551 } }, ganymede: { name: 'Ganymede', type: 'moon', radiusKm: 2634.1, color: '#9b8e7e', - texture: null, parent: 'jupiter', moonOrbit: { aKm: 1070412, periodDays: 7.155 } }, + texture: '1k_ganymede.jpg', parent: 'jupiter', moonOrbit: { aKm: 1070412, periodDays: 7.155 } }, callisto: { name: 'Callisto', type: 'moon', radiusKm: 2410.3, color: '#6b5f52', - texture: null, parent: 'jupiter', moonOrbit: { aKm: 1882709, periodDays: 16.689 } }, + texture: '1k_callisto.jpg', parent: 'jupiter', moonOrbit: { aKm: 1882709, periodDays: 16.689 } }, mimas: { name: 'Mimas', type: 'moon', radiusKm: 198.2, color: '#c8c8c8', texture: null, parent: 'saturn', moonOrbit: { aKm: 185539, periodDays: 0.942 } }, @@ -86,7 +86,7 @@ export const BODIES = { rhea: { name: 'Rhea', type: 'moon', radiusKm: 763.8, color: '#c4c4c4', texture: null, parent: 'saturn', moonOrbit: { aKm: 527068, periodDays: 4.518 } }, titan: { name: 'Titan', type: 'moon', radiusKm: 2574.7, color: '#d9a441', - texture: null, parent: 'saturn', moonOrbit: { aKm: 1221870, periodDays: 15.945 } }, + texture: '1k_titan.jpg', parent: 'saturn', moonOrbit: { aKm: 1221870, periodDays: 15.945 } }, iapetus: { name: 'Iapetus', type: 'moon', radiusKm: 734.5, color: '#8a7a5e', texture: null, parent: 'saturn', moonOrbit: { aKm: 3560851, periodDays: 79.33 } }, @@ -103,7 +103,7 @@ export const BODIES = { // Triton is retrograde — encoded via the negative-period convention (brief §8). triton: { name: 'Triton', type: 'moon', radiusKm: 1353.4, color: '#d6cfc4', - texture: null, parent: 'neptune', moonOrbit: { aKm: 354759, periodDays: -5.877 } }, + texture: '1k_triton.jpg', parent: 'neptune', moonOrbit: { aKm: 354759, periodDays: -5.877 } }, // ---- Pluto system (small-body epoch elements; texture-less spheres) ---- pluto: { @@ -114,7 +114,7 @@ export const BODIES = { w: 113.76329, ma: 14.86012204, epoch: 2451545.0 }, }, charon: { name: 'Charon', type: 'moon', radiusKm: 606.0, color: '#b3a894', - texture: null, parent: 'pluto', moonOrbit: { aKm: 19591, periodDays: 6.387 } }, + texture: '1k_charon.jpg', parent: 'pluto', moonOrbit: { aKm: 19591, periodDays: 6.387 } }, }; // Ordered planet ids (draw / menu order). diff --git a/js/layers/moons.js b/js/layers/moons.js index 92577f3..aab958b 100644 --- a/js/layers/moons.js +++ b/js/layers/moons.js @@ -6,7 +6,8 @@ // focus, to keep the wide view clean (brief §5). export default function create(ctx) { - const { THREE, scene, CONFIG, ui, scale, bodies, focus, toLocal, effectiveE, makeLabel, registerPick } = ctx; + const { THREE, scene, CONFIG, lib, ui, scale, bodies, focus, toLocal, effectiveE, + makeLabel, registerPick, loadTextureInto } = ctx; const entries = []; for (const id in bodies) { @@ -16,6 +17,7 @@ export default function create(ctx) { const mesh = new THREE.Mesh(new THREE.SphereGeometry(1, 24, 16), mat); mesh.visible = true; scene.add(mesh); + loadTextureInto(mat, b.texture); // NASA/USGS map when present; flat color otherwise (§7 fallback) registerPick(mesh, id); const lbl = makeLabel(mesh, b.name, 'body-label moon'); lbl.obj.visible = false; // CSS2DRenderer honors obj.visible (not div.style.display) @@ -34,6 +36,10 @@ export default function create(ctx) { if (!abs) continue; toLocal(abs, e.mesh.position); e.mesh.scale.setScalar(scale.drawRadius(e.b.radiusKm, effectiveE(e.b.parent))); + // tidal lock: spin at the SAME signed orbital rate main.js positions by, so + // one face stays toward the parent (negative period → retrograde for free). + const theta = 2 * Math.PI * ((jd - lib.J2000_JD) / e.b.moonOrbit.periodDays); + e.mesh.rotation.y = theta + Math.PI; const near = focus.id === e.b.parent || focus.id === e.id; e.lbl.obj.visible = show && near; e.lbl.div.classList.toggle('focused', e.id === focus.id);