Skip to content

Repository files navigation

☉ SolSisSim

A lightweight, mathematically accurate 3D solar system simulator that runs entirely in the browser. Built with Three.js + TypeScript + Vite — no backend, no game engine, no texture downloads.

Features

  • Real orbital mechanics — positions are computed by solving Kepler's equation from NASA JPL Keplerian elements (J2000 epoch with secular rates, valid 1800–2050 AD), not by numeric physics integration.

  • Sun, 8 planets and 16 major moons with hierarchical orbits — moons are propagated in their parent planet's local frame:

    • Earth: the Moon
    • Mars: Phobos, Deimos
    • Jupiter: Io, Europa, Ganymede, Callisto
    • Saturn: Titan
    • Uranus: Miranda, Ariel, Umbriel, Titania, Oberon
    • Neptune: Proteus, Triton, Nereid
  • Faithful satellite geometry — the Uranian moons ride in Uranus's equatorial plane, which its 97.8° tilt swings almost perpendicular to the ecliptic; Triton orbits Neptune retrograde (inclination 156.9°); and Nereid runs one of the most eccentric orbits known (e = 0.75), a genuine stress test for the Kepler solver.

  • Orbital paths rendered as osculating-orbit lines that follow their parent body and regenerate as elements drift over centuries.

  • Axial tilt & sidereal rotation for every body (Venus spins retrograde, Uranus rolls on its side).

  • Real surface textures on every body that has ever been mapped — the Sun, all 8 planets and 15 of the 16 moons — loaded asynchronously with a color fallback so the first frame never waits on them. Nereid has never been resolved beyond a few pixels, so it wears a generic space-rock texture: representative of its class, not a map of Nereid.

  • Non-spherical small moons — bodies too small for self-gravity to pull them round are built as triaxial ellipsoids with procedural relief breaking up the silhouette: Phobos (27 × 22 × 19 km), Deimos (15 × 12 × 11 km), Proteus (424 × 396 × 390 km, right at the roundness limit) and Nereid. Phobos and Deimos additionally drive a bump map from their NASA mosaics so crater relief responds to sunlight.

  • Synchronous rotation — every tidally locked moon keeps the same face toward its planet, which is what makes the elongated ones look right.

  • Cloud and haze decks on the bodies that have an atmosphere, drawn as their own shell above the surface so each can carry its own texture, opacity and rotation rate:

    • Venus — an opaque sulfuric-acid cloud deck hiding the Magellan radar surface beneath, and super-rotating: the deck circles the planet in about 4 days while Venus itself takes 243.
    • Titan — the thick orange smog that makes its Cassini-mapped surface invisible in visible light.
    • Triton — a faint nitrogen haze, kept very subtle to match an atmosphere about 1/70,000th the pressure of Earth's.

    Io, Europa, Callisto and others carry only tenuous exospheres — far too thin to read as cloud — so they are left bare. Earth is deliberately not given a cloud deck here; it would be one config entry if wanted.

  • Ring systems for all four giant planets — Saturn uses a real ring strip texture with alpha; Jupiter, Uranus and Neptune use procedural strips baked from their actual ring band structure (radii from the planets' real ring data).

  • Physically-motivated lighting — sunlight intensity is set to π so a Lambertian surface of albedo 1 reflects exactly 1.0 at the sub-solar point, meaning nothing clips and surface maps keep full contrast. Filmic (ACES) tone mapping rolls off the sunlit limb, a cool ambient fill keeps night sides readable, and the Sun carries an additive corona that is excluded from tone mapping so it reads as a light source.

  • Detailed telemetry HUD — four sections covering position (distance to Sun and Earth, light travel time, ecliptic longitude/latitude, solar irradiance), motion (orbital velocity, true/mean/eccentric anomaly), the full set of osculating orbital elements (a, e, i, Ω, ω, periapsis, apoapsis, period) and physical properties (mass, surface gravity, escape velocity, axial tilt, sidereal rotation, ring extent).

  • Time control — pause, reverse, and scale time from real-time up to 1 year per second (opens at 1 hour per second); jump to any past or future date instantly.

  • Camera — free pan/zoom/orbit; click a body or pick it from the menu to lock focus and track it as it moves.

  • Telemetry HUD — name, distance to the Sun, orbital velocity (vis-viva) and orbital period (Kepler's third law) for the selection.

  • Dual scale modes — distances are always 1:1. In "Visual" mode the Sun and planets use a power-law radius scale for visibility, while moons are true to scale relative to their parent (the Moon really is 27% of Earth's rendered radius). "True" mode renders everything at honest 1:1 proportions.

  • Camera starts framed on Earth; ?focus=<id> opens on any body.

Running

npm install
npm run dev       # dev server with HMR
npm run build     # type-check + production build into dist/
npm run preview   # serve the production build locally

The production build is fully static — deploy dist/ to GitHub Pages, Vercel, Netlify or any static host.

Architecture

The math layer is strictly decoupled from rendering (NFR-3.1): nothing in src/math or src/sim imports Three.js, so the ephemeris can be tested headlessly.

src/
├── data/            Static ephemeris JSON + its TypeScript types
│   └── bodies.json    JPL Keplerian elements, physical data, colors
├── math/            Pure math — no rendering dependencies
│   ├── kepler.ts      Kepler solver, element propagation, vis-viva
│   ├── time.ts        Julian date / J2000 century conversions
│   └── vec3.ts        Minimal vector helpers
├── sim/             Simulation model — no rendering dependencies
│   ├── clock.ts       Global simulated clock (scalable, settable)
│   └── system.ts      Body tree, hierarchical position updates
├── render/          Three.js layer
│   ├── sceneManager.ts  Renderer, camera, lights, starfield, controls
│   ├── bodyVisual.ts    Meshes, tilt/spin, orbit lines, rings
│   ├── shapes.ts        Triaxial + relief geometry for irregular moons
│   ├── textures.ts      Texture loading + procedural ring strips
│   └── scale.ts         Dual-scale (visual/true) management
├── ui/              DOM overlay
│   ├── hud.ts         Telemetry panel + sim date readout
│   └── controls.ts    Time, focus, date-travel and scale controls
└── main.ts          Wiring + frame loop

Accuracy notes

  • Planets use the JPL Approximate Positions of the Planets formulation: Keplerian elements at J2000 plus linear rates per Julian century. Within 1800–2050 this is good to roughly arcminute level; outside that range positions extrapolate smoothly but degrade.
  • Moons use mean orbital elements (approximate ephemeris). Semi-major axis, eccentricity, inclination and period are real published values — each moon's period is cross-checked to agree both with Kepler's third law and with its own mean-longitude rate — but the J2000 mean longitudes are not Horizons-grade, so where a moon sits along its orbit may be off by some fraction of a period. Orbit geometry is trustworthy; precise satellite phase and mutual events are not.
  • Coordinate frame is the J2000 ecliptic; moon orbits given relative to their parent's equator are tilted by the parent's obliquity as an approximation of the true pole orientation.
  • Axial tilt is applied about a fixed scene axis (pole precession and exact pole right ascension are not modeled).
  • Sunlight is rendered without inverse-square falloff. True attenuation across 0.39–30 AU would make Neptune ~6000x dimmer than Mercury and effectively black, so each body is lit as though at its own distance; the real irradiance is reported in the HUD (1361 W/m² at Earth, 1.5 W/m² at Neptune).
  • In Visual mode, moons smaller than 3.5% of their parent's radius are eased upward by a power law so they stay visible and clickable — Phobos is truly 0.33% of Mars and would otherwise render sub-pixel. The easing is monotonic, so Phobos still renders larger than Deimos, and any moon at or above the threshold (the Moon, Titan, Ganymede, Callisto) is left exactly true to scale.
  • The clock uses UTC and ignores the ~minute-level UTC↔TT offset, which is irrelevant at visual scales.

Performance

  • Production bundle: ~589 kB JS (~150 kB gzip) + 3.1 kB CSS — well under the 2 MB budget (which excludes texture assets per the SRS). Surface maps total ~3 MB in public/textures/ and load asynchronously after the first frame; bodies render with base colors until each map arrives.
  • Static geometry (unit spheres scaled per body, pre-allocated orbit-line buffers) and a single point light keep frame cost low; orbit lines only regenerate when elements drift ≥ 25 years from their last build.

Texture credits

Planet and ring maps by James Hastings-Trew (Planet Pixel Emporium), obtained via the threex.planets repository. Free to use in projects; see the source site for redistribution terms.

Moon and cloud maps come from three further sources, all derived from NASA mission data:

  • Phobos, Deimos, Io, Europa, Ganymede, Callisto, and the Venus surfaceNASA 3D Resources (public domain), from Viking, Magellan and Galileo imagery.
  • Titan's surface — Steve Albers' cylindrical map, compiled from Cassini data.
  • Ariel, Miranda, Umbriel, Titania, Oberon, Triton, Proteus, Titan's haze, and Nereid's generic rockCelestiaContent, from Voyager 2 and Cassini imagery reprojected by Paul Schenk / Ted Stryk (moons), Gordan Ugarković / Kevin M. Gill (Titan haze) and cubicApocalypse (generic asteroid). These are CC-BY-3.0, CC-BY-4.0 and CC-BY-SA-4.0, not public domain — they require attribution, and the share-alike ones carry conditions if you redistribute modified versions. Note that the one-sided maps listed above are shipped modified, with their unimaged hemispheres reconstructed.

Venus's cloud deck reuses the Planet Pixel Emporium Venus map, which is a cloud-top view rather than a surface map.

All moon maps are downscaled to 1024×512, ample for bodies that never fill much of the frame, keeping the whole texture set at ~3 MB.

Caveats on the imagery itself:

  • The mosaics are contrast-stretched for visibility, so dark bodies (Phobos and Deimos, albedo ~0.07) look far brighter than reality.
  • Voyager 2 only imaged one hemisphere of the Uranian moons and part of Triton — the rest has never been photographed by anything. Published mosaics leave those regions as flat neutral fill, which renders as a blank half-moon, so the imaged terrain is mirrored across the coverage boundary to fill them (scripts note below). Roughly 40–55% of those five Uranian maps and Triton's map is therefore reconstruction, not data — plausible in character but not a record of what is actually there. The mirror is taken about a single global latitude and crossfaded into a longitude-shifted copy, so it neither streaks along the ragged coverage edge nor reads as an obvious reflection, and it fades to smooth toward the unseen pole.
  • Nereid's figure is unknown — it has never been resolved — so its triaxial axes are illustrative, chosen only to match its measured mean radius of 178.5 km.

URL parameters

  • ?focus=<body id> — start with a body framed, e.g. ?focus=saturn.

About

A lightweight, mathematically accurate 3D solar system simulator that runs entirely in the browser.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages