SOLSYS visualizes the solar system with corrected Keplerian physics — from the inner planets out past the Kuiper Belt and Oort Cloud to nearby stars.
The main product is animation: light/dark GIFs of the inner system and a staged 3D zoom from the Oort cloud inward. A side product renders static multi-zoom JPGs (light/dark) and a light-year neighborhood star map. Shared libraries hold orbit math, catalogs, and asteroid-population motion so both products stay in sync.
Built with numpy, pandas, and matplotlib. Orbital elements include elliptical planet orbits, spherical asteroid/Kuiper/Oort shells, Jupiter Trojans/Greeks, Hilda clusters, moons, named asteroids, and hyperbolic interstellar visitors (1I/ʻOumuamua, 2I/Borisov, 3I/ATLAS) from data/interstellar_objects.csv.
| Layer | Path | Role |
|---|---|---|
| CLI | render.py |
Single entry point: animate / static / neighborhood / all |
| Main product | animate/ |
GIF animations (2D inner system + 3D zoom tour); Blender close-ups planned under animate/scenes/blender/ |
| Side product | static/ |
Multi-zoom JPGs light/dark (2D top-down / 3D) and neighborhood star map |
| Shared physics | solsys/physics/ |
Constants, orbits, catalogs, belt generators, view registry |
| Shared motion | solsys/motion/ |
Animated asteroid / Hilda / Trojan / Kuiper / Oort populations |
Outputs
- Main:
output/animate/2d/,output/animate/3d/ - Side:
output/2d/,output/3d/,output/neighborhood/
SOLSYS/
├── render.py # CLI entry point
├── requirements.txt
├── requirements-dev.txt # pre-commit, ruff, radon, xenon
├── pyproject.toml # Ruff config
├── .pre-commit-config.yaml # Git hook definitions
├── .githooks/
│ └── commit-msg # type(SOLSYS[-N]): subject
├── README.md
├── docs/
│ ├── keplers_three_laws.png # Kepler laws diagram
│ └── generate_keplers_laws_figure.py # Regenerates the diagram
├── data/
│ ├── nearby_stars_30.csv # Star catalog (RA/Dec, distances, system_id; includes hosts beyond 30 ly)
│ ├── systems.csv # Star systems (sol, alpha_centauri, barnards_star, trappist_1, tabbys_star, …)
│ ├── stellar_orbits.csv # Multi-star orbits vs system barycenter
│ ├── planets.csv # Exoplanets linked by host_star_uuid
│ ├── interstellar_objects.csv # 1I/2I/3I hyperbolic visitors
│ └── tabbys_star_lightcurve.csv # Downsampled Kepler LC for Tabby's Star inset
│
├── animate/ # MAIN PRODUCT — GIF animations
│ ├── __init__.py
│ ├── solar_system_animator.py # SolarSystemAnimator, renderAllAnimations
│ ├── camera_controller.py # CameraController
│ ├── animation_styles.py # Light/dark styles and timing constants
│ └── scenes/
│ ├── inner_system.py # Fixed 2D inner-system scene
│ ├── zoom_tour.py # Staged 3D Oort → inner zoom
│ ├── exoplanet_system.py # Shared single-host exoplanet top-down animator
│ ├── alpha_centauri.py # A–B close-up, wide triple; Proxima via exoplanet_system
│ ├── sol_centauri_cinematic.py # Sol → α Cen AB cinematic (uses frame transform)
│ ├── barnards_star.py # Barnard's Star planets via exoplanet_system
│ ├── trappist_1.py # TRAPPIST-1 planets via exoplanet_system
│ ├── tabbys_star.py # Tabby's Star dust-cloud dimming schematic
│ ├── interstellar_objects.py # 1I/2I/3I hyperbolic passages (side + oblique)
│ └── blender/ # Future planet close-ups
│ └── README.md
│
├── static/ # SIDE PRODUCT — still images
│ ├── __init__.py
│ ├── solar_system_visualizer.py # SolarSystemVisualizer
│ ├── interstellar_neighborhood_visualizer.py # InterstellarNeighborhoodVisualizer
│ ├── dimension_plotter.py # DimensionPlotter
│ └── hilda_point_generator.py # HildaPointGenerator
│
├── tests/ # Unit tests (stdlib unittest)
│ ├── test_frame_transform.py # Sol ↔ α Cen frame transform
│ └── test_sol_centauri_cinematic.py # Sol → α Cen cinematic helpers
│
├── solsys/ # Shared libraries (no plotting)
│ ├── physics/
│ │ ├── astronomical_constants.py # AstronomicalConstants
│ │ ├── orbit_calculator.py # OrbitCalculator
│ │ ├── frame_transform.py # Sol ↔ α Cen AB barycenter frame transform
│ │ ├── belt_point_generator.py # BeltPointGenerator
│ │ ├── view_definition.py # ViewDefinition
│ │ ├── view_registry.py # ViewRegistry
│ │ ├── point_density_config.py # PointDensityConfig
│ │ └── catalogs/
│ │ ├── planet_catalog.py # PlanetCatalog, PlanetOrbit (Sol, hard-coded)
│ │ ├── moon_catalog.py # MoonCatalog, MoonOrbit
│ │ ├── famous_asteroid_catalog.py # FamousAsteroidCatalog, FamousAsteroidOrbit
│ │ ├── star_catalog.py # StarCatalog
│ │ ├── system_catalog.py # SystemCatalog (multi-star systems)
│ │ └── interstellar_object_catalog.py # InterstellarObjectCatalog (1I/2I/3I)
│ └── motion/
│ ├── mean_anomaly.py # meanAnomalyAtFrame, planetMeanAnomalyRad
│ └── animated_asteroid_population.py # AnimatedAsteroidPopulation, AsteroidPopulationCounts
│
└── output/
├── animate/
│ ├── 2d/ # inner_solar_system_{light,dark}.gif
│ ├── 3d/ # solar_system_{light,dark}.gif
│ ├── alpha_centauri/ # ab / system_wide / proxima_planets GIFs
│ ├── sol_centauri/ # sol_centauri_cinematic_{light,dark}.gif
│ ├── barnards_star/ # barnards_star_planets_{light,dark}.gif
│ ├── trappist_1/ # trappist_1_planets_{light,dark}.gif
│ ├── tabbys_star/ # tabbys_star_dust_{light,dark}.gif
│ └── interstellar_objects/ # {oumuamua,borisov,atlas}_{side,oblique}_{light,dark}.gif
├── 2d/ # Static top-down zoom JPGs (*_{light,dark}.jpg)
├── 3d/ # Static perspective zoom JPGs (*_{light,dark}.jpg)
└── neighborhood/ # interstellar_neighborhood_*ly.jpg
render.py
├── animate/ ← main product (matplotlib GIFs)
│ └── uses solsys.motion + solsys.physics
└── static/ ← side product (matplotlib JPGs)
└── uses solsys.physics
solsys.physics → constants, Kepler/hyperbola math, catalogs
solsys.motion → moving asteroid fields for animation frames
2D views are a top-down projection of the same XYZ geometry used in 3D.
Inner Solar System
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System Zoom
| Light | Dark |
|---|---|
![]() |
![]() |
Sol → Alpha Centauri cinematic
| Light | Dark |
|---|---|
![]() |
![]() |
Inner Solar System With Jupiter
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System With Kuiper Belt
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System With Oort Cloud
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System with Alpha Centauri
| Light | Dark |
|---|---|
![]() |
![]() |
Neighbors Within 10 Light Years
| Light | Dark |
|---|---|
![]() |
![]() |
Neighbors Within 25 Light Years
| Light | Dark |
|---|---|
![]() |
![]() |
Inner Solar System With Jupiter
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System With Kuiper Belt
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System With Oort Cloud
| Light | Dark |
|---|---|
![]() |
![]() |
Solar System with Alpha Centauri
| Light | Dark |
|---|---|
![]() |
![]() |
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/pre-commit install
.venv/bin/pre-commit install --hook-type commit-msgAfter install, commits are gated by:
- pre-commit — Ruff format + lint on
animate/,static/,solsys/,render.py - commit-msg — enforces the commit message rules below
First line must match:
type(SOLSYS): subject
type(SOLSYS-123): subject
| Part | Rule |
|---|---|
type |
One of feat, fix, chore, docs, clean |
| Scope | SOLSYS or SOLSYS-<ticket> (digits only) |
| Subject | Required non-empty text after : |
Examples:
feat(SOLSYS): add light/dark static themes
fix(SOLSYS-42): correct Hilda resonance rate
docs(SOLSYS): document commit message rules
chore(SOLSYS): bump ruff
clean(SOLSYS): remove unused Pluto study script
Merge / revert / fixup / squash commits are allowed through unchanged.
Manual checks:
.venv/bin/pre-commit run --all-files
.venv/bin/ruff format animate static solsys render.py
.venv/bin/ruff check animate static solsys render.py
.venv/bin/radon cc animate static solsys render.py -s -a
.venv/bin/python -m unittest discover -s tests -vRender everything (~several minutes for animations):
export MPLBACKEND=Agg
.venv/bin/python render.py allOr render by product:
.venv/bin/python render.py animate --dimension all
.venv/bin/python render.py animate --dimension 3d
.venv/bin/python render.py animate --system alpha_centauri
.venv/bin/python render.py animate --system sol_centauri
.venv/bin/python render.py animate --system barnards_star
.venv/bin/python render.py animate --system trappist_1
.venv/bin/python render.py animate --system tabbys_star
.venv/bin/python render.py animate --system interstellar
.venv/bin/python render.py animate --system interstellar --object borisov
.venv/bin/python render.py animate --system oumuamua
.venv/bin/python render.py static --dimension 2d
.venv/bin/python render.py neighborhood --ly 10Alpha Centauri (issue #1) is one system_id covering A, B, and Proxima. Animations render to output/animate/alpha_centauri/:
alpha_centauri_ab_{light,dark}.gif— A–B binary close-up (±28 AU)alpha_centauri_system_{light,dark}.gif— wide triple with Proxima (~8.7 kau)proxima_planets_{light,dark}.gif— confirmed Proxima planets (via sharedexoplanet_systemanimator)
Sol → Alpha Centauri cinematic (issue #10) flies from our solar system to the A–B close-up, zooms back out, then finishes on Proxima and its planets — all in Sol XYZ via SolCentauriFrameTransform. Animations render to output/animate/sol_centauri/:
sol_centauri_cinematic_{light,dark}.gif— Sol → AB → wide → Proxima planets
Barnard's Star (issue #15) is a nearby M dwarf (~6 ly) with four confirmed sub-Earth planets. Animations render via exoplanet_system to output/animate/barnards_star/:
barnards_star_planets_{light,dark}.gif— compact planets d, b, c, e
TRAPPIST-1 (issue #7) is a single-host ultracool dwarf (~40.7 ly) with seven confirmed planets. Animations render via exoplanet_system to output/animate/trappist_1/:
trappist_1_planets_{light,dark}.gif— compact resonant chain (b–h)
Tabby's Star (issue #17 / Boyajian's Star / KIC 8462852) has no confirmed planets. The scene visualizes the leading uneven circumstellar dust / debris explanation for its irregular Kepler dips (not a megastructure). Animations render to output/animate/tabbys_star/:
tabbys_star_dust_{light,dark}.gif— real Kepler LC (data/tabbys_star_lightcurve.csv); orbiting dust clumps of different sizes cross the LOS at observed dip times
ʻOumuamua–Earth flyby (issue #2) and interstellar visitors (issue #5) render from
data/interstellar_objects.csv via InterstellarObjectCatalog to
output/animate/interstellar_objects/:
{oumuamua,borisov,atlas}_{side,oblique}_{light,dark}.gif
CLI: render.py animate --system interstellar (all) or --object oumuamua|borisov|atlas.
--system oumuamua remains as an alias for ʻOumuamua only.
- Planet and asteroid positions use Keplerian ellipses (and a hyperbola for
'Oumuamua). - Asteroid / Kuiper / Oort fields use spherical shells in 3D; 2D is the XY projection.
- Hildas follow a 3:2 resonance angular rate relative to Jupiter.
- Jupiter Trojans and Greeks sit near the L4 / L5 Lagrange longitudes.
- Moon orbits are exaggerated for visibility at solar-system zoom levels.
- Coordinate frames (multi-star): Sol scenes use a heliocentric / Sol-barycentric frame in AU, with +X/+Y/+Z from the equatorial Cartesian mapping in
OrbitCalculator.equatorialToCartesianAu(RA/Dec → XYZ). Alpha Centauri scenes use a separate α Cen AB-barycentric frame in AU, plotted face-on in the binary orbital plane (sky inclination stored in CSV but not applied to the 2D schematic).SolCentauriFrameTransforminsolsys/physics/frame_transform.pymaps between those frames: mass-weighted AB barycenter origin fromnearby_stars_30.csv, and rotation from the Centauri orbital plane into Sol XYZ using the A/B(i, Ω)convention shared withOrbitCalculator.ellipticalPosition(toSol/toCentauri). The Sol → Centauri cinematic (animate/scenes/sol_centauri_cinematic.py,--system sol_centauri) consumes this API to place A/B in Sol XYZ while the camera travels from the neighborhood into the binary.
- Additional star systems via
SystemCatalog/data/systems.csv(exoplanet_system.pyfor planet disks; dedicated scenes for dust / other phenomena) - Blender-based planet close-ups / flybys in
animate/scenes/blender/


























