Documentation
¶
Overview ¶
Package screens implements the individual tea.Model screens composed by tui.App: OrbitView (C8), BodyInfo (C9), Maneuver (C20), Help (C9).
Index ¶
- func BodyPixelRadius(b bodies.CelestialBody, isPrimary bool, scale float64, maxPx int) int
- type BodyInfo
- type BurnExecutedMsg
- type Help
- type LaunchSitePreset
- type LaunchView
- type Maneuver
- func (m *Maneuver) HandleKey(msg tea.KeyMsg) (tea.Cmd, bool)
- func (m *Maneuver) LoadNode(idx int, n sim.ManeuverNode)
- func (m *Maneuver) LoadStaged(triggerTime time.Time)
- func (m *Maneuver) Render(w *sim.World, cols, rows int) string
- func (m *Maneuver) ResetEditing()
- func (m *Maneuver) Resize(cols, rows int)
- func (m *Maneuver) SetTargetCraft(ok bool, idx int)
- type Menu
- type MenuAction
- type Missions
- type NavballControlID
- type NodeClearAllMsg
- type NodeDeleteMsg
- type OrbitView
- func (v *OrbitView) ComposeNavballOverlay(w *sim.World, canvasStr string, cCols, cRows int) string
- func (v *OrbitView) HitAt(screenCol, screenRow int) widgets.CellTag
- func (v *OrbitView) HitHudNode(col, row int) (int, int, bool)
- func (v *OrbitView) HitMenuButton(col, row int) bool
- func (v *OrbitView) HitMissionsButton(col, row int) bool
- func (v *OrbitView) HitNavballControl(col, row int) (NavballControlID, bool)
- func (v *OrbitView) IsCanvasClick(col, row int) bool
- func (v *OrbitView) IsHudClick(col int) bool
- func (v *OrbitView) ProjectToOrbit(w *sim.World, screenCol, screenRow int) (time.Duration, bool)
- func (v *OrbitView) Render(w *sim.World, selectedIdx int, totalCols, totalRows int) string
- func (v *OrbitView) RenderHUDColumn(w *sim.World, selectedIdx, width int) string
- func (v *OrbitView) Resize(totalCols, totalRows int)
- func (v *OrbitView) ZoomIn()
- func (v *OrbitView) ZoomOut()
- type Porkchop
- func (p *Porkchop) HandleKey(msg tea.KeyMsg) (tea.Cmd, bool)
- func (p *Porkchop) HitCell(col, row int) (depIdx, tofIdx int, ok bool)
- func (p *Porkchop) Load(w *sim.World, targetIdx int)
- func (p *Porkchop) PendingPlant() (targetIdx int, depDay, tofDay float64, opts sim.TransferOptions, ok bool)
- func (p *Porkchop) Render(w *sim.World, cols, rows int) string
- func (p *Porkchop) SetSelection(depIdx, tofIdx int)
- type SpawnAction
- type SpawnCraft
- func (s *SpawnCraft) CustomStackEmpty() bool
- func (s *SpawnCraft) HandleKey(key string) SpawnAction
- func (s *SpawnCraft) IsCustomSelected() bool
- func (s *SpawnCraft) Render(width int) string
- func (s *SpawnCraft) Reset(systemBodies []bodies.CelestialBody, defaultParentID string)
- func (s *SpawnCraft) SelectedAlongside() bool
- func (s *SpawnCraft) SelectedAltitudeM() float64
- func (s *SpawnCraft) SelectedCustomStages() []spacecraft.Stage
- func (s *SpawnCraft) SelectedLatitudeDeg() float64
- func (s *SpawnCraft) SelectedLaunchpad() bool
- func (s *SpawnCraft) SelectedLoadoutID() string
- func (s *SpawnCraft) SelectedLongitudeEastDeg() float64
- func (s *SpawnCraft) SelectedParentID() string
- func (s *SpawnCraft) SelectedRetrograde() bool
- type SpritePixel
- type Theme
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BodyPixelRadius ¶ added in v0.3.2
BodyPixelRadius returns the body's render radius in pixels. When the canvas is zoomed in enough that the body's true radius projects to at least trueSizeThreshold pixels, render at true size — so the rendered disk represents real surface, and a periapsis marker inside it visually reads as a collision. When zoomed out, fall back to a tier bucket so the body stays visible (true would be sub-pixel at system-wide zoom).
Pass scale=0 to force the tier-bucket path (used when projection metadata isn't available).
The `isPrimary` flag promotes a small body to star tier in the fallback path so the system primary always renders bigger than its planets even when its physical radius wouldn't otherwise put it there.
Types ¶
type BodyInfo ¶
type BodyInfo struct {
// contains filtered or unexported fields
}
BodyInfo is the full-screen detail view for a single celestial body. Entered via `i` from OrbitView; `esc` (handled at App level) returns.
func NewBodyInfo ¶
type BurnExecutedMsg ¶
type BurnExecutedMsg struct {
Mode spacecraft.BurnMode
DV float64
Event sim.TriggerEvent
TriggerTime time.Time
EditingIdx int // -1 = creating a new node; ≥ 0 = replacing world.Nodes[idx]
// Throttle (v0.7.6+) is the per-node throttle [0, 1]. Zero is
// remapped to 1.0 by ManeuverNode.EffectiveThrottle, so callers
// that don't set it (legacy quick-plant paths) get the prior
// full-open behaviour for free.
Throttle float64
// IterateForTarget (v0.8.6 (b)) requests that the app refine the
// commanded Δv via World.IterateBurnDV before planting, so the
// post-burn apsides match what an impulsive Δv at the same
// commanded value would have delivered (compensating finite-burn
// loss). Ignored for impulsive (zero-thrust) and Normal± burns.
IterateForTarget bool
// TargetCraftIdx (v0.9.3+) is the one-based encoding of the
// target slate idx the form was bound to at plant. Zero = no
// target. Mirrors ManeuverNode.TargetCraftIdx; the app passes it
// straight through. Only populated for target-relative modes /
// TriggerNextClosestApproach event.
TargetCraftIdx int
}
BurnExecutedMsg is emitted when the user hits Enter. App consumes it. Event (v0.6.0+) selects the trigger model — TriggerAbsolute uses the app-side default delay; event-relative modes leave TriggerTime zero and let the World's lazy-freeze resolver compute it from the live orbit on the first Tick after plant.
v0.6.4+: TriggerTime non-zero forces the app to plant a real ManeuverNode at exactly that time (skipping the legacy "fire now" path used by quick-plant). Set by LoadNode so a click-to-edit flow preserves the original schedule. EditingIdx ≥ 0 tells the app to remove the original Nodes[idx] before planting, so the edit reads as "replace in place" rather than "duplicate."
v0.6.5: Duration dropped from this message — the App computes it on receipt via spacecraft.BurnTimeForDV(DV) using the live craft's thrust + Isp + mass. Letting the player set both Δv AND duration was over-determined: at fixed thrust + mass the two are the same dial, and the only effect of mismatch was a truncated burn (planned Δv undelivered if the duration was too short). Zero-thrust craft return Duration = 0 from BurnTimeForDV, preserving the impulsive code path even though the form no longer exposes it.
type Help ¶
type Help struct {
// contains filtered or unexported fields
}
Help is the keybinding reference overlay. Invoked via `?` from any screen; `?` or `esc` returns.
type LaunchSitePreset ¶ added in v0.9.2
type LaunchSitePreset struct {
Name string
LatitudeDeg float64
// LongitudeEastDeg is east-positive longitude in degrees relative
// to the body's prime meridian at simTime=0 (our pseudo-Greenwich
// convention — see SpawnSpec.LongitudeOffset doc).
LongitudeEastDeg float64
}
LaunchSitePreset bundles a named real-world launch site with its real-world latitude + longitude (east-positive, relative to Earth's prime meridian). v0.9.2+. The form's LATITUDE field cycles through these so picking "Cape Canaveral" lands the craft on KSC LC-39A, not just at "the right latitude."
type LaunchView ¶ added in v0.11.0
type LaunchView struct {
// contains filtered or unexported fields
}
LaunchView (v0.11.0+) is the ViewLaunch chase-cam screen — a sibling of OrbitView, not an extension. ADR-0002 covers the call. Minimal chrome: title, canvas with the chase-cam scene, footer with key hints; no sidepanel (the orbit screen's body list / target panel are irrelevant during a launch). The HUD launch-readout strip is overlaid on the bottom braille row of the canvas (same precedent as the orbit screen's status overlay).
func NewLaunchView ¶ added in v0.11.0
func NewLaunchView(th Theme, hudSource *OrbitView) *LaunchView
NewLaunchView constructs the chase-cam screen, paired with the supplied OrbitView so the right-side HUD column (VESSEL / PROPELLANT / ATTITUDE / LAUNCH / NAVBALL) reuses the OrbitView's renderers verbatim. Playtest (Slice 1.6) showed the no-sidepanel experiment from the original plan dropped too many readouts (altitude, stage fuel, horizontal velocity) for the launch view to stay flyable; reusing the orbit HUD keeps the chrome legible.
func (*LaunchView) CurrentScale ¶ added in v0.11.0
func (v *LaunchView) CurrentScale(w *sim.World) float64
CurrentScale returns the metres-per-cell scale the chase-cam is currently rendering at — either the player-pinned w.LaunchZoom (when non-zero) or the auto-altitude-driven default sized to this view's canvas. Callers (App's `+/-` handler) pass it to World.NudgeLaunchZoom so the first nudge from auto pins the pre-render scale rather than a hardcoded constant.
func (*LaunchView) Render ¶ added in v0.11.0
func (v *LaunchView) Render(w *sim.World, totalCols, totalRows int) string
Render builds the chase-cam frame for the current world state. Slice 1 chrome: title + canvas + footer; the canvas carries the horizon curve + SurfaceColor fill + pad marker + breadcrumb trail + active-vessel glyph; the HUD launch-readout strip is overlaid on the bottom braille row.
func (*LaunchView) Resize ¶ added in v0.11.0
func (v *LaunchView) Resize(totalCols, totalRows int)
Resize sizes the canvas to leave the right ~30% for the HUD column (mirrors OrbitView's split so the two screens line up when cycling). Reserve 4 rows for title + footer + border.
type Maneuver ¶
type Maneuver struct {
// contains filtered or unexported fields
}
Maneuver is the burn-planning screen. Opening it pauses the sim (app.go handles the pause); closing with Esc cancels, with Enter emits a BurnExecutedMsg that the app applies to the spacecraft.
Per plan §C20: live preview = shadow trajectory on a miniature canvas. v0.2.1: three fields — mode / Δv / duration. v0.6.0: four fields — mode / fire-at / Δv / duration. v0.6.5: three fields again — mode / fire-at / Δv. Duration is no longer an independent input; the planner derives it from Δv via the rocket equation at commit time, since at fixed thrust + mass the two are the same dial — letting the player set both was over-determined and the only effect of mismatch was a truncated burn (planned Δv undelivered if duration was too short). KSP-style: specify Δv, the engine takes as long as it takes.
func NewManeuver ¶
func (*Maneuver) HandleKey ¶
HandleKey routes planner-local keys. Returns (cmd, done) where done=true means the app should exit the maneuver screen (commit or cancel).
Key bindings:
tab / shift+tab — cycle focus across mode / fire-at / Δv fields ←/→ (mode focused) — cycle direction modes ←/→ (fire-at focused) — cycle trigger events (Absolute / NextPeri / NextApo / NextAN / NextDN) enter — commit burn → emits BurnExecutedMsg with rocket-equation duration esc — cancel → plain exit (app handles) ctrl+d — delete the planted node being edited (no-op when creating new) c / C (or ctrl+k) — clear ALL planted nodes for the active craft digits/backspace — forwarded to focused text input
func (*Maneuver) LoadNode ¶ added in v0.6.4
func (m *Maneuver) LoadNode(idx int, n sim.ManeuverNode)
LoadNode pre-populates the form fields from an existing planted node and records the click-to-edit state — used by the v0.6.4 orbit-canvas mouse path. Maps the node's BurnMode + TriggerEvent back to their cycle indices, writes Δv / duration into the text inputs, and stores idx + TriggerTime so the next Enter commit emits a BurnExecutedMsg with EditingIdx = idx + TriggerTime = original schedule. The app then removes Nodes[idx] before planting so the edit replaces in place AND preserves the node's future trigger time.
func (*Maneuver) LoadStaged ¶ added in v0.6.4
LoadStaged opens the form for a NEW node staged at a specific trigger time — used by the v0.6.4 empty-canvas mouse path to "click a point on the orbit, plant a burn there." Distinct from LoadNode in that there's no original to replace (editingIdx stays at -1); the form simply previews and commits with the staged TriggerTime so the new node fires at the click's projected orbit position. Mode / fire-at fall back to defaults (prograde / Absolute); Δv defaults to "100" so the form is immediately usable, focus jumps to the Δv field so the player can type a value without tabbing.
func (*Maneuver) ResetEditing ¶ added in v0.6.4
func (m *Maneuver) ResetEditing()
ResetEditing clears the click-to-edit state so the next commit plants a fresh node rather than replacing one. Called on `m`-key open (new-node intent) and after every BurnExecutedMsg / Esc so the editingIdx doesn't leak across opens.
func (*Maneuver) Resize ¶
Resize handles terminal-size changes. Keep the maneuver canvas ≤ 60 cols wide so the form panel sits cleanly alongside it.
func (*Maneuver) SetTargetCraft ¶ added in v0.9.3
SetTargetCraft binds (or unbinds) the target-craft slate index the form's planted burn will be aimed at. Called by the app when opening the form so the four target-relative burn modes and the TriggerNextClosestApproach event can resolve at plant + fire time. Pass ok=false to clear (no craft target set / target is a body). v0.9.3+.
type Menu ¶ added in v0.7.4
type Menu struct {
// contains filtered or unexported fields
}
Menu is the splash / pause menu surfaced when the player presses Esc on the orbit (home) screen. Three actions: save, load, quit (autosave). Replaces the v0.6.3 inline "Quit and save? y/N" footer prompt with a centered modal that doubles as a "what can I do from here" entry point. v0.7.3.3+.
v0.7.4+ adds clickable controls. The list state shows three labelled buttons; clicking any transitions into a confirm sub-state with [Yes] / [No] buttons. Yes triggers the corresponding MenuAction; No returns to the list. The keyboard path keeps the legacy direct flow (s/l/q execute immediately) so muscle memory still works — the confirm gate is for the mouse path only.
func (*Menu) HandleClick ¶ added in v0.7.4
func (m *Menu) HandleClick(col, row int) MenuAction
HandleClick maps a (col, row) click to a MenuAction. List-state clicks on Save / Load / Quit transition into the corresponding confirm sub-state and return MenuActionNone (the action only fires when the player confirms with Yes). Confirm-state Yes returns the stored action; No returns to the list.
func (*Menu) HandleKey ¶ added in v0.7.4
func (m *Menu) HandleKey(s string) MenuAction
HandleKey maps a raw key string to a MenuAction. Lower- and upper-case both match. The keyboard path skips the click-only confirm gate when in the list state — typing "s" still saves immediately, matching v0.7.3.3 muscle memory. In a confirm state the keys narrow to y / n / enter / esc.
func (*Menu) HitBackButton ¶ added in v0.7.4
HitBackButton reports whether a click at (col, row) lands on the title-row [Back] button. Kept as a public method for App.Update's mouse cascade — though HandleClick also handles [Back], having a dedicated check lets the dispatcher differentiate "left the menu" vs "clicked something inside it." v0.7.4+.
type MenuAction ¶ added in v0.7.4
type MenuAction int
MenuAction enumerates the menu's outcomes. Returned by HandleKey and HandleClick so the caller (App.Update) can perform the actual save / load / quit dispatch — the screen stays decoupled from sim and save packages.
const ( MenuActionNone MenuAction = iota // unhandled key / click MenuActionCancel // esc / [Back] — return to orbit MenuActionSave MenuActionLoad MenuActionQuit )
type Missions ¶ added in v0.7.4
type Missions struct {
// contains filtered or unexported fields
}
Missions is the v0.7.4+ dedicated mission-list screen. Reachable from the orbit-screen title bar's `[Missions]` button (or the keyboard via app.go's MissionsKey). Lists every loaded mission with its current status; the orbit HUD's MISSION block was removed in v0.7.4 to give the right-hand pane back to flight state.
func NewMissions ¶ added in v0.7.4
func (*Missions) HitBackButton ¶ added in v0.7.4
HitBackButton reports whether a click at (col, row) lands on the title-row [Back] button. v0.7.4+.
type NavballControlID ¶ added in v0.9.6
type NavballControlID int
NavballControlID identifies a clickable region in the navball panel. The zero value navballControlNone means "no hit".
const ( )
type NodeClearAllMsg ¶ added in v0.8.6
type NodeClearAllMsg struct{}
NodeClearAllMsg is emitted when the player presses c / C (or the ctrl+k back-compat alias) in the maneuver form. The app handles it by calling World.ClearNodes() and closing the screen. Replaces the v0.8.5-and-earlier `N` global keybinding for the wipe-all case. v0.8.6+; primary binding simplified to `c` in v0.10.1.
type NodeDeleteMsg ¶ added in v0.8.6
type NodeDeleteMsg struct {
EditingIdx int
}
NodeDeleteMsg is emitted when the player presses ctrl+d in the maneuver form while editing a planted node. The app handles it by calling World.DeleteNode(EditingIdx) and closing the screen. Replaces the v0.8.5-and-earlier `N` global "clear all nodes" keybinding for the per-node case. v0.8.6+.
type OrbitView ¶
type OrbitView struct {
// contains filtered or unexported fields
}
OrbitView renders the system's bodies, orbit lines, and a right-side HUD. Phase 0 — no spacecraft yet; C16 will add a glyph + augmented HUD.
func NewOrbitView ¶
NewOrbitView constructs the screen with an initially-small canvas; a Resize call from the root model sizes it to the terminal.
func (*OrbitView) ComposeNavballOverlay ¶ added in v0.11.4
ComposeNavballOverlay is the exported entry the LaunchView calls to drop the same bottom-right navball panel into its canvas (sub-scope 6 / v0.11.4+). recordControls is forced false — the launch screen doesn't take navball clicks; the orbit-screen path keeps its hit-box capture by going through the private helper directly.
func (*OrbitView) HitAt ¶ added in v0.6.4
HitAt translates a screen-space mouse coordinate (col, row) into a CellTag from the orbit canvas. The orbit screen renders title (1 row) + canvasPanel (rounded border = 1 row top, 1 col left) before the canvas content, so we offset (col-1, row-2). Returns a zero-value CellTag when the click lands outside the canvas content area, which the caller treats as "no hit." v0.6.4+.
func (*OrbitView) HitHudNode ¶ added in v0.8.2
HitHudNode resolves a screen-space click against the HUD's NODES block. Returns (craftIdx, nodeIdx, true) when the row matches a recorded NODES entry and the column lands in the HUD region; (-1, -1, false) otherwise. v0.8.2.x:
- row matching uses the post-render scan in scanHudNodeRows.
- hudScrollOffset compensates for terminal scrolling when the rendered HUD overflows the visible area.
func (*OrbitView) HitMenuButton ¶ added in v0.7.4
HitMenuButton reports whether a click at (col, row) lands on the title bar's `[Menu]` button. Title bar lives on row 0 of the rendered orbit view. v0.7.4+.
func (*OrbitView) HitMissionsButton ¶ added in v0.7.4
HitMissionsButton reports whether a click at (col, row) lands on the title bar's `[Missions]` button. v0.7.4+.
func (*OrbitView) HitNavballControl ¶ added in v0.9.6
func (v *OrbitView) HitNavballControl(col, row int) (NavballControlID, bool)
HitNavballControl maps a screen-space click to a navball-panel control, returning navballControlNone (ok=false) on a miss. Hit boxes are recomputed every Render in absolute screen coordinates. The app's mouse handler calls this; the dispatch from each control id into the NavMode cycle / SAS-hold intent is the follow-up wiring step (the panel layout intentionally reserves the room). v0.9.6-polish.
func (*OrbitView) IsCanvasClick ¶ added in v0.6.4
IsCanvasClick reports whether a screen-space (col, row) lands inside the canvas content area (i.e. between the rounded-border edges). v0.6.4 mouse dispatch uses this to distinguish "click on orbit canvas" from "click on HUD" when no body / vessel / node hit lands.
func (*OrbitView) IsHudClick ¶ added in v0.6.4
IsHudClick reports whether a screen-space col lands on the HUD panel (right of the canvas + its border).
func (*OrbitView) ProjectToOrbit ¶ added in v0.6.4
ProjectToOrbit maps a screen-space click to the time-of-flight at which the active craft reaches the orbit point nearest the click. Used by the v0.6.4 empty-canvas mouse path to stage a new burn at "this point along my orbit."
Algorithm: sample 360 true-anomalies on the live craft orbit, project each to canvas pixels, take the smallest screen distance to the click pixel; convert that ν to a time-of-flight via orbital.TimeToTrueAnomaly. ok=false for hyperbolic / no-craft states or when no sample lands on-canvas.
func (*OrbitView) Render ¶
Render composes the frame: canvas on the left, HUD on the right. selectedIdx is the index of the cursor-selected body in system.Bodies.
func (*OrbitView) RenderHUDColumn ¶ added in v0.11.0
RenderHUDColumn exposes the right-side HUD block contents (VESSEL / PROPELLANT / ATTITUDE / LAUNCH / NAVBALL / NODES / etc.) so sibling screens — currently v0.11.0+ LaunchView — can pair the same chrome with their own canvas rather than duplicating each block's formatter. Mutates the hit-test state the same way the in-screen render does; harmless for screens that don't route HUD clicks.
func (*OrbitView) Resize ¶
Resize forwards terminal dimensions to the canvas. Left ~70% for canvas, right ~30% for HUD per plan §Screen details.
type Porkchop ¶ added in v0.3.3
type Porkchop struct {
// contains filtered or unexported fields
}
Porkchop renders a launch-window Δv heatmap for a Hohmann transfer to the target body — grid of departure-day × time-of-flight with cells filled by an intensity character reflecting total Δv.
Simplistic ASCII render (no color) to stay portable across terminals without touching lipgloss color config. Darker/heavier glyph = lower total Δv ("cheaper" transfer). "·" marks infeasible / non-converged.
v0.10.5: a transfer-options sub-menu (toggled with `o`) holds the per-cell Lambert solve params (nRev, retrograde, short/long branch). Toggling re-runs the grid and rescales the TOF axis so multi-rev cells live in a sensible TOF range.
func NewPorkchop ¶ added in v0.3.3
NewPorkchop constructs an empty screen. Call Load(world, targetIdx) before the first render to populate the grid.
func (*Porkchop) HandleKey ¶ added in v0.3.3
HandleKey routes arrow keys within the grid. Returns done=true on Esc (cancel) or Enter (plant → app reads PendingPlant()) to signal the app should return to orbit view. Enter also sets the plant flag, checked by the app immediately after done=true.
With the transfer-options sub-menu open (`o`), keys instead drive the option toggles (n nRev / r retrograde / b branch) and esc/enter/o closes the menu — re-solving the grid on close.
func (*Porkchop) HitCell ¶ added in v0.6.4
HitCell maps a screen-space (col, row) onto the porkchop grid's (depIdx, tofIdx). Title + blank line take rows 0 and 1; grid starts at row 2. Each row begins with "tof XXXd │" = 10 chars (gridLead) before the first cell. Returns ok=false when the click lands outside the grid's pixel rectangle. v0.6.4 mouse dispatch sets selDep / selTof from the result.
func (*Porkchop) Load ¶ added in v0.3.3
Load computes the porkchop grid for the given target body and caches it on the screen. Cheap to call once on open; not recomputed per frame since the grid doesn't change unless the craft's state or target shifts, and the player pauses on this screen to select a cell anyway. v0.10.5: resets transfer options to single-rev prograde short on each fresh Load (the sub-menu drives subsequent re-solves).
func (*Porkchop) PendingPlant ¶ added in v0.4.1
func (p *Porkchop) PendingPlant() (targetIdx int, depDay, tofDay float64, opts sim.TransferOptions, ok bool)
PendingPlant returns the selected (targetIdx, depDay, tofDay, opts) if the user pressed Enter on a feasible cell; ok=false if no plant is pending (Esc-close or infeasible cell). Consumes the pending flag — next call returns ok=false until the user plants again. v0.10.5 also returns the active TransferOptions so PlanTransferAt uses the same nRev/retrograde/branch the cell was scored against.
func (*Porkchop) SetSelection ¶ added in v0.6.4
SetSelection moves the cursor to (depIdx, tofIdx) — used by the v0.6.4 mouse dispatch on click. Bounds-checked; out-of-range indices are ignored.
type SpawnAction ¶ added in v0.8.2
type SpawnAction int
SpawnAction enumerates the form's outcomes.
const ( SpawnActionNone SpawnAction = iota SpawnActionCancel // esc SpawnActionConfirm // enter — caller reads accessors )
type SpawnCraft ¶ added in v0.8.2
type SpawnCraft struct {
// contains filtered or unexported fields
}
SpawnCraft is the modal form opened by `n` on the orbit screen. v0.8.2+: four fields — craft type, parent body, altitude, and direction (prograde / retrograde). v0.8.3+ added a POSITION toggle (orbit / alongside). v0.9.2+ extended POSITION with a third option (launchpad) and the ALTITUDE field doubles as a LATITUDE picker when launchpad is selected. Tab cycles field focus; ←/→ edit the focused field; Enter spawns; Esc cancels.
func NewSpawnCraft ¶ added in v0.8.2
func NewSpawnCraft(th Theme) *SpawnCraft
NewSpawnCraft constructs the screen.
func (*SpawnCraft) CustomStackEmpty ¶ added in v0.10.1
func (s *SpawnCraft) CustomStackEmpty() bool
CustomStackEmpty reports Custom-selected-but-no-stages — the one confirm state the caller must reject (an empty stack is not a spawnable craft). v0.10.1+.
func (*SpawnCraft) HandleKey ¶ added in v0.8.2
func (s *SpawnCraft) HandleKey(key string) SpawnAction
HandleKey maps a raw key string to a SpawnAction. Tab cycles fields; ←/→ edit the focused field; Enter commits; Esc cancels.
func (*SpawnCraft) IsCustomSelected ¶ added in v0.10.1
func (s *SpawnCraft) IsCustomSelected() bool
IsCustomSelected reports whether the cursor is on the synthetic "Custom…" CRAFT TYPE entry (the last row). v0.10.1+.
func (*SpawnCraft) Render ¶ added in v0.8.2
func (s *SpawnCraft) Render(width int) string
Render returns the modal form. Width is the terminal width.
func (*SpawnCraft) Reset ¶ added in v0.8.2
func (s *SpawnCraft) Reset(systemBodies []bodies.CelestialBody, defaultParentID string)
Reset prepares the form for a fresh open. systemBodies is the list of bodies in the active system; defaultParentID is the body the parent-field cursor lands on initially (typically the active craft's current primary). v0.8.2+: replaces the v0.8.2-pre no-arg Reset.
func (*SpawnCraft) SelectedAlongside ¶ added in v0.8.3
func (s *SpawnCraft) SelectedAlongside() bool
SelectedAlongside reports whether the player picked the "alongside active craft" position. v0.8.3+.
func (*SpawnCraft) SelectedAltitudeM ¶ added in v0.8.2
func (s *SpawnCraft) SelectedAltitudeM() float64
SelectedAltitudeM returns the chosen altitude above the parent's mean radius (m).
func (*SpawnCraft) SelectedCustomStages ¶ added in v0.10.1
func (s *SpawnCraft) SelectedCustomStages() []spacecraft.Stage
SelectedCustomStages returns a copy of the player-assembled stack (bottom-first), or nil when Custom is not selected. The spawn path treats a nil/empty result as "no custom craft". v0.10.1+.
func (*SpawnCraft) SelectedLatitudeDeg ¶ added in v0.9.2
func (s *SpawnCraft) SelectedLatitudeDeg() float64
SelectedLatitudeDeg returns the chosen surface latitude (degrees north) when SelectedLaunchpad is true. Defaults to KSC LC-39A (28.6083°N) when the cursor is out of range. v0.9.2+.
func (*SpawnCraft) SelectedLaunchpad ¶ added in v0.9.2
func (s *SpawnCraft) SelectedLaunchpad() bool
SelectedLaunchpad reports whether the player picked the surface-launchpad position. v0.9.2+.
func (*SpawnCraft) SelectedLoadoutID ¶ added in v0.8.2
func (s *SpawnCraft) SelectedLoadoutID() string
SelectedLoadoutID returns the loadout ID for the current cursor, or "" when the synthetic Custom entry is selected (the caller then reads SelectedCustomStages instead). v0.10.1+.
func (*SpawnCraft) SelectedLongitudeEastDeg ¶ added in v0.9.2
func (s *SpawnCraft) SelectedLongitudeEastDeg() float64
SelectedLongitudeEastDeg returns the chosen surface longitude offset (degrees east of pseudo-Greenwich). Defaults to KSC (-80.604°E) when the cursor is out of range. v0.9.2+.
func (*SpawnCraft) SelectedParentID ¶ added in v0.8.2
func (s *SpawnCraft) SelectedParentID() string
SelectedParentID returns the body ID the cursor is on, or empty if the body list is unset (caller falls back to the active craft's primary).
func (*SpawnCraft) SelectedRetrograde ¶ added in v0.8.2
func (s *SpawnCraft) SelectedRetrograde() bool
SelectedRetrograde reports whether the player picked retrograde.
type SpritePixel ¶ added in v0.11.3
SpritePixel is one braille sub-pixel of a composed launch sprite — a world-frame offset from the vessel anchor (`c.State.R + bodyPos`) plus the color the render path should PlotColored at that position. No glyph: braille dots are direction-agnostic, so a tilted rocket renders smoothly at any pitch without per-glyph rotation (v0.11.3 playtest pivot from ASCII glyphs to braille pixels — see docs/v0.11-plan.md "Resolved at slice-open").
func ComposeFlame ¶ added in v0.11.3
func ComposeFlame(stages []spacecraft.Stage, cmdWorld orbital.Vec3, basis widgets.Basis, scaleMPerPx float64, throttle float64, frameIdx int) []SpritePixel
ComposeFlame builds exhaust-flame pixels extending below Stages[0]'s base along the -cmdWorld direction. Same `spriteWidthPx` width as the rocket sprite. Length-binned by throttle into 3 bins:
- throttle ≤ 0 or no stages: returns nil.
- 0 < throttle ≤ 1/3: 4 sub-pixel rows (1 cell tall).
- 1/3 < throttle ≤ 2/3: 8 sub-pixel rows.
- 2/3 < throttle: 12 sub-pixel rows.
frameIdx selects one of two pulse offsets — frame B shifts the flame down by 1 px so the dot pattern within each cell visibly changes between frames at the ~100 ms wall-clock cadence. Colour: amber `render.ColorWarning`.
func ComposeLaunchSprite ¶ added in v0.11.3
func ComposeLaunchSprite(stages []spacecraft.Stage, cmdWorld orbital.Vec3, basis widgets.Basis, scaleMPerPx float64) []SpritePixel
ComposeLaunchSprite builds the composed-from-stages rocket sprite as a list of braille sub-pixels. Stages stack bottom-to-top from Stages[0] along the projection of cmdWorld into the chase-cam basis (so a gravity-turned rocket leans visibly); each stage contributes a `spriteWidthPx × Stage.LaunchSpriteRowsPx` filled rectangle of pixels in the stage's catalog color. Returns nil when no stage has a non-zero LaunchSpriteRowsPx — caller falls back to the vessel's single Glyph render.
Each "pixel" is one braille sub-cell dot (`scaleMPerPx` metres across); the canvas's PlotColored accumulates dots per cell and renders the resulting braille char.