Scales and display choices
Space is almost entirely empty. Rendering it “to scale” with everything in the same frame is impossible on any normal display. Each view makes a specific compromise.
The problem, in one table
At true proportional scale with Earth’s orbit drawn at 15 world units:
| Object | True radius (world units) | Where it’d appear |
|---|---|---|
| Sun | 109 | Larger than Mars’s orbit |
| Earth | 1.0 | ✅ |
| Jupiter | 11.2 | Visible dot |
| Neptune | 3.9 | Invisible dot at x=451 |
| Pluto | ~0.7 | Lost in the noise |
At this scale the Sun is bigger than the inner solar system, and Neptune is literally off the screen. That’s why almost every solar-system image you’ve seen — including NASA’s own educational art — cheats on distance, size, or both.
What each view cheats on
solar-system.html — the “pleasing” view
Compresses both sizes and distances so the whole system fits comfortably. Orbital periods (speeds) stay accurate.
Planet Real scaled This view Compression
Mercury 5.85 8 1.37×
Earth 15 (anchor) 15 1×
Jupiter 78 28 0.36×
Neptune 451 58 0.13×
Gas giants are also drawn at ~30% of their true relative radius so they don’t dominate.
Moon systems (Jupiter, Saturn) use an additional moonScale: 0.5 so
that the outermost moon orbit rings (Callisto, Iapetus) stay within their
planet’s gap and do not overlap neighbouring planet orbit rings.
Goal: you can see all 8 planets at once.
scale.html — the “honest” view
Keeps sizes AND distances at their real proportions. Uses 1 unit = 100 000 km, so:
- Sun radius ≈ 7 units
- Earth radius ≈ 0.064 units (invisible from far away)
- Neptune orbit ≈ 45 000 units
Planets are therefore essentially invisible at any zoom that shows more than one of them. The view compensates with pixel-size marker sprites that stay constant on screen regardless of camera distance, so bodies are findable from far out. Zoom in to see the actual sphere.
Goal: you can feel how empty the solar system really is.
galaxy.html — the Milky Way
Compresses the Milky Way (100 000 ly diameter) into a 500-unit-radius disk. The Sun orbits a galactic centre 150 units away, which is a reasonable approximation of its real 26 000 ly from Sagittarius A* at this scale.
Stars rotate differentially (ω = v_c / r) in a vertex shader — so stars at the Sun’s radius move with it, inner stars whip around faster, outer stars lag. This is physically accurate for the Milky Way’s flat rotation curve. See physics.md § Galactic rotation.
Goal: you can see the Sun’s place in the galaxy and how the galaxy rotates.
universe.html — the cosmic hierarchy
1 world unit = 1 million light-years. At this scale the Milky Way is a
0.1-unit disk and the observable universe is a 46 000-unit sphere.
Switches between preset zoom levels (Local Group → Virgo Supercluster →
Laniakea → Cosmic Web → Observable Universe) with labels appearing and
disappearing based on camera distance.
Named objects (Andromeda, Virgo Cluster, Great Attractor, etc.) are placed at their real RA/Dec directions from the Milky Way — the cosmic web filaments and background galaxies are procedural.
Goal: you can navigate the structure of the cosmos.
Why not always “to scale”?
For intuition-building, compression beats accuracy. The pleasing view is more useful for “here’s what the solar system is” than the honest one — because on the honest one, you can’t see anything. The combination of both (and clear honesty about which is which) is the pedagogical sweet spot.
Slider-driven unification (#91)
solar-system.html now exposes two scale sliders (size, distance) that
interpolate per-planet between the compressed PLANETS-table values
(slider 0) and real astronomical proportions (slider 1). The “pleasing
view vs honest view” framing collapses into a single view where the user
feels the compromise rather than choosing between two static
visualizations. Slider 1 is the same physical reality scale.html shows;
once the slider covers all of scale.html’s use cases, scale.html is
deleted as a follow-up cleanup.
The slider state is also a programmatic, animatable axis of the
storytelling stack: setScale({ size, distance }, { duration, curve }) and
per-body setBodyScale(id, …) are the same API shape voyage scripts use
on the time and (forthcoming) model axes. See docs/storytelling.md for
the cross-axis conventions.
Exaggeration sub-axis
A third slider exposes the implicit ~1500× radius inflation at slider position 1. The two endpoints in solar-system.html use different rulers — radii are anchored on Earth-radius=1 unit, distances on 1 AU=15 units — and the ratio between those rulers is the inflation. At exaggeration=0 the radius ruler collapses onto the distance ruler (planets become sub-pixel; markers take over via the existing #91 fade logic). At exaggeration=1 the scene matches the pre-amendment behavior. At exaggeration=2 (cinematic) radii are doubled over the default.
STRICT_FACTOR = EARTH_RADIUS_KM / (KM_PER_AU / 15) ≈ 1/1565 is derived in solar-system-scale.js from src/data/constants.js and the project convention “Earth at world distance 15 in solar-system.html”. Mapping is log-uniform on slider [0, 1] (continuity at pivot, otherwise 99% of the slider feels “barely visible”) and linear on [1, 2].