Documentation
¶
Index ¶
- Variables
- func TickCmd(d time.Duration) tea.Cmd
- type ActiveBurn
- type Clock
- type Focus
- type FocusKind
- type HohmannPreview
- type ManeuverNode
- type SOISegment
- type TickMsg
- type World
- func (w *World) BodyPosition(b bodies.CelestialBody) orbital.Vec3
- func (w *World) ClearNodes()
- func (w *World) CraftInertial() orbital.Vec3
- func (w *World) CraftTrail() []orbital.Vec3
- func (w *World) CraftVisibleHere() bool
- func (w *World) CycleFocus(forward bool)
- func (w *World) CycleSystem()
- func (w *World) EffectiveWarp() float64
- func (w *World) FocusName() string
- func (w *World) FocusPosition() orbital.Vec3
- func (w *World) FocusZoomRadius() float64
- func (w *World) HohmannPreviewFor(bodyIdx int) HohmannPreview
- func (w *World) NodeInertialPosition(n ManeuverNode) orbital.Vec3
- func (w *World) PlanNode(n ManeuverNode)
- func (w *World) PlanTransfer(targetIdx int) (*planner.TransferPlan, error)
- func (w *World) PlanTransferAt(targetIdx int, depDay, tofDay float64) (*planner.TransferPlan, error)
- func (w *World) PorkchopGrid(targetIdx int, depDays, tofDays []float64) ([][]float64, error)
- func (w *World) PostBurnState(n ManeuverNode) (physics.StateVector, string)
- func (w *World) PredictedSegments(post physics.StateVector, totalSeconds float64, samples int) []SOISegment
- func (w *World) RefinePlan() (correctionDv, arrivalDv float64, err error)
- func (w *World) ResetFocus()
- func (w *World) System() bodies.System
- func (w *World) Tick()
Constants ¶
This section is empty.
Variables ¶
var WarpFactors = []float64{1, 10, 100, 1000, 10000, 100000}
WarpFactors are the discrete time-warp steps per docs/plan.md §Time-warp UX.
Functions ¶
Types ¶
type ActiveBurn ¶ added in v0.2.1
type ActiveBurn struct {
Mode spacecraft.BurnMode
DVRemaining float64
EndTime time.Time
PrimaryID string
}
ActiveBurn is the runtime state of an in-progress finite burn. Set by executeDueNodes when a node with Duration>0 fires; cleared by the integrator when DVRemaining hits zero or SimTime passes EndTime. PrimaryID is propagated from the originating ManeuverNode (empty for legacy nodes) — diagnostic only; the integrator always works in the craft's current primary frame.
type Clock ¶
type Clock struct {
SimTime time.Time
WarpIdx int
Paused bool
BaseStep time.Duration // real-time step per tick at warp 1×
}
Clock tracks sim-time advancement and the currently active warp factor.
func (*Clock) Advance ¶
func (c *Clock) Advance()
Advance moves SimTime forward by BaseStep × warp. Called once per tick.
type Focus ¶ added in v0.2.0
Focus describes the current OrbitView center. The zero value (FocusSystem, BodyIdx=0) is the v0.1.0 behavior.
type FocusKind ¶ added in v0.2.0
type FocusKind int
FocusKind enumerates what the OrbitView canvas is centered on.
const ( // FocusSystem centers on the system primary (Sun) and auto-fits to the // outermost body's apoapsis. This is the v0.1.0 default. FocusSystem FocusKind = iota // FocusBody centers on a specific body by its index in System().Bodies. FocusBody // FocusCraft centers on the spacecraft's inertial position. Only // reachable when CraftVisibleHere is true. FocusCraft )
type HohmannPreview ¶ added in v0.2.0
type HohmannPreview struct {
TargetName string
DV1, DV2 float64 // m/s
TTransfer float64 // seconds
Valid bool // false when inputs are degenerate
Note string // human-readable reason when !Valid
}
HohmannPreview summarises a reference heliocentric (system-primary- centered) Hohmann transfer from the craft's current distance to a target body's orbital radius. The numbers assume both legs are circular and coplanar — textbook Hohmann. Phasing is ignored; this is a "what would it cost?" display, not a physically-accurate multi-impulse planner.
func (HohmannPreview) Format ¶ added in v0.2.0
func (p HohmannPreview) Format() []string
Format renders the preview as 3 short lines for the HUD.
type ManeuverNode ¶ added in v0.2.0
type ManeuverNode struct {
TriggerTime time.Time
Mode spacecraft.BurnMode
DV float64
Duration time.Duration
PrimaryID string
}
ManeuverNode represents a planned burn that will fire when World.Clock.SimTime reaches TriggerTime. Nodes are forward-looking only; once fired, they are removed from World.Nodes.
Duration controls finite vs impulsive: zero = instant Δv (legacy v0.1 path); non-zero = sustained engine burn lasting up to Duration or until DV is delivered, whichever first. Finite-burn execution is driven by World.ActiveBurn during subsequent ticks.
PrimaryID is the body whose frame the burn was planned in (empty = the craft's home primary at plant time, which is the v0.1 default and keeps legacy nodes working). Auto-plant transfers (v0.3.1) plant a geocentric departure plus a heliocentric arrival; PrimaryID lets the planner UI render a frame-distinct glyph and lets the burn- execution layer warn if a node fires in an unexpected frame.
type SOISegment ¶ added in v0.2.0
type SOISegment struct {
PrimaryID string
Points []orbital.Vec3 // inertial, system-primary-centered
}
SOISegment is a contiguous run of predicted-trajectory samples that share the same owning SOI primary. PrimaryID == craft's home primary means "still in the home SOI"; a different ID means the segment has crossed into another body's sphere of influence.
type TickMsg ¶
TickMsg is emitted by the Bubble Tea runtime on each physics step. The embedded time.Time is the wall-clock time of the tick, unused by the physics integrator but handy for throttling UI updates.
type World ¶
type World struct {
Systems []bodies.System
SystemIdx int
Calculator orbital.Calculator
Clock *Clock
// Craft is the player vessel. Spawns around Earth in Sol at startup.
// Nil when no primary is loaded (unreachable in v0.1).
Craft *spacecraft.Spacecraft
// Focus selects what the OrbitView canvas is centered on. Zero value
// (FocusSystem) matches v0.1.0 behavior.
Focus Focus
// Nodes holds planned burns, sorted by TriggerTime. Each fires
// automatically when Clock.SimTime reaches its trigger.
Nodes []ManeuverNode
// ActiveBurn is non-nil while a finite-duration burn is mid-execution.
// Set by executeDueNodes when a Duration>0 node fires; cleared by
// integrateSpacecraft when DVRemaining hits zero or SimTime ≥ EndTime.
ActiveBurn *ActiveBurn
// contains filtered or unexported fields
}
World holds the simulation state: loaded systems, active-system index, the sim-clock, and — post-C15 — the spacecraft.
func NewWorld ¶
NewWorld loads the embedded systems, seeds clock at J2000 + 50 ms base step, and spawns a spacecraft in LEO around Sol's Earth.
func (*World) BodyPosition ¶
func (w *World) BodyPosition(b bodies.CelestialBody) orbital.Vec3
BodyPosition returns the inertial position (m) of a body in the current system at the current sim time. Primary (index 0) is anchored at origin. Bodies with ParentID set (moons; v0.5.0+) are resolved recursively as parent_position + position-relative-to- parent, so Luna sits in Earth's frame, Io in Jupiter's, etc.
func (*World) ClearNodes ¶ added in v0.2.0
func (w *World) ClearNodes()
ClearNodes wipes every pending node.
func (*World) CraftInertial ¶
CraftInertial returns the spacecraft's inertial position (Sun-centered) for rendering on the heliocentric canvas. Adds craft's primary-centric position to the primary's inertial position.
func (*World) CraftTrail ¶ added in v0.5.2
CraftTrail returns the trail samples in oldest-to-newest order. The returned slice is a fresh copy — callers can iterate / reverse safely. Empty when the craft has just spawned and hasn't accumulated trailIntervalSec of sim time yet.
func (*World) CraftVisibleHere ¶
CraftVisibleHere reports whether the spacecraft should be drawn in the currently-viewed system. v0.1 Craft lives in Sol only.
func (*World) CycleFocus ¶ added in v0.2.0
CycleFocus advances the focus to the next target (or previous if forward=false). Order: System → Body(0) → Body(1) → … → Body(n-1) → Craft (only if CraftVisibleHere) → System.
func (*World) CycleSystem ¶
func (w *World) CycleSystem()
CycleSystem advances to the next system (wraps). Recreates the calculator. Spacecraft does not follow — remains in Sol per plan §MVP scope. Resets focus to system-wide because body indices don't carry across systems and the craft is only visible in Sol.
func (*World) EffectiveWarp ¶
EffectiveWarp exposes the clamped warp for HUD display. Returns the same as Clock.Warp() when the user isn't hitting the step-size guard.
func (*World) FocusName ¶ added in v0.2.0
FocusName returns a short human label for the current focus.
func (*World) FocusPosition ¶ added in v0.2.0
FocusPosition returns the inertial (system primary-centric) position of the current focus target. Origin for FocusSystem.
func (*World) FocusZoomRadius ¶ added in v0.2.0
FocusZoomRadius suggests a world-space radius for auto-fit. Canvas.FitTo uses ~90% of the smaller pixel axis, so a returned radius R yields a frame that comfortably shows a circle of radius R around the focus.
func (*World) HohmannPreviewFor ¶ added in v0.2.0
func (w *World) HohmannPreviewFor(bodyIdx int) HohmannPreview
HohmannPreviewFor computes a preview to the indicated body index in the current system. Uses the system primary's GM, the craft's current inertial distance as r1, and the target's semimajor axis as r2.
func (*World) NodeInertialPosition ¶ added in v0.2.0
func (w *World) NodeInertialPosition(n ManeuverNode) orbital.Vec3
NodeInertialPosition returns the inertial (system-primary-centered) position where the node will fire. Forward-integrates the craft state from now to the node's trigger time using SOI-aware Verlet sub- stepping, then adds the OWNING primary's inertial position — the frame may differ from the craft's current primary if the trajectory crossed an SOI boundary.
Returns zero Vec3 if the craft is nil or the node is already past-due.
func (*World) PlanNode ¶ added in v0.2.0
func (w *World) PlanNode(n ManeuverNode)
PlanNode inserts a node into World.Nodes, keeping the slice sorted by TriggerTime. Past-dated nodes are allowed — they fire on the next Tick.
func (*World) PlanTransfer ¶ added in v0.3.1
func (w *World) PlanTransfer(targetIdx int) (*planner.TransferPlan, error)
PlanTransfer constructs a Hohmann auto-plant to the body at the given index in the active system and plants the resulting two-burn plan onto World.Nodes (departure + arrival). Returns the plan so callers can inspect Δv totals; returns nil and an error if the geometry is degenerate (target index invalid, target is the system primary, or craft state isn't ready).
Phasing is not enforced — the plan assumes ideal alignment, matching the v0.3.1 sandbox scope per docs/plan.md. Porkchop-plot polish for real launch windows is v0.3.2.
func (*World) PlanTransferAt ¶ added in v0.4.1
func (w *World) PlanTransferAt(targetIdx int, depDay, tofDay float64) (*planner.TransferPlan, error)
PlanTransferAt constructs a Lambert-based transfer for a specific (departure-day, time-of-flight) pair — the cell selected on the porkchop plot — and plants the resulting two-burn plan onto World.Nodes. Parking and capture orbit parameters match PlanTransfer / PorkchopGrid so a cell's planted Δv equals the cell's scored Δv to within Lambert iteration tolerance.
depDay / tofDay are in days; depDay is an offset from w.Clock.SimTime. Used by the porkchop screen's Enter-to-plant path (v0.4.1).
func (*World) PorkchopGrid ¶ added in v0.3.3
PorkchopGrid computes a launch-window grid for a Hohmann-style transfer to the target body. Axes: depDays (offsets from now) and tofDays (time of flight). Each cell = total Δv (departure + capture, m/s); NaN for cells where Lambert didn't converge.
Uses the same parking-orbit and capture-orbit defaults as PlanTransfer (craft's current |r| at departure, 200 km altitude at destination).
func (*World) PostBurnState ¶ added in v0.2.0
func (w *World) PostBurnState(n ManeuverNode) (physics.StateVector, string)
PostBurnState returns the craft's primary-relative state vector immediately after the given node would fire, plus the ID of the primary that frame is relative to. Forward-integrates SOI-aware to the trigger time, then applies the Δv in the node's direction mode. The PrimaryID return lets callers (OrbitView post-burn preview) correctly translate state.R into inertial coords when the burn fires in a frame other than the craft's home primary — critical for the v0.3.1 auto-plant arrival node, which fires heliocentrically (or in the destination SOI) by construction.
func (*World) PredictedSegments ¶ added in v0.2.0
func (w *World) PredictedSegments(post physics.StateVector, totalSeconds float64, samples int) []SOISegment
PredictedSegments forward-integrates a post-burn state by totalSeconds and partitions the trajectory into SOISegments. Pre-v0.3.0 the predictor locked to the home primary's μ throughout, which made post-escape segments geometrically wrong even though their coloring was correct. v0.3.0: when a sub-step crosses a sphere-of-influence boundary, rebase the state vector to the new primary's frame and switch μ for subsequent steps. Output shape (a slice of SOISegments) is unchanged so the renderer keeps working.
Body positions are still snapshot at Clock.SimTime — accurate for short horizons relative to target body orbital period; an approximation flagged in commit history for interplanetary horizons.
func (*World) RefinePlan ¶ added in v0.4.1
RefinePlan re-runs a heliocentric Lambert from the craft's current state to the destination body at the pending arrival node's TriggerTime, plants a mid-course correction burn at the current sim-time for Δv = |v1_lambert − v_craft_heliocentric|, and replaces the arrival node's Δv with |v2_lambert − v_target_heliocentric| via CaptureBurnDeltaV. Closes the porkchop / PlanTransfer loop by giving the player a way to correct drift during a coast.
Returns (correctionDv, refinedArrivalDv, error). err != nil if no pending arrival node exists (PlanTransfer / PlanTransferAt hasn't been called, or arrival already fired) or Lambert fails to converge.
The correction burn's mode (prograde vs retrograde) is picked by the sign of (v1_lambert − v_craft) · v_craft: aligned → prograde, else retrograde. This is a scalar approximation — full vector mid-course correction would need a new burn mode; for v0.4.1 scalar-along- velocity corrections are sufficient to close small drifts.
func (*World) ResetFocus ¶ added in v0.2.0
func (w *World) ResetFocus()
ResetFocus snaps back to the system-wide view.