src/data/planets.js
// ————————————————————————————————————————————————
// Planetary data — the single source of truth.
//
// All values are REAL astronomical quantities (NASA planetary fact sheets,
// orbital elements from the JPL approximate-elements table — fit valid
// AD 1800–2050 to about an arcminute, multi-century to a few arcminutes).
// - radiusKm: mean equatorial radius, km
// - orbitKm: semi-major axis of orbit around the Sun, km
// (omitted on the Sun itself)
// - orbitalPeriodDays: sidereal orbital period, Earth days
// (omitted on the Sun itself)
// - axialTiltRad: obliquity (tilt of rotation axis relative to orbit normal)
// - color: CSS/Three.js hex (approximate, for stylized rendering)
// - isStar: true on the Sun only
//
// Kepler orbital elements at J2000.0 (JD 2451545.0):
// - e: eccentricity
// - iRad: inclination to the ecliptic (radians)
// - ascNodeRad: Ω, longitude of ascending node (radians)
// - argPerihelionRad: ω, argument of perihelion (radians)
// For Earth (i ≈ 0) Ω = 0 by convention and ω
// carries the longitude of perihelion ϖ.
// - meanLongitudeJ2000Rad: L₀, mean longitude at J2000.0 (radians)
//
// Linear secular rates (per Julian century, 36525 days), same units as
// above. Per the JPL approximate-elements table; semi-major-axis drift
// is intentionally not stored (Mercury's a changes ≈ 55 km per Julian
// century, far below this project's display scaling).
// - eRate, iRadRate, ascNodeRadRate, argPerihelionRadRate,
// meanLongitudeRadRate
//
// Each entry has:
// - id: stable, lowercase, language-independent identifier used as a key
// in view state, preset dropdowns, and lookup tables.
// - names: localized display names, keyed by SUPPORTED_LANGS from src/i18n.js.
// Extend by adding new language keys — no schema change needed.
//
// Views apply their own display scaling on top of these real values — see
// docs/scales.md for each view's scaling rationale.
// ————————————————————————————————————————————————
const D2R = Math.PI / 180;
// Deriving ω = ϖ − Ω (and similarly for rates) from the JPL form, kept as
// inline arithmetic so the JPL-table values are visible as comments.
const _mercury = {
e: 0.20563593,
iRad: 7.00497902 * D2R,
ascNodeRad: 48.33076593 * D2R, // Ω
argPerihelionRad: (77.45779628 - 48.33076593) * D2R, // ω = ϖ − Ω = 29.127°
meanLongitudeJ2000Rad: 252.2503235 * D2R, // L₀
eRate: 0.00001906,
iRadRate: -0.00594749 * D2R,
ascNodeRadRate: -0.12534081 * D2R,
argPerihelionRadRate: (0.16047689 - -0.12534081) * D2R, // dω/dt = dϖ/dt − dΩ/dt
meanLongitudeRadRate: 149472.67411175 * D2R,
};
const _venus = {
e: 0.00677672,
iRad: 3.39467605 * D2R,
ascNodeRad: 76.67984255 * D2R,
argPerihelionRad: (131.60246718 - 76.67984255) * D2R, // ω = 54.923°
meanLongitudeJ2000Rad: 181.9790995 * D2R,
eRate: -0.00004107,
iRadRate: -0.0007889 * D2R,
ascNodeRadRate: -0.27769418 * D2R,
argPerihelionRadRate: (0.00268329 - -0.27769418) * D2R,
meanLongitudeRadRate: 58517.81538729 * D2R,
};
const _earth = {
e: 0.01671123,
iRad: -0.00001531 * D2R, // ≈ 0 (JPL fit residual)
ascNodeRad: 0, // undefined at i ≈ 0 → 0
argPerihelionRad: 102.93768193 * D2R, // ϖ acts as ω here
meanLongitudeJ2000Rad: 100.46457166 * D2R,
eRate: -0.00004392,
iRadRate: -0.01294668 * D2R,
ascNodeRadRate: 0,
argPerihelionRadRate: 0.32327364 * D2R, // dϖ/dt
meanLongitudeRadRate: 35999.37244981 * D2R,
};
const _mars = {
e: 0.0933941,
iRad: 1.84969142 * D2R,
ascNodeRad: 49.55953891 * D2R,
argPerihelionRad: (-23.94362959 - 49.55953891) * D2R, // ω = 286.497° (kept signed; consumers normalize)
meanLongitudeJ2000Rad: -4.55343205 * D2R,
eRate: 0.00007882,
iRadRate: -0.00813131 * D2R,
ascNodeRadRate: -0.29257343 * D2R,
argPerihelionRadRate: (0.44441088 - -0.29257343) * D2R,
meanLongitudeRadRate: 19140.30268499 * D2R,
};
const _jupiter = {
e: 0.04838624,
iRad: 1.30439695 * D2R,
ascNodeRad: 100.47390909 * D2R,
argPerihelionRad: (14.72847983 - 100.47390909) * D2R, // ω = 274.254°
meanLongitudeJ2000Rad: 34.39644051 * D2R,
eRate: -0.00013253,
iRadRate: -0.00183714 * D2R,
ascNodeRadRate: 0.20469106 * D2R,
argPerihelionRadRate: (0.21252668 - 0.20469106) * D2R,
meanLongitudeRadRate: 3034.74612775 * D2R,
};
const _saturn = {
e: 0.05386179,
iRad: 2.48599187 * D2R,
ascNodeRad: 113.66242448 * D2R,
argPerihelionRad: (92.59887831 - 113.66242448) * D2R, // ω = 338.937°
meanLongitudeJ2000Rad: 49.95424423 * D2R,
eRate: -0.00050991,
iRadRate: 0.00193609 * D2R,
ascNodeRadRate: -0.28867794 * D2R,
argPerihelionRadRate: (-0.41897216 - -0.28867794) * D2R,
meanLongitudeRadRate: 1222.49362201 * D2R,
};
const _uranus = {
e: 0.04725744,
iRad: 0.77263783 * D2R,
ascNodeRad: 74.01692503 * D2R,
argPerihelionRad: (170.9542763 - 74.01692503) * D2R, // ω = 96.937°
meanLongitudeJ2000Rad: 313.23810451 * D2R,
eRate: -0.00004397,
iRadRate: -0.00242939 * D2R,
ascNodeRadRate: 0.04240589 * D2R,
argPerihelionRadRate: (0.40805281 - 0.04240589) * D2R,
meanLongitudeRadRate: 428.48202785 * D2R,
};
const _neptune = {
e: 0.00859048,
iRad: 1.77004347 * D2R,
ascNodeRad: 131.78422574 * D2R,
argPerihelionRad: (44.96476227 - 131.78422574) * D2R, // ω = 273.181°
meanLongitudeJ2000Rad: -55.12002969 * D2R,
eRate: 0.00005105,
iRadRate: 0.00035372 * D2R,
ascNodeRadRate: -0.00508664 * D2R,
argPerihelionRadRate: (-0.32241464 - -0.00508664) * D2R,
meanLongitudeRadRate: 218.45945325 * D2R,
};
export const PLANETS = [
{
id: 'sun',
names: { fr: 'Soleil', en: 'Sun' },
isStar: true,
color: 0xfff2b3,
radiusKm: 696340,
axialTiltRad: 0.1265, // ~7.25° relative to the ecliptic
},
{
id: 'mercury',
names: { fr: 'Mercure', en: 'Mercury' },
color: 0xa39a8b,
radiusKm: 2439.7,
orbitKm: 57.91e6,
orbitalPeriodDays: 87.969,
axialTiltRad: 0.001,
..._mercury,
},
{
id: 'venus',
names: { fr: 'Vénus', en: 'Venus' },
color: 0xe6b56b,
radiusKm: 6051.8,
orbitKm: 108.21e6,
orbitalPeriodDays: 224.701,
axialTiltRad: 3.096, // retrograde — but we don't simulate spin direction
..._venus,
},
{
id: 'earth',
names: { fr: 'Terre', en: 'Earth' },
color: 0x5b8fd9,
radiusKm: 6371.0,
orbitKm: 149.6e6,
orbitalPeriodDays: 365.256,
axialTiltRad: 0.4091, // 23.4°
..._earth,
},
{
id: 'mars',
names: { fr: 'Mars', en: 'Mars' },
color: 0xd1553b,
radiusKm: 3389.5,
orbitKm: 227.94e6,
orbitalPeriodDays: 686.971,
axialTiltRad: 0.4398, // 25.2°
..._mars,
},
{
id: 'jupiter',
names: { fr: 'Jupiter', en: 'Jupiter' },
color: 0xd3a87a,
radiusKm: 69911,
orbitKm: 778.48e6,
orbitalPeriodDays: 4332.589,
axialTiltRad: 0.0546, // 3.1°
..._jupiter,
},
{
id: 'saturn',
names: { fr: 'Saturne', en: 'Saturn' },
color: 0xe3c98a,
radiusKm: 58232,
orbitKm: 1432.04e6,
orbitalPeriodDays: 10759.22,
axialTiltRad: 0.4668, // 26.7°
rings: { innerKm: 74500, outerKm: 140220 },
..._saturn,
},
{
id: 'uranus',
names: { fr: 'Uranus', en: 'Uranus' },
color: 0x9fd8e0,
radiusKm: 25362,
orbitKm: 2867.04e6,
orbitalPeriodDays: 30688.5,
axialTiltRad: 1.7063, // 97.8° — essentially rolling on its side
..._uranus,
},
{
id: 'neptune',
names: { fr: 'Neptune', en: 'Neptune' },
color: 0x4a6fd9,
radiusKm: 24622,
orbitKm: 4514.95e6,
orbitalPeriodDays: 60190.03,
axialTiltRad: 0.4943,
..._neptune,
},
];
// Lookup helpers
export const planetById = (id) => PLANETS.find((p) => p.id === id);
// Derived quantities — the orbital period ratio drives the "1× speed" animation.
// Earth = 1.0 by convention. Mercury = 0.24 means it orbits 4.15× faster than Earth.
// Returns null for objects with no orbital period (e.g. the Sun), so callers
// can filter or skip rather than propagate NaN.
export const orbitalPeriodYears = (p) =>
p.orbitalPeriodDays != null ? p.orbitalPeriodDays / 365.25 : null;
← Astrarium