Skip to Content
πŸ“„ Fibonacci Laws β€” Read the paper
3D SimulationTechnical Details

3D Simulation Technical Guide

This guide explains how the Interactive 3D Solar System Simulation works under the hood. It covers the mathematical foundations, the calculation order, and how each orbital parameter is configured.

Intended audience: Developers, researchers, and anyone curious about the technical implementation. Basic familiarity with JavaScript and trigonometry is helpful but not required.

Developer Quick Start

The simulation lives in a single file: script.js (~30,000 lines). Here are the five functions you’ll touch most:

FunctionLineWhat it does
moveModel(pos)~25729Positions every object: ΞΈ = speed Γ— pos βˆ’ startPos Γ— (Ο€/180)
updatePositions()~25457Reads 3D scene β†’ computes RA/Dec and distances
createPlanet(pd)~28401Builds the Three.js containers for one object
updatePredictions()~27724Analytical: obliquity, year lengths, precession rates
render()~12838Animation loop: ties everything together

Where to look first: Object definitions (lines ~1835–3708) define every celestial body’s parameters. The hierarchy wiring (lines ~4525–4624) shows which object is nested inside which. These two sections plus moveModel cover 80% of what the simulation does.


Core Principles

The simulation is built in Three.jsΒ  and uses two fundamental units:

ConceptSimulation ValueReal-World Equivalent
One solar year2Ο€ radians365.242189 days
One AU100 units149,597,870.7 km

Since the circumference of a circle is 2Ο€r, all orbital calculations derive from these base values:

  • Time: All periods are expressed relative to one solar year = 2Ο€
  • Distance: All distances are expressed relative to 1 AU = 100

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).


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)
  • Interactive mind map: Explore the simulation’s structure at mindmap.holisticuniverse.comΒ 
  • Excel spreadsheet: The full spreadsheet with all settings and calculations is available on request
  • Configuration: All values in the simulation match the Formulas and the theory described in this documentation
Screenshot of Excel spreadsheet showing technical configuration settings for the 3D simulation, including orbital parameters, precession cycles, eccentricity values, and mathematical constants

Code Architecture

The simulation lives in a single file (script.js, ~30,000 lines) built on Three.jsΒ  with dat.guiΒ  for controls. The code is organized into five major blocks:

1. Constants & Derived Values (top ~1,800 lines)

All model parameters are declared upfront as constants β€” nothing is hard-coded deeper in the file. From these inputs, the code derives all secondary values: precession cycle lengths (H/3, H/5, H/8, H/13, H/16), the Balanced Year, gravitational parameters, planetary masses, and AU distances.

An OrbitalFormulas object provides reusable helper functions: Kepler’s equation solver, mean/true anomaly conversion, orbital velocity, semi-axis calculations, and heliocentric distance.

2. Scene Construction (~lines 1,800–6,000)

Each celestial body is defined as a JavaScript object with orbital parameters (speed, tilt, eccentricity, start position, precession period). Three.js builds a nested hierarchy of 3D containers:

scene └── startingPoint β”œβ”€β”€ earthWobbleCenter (fixed at origin, visualization only) β”œβ”€β”€ earth (axial precession, βˆ’H/13) β”‚ β”œβ”€β”€ earthInclinationPrecession (+H/3) β”‚ β”‚ β”œβ”€β”€ midEccentricityOrbit (visualization helper, sibling) β”‚ β”‚ └── earthEclipticPrecession (+H/5, tilt βˆ’0.634Β°) β”‚ β”‚ └── earthObliquityPrecession (βˆ’H/8, tilt +0.634Β°) β”‚ β”‚ └── earthPerihelionPrecession1 (+H/16) β”‚ β”‚ └── earthPerihelionPrecession2 (βˆ’H/16, eccentricity offset) β”‚ β”‚ └── barycenterEarthAndSun β”‚ β”‚ β”œβ”€β”€ sun (1 AU, speed 2Ο€/yr) β”‚ β”‚ β”œβ”€β”€ earthPerihelionFromEarth (copy of barycenter position) β”‚ β”‚ β”œβ”€β”€ moon (6 precession layers under earth.pivotObj) β”‚ β”‚ └── mercury … neptune (5-layer hierarchy each) β”‚ └── rotationAxis (axial tilt, celestial sphere) └── invariable plane, stars, constellations, Milky Way

Each precession cycle is a separate container rotating at its own rate. Because the containers are nested, each rotation is applied on top of the previous one β€” the physical principle of superimposed precessions maps directly to Three.js parent-child transforms.

Earth is unique in this hierarchy: it has six nested precession layers (the two counter-rotating reference points from the model). earthWobbleCenter is a separate visualization object fixed at the origin β€” it is not a parent container of earth. All other planets use a 5-layer hierarchy (perihelion precession sandwich + yearly geocentric revolution + orbit frame + planet), with inclination oscillation computed analytically rather than geometrically.

3. GUI & Controls (~lines 6,000–12,800)

The dat.gui panel provides:

  • Date/time input β€” type any date or Julian Day; the simulation jumps to that epoch
  • Simulation controls β€” run/pause, speed selection (1 second = 1 real second up to 1,000 years), step forward/backward, tracing
  • Planet hierarchy inspector β€” live display of every object’s position, rotation, and orbital elements, exportable to Excel
  • Predictions panel β€” live readout of day/year lengths, precession periods, obliquity, eccentricity, inclination, and perihelion longitude at the current epoch

4. Animation Loop (~line 12,838)

The render() function runs every frame and advances the universal time counter:

o.pos += speedFactor Γ— speed Γ— delta

To balance accuracy with performance, updates are split into tiers:

  • Every frame: orbital positions (moveModel), orbit traces, camera
  • 20 Hz: date/time display
  • 10 Hz: heavy astronomy (inclinations, invariable plane balance, predictions, anomalies)
  • 30 Hz: visual effects (lighting, lens flare, glow)

5. Position Calculations (~lines 25,000+)

moveModel(pos) is the core function. For each object it computes:

ΞΈ = obj.speed Γ— pos βˆ’ obj.startPos Γ— (Ο€ / 180)

Then it positions the object by rotating its orbitObj:

orbitObj.rotation.y = ΞΈ

All orbits in the simulation are circular β€” every object has a === b (semi-major equals semi-minor axis). This is a core design principle: the model builds complex orbital motion entirely from uniform circular rotations layered through the nested container hierarchy, not from ellipse equations. The elliptical paths observed in nature emerge from the superposition of multiple circular motions at different rates.

The code contains infrastructure for elliptical orbits (a β‰  b branch in moveModel), but no object currently uses it. If activated, it would position both pivotObj and rotationAxis at (cos(ΞΈ) Γ— a, 0, sin(ΞΈ) Γ— b) instead of using a Y-rotation.

Then updatePositions() transforms world-space coordinates into Earth’s equatorial frame to compute RA/Dec for every planet β€” entirely in the browser, no external APIs.


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. For the complete list of values, see Configuration: Simulation Input Constants.

Core Cycle Parameters

ParameterDescription
holisticyearLengthThe master cycle length (333,888 years). All precession periods are derived by dividing this value by Fibonacci-related numbers (3, 5, 8, 13, 16).
perihelionalignmentYearThe year when the longitude of perihelion was exactly 90Β° (aligned with December solstice). According to J. Meeus’s formula, this was 1246 AD. This anchor date determines where we are in all precession cycles.
perihelionalignmentJDThe same alignment date expressed as a Julian Day number (2,176,142), used for precise date calculations.
temperatureGraphMostLikelyA value from 0 to 16 (in 0.5 steps) that positions us within the obliquity cycle. Value 14.5 means we are 14.5/16 of the way through the current Holistic-Year since the Balanced Year. This determines the Balanced Year calculation: 1246 - (14.5 Γ— 20,868) = -301,340 BC.

Year & Day Length Parameters

ParameterDescription
inputmeanlengthsolaryearindaysThe reference solar year length (365.2421897 days). This is the primary input from which mean values are calculated. The actual mean is rounded to fit exactly within the Holistic-Year cycle.
meansiderealyearlengthinSecondsThe sidereal year in seconds (31,558,149.724). This is the fixed anchor of the model - it never changes because it measures Earth’s orbit relative to fixed stars. All day/year calculations derive from this constant.
meansiderealyearAmplitudeinSecondsaDayControls how much the sidereal year (in days) varies over the perihelion precession cycle. The sidereal year in seconds is fixed, but the number of days varies because day length changes with eccentricity.
meansolaryearAmplitudeinSecondsaDayControls how much the solar year varies over the obliquity cycle. As obliquity changes, the timing of equinoxes shifts slightly.
meanAnomalisticYearAmplitudeinSecondsaDayControls how much the anomalistic year (in days) varies over the perihelion precession cycle.

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.919Β°). 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.2316 days) to ensure the model aligns precisely with observed solstice times and produces clean Julian Day numbers at the Balanced Year.
correctionSunAngular correction (0.2774Β°) 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.

Obliquity Parameters

ParameterDescription
earthtiltMeanThe mean obliquity (23.41398Β°). This is Earth’s average axial tilt over a full obliquity cycle. The value is optimized to match IAU 2006 precession rates.
earthInvPlaneInclinationAmplitudeThe amplitude of obliquity oscillation (0.633849Β°). Obliquity varies from (mean - amplitude) to (mean + amplitude) as the Axial Tilt and Inclination Tilt effects add or cancel. Total range: 22.21Β° to 24.71Β°.
earthInvPlaneInclinationMeanMean inclination of Earth’s orbit to the invariable plane (1.481592Β°). This determines the center point of the inclination oscillation.
earthRAAngleRight Ascension correction angle (1.258454Β°). This is the most complex parameter - it depends on temperatureGraphMostLikely, earthtiltMean, and earthInvPlaneInclinationAmplitude. It ensures the PERIHELION-OF-EARTH is correctly positioned relative to the start date.

Eccentricity Parameters

ParameterDescription
eccentricityBaseBase orbital eccentricity (0.015321). This is the arithmetic midpoint of the eccentricity cycle (time-averaged mean = 0.015387).
eccentricityAmplitudeAmplitude of eccentricity oscillation (0.0014226). Eccentricity varies from ~0.0139 (minimum) to ~0.0167 (maximum) over the 20,868-year cycle.

Longitude of Perihelion Parameters

ParameterDescription
helionpointAmplitudePrimary amplitude (5.05Β°) for the longitude of perihelion calculation. This represents the main oscillation in perihelion position within each precession cycle.
mideccentricitypointAmplitudeSecondary amplitude (2.4587Β°) that adds a harmonic to the perihelion longitude. Combined with the primary amplitude, this produces the observed wobble pattern in perihelion position.

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 (63.63 seconds). Delta-T is the difference between Terrestrial Time and UTC, which changes over time due to Earth’s variable rotation.

Calculation Order

The precession movements must be applied in a specific order. In Three.js, each movement is nested inside the previous one:

earth.pivotObj.add(earthInclinationPrecession.containerObj); earthInclinationPrecession.pivotObj.add(earthEclipticPrecession.containerObj); earthEclipticPrecession.pivotObj.add(earthObliquityPrecession.containerObj); earthObliquityPrecession.pivotObj.add(earthPerihelionPrecession1.containerObj); earthPerihelionPrecession1.pivotObj.add(earthPerihelionPrecession2.containerObj); earthPerihelionPrecession2.pivotObj.add(barycenterSun.containerObj); barycenterSun.pivotObj.add(earthHelionPoint.containerObj);

The calculation chain:

  1. Earth β†’ Sets Inclination Precession (333,888 Γ· 3 years)
  2. Inclination Precession β†’ Sets Ecliptic Precession (333,888 Γ· 5 years)
  3. Ecliptic Precession β†’ Sets Obliquity cycle (333,888 Γ· 8 years)
  4. Obliquity cycle β†’ Sets Perihelion Precession (first pass)
  5. Perihelion Precession 1 β†’ Sets Perihelion Precession (second pass)
  6. Perihelion Precession 2 β†’ Sets Sun Barycenter location
  7. Barycenter Sun β†’ Sets PERIHELION-OF-EARTH location

The cumulative effect produces the Axial Precession duration of 333,888 Γ· 13 years around the EARTH-WOBBLE-CENTER.


Configuration Settings

Mean Solar Year Length

The solar year length is calculated from the Holistic-Year:

meanSolarYearLengthInDays = Math.round(365.2421897 * (333888/16)) / (333888/16);

The experienced solar year length varies due to Earth’s motion around the EARTH-WOBBLE-CENTER and the counter-motion of the PERIHELION-OF-EARTH around the Sun. If this value is set incorrectly, historic solstice dates won’t match observations.


Earth Variables

The Earth object contains all settings for Earth’s orbit around the EARTH-WOBBLE-CENTER:

{ "name": "Earth", "size": (12756.27 / 149597870.698828) * 100, // Diameter relative to AU "speed": -Math.PI * 2 / (333888/13), // Axial precession speed "rotationSpeed": Math.PI * 2 * (365.242188997508 + 1), // Daily rotation "tilt": -23.41398, // Mean axial tilt "orbitRadius": -0.0014226 * 100 // Eccentricity amplitude }
ParameterFormulaPurpose
size(Earth diameter / 1 AU) Γ— 100Visual scale
speed2Ο€ / (333,888 Γ· 13)Axial precession rate (negative = clockwise)
rotationSpeed2Ο€ Γ— (solar days + 1)Earth’s daily rotation
tilt-23.41398Β°Mean axial tilt
orbitRadius-0.0014226 Γ— 100Distance to EARTH-WOBBLE-CENTER

Inclination Precession

{ "name": "Earth Inclination Precession", "startPos": ((balancedYear - startYear) / (333888/3) * 360), "speed": Math.PI * 2 / (333888/3) }

The startPos is calculated from the Balanced Year (-301,340 BC). This is when the solstice aligned with the PERIHELION-OF-EARTH while the Inclination Tilt and Axial Tilt were exactly opposite - a perfectly balanced state.

Counter-rotating motions: Earth’s speed (Axial Precession) is negative (clockwise), while Inclination Precession speed is positive (counter-clockwise). These two opposing motions are the foundation of the Holistic Universe Model.


Ecliptic Precession

{ "name": "Earth Ecliptic Precession", "startPos": ((balancedYear - startYear) / (333888/5) * 360), "speed": Math.PI * 2 / (333888/5), "orbitTiltb": -0.634 // Tilt amplitude (negative) }

The orbitTiltb value of -0.634Β° is opposite to the Obliquity cycle’s value of +0.634Β°. These opposing tilts combine to produce the total obliquity variation.


Obliquity Cycle

{ "name": "Earth Obliquity Precession", "startPos": -((balancedYear - startYear) / (333888/8) * 360), "speed": -Math.PI * 2 / (333888/8), "orbitTiltb": 0.634 // Tilt amplitude (positive) }

Note the negative startPos and speed - this cycle runs opposite to the Ecliptic Precession, creating the combined obliquity effect.


How the Two Tilts Work in the 3D Scene

Each object created by createPlanet builds four nested Three.js containers:

containerObj β†’ rotation.x = orbitTilta, rotation.z = orbitTiltb (FIXED tilt) position = (orbitCentera, orbitCenterc, orbitCenterb) (FIXED offset) └── orbitObj β†’ rotation.y = ΞΈ(t) (ANIMATED by moveModel each frame) β”œβ”€β”€ pivotObj (children attach here via hierarchy wiring) └── rotationAxis (axial tilt + spin) └── planetObj (visible mesh)

Note: pivotObj and rotationAxis are siblings under orbitObj, not parent-child. The hierarchy wiring (.add() calls) attaches child objects to pivotObj. The visual mesh lives under rotationAxis.

The containerObj properties are permanent β€” tilts and position offset are set once at creation and never change. The orbitTiltb tilt physically tips the orbital plane. Because children attach to the pivotObj (inside the orbitObj), the parent’s animated Y-rotation carries the child’s tilt direction around as it sweeps. This is the core mechanism: a fixed tilt whose direction is swept by the parent’s orbital rotation.

What each tilt does in the Earth frame:

The Ecliptic Precession tilt (-A) sits inside the Inclination Precession orbitObj, which rotates at H/3. So this tilt direction is swept around at the H/3 rate (one full revolution per 111,296 years).

The Obliquity Precession tilt (+A) sits one level deeper β€” inside both the Inclination Precession (H/3) and the Ecliptic Precession (H/5) orbitObjs. Both parent rotations carry its tilt direction, so the net sweep rate is 3 + 5 = 8 β†’ one revolution per H/8 = 41,736 years.

TiltCarried by parentsNet sweep rate in Earth frame
Ecliptic Precession (-A)Inclination Precession (H/3)H/3
Obliquity Precession (+A)Inclination (H/3) + Ecliptic (H/5)3 + 5 = H/8

How this creates the obliquity cycle:

Earth’s spin axis is defined by rotationAxis.rotation.z = -23.41Β° at the earth level β€” outside the precession hierarchy. It is fixed in the Earth frame.

The two tilts create two rotating perturbations to the orbital plane normal. As each tilt direction sweeps past the spin axis, it alternately increases and decreases the angle between the spin axis and the orbital plane β€” the obliquity.

  • The ecliptic tilt (-A) sweeps at H/3 β†’ produces a slow obliquity oscillation with period H/3
  • The obliquity tilt (+A) sweeps at H/8 β†’ produces the ~41,000-year Milankovitch obliquity signal

The combined effect on the obliquity is the sum of these two projections onto the spin axis direction: mean βˆ’ AΒ·cos(H/3) + AΒ·cos(H/8).

When both components reinforce (both cosines at -1), the obliquity reaches its maximum of ~24.68Β°. When both oppose (both cosines at +1), it reaches its minimum of ~22.15Β°. The total range is Β±2A = Β±1.27Β°.

How this creates the inclination oscillation:

The inclination to the invariable plane depends on the combined magnitude and direction of the two tilts. The parent Inclination Precession container (H/3) precesses the ascending node direction at H/3. The analytical formula captures this as: mean βˆ’ AΒ·cos(H/3).

The Fibonacci identity at work: the two tilt rates (H/5 and H/8) and the inclination precession rate (H/3) satisfy 3 + 5 = 8. This identity is why the obliquity tilt’s net sweep rate (3 + 5 = 8) lands exactly on the Fibonacci number 8, producing the H/8 obliquity cycle from components at H/3 and H/5.


Perihelion Precession (Two Parts)

The Perihelion Precession is applied twice with opposite values:

Part 1:

{ "name": "Earth Perihelion Precession1", "startPos": ((balancedYear - startYear) / (333888/16) * 360), "speed": Math.PI * 2 / (333888/16), "orbitTilta": -1.26 // RA correction angle }

Part 2:

{ "name": "Earth Perihelion Precession2", "startPos": -((balancedYear - startYear) / (333888/16) * 360), "speed": -Math.PI * 2 / (333888/16), "orbitCentera": -0.015321 * 100 // Base eccentricity }

How the counter-rotation works in the 3D scene:

This uses the same β€œsandwich” principle as the two tilts, but for position instead of tilt:

earthPerihelionPrecession1.containerObj (orbitTilta = -earthRAAngle) └── orbitObj rotates at +H/16 (prograde) └── earthPerihelionPrecession2.containerObj (orbitCentera = -eccentricityBase Γ— 100) └── orbitObj rotates at -H/16 (retrograde, cancels the prograde) └── barycenterEarthAndSun, PERIHELION-OF-EARTH, Sun

The base eccentricity offset (orbitCentera = -0.015321 Γ— 100) is a fixed position on PerihelionPrecession2’s containerObj. It sits inside PerihelionPrecession1’s orbitObj, which rotates at +H/16. So the offset is swept around at the perihelion precession rate β€” this IS the perihelion direction precessing.

PerihelionPrecession2’s orbitObj then counter-rotates at -H/16, canceling the precession for everything inside. The Sun, Barycenter, and PERIHELION-OF-EARTH orbit in the correct non-precessing frame, but they are positioned at the eccentricity offset that sweeps with the perihelion.

The Barycenter Sun adds the eccentricity variation (amplitude = 0.0014226 Γ— 100) on top of the base eccentricity:

{ "name": "Barycenter Sun", "orbitRadius": 0.0014226 * 100 // Eccentricity amplitude }

Together, the base offset (sweeping with perihelion) plus the amplitude create the full eccentricity cycle: the distance from Earth to the EARTH-WOBBLE-CENTER varies between (base - amplitude) and (base + amplitude) as the perihelion precesses.

The PERIHELION-OF-EARTH is a placeholder object at the Barycenter Sun position to prevent complex Barycenter calculations from interfering with planet position calculations.

The Balanced Year:

const balancedYear = 1246 - (14.5 * (333888/16)); // = -301,340 BC

This represents 14.5 Perihelion Precession cycles before 1246 AD, aligned to explain the obliquity-driven temperature cycles.


Sun

{ "name": "Sun", "startPos": 0.28, // Correction for exact solstice time "speed": Math.PI * 2, // One solar year "rotationSpeed": Math.PI * 2 / (365.2422 / 27.32),// Visual rotation (~27.32 days, simplified) "tilt": -7.155, // Solar axial tilt "orbitRadius": 100 // 1 AU }
ParameterValueNotes
startPos0.28Β°The June Solstice 2000 occurred at ~01:47 UTC, not exactly midnight
speed2Ο€Exactly one solar year
orbitRadius100Exactly 1 AU from PERIHELION-OF-EARTH
tilt-7.155Β°Solar axial tiltΒ 

Phase Alignment: How startPos Works

Every precession object needs to start at the correct position in its cycle at the model start date. The startPos parameter (in degrees) achieves this with a single formula:

startPos = (balancedYear - startYear) / cycleLength Γ— 360

Since the Balanced Year (-301,340 BC) is the reference epoch where all precession cycles are at their zero phase, dividing the elapsed time by the cycle length gives the fractional cycle completed, and multiplying by 360 converts to degrees.

Examples from the configuration:

ObjectCyclestartPos formula
Inclination PrecessionH/3(balancedYear βˆ’ startYear) / (H/3) Γ— 360
Ecliptic PrecessionH/5(balancedYear βˆ’ startYear) / (H/5) Γ— 360
Perihelion Precession 1H/16(balancedYear βˆ’ startYear) / (H/16) Γ— 360

Retrograde objects negate their startPos:

ObjectstartPos
Obliquity Precessionβˆ’(balancedYear βˆ’ startYear) / (H/8) Γ— 360
Perihelion Precession 2βˆ’(balancedYear βˆ’ startYear) / (H/16) Γ— 360

The negation matches the negative speed of these retrograde layers, ensuring the phase offset is in the correct direction.

How moveModel uses it:

In moveModel(), the startPos is subtracted from the time-evolved angle:

ΞΈ = speed Γ— pos βˆ’ startPos Γ— (Ο€ / 180)

At pos = 0 (the model start date), this gives ΞΈ = βˆ’startPos Γ— (Ο€/180), placing the object at its correct initial phase. As time advances, speed Γ— pos evolves the phase forward (or backward for retrograde objects).


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β€³"

Why Values Stay Consistent

The updatePositions() function runs after every orbit/precession update. Since it re-projects the current world-space vector into the live-tilted equator of earth.rotationAxis, any changes to Earth’s tilt, precession rate, or date/time are automatically reflected.


How Other Planets Work

Every planet (Mercury through Neptune, plus Pluto, Halley’s comet, and Eros) uses the same counter-rotation sandwich as Earth’s perihelion precession. The hierarchy, using Jupiter as an example:

barycenterEarthAndSun └── jupiterPerihelionDurationEcliptic1 (prograde, H/5 perihelion precession) └── PERIHELION JUPITER (speed: +2Ο€/yr, perihelion offset) └── jupiterPerihelionDurationEcliptic2 (retrograde, -H/5 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.

Dynamic inclination is computed analytically for all planets:

i(t) = mean + amplitude Γ— cos(Ξ©(t) - phaseOffset)

where Ξ©(t) is the ascending node on the invariable plane, precessing at the planet’s perihelion precession rate. As the ascending node sweeps around, the inclination oscillates between (mean - amplitude) and (mean + amplitude). These computed values are displayed in the GUI predictions panel but do not change the 3D orbital tilt.

Key Differences from Earth

AspectEarthOther Planets
Precession layers6 nested (inclination, ecliptic, obliquity, 2Γ— perihelion, barycenter)5 layers (2Γ— perihelion precession sandwich, yearly revolution, orbit frame, planet)
Orbital tiltTwo dynamic tilts creating obliquity + inclination cyclesStatic J2000 tilt on containerObj
InclinationGeometric (from two-tilt mechanism) + analytical formulaAnalytical formula only
Perihelion precession rateH/16 = 20,868 yearsPlanet-specific (e.g., Jupiter: H/5, Saturn: -H/8)

Moon

The Moon uses Earth as its center (not the Sun). It has six nested precession layers, following the same containerObj/orbitObj/pivotObj pattern:

earth.pivotObj └── moonApsidalPrecession β€” apsidal precession (~8.85 yr), carries eccentricity offset └── moonApsidalNodalPrecession1 β€” apsidal-nodal beat (~206 days, retrograde) └── moonApsidalNodalPrecession2 β€” cancels beat (prograde, same period) └── moonLunarLevelingCyclePrecession β€” lunar leveling cycle (retrograde) └── moonNodalPrecession β€” nodal precession (~18.6 yr, retrograde), carries ecliptic inclination tilt └── moon β€” tropical month orbital speed

The apsidal precession layer carries the orbital eccentricity offset (orbitRadius). The nodal precession layer carries the ecliptic inclination tilt (orbitTilta/orbitTiltb). All intermediate layers are pure rotation layers with zero radius and zero tilt.

The detailed settings for each body are available in the Excel spreadsheet (on request).


3D Scene vs Analytical Formulas

The simulation computes values through two independent channels. Understanding which channel produces which output is important when reading the code.

3D-derived values β€” computed by reading positions from the scene hierarchy:

The moveModel() function positions all objects each frame. Then updatePositions() reads their world-space coordinates and transforms them into Earth’s equatorial frame to produce:

  • RA and Declination for every planet, the Sun, and the camera
  • Distances (Earthβ†’planet, Sunβ†’planet, perihelionβ†’planet)

These values emerge from the full 3D geometry β€” all precession layers, orbital tilts, and eccentricities are encoded in the scene hierarchy and reflected automatically in the output.

Analytical formulas β€” computed independently from the scene:

Several values are computed by dedicated functions that use the same input constants but do not read the 3D scene:

FunctionWhat it computesCycles used
computeObliquityEarth()Earth’s axial tiltH/3 and H/8 cosines
computeInclinationEarth()Earth’s orbital inclination to invariable planeH/3 cosine
computePlanetInvPlaneInclinationDynamic()Planet inclinations to invariable planePlanet-specific periods

These functions run on a 10 Hz throttle (not every frame) and feed the GUI predictions panel, year length calculations, and path visualizations. They produce the same numerical results as the 3D geometry β€” the formulas are the analytical representation of what the nested containers create geometrically.

Why both? The 3D scene is the primary computation β€” it produces RA/Dec and distances that can only be derived from the full hierarchical transform. The analytical formulas provide values that could be read from the scene geometry (like obliquity) but are faster to compute directly. They also allow displaying predictions without waiting for the full scene update.

Update sequence each frame:

StepFunctionWhat it doesFrequency
1pos += speedFactor Γ— speed Γ— deltaAdvance timeEvery frame
2trace(pos)Orbit trace samplingEvery frame
3moveModel(pos)Position all objects in the sceneEvery frame
4updatePositions()Read 3D scene β†’ RA/Dec, distancesEvery frame
5updatePositionDisplayStrings()Format RA/Dec for GUI20 Hz
6updatePredictions()Analytical: obliquity, year lengths, precession10 Hz
6updateDynamicInclinations()Planet inclination formulas10 Hz
6updateAscendingNodes()Ascending node positions10 Hz
6updatePlanetAnomalies()True/mean anomalies10 Hz
6updateInvariablePlaneBalance()Invariable plane checks10 Hz
7updateElongations(), updatePerihelion()Elongation angles, perihelion tracking10 Hz
8updateDomLabel()DOM label updates5 Hz
9updateLightingForFocus(), updateFlares()Lighting, lens flares30 Hz
10updateFocusRing(), animateGlow()Focus ring, glow animation10 Hz
11renderer.render(scene, camera)Draw frameEvery frame

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
Holistic-Year333,888 yearsMaster cycle length
Balanced Year-301,340 BCSystem equilibrium point

The simulation demonstrates that all precession phenomena emerge from two simple counter-rotating motions:

  • Earth around EARTH-WOBBLE-CENTER (clockwise, 333,888 Γ· 13 years)
  • PERIHELION-OF-EARTH around Sun (counter-clockwise, 333,888 Γ· 3 years)

Key Takeaways

  1. Two base units - 2Ο€ for time (1 year), 100 for distance (1 AU)
  2. Nested calculations - Each precession builds on the previous in a specific order
  3. Counter-rotating motions - Negative speeds (clockwise) vs positive speeds (counter-clockwise)
  4. Browser-based calculations - All RA/Dec values computed locally, no external APIs
  5. Geocentric frame β€” The Sun orbits Earth at 2Ο€/year; planets use +2Ο€/βˆ’2Ο€ layers for the heliocentric-to-geocentric conversion
  6. Two computation channels β€” RA/Dec from 3D scene geometry; obliquity and inclination from analytical formulas
  7. Excel parity - All simulation values match the Excel spreadsheet calculations

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

Last updated on: