terminal-space-program
Terminal-native orbital-mechanics rocket simulator. A take on Kerbal Space
Program that lives in your terminal, distributed as a single static Go binary.
┌───────────────────────────────────────────────────────────┐
│ terminal-space-program — Sol │
│ ┌─────────────────────────────────────┐ ┌───────────────┐ │
│ │ · · │ │ CLOCK │ │
│ │ · · │ │ T+2026-04-23│ │
│ │ · ⊙ · · ⊕ · │ │ warp: 100x │ │
│ │ · · │ │ │ │
│ │ · · │ │ VESSEL │ │
│ │ │ │ LEO-1 │ │
│ │ │ │ alt: 200 km │ │
│ └─────────────────────────────────────┘ │ v: 7.78 km/s│ │
│ [q] quit [s] system [m] burn [?] help └───────────────┘ │
└───────────────────────────────────────────────────────────┘
Install
Latest release: v0.3.3.
# Linux x86_64
curl -L https://github.com/jasonfen/terminal-space-program/releases/latest/download/terminal-space-program-linux-amd64.tar.gz | tar xz
./terminal-space-program
Replace linux-amd64 with linux-arm64, darwin-amd64, darwin-arm64, or
windows-amd64 (use the .zip variant on Windows).
No Go toolchain, no libc dance. CGO_ENABLED=0 static binaries.
Build from source
git clone https://github.com/jasonfen/terminal-space-program
cd terminal-space-program
go build ./cmd/terminal-space-program
./terminal-space-program
Requires Go 1.24+ (bubbletea dependency chain).
Quick tour
You spawn in low Earth orbit at 200 km altitude. The left panel is the
canvas — Sun at the center, planets on their actual orbits, your
spacecraft as a small cluster. The right HUD shows clock, vessel state,
selected body, planted nodes, and (when relevant) the Hohmann preview to
the selected target. Time-warp with . / , to watch planets move; pause
with 0 or space.
To make something happen:
- Press
←/→ to scroll the cursor through bodies. Pick Mars.
- Press
P to plant a Hohmann transfer — two nodes appear on the canvas
(one in Earth's frame, one in Mars's), the HUD lists them with their
Δv and time-to-fire.
- Time-warp forward. Watch the departure node fire when its trigger time
hits. Your trajectory unrolls past Earth's SOI, the predictor switches
frames, and the curve bends sunward as it should.
- The arrival node fires near Mars. (Phasing isn't enforced in v0.3.1 —
the sandbox assumes Mars is where you need it. Real launch-window
selection comes with the porkchop plot in v0.3.2.)
For finite engine burns instead of instant Δv, press m to open the
planner — set mode, Δv, and a non-zero duration. The integrator switches
from Verlet (energy-conserving free flight) to RK4 (handles the non-
conservative thrust force) and ticks the burn across multiple frames with
mass loss tracked from the rocket equation.
Keybindings
Global
| Key |
Action |
q, Ctrl+C |
Quit |
? |
Toggle help overlay |
Esc |
Back / close panel |
s |
Switch system (Sol → Alpha Cen → TRAPPIST-1 → Kepler-452) |
i |
Body info screen |
0, Space |
Pause / resume sim |
. / , |
Warp up / down (1× → 100000×; clamped to ≤10× during a burn) |
Orbit view
| Key |
Action |
→ / l |
Cursor: next body |
← / h |
Cursor: previous body |
+ / - |
Zoom in / out |
f / F |
Cycle camera focus forward / backward (system → bodies → craft) |
g |
Reset camera focus to system |
n |
Plan a default node (T+5min, prograde, 50 m/s) |
N |
Clear all planned nodes |
P |
Auto-plant Hohmann transfer to selected body (v0.3.1) |
k |
Porkchop plot for selected body (v0.3.3) |
m |
Open maneuver planner |
Maneuver planner (m)
| Key |
Action |
Tab / Shift+Tab |
Cycle field focus (mode → Δv → duration) |
← / → |
Cycle direction mode (when mode field is focused) |
| digits / backspace |
Edit Δv or duration value |
Enter |
Commit burn |
Esc |
Cancel and back to orbit view |
A duration of 0 plants an impulsive burn (instant Δv). A non-zero
duration starts a finite burn that runs for up to that many seconds, or
until the requested Δv is delivered, whichever first.
Features (v0.3.3)
- Porkchop plot (
k). Press k on a selected target to open a
Δv heatmap gridded over departure day (0–365) and time of flight
(100–400 days). Each cell shows the total budget (departure Δv +
capture Δv) for a Lambert-derived Hohmann-style transfer starting
that day with that TOF. Intensity ramp █▓▒░ from cheapest to most
expensive; · marks non-converged / infeasible cells. The cursor
(←/→ dep, ↑/↓ tof) snaps to the minimum-Δv cell on open and
reads out the selected cell's total. Uses synthetic planar-circular
approximations of body orbits for the ephemeris so textbook Hohmann
alignment lands a cell that matches PlanHohmannTransfer within ~15%.
- Multi-revolution Lambert (
LambertSolveRev(..., nRev int)).
For N≥1, the universal-variables z-bracket starts at (2πN)². Single
branch per N (lower-z side); min-energy / multi-branch selection is
a v0.4 polish item if needed.
Features (v0.3.2)
- Perceived body size. Planets and moons render as filled disks
sized by physical-radius tier (moon / terrestrial / gas giant /
star) rather than single dots. The system primary gets a hollow ring
with a filled center to distinguish it from the planets that orbit it.
Sizes are bucketed for readability — even the Sun would be a sub-
pixel speck at Sol-wide zoom if rendered to true scale.
- Vessel orbit path. The craft's current Keplerian orbit ellipse
is drawn live on the canvas (dotted, stride 3) so the player can see
their trajectory at a glance without mentally re-deriving it from a
velocity vector. Renders in the craft's home primary frame,
translated into the system frame so it sits alongside planet orbits.
Hyperbolic escape trajectories are still shown via the SOI-segmented
preview from the maneuver planner.
Features (v0.3.1)
- Auto-plant Hohmann transfer (
P). Select a target body, press one
key, two nodes plant: a geocentric departure burn at parking-orbit
periapsis (raises apoapsis past Earth's SOI), and a destination-frame
arrival burn (drops into low capture orbit). Patched-conic Δv math
matches Curtis Example 8.3 within 5% for Earth → Mars.
- Multi-frame nodes. Each
ManeuverNode carries a PrimaryID tag
identifying which body's frame the burn was planned in. The orbit-view
glyph cluster grows for foreign-frame nodes so the player can see at a
glance which leg is which on auto-planted transfers.
- Frame-aware
PostBurnState. Returns the post-burn state plus the
ID of the primary that frame is relative to — critical for nodes that
fire after the trajectory crosses an SOI boundary.
Features (v0.3.0)
- Lambert solver.
planner.LambertSolve(r1, r2, dt, mu) reproduces
Curtis Example 5.2 within 0.5%; round-trip via Verlet returns to r2
within integrator tolerance. Single-rev prograde only — multi-rev
branches and explicit retrograde handling deferred to v0.3.2.
- SOI-aware predictor. When a sub-step crosses a sphere-of-influence
boundary, the state is rebased to the new primary's frame and μ
switches for subsequent steps. The closing point of each outgoing
segment lands at the actual crossing — no time gap, join continuous
in inertial coords. Resolves the LEO reference-frame trap that v0.2's
predictor punted on (predicted post-escape trajectories were
geometrically wrong even though their coloring was correct).
Features (v0.2.1)
- Finite-duration burns.
Spacecraft.Thrust (1 kN default) drives
per-sub-step engine acceleration via an RK4 integrator path that
handles the non-conservative force cleanly (Verlet would silently
drift). Mass flow dm/dt = -Thrust/(Isp·g0) debits fuel each tick.
Burn ends on Δv delivered, fuel exhausted, or duration elapsed.
- Active-burn HUD. Orbit screen renders a
BURN ACTIVE block while
a burn is in flight (mode, Δv-to-go, T-remaining). Time-warp clamps
to ≤10× during a burn so the integrator keeps temporal resolution on
the burn window.
Features (v0.2)
- View focus / camera follow.
f/F cycles the camera target
across the system primary, every body, and the spacecraft (Sol only);
g resets to the system view.
- Maneuver nodes.
n plants a node on the current orbit; N
clears all pending nodes. Nodes render on-canvas at their projected
inertial position and list in the HUD; firing pops them automatically.
- SOI-segmented trajectory viz. The predicted post-burn trajectory
is partitioned by dominant SOI. Home-SOI samples render dashed,
foreign-SOI samples solid so capture arcs read visually distinct.
- Hohmann preview HUD. When the cursor-selected body has orbital
data, the SELECTED block renders reference heliocentric Δv1 / Δv2 /
transfer time. Earth → Mars matches Curtis §6.2 within 10%.
Features (v0.1)
- Viewer. Physically-plausible renderings of Sol, Alpha Centauri,
TRAPPIST-1, and Kepler-452. Planets move under time warp; orbit lines
from the same Kepler math that places the planets.
- Spacecraft. One vessel in low Earth orbit, propagated with
velocity-Verlet on a patched-conic two-body model. Energy-conservation
verified under 1% drift across 1000 orbits (we ship at ~1e-7%).
- Burns. Impulsive burns with prograde / retrograde / normal± /
radial± modes, rocket-equation fuel accounting, live shadow-trajectory
preview in the planner.
- Time warp. Six discrete steps (1× → 100000×) with integrator-aware
clamping so sim-time can't outrun numerical stability.
- Single binary. 5-target GoReleaser matrix (linux+darwin amd64/arm64,
windows amd64),
CGO_ENABLED=0, -ldflags "-s -w".
Deferred to v0.4+
- Enter-to-plant from the porkchop cursor (reuses
PlanTransfer
once it accepts explicit departure offsets).
- Explicit retrograde-flag for Lambert (today both branches work,
but the selection is driven by the bracket starting point, not a
caller hint).
- Inclination-change planner for out-of-plane corrections.
- Vessel position history trail (distinct from current orbit
ellipse).
- Zoom-level LOD for body size and orbit density.
- Mid-course corrections, save/load, multi-system spacecraft,
N-body perturbations, config-file custom systems, mouse.
Implementation plan
Full design doc: docs/plan.md. Summary:
- Phased physics progression (viewer → Verlet → impulsive burns → finite
burns + RK4 → SOI-aware predictor + Lambert → auto-plant transfers).
- Bubble Tea root model with screen-level sub-models (orbit / bodyinfo /
maneuver / help).
- GoReleaser single-workflow CI; release artifacts on tag push.
Credits
Architectural foundation lifted (with MIT attribution) from
furan917/go-solar-system.
See NOTICE.md for the full acknowledgments list.
License
MIT. See LICENSE.