← Design Design

Player-owned stations — design capture

Captured 2026-07-19. The "stations design" cross-referenced by docs/design-fleet.md ("[Haulers]"/"[Traders]" require player stations) and docs/design-economy.md. Sequenced **step 2…

Captured 2026-07-19. The “stations design” cross-referenced by docs/design-fleet.md (“[Haulers]”/”[Traders]” require player stations) and docs/design-economy.md. Sequenced step 2 in both dependency orders: it lands after the economy foundation (commodities, cargo, mining/salvage, station trading — Econ E0–E4) and before the fleet roles that buy and sell against it. Not yet scheduled.

The one-line fantasy is already in the story bible (docs/story-outline.md:190): “Player stations | Waypoints. Vann builds ‘home’ because he can’t go back to his original one.” A player station is the first thing in the game the player MAKES rather than finds — a fixed point of their own in a one-way galaxy.

What already exists (2026-07-19 audit — build on it, don’t reinvent)

A Station is a live, shootable, dockable entity today; the gap is that every station is content-authored at boot, never built at runtime. The pieces a player station needs, that already ship:

  • Station (features/stations/Station.cs) — an Area2D spawned from a StationDef, with a traced hull collision polygon, a dock zone (DockRadius = VisualRadius + DockBuffer), a Health shield/hull that when beaten down sets Disabled (turrets go dark, hull dims — “a disabled picket is a window, not a kill”), map-intel fog-of-war meta, and ArmTurrets() — procedural ring OR author-defined Mounts painted by the HardpointEditor. All of the danger-interaction machinery is already here.
  • StationDef (features/universe/StarSystemDef.cs)Id, Name, Type (Trade/Defense/Shipyard/Refinery, common/Taxonomy.cs), OrbitRadius, Angle, FactionId, turret fields (Weapon, Turrets, Mounts), Shield/ShieldRegen/Hull (defaults 250/18/600), and SupplySkew. Stations are placed either as OrbitDef.Stations (child of a planet, orbits it) or a free-floating orbit entry of Kind == "station" (orbits the star).
  • DockScreen (features/stations/DockScreen.cs) — the docked UI: REPAIR, REFUEL, SELL (one row per held commodity), REFINE (Refinery stations only), DEPART. Sell/refine already read the player’s ship CargoHold. The deposit/withdraw UI is a fourth section in this same screen, not a new screen.
  • GatherBrain (features/ai/GatherBrain.cs) — independent miners and salvagers fly a full hold to the nearest station and Cargo.Clear() it: “NPCs bank no ledger — the cargo just clears.” A player station is exactly the place that ledger should start existing.
  • EconomySnapshot (features/debug/EconomySnapshot.cs) — the F8 read-model already has the plug points wired to zero: Quantity is hardcoded 0 (“stations hold no per-commodity stock yet … the day stock ships it is a one-line wire-up”), and Outgoing is 0 with InboundCargo as the documented outbound plug point (“an outbound source feeds the same shape once haulers land”). A player station’s stored stock is that Quantity field; a hauler draining it is that Outgoing field.
  • FactionState (features/factions/FactionState.cs)PlayerId = "faction.player" already exists (it is the collision-layer owner the dock zone wakes on). Turrets inherit their station’s faction, so a faction.player station’s guns shoot whoever the player is at war with, for free.

What does NOT exist yet (the genuinely new work)

  1. Runtime station spawn. Nothing builds a Station into the live tree after boot; StarSystem instances them from JSON once. A player station must be constructed on demand and parented into the current StarSystem.
  2. World-state persistence. The only things that persist today are input bindings and audio settings (user://); there is no save of runtime-created world objects. A “home” that vanishes on reload is not a home — persistence is a hard prerequisite, and it does not exist. This is the single biggest dependency this design surfaces.
  3. Station-side storage. CargoHold lives on the ship and is emptied, not banked. A delivery-hold platform needs a persistent hold on the station that the player deposits into and withdraws from.
  4. Player hull art. Station.HullSpriteByFaction covers civilian / militia / pirate only; a faction.player station falls back to the civilian dreadnought today. A dedicated player-station silhouette is a nice-to-have, not a blocker.

MVP — the delivery-hold platform

Per docs/design-universe.md’s repair-supply-chain framing (the buildable MVP is a manual haul, “automation slots in later without changing the delivery interaction itself, since ‘cargo arrives at the gate’ doesn’t care whether a player or a drone carried it”), the first player station is a dumb, persistent locker in space — no market, no automation.

  • What it stores. One persistent CargoHold on the station (the same CargoHold type the ship uses — a capacity in units holding commodity stacks), sized generously (a few multiples of the ship hold, tune to ~500–1000 units) so it is a stockpile, not a second backpack. It stores any commodity: raw ore, salvage, refined components alike.
  • Who can deliver.
  • The player, by docking: the DockScreen gains a STORAGE section below CARGO — one DEPOSIT row per held commodity (hold → station) and one WITHDRAW row per stored commodity (station → hold, capped by ship free capacity). This is the MVP retrieval path: you dock and pull your stuff out.
  • Own-fleet gather ships, immediately and for free: GatherBrain already runs a full hold to the nearest station and clears it. For an owned target station, bank the hold into the station’s CargoHold instead of Clear()ing it (respecting free capacity; overflow stays in the ship hold and it loiters or re-routes). This is what makes a forward mining station worth building — your miners fill it while you are elsewhere.
  • Independents keep clearing to the void as they do now (they bank no ledger); depositing into a player’s hold is an own-fleet behavior, not a gift from unaligned NPCs.
  • How the player retrieves. Dock → STORAGE → WITHDRAW (or SELL straight from the ship hold at a Trade-type station as today). No teleport, no remote access in the MVP — the waypoint is a real place you fly back to.

Cost + build flow

Cost model — reuse the mineral chain, don’t invent a build currency. Mirroring design-universe.md’s gate-repair rule (“reuse an existing commodity … rather than invent a single-purpose item — no new drop table”), a station is bought with a structural-material cost + a credits fee:

  • Materials: a batch of the T1 structure commodity — raw Ferrite (baseWorth 4) or its refined Alloy Plate (baseWorth 11), which is literally described in commodities.json as “banked into hull and structure stock.” A delivery-hold platform on the order of ~150–250 Alloy Plate (or a larger raw-Ferrite equivalent) is a meaningful sink for a player who has run the mine→refine loop a few times, without being an endgame wall. Higher station types (defense, refinery) cost more and add a higher-tier component (Armor Plating / Weapon Core).
  • Credits: a flat fee on top, paid from PlayerWallet, in the low thousands — the same wallet that pays for repairs, so it competes with the existing credit sinks for pacing.
  • Where the materials come from: the ship hold at build time (you haul the plates to the build site), consumed on confirm — the same consume-cargo interaction the gate-repair MVP uses.

Where placement is legal. Reuse the existing orbit-slot model rather than free placement anywhere:

  • Placement is into an orbital slot in the current system — a free-floating station orbit (Kind == "station", orbits the star) or a slot around an existing planet (OrbitDef.Stations). The build UI offers the legal slots; the player is not dropping a station into a star or on top of a belt rock.
  • Separation rule: a candidate slot is legal only if it clears existing stations and bodies by more than the sum of their VisualRadius + DockBuffer (the same radii the hull collision and dock zone already use) — no overlapping dock zones.
  • Belt/graveyard proximity matters for support stations: a station built near a belt is where your assigned miners will dump (they pick NearestStation), so “build near the ore” is an emergent placement incentive, not a special rule.
  • One per system (MVP limit). The fantasy is a waypoint — a home per system, not a wall of stations. One player station per StarSystem for the MVP; lift the cap later if fleet logistics want relay chains. This also sidesteps station-spam pathologies in the presence-gated sim before they can start.

Build time. Instant-spawn is the simplest MVP and is acceptable (consume cost → station appears). The recommended small step up is a short build timer (a construction state on the placed Station, hull dimmed / turrets inert until complete) — this creates the natural danger window (below) without new systems: it is just the existing Disabled dimming reused as an “under construction” look.

What it DOES, staged

The delivery-hold platform is deliberately the floor; each later stage wires a plug point that already exists.

  1. Hold (MVP). Persistent storage; deposit/withdraw at the dock; own-fleet miners bank into it. No prices, no automation.
  2. Buy/sell (stage 1). The station posts a market: it stocks commodities and buys/sells them, wiring the EconomySnapshot.Quantity plug (currently hardcoded 0) to the station’s real stored stock, and giving DockScreen SELL/BUY rows a player-station counterpart. Now the station is a market node your traders can arbitrage against, not just a locker. Supply/demand rides the existing SupplySkew field until real per-commodity stock pricing ships.
  3. Automation slots (stage 2). Station modules: a refinery module (flips the station to expose the existing Refinery REFINE rows), a defense module (arms turrets via the existing ArmTurrets — see Danger), a drone bay (own miners/salvagers/haulers based here on a tight leash — the escort primitive’s carrier anchor, docs/design-fleet.md). Modules are the “automation slots in later” half of the universe-doc promise: the hold and delivery interaction never change, the station just starts doing work while you are away.

Fleet interlock (why this is step 2, before roles)

docs/design-fleet.md’s role list makes the dependency explicit — two roles cannot exist until player stations do:

  • [Haulers] “keep player-station stock at set levels” — a hauler’s order is (source station, target station, commodity, target level); it moves stock between player stations (or from a market to a player station). It wires the EconomySnapshot.Outgoing plug (a station- departure feeding the same InboundCargo shape in reverse).
  • [Traders] “buy/sell from/to player stations for profit” — a trader arbitrages price differentials (the danger/supply skew already in SellMath) between a player station and remote markets.

Both need a player station as an endpoint, which is why the platform lands first. Recruit/assign UI implication: the right-side fleet panel (design-fleet.md) role assignment for a hauler/trader must let the player pick a player-station endpoint from a list of their own stations — so the station registry (which stations the player owns, per system) that persistence produces is also the data source the assign UI reads.

Danger interaction

The danger=richness rule (docs/design-economy.md) gets teeth for stations: a stockpile in a deadly system is a target, and almost all of the mechanism already exists.

  • Pirates raid. A raider pack (the escort primitive with the station as its anchor target, design-fleet.md) can attack a player station. The station’s Health shield already models this: beaten down → Disabled (turrets dark, hull dimmed). New consequence: while a player station is Disabled, raiders can loot its delivery hold — a disabled station is a window on your stockpile, not just its guns. This makes an undefended forward station in Karda/Veil a real risk, not free storage.
  • Defense is the existing turret system. ArmTurrets already rings a hull with turrets (procedural or author-mounted) that inherit faction and shoot by standings. A player Defense-type station, or a defense module (stage 2), arms the platform; turrets suppress while the shield is down and resume when it regenerates — shipped behavior. A player station defends itself the moment it is armed, with zero new combat code.
  • The knobs are content, not hardcode: shield pool, regen, turret count and mounts are all StationDef fields — a cheap hold platform ships soft, an expensive fortified one ships hard.

Sequencing — implementation card dependency list

Ordered; each card is independently shippable and moves the board one step.

  1. World-state persistence (prerequisite, may predate this feature). Save/load of runtime-created world objects to user://. Nothing like it exists today (only input/audio settings persist). If a save system is already planned for other runtime state (fleet, wallet, discovered lanes), player stations ride it; if not, this card scopes the minimal version: persist the set of player-built StationDefs + their stored CargoHold contents, per system, and re-spawn them on load. Hard blocker for the “home” fantasy — do not ship a station that vanishes on reload.
  2. Runtime station spawn + player ownership. Build a Station from a StationDef into the live current StarSystem after boot; add faction.player to HullSpriteByFaction (or accept the civilian fallback); a player-station registry (owned stations per system) that the fleet assign UI and persistence both read.
  3. Station-side storage hold + dock deposit/withdraw. A persistent CargoHold on owned stations; DockScreen STORAGE section (deposit/withdraw rows, mirroring the SELL/REFINE row pattern); GatherBrain banks an owned target station’s hold instead of clearing.
  4. Build UI + placement validation. Orbit-slot picker in the current system, legality checks (free slot, separation via VisualRadius + DockBuffer, one-per-system), cost check + consume (Ferrite/Alloy Plate from hold + credits from wallet), optional build timer reusing the Disabled dimming.
  5. Buy/sell stock (stage 1). Wire EconomySnapshot.Quantity to real station stock; player-station market rows.
  6. Fleet haulers/traders (design-fleet.md step 3). Consume the above; wire EconomySnapshot.Outgoing. Depends on 3 + 5.
  7. Automation modules (stage 2). Refinery / defense / drone-bay modules. Depend on 2 (station entity) + the drone/escort primitive.

Steps 1–4 are the MVP delivery-hold platform. 5–7 are the layered depth.

Alternatives considered + rejected

  • Mobile base / station-as-ship. Rejected: Station is a static, orbit-anchored Area2D with a traced hull; mobility belongs to the Vindicator host-cradle progression (design-fleet.md “permanent prime hull”), not to stations. A station is a fixed point by design — that is the whole “waypoint / home” fantasy.
  • Free placement anywhere in space. Rejected: breaks the orbit-slot content model every existing station uses and invites station spam in the presence-gated one-world-space sim. Orbit slots + separation keep placement legible and collision-safe for free.
  • Ship-hold storage reused verbatim, no persistence. Rejected: a home that does not survive reload is not a home. Persistence is the point, not a polish pass — hence it leads the sequencing.
  • A bespoke “Station Kit” build item. Rejected for the same reason design-universe.md rejected a bespoke “Gate Repair Kit”: reuse Ferrite/Alloy Plate (already in commodities.json, already mineable and refinable) so building a station is a sink for the economy that exists, with no new drop table or shop entry.
  • Resources-only, no credit fee. Rejected: credits are the established pacing sink (wallet, repair costs); a pure-materials price would decouple station-building from the credit economy the rest of the dock screen runs on.
  • Instant remote access to station storage. Rejected for the MVP: remote withdrawal deletes the reason to fly back, collapsing the waypoint into a menu. Retrieval-by-docking keeps stations places. (Remote read-only stock visibility via the trade-data tiers is a fine later perk — that is information, not teleporting cargo.)

Codex-draft — player-voiced article (goes to assets/codex/ WHEN the MVP ships)

Per the Codex rule (CLAUDE.md), the codex directory stays implementation-accurate — this draft lives here until the mechanic ships, then lands as assets/codex/stations-player.md in the same change, trimmed to what actually shipped.

Building a Home

You can’t go back to the station you woke up in. So build another.

A platform of your own is the first thing out here that’s yours — not salvaged, not captured, made. Haul the plating to an empty orbit, pay the yard fee, and a hull unfolds into a fixed point you can always fly back to.

What it does at first. It holds things. Dock, and you can leave cargo in the station’s hold instead of carrying it — a stockpile that stays put while you range out for more. Miners you’ve assigned will dump their runs here too, so a platform parked by a rich belt fills its hold on its own while you’re three jumps away.

Where you can put one. In an open orbit, clear of other hulls — one to a system. The yard won’t let you wedge it into a star or bury it in a belt. Build it near your ore and your fleet’s runs get short; build it on a frontier and you’ve got a forward base one jump from the danger.

What it costs. Structural plate and a credits fee — the same Ferrite and Alloy Plate you’ve been selling. A basic hold platform is cheap enough to throw up early; a fortified one with guns costs more and eats higher-grade stock.

It can be hit. A station isn’t safe just because it doesn’t move. Beat its shield down and its guns go dark — and if you left a stockpile inside, raiders will help themselves while it’s cold. Out where the ore is richest, an undefended hold is bait. Arm it, or don’t leave anything in it you’d miss.

Later, a platform becomes more than a locker — a market that buys and sells, a refinery, a drone bay, a link in a supply line your haulers run without you. But that starts here: an empty orbit, and something of yours in it.