Live app: https://protonmatter.github.io/sol/
A deterministic, math-first solar-cycle / space-weather simulation engine and a layered learning + research web app built on top of it. Sol is Latin for the Sun — this is not a file explorer.
The design goal is a state-estimation engine, not a shader: a reduced solar-surface
physics model produces immutable, versioned SolarState snapshots, and the renderer only
ever consumes those snapshots. The UI never invents physical values.
Product north star: See the real Sun → understand what's happening on it → then see exactly what the model knows, how it knows it, and what it still can't claim.
-
Engine + data pipeline (Rust + Python)
- Rust workspace:
solar-core(reduced flux-transport model + diagonal Kalman-style assimilation primitive),solar-ingest,solar-cli, andsolar-ephemeris— a zero-dependency VSOP2013 / ELP-MPP02 / TOP2013 ephemeris + topocentric sky engine, published on crates.io. - Python tooling for deterministic fixtures, public-data ingest (NOAA/SWPC, Helioviewer, JPL Horizons), snapshot-series generation, and validation.
- Versioned JSON contracts:
solar-state-snapshot.v2,ephemeris-snapshot.v2,observation-frame.v1,model-run-manifest.v1,operational-readiness.v1, plusseries-manifest.v1. The snapshot shapes are each defined once —docs/solar-state-snapshot-v2.schema.jsonanddocs/ephemeris-snapshot-v2.schema.json— and enforced across Rust, Python, and the browser viatools/validate_snapshot.pyandtools/validate_ephemeris_snapshot.py.
- Rust workspace:
-
Web app (
apps/web/) — a dependency-free, no-build static app that renders the snapshots (the redesign is merged;masteris the only branch and deploys to GitHub Pages):- Real NASA SDO/HMI imagery as the observed photosphere, with the model's active-regions / magnetic field / confidence composited on top (observed-vs-model always labelled).
- A real star catalogue everywhere stars appear: the naked-eye Hipparcos catalogue (8,867 stars, V ≤ 6.5 — true positions, parallax distances, B−V colours) backs the Solar-System view's sky, the Milky-Way view, and a light-year-scale Solar neighbourhood view; the on-device engine reduces 108 bright stars with proper motion for My Sky.
- Three destinations (The Sun · My Sky · Solar System), with the Sun surface layered through progressive-disclosure drawers (layers & region inspection → space-weather impact → the model under the hood); a beginner "glance" by default, research depth on request.
- Onboarding tour, a glossary of every science term, an interactive cycle stage rail, a time scrubber / playback of an idealized 11-year cycle, and a real butterfly diagram (sunspot latitude vs. time).
- The real engine in the browser:
solar-coreis compiled to WebAssembly (crates/solar-wasm) and loaded as an ES module, so a "Run the engine live" control re-solves the actual model in ~2 ms — same validated snapshot contract, no Node/bundler.
See docs/STATUS.md for exactly what's done and what's left, and docs/WEB_REDESIGN_SPEC.md for the full redesign plan. A proposed next direction — a solar-system + local-sky (ephemeris) engine, "NASA Eyes meets SkyView, grounded in facts" — is specced in docs/SOLAR_SYSTEM_SPEC.md.
# Serve it (required — the app is native ES modules, which browsers block over file://)
python -m http.server 8000 --directory apps/web
# then open http://localhost:8000My Sky, Solar System, and the "Run the engine live" control run the real Rust
engines compiled to WebAssembly. The .wasm binaries are not committed (they are
built from source at deploy); build them once locally or those surfaces will explain
they're unavailable and fall back:
rustup target add wasm32-unknown-unknown # one-time
python tools/build_wasm.py # stages apps/web/pkg/*.wasmThe 3-D View draws its surfaces from three sources, in priority order:
-
Real photographic maps (NASA Blue Marble + Solar System Scope CC-BY + USGS moon mosaics) for every body that has one. They are a COMMITTED baseline — deploys must not depend on a third-party host being up — and refreshed, not obtained, by:
python tools/fetch_textures.py # ~6 MB, refresh only -
Committed vector geography, which ships with the repository and needs no download: Earth's real coastlines, lakes and permanent ice (Natural Earth 1:110m, public domain) and the Moon's maria at their IAU/USGS coordinates. Generated by
tools/generate_geography.pyand rasterised in the browser, so every deployment shows real geography rather than noise. -
Procedural shaders for the bodies neither of the above covers — Mars and Mercury, whose catalogued features have real positions but no published albedo. See
tools/ephemeris-data/geography/README.mdfor why guessing was rejected.
The view also draws the 21 major moons of Mars, Jupiter, Saturn, Uranus and Neptune from JPL
Horizons elements (tools/ephemeris-data/moons/), validated in CI against Horizons state vectors
to within 0.139° angular and 0.19% radial error across 11,985 interleaved checks. They are shown
only from January 2021 through December 2030, the exact interval independently checked for every
moon. Ten of them wear committed USGS global mosaics and all are shaded at their published
geometric albedo; a transiting moon casts its real umbra/penumbra on the planet's disc, computed
from physical positions (never the inflated display orbits), and a moon inside its planet's
shadow cone goes eclipse-dark.
# The live "today" snapshot — a deterministic ILLUSTRATIVE fixture (static bipole
# painting; its manifest says so). The real flux-transport engine is `solar-cli simulate`
# (below) and the in-browser WASM run.
python tools/generate_fixture_snapshot.py \
--out apps/web/data/latest-state.json \
--observations-out tests/fixtures/live-swpc-normalized.json --seed 42
# The solar-cycle series for timeline playback + the butterfly diagram
python tools/generate_series.py
# Validate everything
python tools/validate_snapshot.py apps/web/data/latest-state.json
python tools/validate_operational_readiness.py apps/web/data/latest-state.json
python tools/validate_web_static.py --root apps/webcargo test --workspace
cargo run -p solar-cli -- simulate --steps 48 --dt-hours 1 --seed 42 \
--out apps/web/data/latest-state.jsonThe solar-ephemeris engine (zero-dependency positions + topocentric sky) is published
on crates.io:
cargo add solar-ephemeris # https://crates.io/crates/solar-ephemerisSee crates/solar-ephemeris/README.md for install and usage.
Full developer instructions: docs/INSTRUCTIONS.md.
Install the locked JavaScript validation tools, then run the fast cross-language contract:
npm ci --ignore-scripts
python tools/validate_sdlc.py
python tools/validate_docs.py
python tools/validate_ux_contract.py
PYTHONPATH=tools python -m unittest discover -s tests/python -p 'test_*.py' -v
npm test
python tools/typecheck_web.py
python tools/validate_web_static.pyThe full CI additionally builds/tests Rust and WASM, runs the real app in Chromium with WebGL visual assertions, compares deterministic snapshots across Linux/macOS/Windows, and enforces at least 90% Rust, Python, and denominator-complete web line coverage. See CONTRIBUTING.md and docs/VALIDATION_PLAN.md.
apps/web/ Static web app (index.html, app.js, styles.css)
apps/web/data/ Snapshots the app reads: latest-state.json, feed-status.json,
latest-observations.json, series/ (cycle frames + manifest)
crates/ Rust workspace (solar-core, solar-ingest, solar-cli, …)
python/ Runnable prototype (synthetic solar maximum image)
tools/ Python generators, ingest, validators + shell helpers (watch-ci.sh)
docs/ Specs, requirements, RFCs/ADRs, UX, validation, status + operations
tests/ Fixtures and golden snapshots
Behavior starts with a stable requirement in
docs/requirements.json, links to the governing specification,
and ends with implementation, verification, and a named CI gate. Material contract,
privacy, UX-workflow, architecture, or release-policy changes use the
docs/rfcs/ process; durable architecture decisions use
docs/adr/.
The lifecycle is documented in docs/SDLC.md, the standards boundary in
docs/STANDARDS.md, and the progressive-disclosure/accessibility
contract in docs/UX_GUIDELINES.md. CI validates all of them
before the tested SHA can deploy.
A reproducible solar-maximum state from a solar-cycle activity index, a bipolar active-region birth model, differential rotation, surface flux transport, and probabilistic flare/CME hazard fields.
solar-cli simulate --observations <report.json> corrects the scalar activity forecast
with the daily pipeline's observed activity index through the diagonal Kalman-style
update below — freshness-damped from the report's own staleness evaluation, and gated on
attributable provenance (frames without a source are disclosed, not embedded). The
snapshot is emitted in Assimilation mode with the evidence frames attached; the Br
grid remains synthetic and says so — spatial assimilation waits for real magnetogram
frames (ROADMAP v0.4). Unusable observations leave the run Synthetic with a warning
saying why; degraded inputs never inflate the mode. See ADR 0005.
forecast x_f = M(x_t)
residual r = y - H(x_f)
gain K = P_f / (P_f + R)
analysis x_a = x_f + freshness_gain * K * r
variance P_a = (1 - K) * P_f
This app is operational for deterministic research and learning workflows only. It is
not operational space-weather forecasting. operational_readiness.space_weather_operational
stays false until calibrated physical units, historical validation, comparison against
operational SWPC products, adapter-freshness monitoring, alerting, and approval evidence
exist. Normalized magnetic values are labelled normalized — never asserted as Gauss/Mx.
Claims are anchored to public, inspectable products: NOAA SWPC,
Helioviewer, NASA SDO
browse imagery, JPL/NAIF SPICE, and
NN/g progressive disclosure.
No SpaceX equivalence or proprietary internal JPL/SpaceX algorithm is claimed.
See docs/STANDARDS.md for exact IETF, W3C, NIST, OWASP, and
usability-guidance scope; no blanket certification or conformance is claimed.
MIT OR Apache-2.0.