Skip to Content
📄 ESSRT — Read the paper
3D SimulationTechnical Details

3D Simulation Technical Guide

This guide explains the concepts behind the Interactive 3D Solar System Simulation: the geocentric frame it renders in, the input constants that drive it, and how it computes positions. It is written for developers, researchers, and anyone curious about the technical implementation; basic familiarity with JavaScript and trigonometry is helpful but not required.

This page establishes:

Code-level documentation lives upstream. The simulator’s own docs are the source of truth for its internals — scene-graph hierarchy, constants reference, the render loop, the equation of centre and the N-body engine. They are kept current with the code; this page is not. See the docs/ directory in the simulator repository.


The Geocentric Frame

The simulation places Earth at the center of the scene — a geocentric reference frame. The Sun orbits Earth (not the other way around), and all planets revolve around the Sun, which itself revolves around Earth. This is a natural choice because the model describes precession cycles as seen from Earth’s reference frame.

How it works in the 3D scene:

The Sun has speed: 2π — exactly one revolution per year around barycenterEarthAndSun. Since barycenterEarthAndSun is nested inside Earth’s precession hierarchy, the Sun inherits all of Earth’s precession rotations while orbiting at 1 AU.

For other planets, a yearly revolution sandwich converts heliocentric orbits into the geocentric frame:

PerihelionFromEarth (speed: +2π/yr, perihelion offset position) └── ... └── RealPerihelionAtSun (speed: −2π/yr, orbit size, inclination tilt) └── Planet (own orbital speed)

The +2π layer makes the planet’s orbit center revolve at the same rate as the Sun — keeping the planet centered on the Sun as seen from Earth. The −2π layer cancels this revolution for the orbit inside, so the planet orbits at its own heliocentric rate. The net effect: the planet orbits the Sun, which orbits Earth, producing the correct apparent geocentric motion (annual retrograde loops, elongations, and zodiac transit).

The two base units of the scene are 2π radians = one solar year and 100 units = 1 AU; every period and distance is expressed relative to those.


Start Date Alignment

The simulation’s start date is aligned to the June Solstice of 21 June 2000, 00:00 UTC.

At this moment, the Sun was at its highest declination (RA ~6h / ~18h), corresponding to maximum obliquity effect.

The June Solstice doesn’t occur at exactly the same time each year. The calendar uses 365.2425 days (accounting for leap years), which doesn’t perfectly match the actual solar year length. The simulation accounts for this offset.


Source Code & Data

  • Simulation code: Available on GitHub  (see the simulation source files)
  • Model documentation: The simulator’s own docs — architecture, constants, verification gates — are in the repository’s docs/
  • Configuration: All values in the simulation match the Formulas and the theory described in this documentation

Input Parameter Reference

The simulation is driven by a set of input constants. All other values (day lengths, year lengths, precession rates, orbital positions) are derived from these inputs.

Core Cycle Parameters

ParameterDescription
perihelionalignmentYearThe year when the longitude of perihelion was exactly 90° (aligned with December solstice). According to J. Meeus’s formula (the IAU mean elements), this was 1246 AD — a dated alignment event, used by the scene’s perihelion-date readouts.
perihelionalignmentJDThe same alignment date expressed as a Julian Day number (2,176,154), used for precise date calculations.
kDeviceWheelPeriodYearsThe recorded J2000 turn periods of the five wheels of the 3D scene’s scaffold. They are a pose of the scaffold only: no observable rides them — the engine places the Earth frame, the Sun and the Moon over it.

Year & Day Length Parameters

ParameterDescription
meansiderealyearlengthinSecondsThe sidereal year in seconds (31,558,149.76). This is the J2000 anchor of the model — held constant within the modern-era scope, where all day/year calculations derive from it. The value itself drifts very slowly at geological timescales via solar mass loss (Kepler’s third law); see Expanding Resonance for the deep-time layer.

Model Start Position Parameters

ParameterDescription
startmodelJDThe model’s reference date as a Julian Day (2,451,716.5 = June 21, 2000 at 00:00 UTC). All orbital positions are calculated relative to this point.
startmodelYearThe same date as a decimal year (2000.5 = mid-2000). Used for year-based calculations.
whichSolsticeOrEquinoxDetermines which astronomical event the model aligns to at start: 0 = March Equinox, 1 = June Solstice, 2 = September Equinox, 3 = December Solstice. Default is 1 (June Solstice).
startAngleModelEarth’s orbital angle at the start date (89.91949879°). The June Solstice occurs at exactly 90°, but the model starts at midnight UTC which is slightly before the actual solstice time (01:47 UTC).
correctionDaysFine-tuning offset (-0.8288 days) to ensure the model aligns precisely with observed solstice times.
correctionSunAngular correction (0.49715°) because the model starts at 00:00 UTC but the June Solstice 2000 occurred at 01:47 UTC. This shifts the Sun’s starting position to match reality.

Physical Constants

ParameterDescription
currentAUDistanceThe length of 1 Astronomical Unit in kilometers (149,597,870.698828 km). Used for converting simulation units to real distances.
speedOfLightSpeed of light (299,792.458 km/s). Used for light-time calculations when computing apparent vs. true positions.
deltaTStartThe Delta-T value at the model start date (56.08 seconds). Delta-T is the difference between Terrestrial Time and UTC, which changes over time due to Earth’s variable rotation.

Right Ascension & Declination Calculations

All celestial position values in the simulation are calculated entirely in the browser - no external API calls. The calculations are deterministic based on the current Julian Date.

Step 1: Get World Positions

Each frame, the simulation retrieves the 3D positions of celestial bodies:

earth.rotationAxis.getWorldPosition(EARTH_POS); // Earth center sun.planetObj.getWorldPosition(SUN_POS); // Sun center obj.planetObj.getWorldPosition(PLANET_POS); // Current planet

Step 2: Transform to Earth-Equatorial Frame

The planet’s position is converted to Earth’s local coordinate system, which includes the axial tilt and the 90° rotation that starts the simulation at the June Solstice:

LOCAL.copy(PLANET_POS); earth.rotationAxis.worldToLocal(LOCAL); // World → Earth frame

The line earth.containerObj.rotation.y = (Math.PI/2) * whichSolsticeOrEquinox applies the 90° rotation so that 0h RA still points at the March Equinox even though the simulation begins at the June Solstice.

Step 3: Convert to Spherical Coordinates

SPHERICAL.setFromVector3(LOCAL); obj.ra = SPHERICAL.theta; // θ → Right Ascension (radians) obj.dec = SPHERICAL.phi; // φ → Declination (radians)

Since LOCAL is already in the tilted equatorial frame, θ directly gives the RA and φ gives the Declination - no additional trigonometry needed.

Step 4: Format for Display

The raw radians are converted to sexagesimal notation:

obj.raDisplay = radiansToRa(obj.ra); // "12h34m56s" obj.decDisplay = radiansToDec(obj.dec); // "+12°34′56″"

Earth’s own frame is placed from the engine each frame, so any change to its tilt, precession rate or date is reflected in the next projection.


How Other Planets Work

Every planet (Mercury through Neptune) uses the same counter-rotation sandwich as the geocentric frame conversion. The hierarchy, using Jupiter as an example:

barycenterEarthAndSun └── jupiterPerihelionDurationEcliptic1 (prograde, one turn per planets.jupiter.perihelionEclipticYears) └── PERIHELION JUPITER (speed: +2π/yr, perihelion offset) └── jupiterPerihelionDurationEcliptic2 (retrograde at the same rate, cancels #1) ├── Jupiter Real Perihelion At Sun (orbit size, inclination tilt, -2π/yr) │ └── Jupiter (orbital speed, axial tilt, mesh) └── Fixed Perihelion At Sun (fixed perihelion reference, sibling)

The same sandwich principle applies: Ecliptic1 carries the perihelion marker at the precession rate; Ecliptic2 cancels the precession for the orbit inside. The planet orbits the Sun in the correct heliocentric frame, while its perihelion direction precesses independently.

The +2π/yr and −2π/yr layers are the geocentric frame conversion — they make the orbit center revolve with the Sun while letting the planet orbit at its own rate inside.

Orbital inclination is encoded as a static tilt on the RealPerihelionAtSun container, decomposed into two components based on the J2000 ascending node (Ω) and inclination (i):

orbitTilta = i × sin(Ω) // rotation.x component orbitTiltb = i × cos(Ω) // rotation.z component

This orients the orbital plane at the correct angle to the ecliptic. The tilt is fixed at J2000 values — it does not precess in the 3D scene.

Inclination of date — the inclinations the panels display for the seven planets (ecliptic and invariable-plane) come from the N-body element chain of date; Earth’s is the engine’s orbit normal against the invariable plane.

Key Differences from Earth

AspectEarthOther Planets
Orbital tiltTwo dynamic tilts creating obliquity + inclination cyclesStatic J2000 tilt on containerObj
InclinationThe engine’s orbit normal against the invariable planeThe N-body element chain of date
Perihelion precession rateThe perihelion-of-date container (the published perihelion-of-date beat is ~20,938 years)The N-body chain’s own elements of date; the published periods are its leading secular eigenfrequencies

Moon

The Moon uses Earth as its center (not the Sun). It has six nested precession layers, following the same containerObj/orbitObj/pivotObj pattern. The signed layer rates sum exactly to the tropical month, and all layer phases are anchored to the J2000 lunar orbital elements:

earth.pivotObj └── moonApsidalPrecession — apsidal precession (+8.84765 yr of-date, prograde), carries eccentricity offset └── moonApsidalNodalPrecession1 — apsidal-nodal meeting cycle (−5.99701 yr, retrograde) └── moonApsidalNodalPrecession2 — counter-rotation (+5.99701 yr): the pair is inert (net zero) └── moonLunarLevelingCyclePrecession — apsidal canceller (−8.84765 yr, of-date pair): mirrors the apsidal layer in rate and phase └── moonNodalPrecession — nodal precession (−18.6132112 yr of-date, retrograde), pure rotation └── moon — draconitic-month orbital speed (27.2122209 d), carries the ecliptic inclination tilt

The apsidal precession layer carries the orbital eccentricity offset (orbitRadius). The moon container carries the ecliptic inclination tilt (orbitTilta/orbitTiltb) — placed below the nodal rotation so the nodal layer’s own spin regresses the tilted orbit plane (measured −19.35°/yr, matching the observed nodal plane motion). All intermediate layers are pure rotation layers with zero radius and zero tilt.

The detailed settings for each body are browsable in the simulation’s Planet Orbit Analysis (Tools menu) and in the published @essrt/model-values registry.


Summary

ComponentKey ValuePurpose
Base time unit2π = 1 solar yearAll periods relative to this
Base distance unit100 = 1 AUAll distances relative to this
Start dateJune Solstice 2000Reference point for all calculations

The published periods are the model’s dynamical values (Earth’s Clock); the seven planets render from the N-body element chain.


Key Takeaways

  1. Two base units - 2π for time (1 year), 100 for distance (1 AU)
  2. Counter-rotating motions - Negative speeds (clockwise) vs positive speeds (counter-clockwise)
  3. Browser-based calculations - All RA/Dec values computed locally, no external APIs
  4. Geocentric frame — The Sun orbits Earth at 2π/year; planets use +2π/−2π layers for the heliocentric-to-geocentric conversion
  5. Cross-surface parity - All simulation values match the Orbital Calculator and the published model-values registry

Return to the Interactive 3D Simulation or explore the Formulas for the complete analytical formulas.

Last updated on: