Flight-dynamics manual - 3 bodies - schematic two-body model
Astrodynamics
The mission map is not decoration: each body moves on a real Keplerian orbit solved every frame. This page documents the math, the constants, and the boundary between honest physics and schematic visuals — sourced directly from the code that runs the map.
Live system
Below is the actual map component, identical to the one on the home page. Every formula in the following sections is what positions these bodies. Use the Time control to change the simulation rate, Stack to reveal project moons, Refs to toggle the JPL layer, and drag / scroll to move the camera.
Controls
Legend
Interactive orbit map. Distance and speed encode project complexity; body size encodes project volume. Reference planets (Refs) and close-approach pings ride the same simulated clock.
Complexity → orbit scale
Each project carries three 1–5 complexity ratings. A weighted average becomes the project's
score, and the score maps to the semi-major axis a — the orbit's size —
so larger / more complex projects sit farther from the star.
score = volume × 0.35 + architecture × 0.45 + polish × 0.2 a (semi-major) = map(score, 1..5 → 128..286 px) radius = map(volume, 1..5 → 9..25 px)
Architecture is weighted highest (0.45) because system design is the strongest signal of engineering depth. Body size tracks volume alone, so a project can read as physically large from surface area even when its score is moderate.
| Code | Project | V/A/P | Score | a (px) | e | AU | Period (d) | °/day |
|---|---|---|---|---|---|---|---|---|
| MSN-02 | Kibo | 2/2/1 | 1.8 | 160 | 0.2 | 0.794 | 258 | 1.393 |
| MSN-01 | Aphelion | 4/4/3 | 3.8 | 239 | 0.14 | 2.8 | 1,711 | 0.21 |
| MSN-03 | Cosmic Gyoza Express | 5/5/2 | 4.4 | 262 | 0.28 | 3.614 | 2,509 | 0.143 |
Ellipse geometry
Kepler's first law: each body orbits on an ellipse with the star at one focus, not the
center. From the semi-major axis a and eccentricity e the rest of the
shape follows.
b = a · √(1 − e²) // semi-minor axis cx = −a · e // ellipse centre, offset from the star at the origin rx = a, ry = b // then rotate by the argument of periapsis ω
c = a·e from the centre, so the body is closest
(periapsis) on the star side and farthest (apoapsis) opposite. Eccentricity here is
exaggerated for clarity.
Kepler's equation & the solver
The hard part is where a body is at a given time. Time enters as the mean anomaly M (which advances uniformly), but position needs the eccentric anomaly E. They are related by Kepler's transcendental equation, solved each frame with a
few Newton iterations — the same procedure JPL documents for approximate planetary positions.
M = E − e · sin E // Kepler's equation (no closed form) E ← E − (E − e·sin E − M) / (1 − e·cos E) // Newton step, iterated ~7× x = a · (cos E − e) // position in the orbital plane y = b · sin E (x, y) → rotate by ω (argument of periapsis)
P on the ellipse. Its vertical projection meets the radius-a
auxiliary circle at Q; the centre angle to Q is the eccentric anomaly
E. Equal time steps in M give unequal arc length along the ellipse — that
is why bodies visibly speed up near the star (Kepler's second law).
The unified ecosystem law
Project bodies and real JPL planets obey one law. The same screen-distance → AU mapping that places the reference planets is inverted for project bodies, then Kepler's third law (period² ∝ semi-major³) sets each period. A project sitting on a given visual ring therefore orbits at the same rate as a planet on that ring.
au = ((a − 70) / 101)² // inverse of the JPL display mapping periodDays = 365.25 · au^1.5 // Kepler's third law, year-normalised meanMotion = 360 / periodDays // degrees per simulated day
Because the mapping round-trips, feeding the real planets' on-screen radii back through this law reproduces their true periods (~88, ~366, ~687, ~4332 days — see the reference table below). The project bodies thus obey genuine Keplerian physics derived from their visual distance, not an arbitrary constant.
Speed regulator & simulated clock
All motion is driven by one simulated-day clock. The Time control sets how many simulated days
pass per real second; the same value scales every body, so relative speeds stay correct at any
setting. The clock accumulates deltas rather than elapsed × speed, so
changing speed never teleports a body, and pausing is simply "stop accumulating".
simDays += (deltaMs / 1000) · daysPerSecond
| Preset | days / sec | Notes |
|---|---|---|
| Static | 0 | Frozen — server-rendered snapshot positions. |
| Real-time | 1 / 86400 | True 1:1 — honest, near-imperceptible motion. |
| 1 day/s | 1 | Mercury ~88 s/rev, Earth ~366 s/rev. |
| 1 wk/s ◂ default | 7 | Default — Mercury ~13 s, Earth ~52 s. |
| 1 mo/s | 30 | Fast survey view of the whole ecosystem. |
The selection persists in localStorage. Under prefers-reduced-motion the
map starts at Static; moving the slider is treated as explicit consent and the ecosystem
animates from then on.
Reference-body layer (JPL Horizons)
Four real planets are animated from osculating orbital elements captured from NASA/JPL Horizons at build time (epoch 2026-06-15). The browser makes no API calls — the snapshot is static data. Each planet rides the same simulated clock, so its visible period scales with the speed setting while preserving true relative motion (Mercury still laps Earth).
M = M₀(epoch) + simDays · meanMotion // advance from the snapshot mean anomaly E = solveKepler(M, e) // same Newton solver as project bodies (x, y) = ( rx·(cos E − e), ry·sin E ) → rotate by ω
| Body | a (AU) | e | Period (d) | °/day | Visible @ 7 d/s |
|---|---|---|---|---|---|
| Mercury | 0.387 | 0.206 | 88 | 4.0923 | ~13 s |
| Earth | 1.001 | 0.016 | 366 | 0.9842 | ~52 s |
| Mars | 1.524 | 0.093 | 687 | 0.5241 | ~2 min |
| Jupiter | 5.202 | 0.048 | 4,332 | 0.0831 | ~10 min |
Project moons (stack satellites)
Each project planet carries moons — one per core stack component. A moon runs the same two-body Kepler solve as a planet, but about its planet instead of the star; the planet's heliocentric motion then carries the whole moon system along (a vector sum each frame).
a_moon = semiMajorRadii · planet.radius // distance authored in planet radii periodDays = 12 · semiMajorRadii^1.5 // same Kepler shape, per planet moonPos = planetPos + moonLocal // planet-centred vector sum
Distances are in planet radii so moons scale with their planet. Moons are hidden at system scale and reveal when the parent is selected, when camera zoom ≥ 1.3, or when the Stack layer is forced on. Moon masses and mutual perturbation are out of scope — deliberately schematic.
Visual polish (not physics)
A few effects are presentation, not simulation:
- Trails — 9 sampled positions across the last 7.5% of each body's period along its real orbit curve (not particles).
- Camera — UI easing toward a target transform (
current += (target − current) · 0.14), not a physical body. - Signal sweep — a rotating radial line and expanding ring; both stop under reduced motion.
Limitations (the honest part)
- No N-body gravity, masses, velocities, accelerations, or gravitational constant
μ. - No real astronomical scale — complexity is mapped into orbit size.
- Reference bodies animate from a snapshot of elements, not live ephemeris.
- Runtime math is intentionally duplicated from the build-time model so the browser script stays self-contained.
The intended compromise: realistic behaviour with schematic visuals.
References & source map
External sources that informed the formulas and terminology (verified official NASA/JPL pages):
- Orbits and Kepler's Laws NASA Science Conceptual basis: elliptical orbits, the primary at one focus, non-uniform speed, and longer periods farther out.
- Approximate Positions of the Planets JPL Solar System Dynamics Keplerian elements and the exact Kepler-equation Newton solve (M = E − e·sin E; x' = a(cos E − e), y' = a√(1−e²)·sin E) the map reuses.
- Horizons API documentation JPL Solar System Dynamics Osculating orbital-element vocabulary (EC, W, MA, A, N) for the reference-body snapshot fetched at build time.
- Horizons system JPL Solar System Dynamics The ephemeris system the reference-body elements are sourced from.
- CAD (Close-Approach Data) API JPL Solar System Dynamics Source of the ambient close-approach source markers (pings) on the map.
- CSPICE conics_c NASA/JPL NAIF Conic-element → state vocabulary (periapse argument, mean anomaly at epoch, μ) the schematic model deliberately simplifies.
| Idea | Reference | File |
|---|---|---|
| Ellipse with the star at one focus | NASA Kepler's laws | src/data/orbit-model.ts |
| Semi-major axis / eccentricity | JPL approximate positions | src/data/orbit-scale.ts |
| Kepler's equation (Newton solve) | JPL approximate positions | src/data/orbit-model.ts, src/scripts/orbit-map.ts |
| Osculating element vocabulary | JPL Horizons API | src/content.config.ts, src/data/orbit-scale.ts |
| Conic-to-state concept | NAIF CSPICE conics_c | src/scripts/orbit-map.ts |