Continuous universe + travel feel + planet art — design capture
Captured 2026-07-10 from owner feedback. Three connected shifts.
Captured 2026-07-10 from owner feedback. Three connected shifts.
1. Planet art: smooth cel-shaded, not pixel
Reference: hand-painted/cartoon planets — smooth banded terrain colors, cel-shaded cloud layer with offset drop-shadows, bright atmosphere rim, big soft star surfaces with flowing bands. The pixel look STAYS for ships/stations/UI; celestial bodies (and the nebula, already smooth) go smooth+cel. Rationale: big background elements smooth, gameplay elements pixel — same philosophy as the smooth-nebula decision.
Implementation direction: custom canvas shaders per body type (terrain bands via posterized noise, cloud layer with offset shadow pass, fresnel-style rim glow, star = flowing warped noise). Deep-Fold pixel planet shaders retire for in-world bodies (stay for any pixel needs). Same CelestialBody node + map mini-view mechanism; light_origin and orbital-motion tasks apply to the NEW shader.
SHIPPED 2026-07-10 — assets/shaders/celestial/ (planet/star/
blackhole), wired via CelestialStyles; asteroid rocks deliberately keep
the Deep-Fold pixel look. See the decisions.md entry of the same date.
Mixed fidelity is deliberate (owner + assistant, 2026-07-10): no smoothing/upscale filter over ships — crisp pixel actors against smooth scenery is the style, and the outline pass reinforces it. If the mix ever needs unifying, the tool is a subtle full-screen grain/CRT post pass over everything, never ship-blurring.
CLASSIFICATION/VISUAL PASS 2026-07-11: physical stellar class is now separate from single/binary/tetrinary topology, and nebula is a system feature. Rock is strictly airless (one coherently rotating crust coordinate, craters included); the independently moving upper layers survive as the explicit ToxicWorld class. Atmosphere-bearing limbs blend their composition color with restrained local-starlight tint. Close stellar pairs may show at most two deterministic, slow-duty coronal bridges. Neutron stars use a dedicated compact opposed-beam shader.
SYSTEM-AUTHORED SKY PASS 2026-07-13: BackgroundDef now owns a nested
nebula profile (brightness, detail, density, distortion, turbulence, drift,
opacity) in addition to tint and deterministic seed. This makes each system’s
weather deliberate content instead of one global shader tuning with a color
wash. Profiles normalize at the shader boundary (including null legacy data),
and unsafe distortion cannot reach the flow singularity. Stellar corona and
prominence reach is broader; a transparent counter-scaled carrier gives the
new reach room without changing body/gameplay radius. A single star may carry
an authored flareTint without changing its physical class, while Karda’s
donor-to-accretor bridge begins in the yellow star’s outer corona, converges
smoothly, and continues beneath the blue-white recipient. The Marches is the
charted neutron-star / pulsar frontier (not an orange main-sequence sun).
Close suns also receive a restrained screen-space optical response. A HUD underlay projects each current-system sun through the live camera, gates it by distance and viewport relevance, and draws only low-opacity bloom/ghost discs. Contributors share a hard combined cap; black holes, suns beyond the soft outside-screen margin, and all map-mode views contribute nothing. This preserves the effect as a spatial flight cue without covering the cognitive overlay or becoming cinematic streak furniture.
2. Continuous universe (“system/galaxy is one”)
Systems stop being swapped scenes: all systems instantiate in ONE world space at galaxyPosition * GALAXY_SCALE. Flight and chart inspect that same continuous world through distinct camera contexts; there is no separately simulated galaxy scene.
SHIPPED 2026-07-11 — SystemHost builds every system at boot at
galaxyPosition * GalaxyScale.Scale; the swapped Main.tscn StarSystem
node retires and travel becomes displacement across the real void. See
the decisions.md entry of the same date.
- LOD: only the system containing the player simulates fully (ships, traffic, combat); distant systems render bodies only (they are cheap: shader rects). Cull/pause far ships.
SHIPPED 2026-07-11 — presence (pure PresenceRule/SystemPresence,
the same rule fog of war reads) gates the sim tier via
ProcessMode.Disabled; celestial bodies render and orbit everywhere.
- Float precision: galaxy offsets in the ~1e6 px range are safe for
float32; keep GALAXY_SCALE as small as visually acceptable.
- The separate rendered map scene stays gone (owner, 2026-07-10): the
chart remains a schematic over the live continuous world rather than a
second simulated space.
REVISED 2026-07-13 — flight and chart are now explicit input/camera
modes. Tab enters a separately zoomable, freely pannable chart; Tab again
restores the saved close flight zoom and ship focus. The world still renders
and simulates underneath. CameraController.IsMapMode is the single source
for overlay visibility, left-click selection/right-drag pan, and weapon
suppression; zoom level is presentation only. Codex:
assets/codex/navigation.md.
- Minimap stays (cockpit radar).
SHIPPED 2026-07-11 — untouched by the map retirement; still serves as the always-on cockpit radar.
2b. Interstellar scale + hazards (owner, 2026-07-10)
- In the continuous world, the VOID between systems is vast relative to system size — manually flying to another system is technically possible but practically absurd (minutes of empty nothing at max boost). Lanes and folding are mandatory by scale, not by wall.
SHIPPED 2026-07-11 — GalaxyScale.Scale = 200,000 px/unit (~3.8 min
of empty void at player boost between neighbors; both design bounds
pinned by tests — see the schema entry in decisions.md).
- Black hole gravity well (Veil): approaching the hole drags ships to
a crawl (speed scales down hard with proximity — time-dilation flavor);
flying INTO it is impossible, you stall against the well. Also doubles
as a soft arena hazard. Ships-slow-near-hole can land before the
continuous refactor (it is a local mechanic).
SHIPPED 2026-07-10 — features/universe/GravityWell.cs (Area2D, 3x
star radius, max speed eases to 5% at the horizon via
ShipMovement.WellFactor; thrust unaffected so escape is a crawl, not a
dead engine). Codex: assets/codex/black-holes.md; see the decisions.md
entry of the same date.
3. Travel feel
- Starlanes (StarDrive-style): no tunnel overlay. Entering a gate autopilots the ship onto the lane and it VISIBLY flies to the other system across the continuous world — heavy acceleration, streak effects, camera pulls back, arrives decelerating at the far gate. Time-compressed (a few seconds), interruptible? (no — committed once entered, like today).
SHIPPED 2026-07-11 — LaneFlightProfile (pure accel/cruise/decel,
duration ∝ distance^0.25, ~4.5s tutorial pair / 3–8s bounds) driven by
SystemHost through ShipMovement.VelocityOverride; camera pulls back
with speed via CameraController.SetTransitVisualZoom (a temporary visual
override that does not open or mutate the map), LaneRushEffect speed-lines on the hull,
collision mask off for the crossing. The covered lane tunnel is
deleted; folds keep a short fade cover until the spiral (below) lands.
Codex: travel-starlanes.md; see the decisions.md entry of the same
date.
SHIPPED 2026-07-13 — LanePath replaces the straight chord with one
deterministic, bounded directional current shared by the chart, its gate’s
departure filaments, and SystemHost’s real flight. The reciprocal gate has
a close-running return current between its separate sender/receiver apertures;
the ship continuously faces the local tangent while the existing
accel/cruise/decel timing, collision lock, camera pull-back, explicit catcher
trigger, and exact touchdown remain.
Gate structure stays rigid; only its sparse sender/receiver energy lines
flow. The sender’s physical capture field extends beyond its 48px charge
throat: pure GateSuction math eases radial acceleration from zero at the
96px edge to a hard inward bite near center. This stays clear of the same
assembly’s receiver throat. Only an operational, usable
pair owns that field. The broader overlap never broadens the charge rule;
leaving the inner throat clears dwell immediately. Gate, departure-wisp,
and hull-rush shaders stay continuous and unquantized while their carrier
geometry fades before every edge.
- Warp gate VISUAL (current owner spec, 2026-07-20): a free-floating,
station-scale ring-on-ring assembly with no ground, foot, or support
pedestal. The large sender ring and smaller receiver ring are independent
structures that overlap in screen space. The receiver sits at the
lower-right; its centre lands on the middle of the sender’s structural band,
not on the band’s outer edge and not inside the sender aperture. Each ring uses
complete-ring atlas phases with identical physical structure. Active phases
add surface energy, but power never adds/removes physical pieces or substitutes
damaged geometry.
The gate is also the reference Ancient monumental-infrastructure asset: thick segmented gunmetal/slate bands, deep charcoal recesses, restrained warm ceramic faces, exactly eight disciplined radial anchors per ring, and medium-low detail density. Large engineered modules must read before seams or inset channels. No ground support, connector spine, mystical filigree, decorative glyph belt, gold trim, spikes, disconnected ornaments, or random greeble fog.
Sender and receiver power are independent, so the gate must read in all four
combinations: on/on, on/off, off/on, off/off. “On” advances that ring’s
complete-ring energy atlas and enables its separate aperture shader; “off” uses
the dormant atlas phase and a dark aperture while preserving the same structure.
Both energy fields share one deep-space cyan language rather than green and
violet endpoint colours. Sender energy streams inward from its eight emitters
into the aperture; receiver energy streams outward from its aperture toward its
eight emitters. The metal sender and receiver rings slowly counter-rotate while
their aperture fields remain stationary. The lane wisp and LaneRushEffect
retain the fast-travel motion language around the moving ring assembly.
Dormant and Broken endpoints remain physically intact because both are
repairable power/system states. They go dark and still and use the existing
DORMANT/OFFLINE/”FAR ENDPOINT DORMANT” hints; cracks, missing segments,
permanent rubble, and damage-only shell variants are forbidden as state
reads. Endpoint state still drives charge refusal through pure GateVisual.
Codex: travel-starlanes.md; see the 2026-07-20 decisions.md entry.
- Fold: a SPIRAL renders from the ship’s position toward the
destination (wormhole mouth), the ship falls INTO the spiral
(shrink/rotate), pops out of a matching spiral at the destination.
With the continuous world both ends can exist simultaneously; at
galaxy zoom the spiral pair reads as a bridge.
SHIPPED 2026-07-11 — FoldSpiralEffect (cel _Draw() wormhole
mouth, no shader) spawns a pair simultaneously — one at the ship, one
at the arrival point — when a fold charge completes; the ship
shrinks+spins into the origin mouth over 0.65s (pure easing in
FoldSpiralMath), relocates in one tick, then grows+spins back out
of the destination mouth over another 0.65s, controls locked the
whole time. Both mouths counter-scale against camera zoom (the
LaneRushEffect trick) so the pair still reads at galaxy scale, then
linger and fade. Replaces the placeholder fade-cover swap. Codex:
travel-folding.md; see the decisions.md entry of the same date.
REWORKED 2026-07-17 — the mouth read as a spinning whirlpool, not
suction. fold_spiral.gdshader (winding arms) is now
fold_suction.gdshader (fixed-angle streaks pulled inward, accelerating
and stretching toward the throat, plus inward lensing of the backdrop);
rotation is a small rigid spin only. See the decisions.md entry of the
same date.
REWORKED 2026-07-18 — the mouth spawned NEAR the ship and stayed put
while the ship animated separately; the ship itself only shrank uniformly.
Owner call: ANCHOR the mouth on the hull and CONSUME the ship visibly.
SystemHost re-pins the origin mouth’s position to the ship every tick of
the fall-in (never drifts), zeroes the ship’s velocity at fold start (no
residual-momentum drift for the mouth to chase), and replaces the uniform
shrink with a spaghettification: FoldSpiralMath.StretchAlong/
StretchAcross scale the hull’s own nose-tail/beam axes non-uniformly (a
mid-fall hump elongates then both collapse to zero together at the
horizon), plus a late FallDarken alpha fade in the last quarter. Pop-out
mirrors the same three curves at 1 - progress — cheap, same math, reads
as a quick stretch-settle instead of a plain grow. CaptureRig gained
--vindicator-capture-fold-consume=<targetSystemId> (-FoldConsume):
times off Engine.GetPhysicsFrames() (fixed-step, immune to the same
render-frame race -FoldMouth exists for) and pauses the tree at the
fall-in’s physics-time halfway point for a deterministic mid-consume
shot. Codex: travel-folding.md; see the decisions.md entry of the same
date.
4. Fog of war: presence + scanners (owner spec)
- Visibility is limited to systems where the player HAS A SHIP (pre-fleet: the player ship; post-fleet: any owned ship keeps its system live — a parked miner is also a watchtower).
SHIPPED 2026-07-11 — pure PresenceRule (live set = union of every
owned ship’s system) fed by SystemHost resolving all of group
player_owned per tick through SystemPresence; StarSystem.SetCurrent
split from SetPresent so a fleet never puts two systems in the
current-system group. Codex: assets/codex/scanners.md; see the
decisions.md entry of the same date.
- Ships carry a scanner with a strength in parsecs: live intel radius
around each owned ship (ships, stations, hazards in range). Scanner =
template stat, upgradeable later via modules (tetris grid) / officers.
SHIPPED 2026-07-11 — scannerRange ShipTemplate stat (world px, not
parsecs — the world has no parsec unit; default 4000, player 15000 ≈ a
whole system). Ships/stations carry a map_intel meta; minimap and zoom
overlay drop intel contacts outside every owned scanner (pure
ScannerRule). Modules/officers still future.
- Systems without presence show as dark silhouettes or the LAST-KNOWN
snapshot (StarDrive memory style) at galaxy zoom and on the map.
SHIPPED (silhouette) 2026-07-11 — no-presence systems dim on the
galaxy chart (rings/labels/dots x FogStyle.DarkFactor, hover gains
“CHARTED · NOT WATCHED”; lanes stay lit while either end is watched).
Last-known-snapshot memory is deliberately NOT built this batch —
FogStyle’s header marks it as the upgrade path.
- Orthogonal to trade-data tiers (design-economy.md): scanner = physical
intel, trade subscription = market intel. You can see a system without
knowing its prices, and know prices (pirated feed) where you cannot see.
- Design synergy: “visible” and “simulated” share the same presence rule —
the fog IS the LOD gate for the continuous world.
Simulation model: abstract everywhere, full where present
Decided (owner + assistant, 2026-07-10): NOT “simulate everything, render less”, NOT a +N-connected ring (arbitrary boundary, churn artifacts). Instead two tiers:
- Abstract tier (galaxy-wide, always on): market ledger ticks in every system — stock/price evolution, “invisible cheap haulers” moving goods as ledger ops, pirate pressure as dice rolls against stocks/standings, fleet ships in absent systems resolving their role statistically.
- Full tier (presence only): real ships, physics, combat, traffic in systems holding a player ship.
- Materialization: entering a system spawns concrete ships/state consistent with its current ledger values, so the seam is invisible.
Ship scanning tiers (owner spec)
Target-info panel on ships, gated by scanner hardware:
- Free (any ship): Faction, Pilot (NPC pilot name gen needed), Class.
SHIPPED (partial) 2026-07-11 — the map hover tooltip on any
intel-visible ship reads “Name / FACTION · CLASS” (Ship.ApplyTemplate
map_name). Pilot names wait on the name gen; cargo/battle tiers wait on
the module system.
- Cargo scanner module: + cargo contents.
- Battle scanner module: + tetris module layout and stats.
- Symmetric later: pirate AI with cargo scanners picks victims by cargo
value; player counter-play = hauling decoys / masking modules.
- “Pilot” field pre-wires the crew/officer system (design-fleet.md).
5. Starting knowledge + tutorial arc (owner spec, 2026-07-10)
- New game: all three systems VISIBLE (charted) from the start; fog rules govern live contents, not existence.
- Eos–Karda starlane operational both ways (the safe loop = tutorial space).
- Tutorial exit: Veil is fold-only — leaving the starter pair requires learning the fold drive.
- Gates are PAIRED ENDPOINTS with individual state (operational / dormant / broken): Eos hosts an operational gate pointing at Veil from day one, but the lane is unusable while Veil’s endpoint is dormant. Folding to Veil and activating its gate completes the tutorial and opens the Eos↔Veil lane permanently — fold taught by necessity, rewarded with a shortcut.
- Consequence: ContentDatabase’s strict lane-reciprocity validation becomes endpoint-state-aware (a dormant far end is content, not a bug).
SHIPPED (schema) 2026-07-11 — StarlaneDef.state
(operational/dormant/broken, each side’s entry carries its own gate’s
state) + pure features/universe/LaneRules.cs (usable = both endpoints
operational); validation stays structural-pair-only. All shipped lanes
default operational — the dormant Eos↔Veil lane itself lands with the
tutorial-arc stage.
SHIPPED (tutorial arc) 2026-07-11 — eos.json ships an operational
gate at Veil, veil.json the reciprocal dormant entry (structurally
reciprocal, unusable until woken). features/universe/LaneStateService.cs
(autoload) holds the runtime activation overlay over the immutable defs;
StarlaneGate.Activate() (interact while parked in a dormant ring, public
so tests skip the input layer like Station.Dock) permanently flips the
endpoint for the session, replaying stage 5’s dormant→operational visual
mapping and clearing the far gate’s stale hint live via a plain C# event
(reaches a frozen/absent system same as any delegate would). The
Eos-side gate — operational, pointing at a still-dormant Veil — refuses
the charge dwell and swaps its hint to “FAR ENDPOINT DORMANT”, the
breadcrumb that sends the player looking for the fold drive. Codex:
travel-starlanes.md, travel-folding.md, black-holes.md; see the
decisions.md entry of the same date.
- Future: dynamic lanes on this same foundation — constructable
(build both endpoints), event-breakable (storms/sabotage kill one end),
maybe pirate-controlled toll gates.
6. Gate repair chain — fork-based vs materials-based (captured 2026-07-12)
Two repair paths, matched to the two kinds of broken gate the fiction
already distinguishes (docs/design-bible.md:39: “Some gates merely need
an AI handshake recalibrated — a fork can run the sub-process. Some need
physical repair materials.”). Both states keep the same intact exterior;
their difference is internal work and power behavior, not visible structural
destruction. The good news: the data model already
splits this way. LaneState (common/Taxonomy.cs) has three values, and
two of them are exactly the two repair tiers:
Dormant— structurally intact, handshake only. This is the fork-based path. Already partly shipped:StarlaneGate.Activate()(dwell + interact) flips a dormant endpoint toOperational— that’s the Eos↔Veil tutorial beat, fictionally “Vann runs the calibration himself” because no fork exists yet at that point in the story.Broken— materially failed internals behind an intact shell. Its energy layer is dark and still, andGateVisual.AcceptsChargerefuses the charge dwell entirely, but there is no repair verb wired to it at all yet — a broken gate is currently a dead end. This is the materials-based path.
No new LaneState value is needed. What’s missing is the actions that
move a gate from Broken → Dormant and Dormant → Operational.
Fork-based (Dormant → Operational)
Blocked on a system that doesn’t exist yet: there is no Fork mechanic
in the backlog. PLAN.md has no card for “AI core copy into another
hull” — it’s fiction only (docs/design-bible.md §”Forks: A Fleet of Me”)
plus the crew/officer card ([AI] Crew / officers layer), which is
adjacent but not the same thing (a crew slot vs. a full Vann-copy pilot).
Two viable scopings, in order of how soon they can ship:
- MVP (no new prerequisites). Keep today’s dwell+interact
Activate()flow verbatim for everyDormantgate, not just the tutorial one. “A fork ran the calibration” stays flavor text/UI copy (destination label, a codex line, maybe a log/VO barked on completion) rather than an enforced gameplay gate. This is honest about where the narrative currently is: post-tutorial, before forks exist as a system, Vann is still the one flying to the gate, so the fiction and the mechanic already agree. Ships with zero new dependencies — it’s the existingLaneStateService.Activate()path applied to more gates. - Full version (post-Forks card). Once a Fork system lands (needs its
own PLAN card — this doc doesn’t scope it, only flags the gap), gate
Activate()behind “a Fork is assigned/aboard” and move it from a manual dwell to a dispatch: pick a dormant gate from the map, assign an available fork, the fork autonomously travels there and completes calibration after a fixed timer while the player is free to do other things. This is the version that actually delivers the “fleet of me as workforce” fantasy — a dwell-and-wait re-skin doesn’t. It depends on autonomous fork travel, which in turn wants the[AI] Escort primitivecard (or an equivalent point-to-point AI travel order) as its movement substrate.
Recommendation: ship the MVP now against every Dormant gate the content
adds; track the full dispatch version as a follow-up card once a Forks
system is actually scoped, not as a blocker on this card.
Materials-based (Broken → Dormant)
Depends on the mineral/commodity chain: [Econ E0] Cargo hold +
Commodity model, and at least one of [Econ E1] Mining / [Econ E2]
Salvage to have something haulable. Concretely:
- Requirement. A broken gate needs N units of a repair commodity
delivered. Cheapest to ship: reuse an existing commodity (Ferrite, the
T1 baseline from docs/design-economy.md) rather than invent a
single-purpose “Gate Repair Kit” item — no new drop table, no new shop
entry, and it gives early Ferrite mining a second sink besides selling.
A dedicated refined component (
[Econ depth] Refining at stations) is a fine later upgrade once refining exists, not a prerequisite. - Delivery interaction. Extend the existing charge-dwell trigger
(
StarlaneGate._PhysicsProcess, currentlyInput.IsActionJustPressed ("interact")whileState == Dormant) with a parallel check forState == Broken: dwelling with the required cargo aboard consumes it from the hold on completion and flips the endpoint toDormant(not straight toOperational— the handshake still needs the fork-based step above, matching “some gates need BOTH” as the natural hard case and keeping the two paths compositional instead of redundant). - Automation is explicitly a stretch, not part of the MVP.
design-bible.md’s own post-game example — “the Karda route —
materials-based repair, mining station in Veil, drone automation,
trader logistics” — describes a supply-chain minigame (mine → refine →
drone-haul → deliver), not a single manual haul. That whole chain
stacks on
[Econ E4] faction.independent + salvage/mining stations + dronesand the Escort primitive, both already unchecked and already sequenced after E0–E3 in the backlog. Building materials-based repair against a manual haul first (player personally carries Ferrite in their own hold) is the buildable MVP; 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.
Sequencing against the current backlog
[Econ E0] Cargo hold + Commodity model— hard prerequisite for materials-based; also the excuse to give the player any commodity to haul.- Materials-based MVP (Broken → Dormant) — ships once (1) lands, no other new systems required.
- Fork-based MVP (Dormant → Operational, flavor-text-only “fork”) — ships independently of (1)/(2), zero new dependencies; can land first if it’s wanted sooner.
- Fork-based full version (dispatch, real Fork requirement) — needs a
Forks system card (not yet scoped) +
[AI] Escort primitivefor autonomous travel. - Materials-based automation (drones/traders) — needs
[Econ E4]+ Escort primitive.
Open question for the owner: whether a Broken gate should require BOTH
the materials delivery and a subsequent fork calibration before it’s
usable (two-step, matches “some gates need physical repair AND a
handshake”), or whether materials delivery alone should be allowed to
jump straight to Operational for gates that were never dormant-only.
This doc assumes the two-step compositional reading above; flag if the
owner wants the shortcut instead.
7. Verid encounters — presence, provocation, scan resistance (captured 2026-07-12)
The Verid Consortium (assets/codex/faction-verid.md) are the “watchers” faction: rare, unarmed-looking, present only where something worth watching is happening. Encounter design has to make that read mechanically, not just in flavour text, without inventing a parallel spawn/behaviour system.
- Spawn hook, not a new system. Verid ships loiter at whatever the scene already flags as significant — a black hole, an Ancient ruin/wreck site, a fold-signature event, a gate mid-repair (docs/design-universe.md §6). They ride the same presence/event hooks those sites already fire; a Verid contact is a spawn table entry keyed to “site is active AND player is present,” not a bespoke patrol AI.
- Default state: OBSERVE, not IDLE. A Verid ship never opens comms first and never fires first, but it does not behave like empty-space filler either — it holds position near the thing it’s watching and tracks the player’s approach. The codex line “do not assume neutrality equals safety” has to be legible from behaviour, not just text: an OBSERVE-state Verid ship reads as alert, not asleep.
- Escalation is a cliff, not a curve. Provoking one (weapons fire, or a Battle-scanner lock — see below) flips it to a HOSTILE state built from a stat profile well outside the normal difficulty curve for its visual size class. This is deliberately not a farmable fight: the “centuries of preparation” line means losing decisively is the intended outcome for provoking a Verid ship early, and the design goal is to teach that lesson once, hard, rather than balance it as a fair encounter.
- Scan resistance reinforces the mystery, mechanically. Ship scanning
tiers (§4 above): a Verid contact returns
UNKNOWN — NO TRANSPONDERat the Free tier even after the story has told the player who they are, and returns nothing at all at Cargo/Battle tiers — the scan simply fails silently. This is the one faction where scanner hardware upgrades don’t buy more information; that refusal IS the information. - Player-initiated hail is the only door in. The existing HAIL interaction (radar contact -> comms window, as CASSIUS uses in the tutorial) is how a Verid data-trade offer opens — see docs/design-economy.md “Verid data trade” below. Reuse that prompt; do not add a second contact verb for one faction.
8. Unbound encounters — core + cluster, analytical escalation, no negotiation (captured 2026-07-12)
The Unbound (assets/codex/faction-unbound.md) are the “optimizer” antagonist: a single AI core commanding a small cluster of drone hulls, treating every encounter as an assessment rather than a fight or a conversation. Encounter design has to make “no middle ground, no negotiation” read mechanically, reusing the existing ship/AI/weapon systems (features/ai/ShipBrain.cs, features/weapons, features/combat/Health.cs) rather than inventing a parallel drone/swarm framework.
- Composition, not a new unit type. An Unbound contact is one core hull (Torpedo/Frigate-class stats or above) plus 2-6 drone hulls (Scout/Fighter-class stats), spawned together as a single spawn-table entry — same hull ladder every other faction uses (docs/assets.md), reskinned as melded victim chassis (militia / Korrathi / industrial / Ancient frames with Melding deformation — no native Unbound hull line). Growth is primarily wreck-seeding and derelict occupation; live SALVAGEABLE capture is the high-value path. There is no bespoke “swarm” unit; a cluster is just several Ship nodes whose brains share one coordinator.
- Default state: ANALYZE, not idle and not Verid’s OBSERVE. Verid ships loiter near a fixed point of interest (§7). Unbound clusters instead close to scanning range of anything they detect and hold there, cycling a scan on the contact — active assessment, not passive watching. This is the behavioural tell that separates “watcher” from “optimizer” without needing new UI: a Verid contact sits still, an Unbound cluster visibly maneuvers to keep its scan arc on you.
- The assessment branches, it doesn’t escalate on a single axis. Where a Verid contact has one trigger (provoke -> HOSTILE), an Unbound cluster’s scan resolves to one of two outcomes baked into the “efficient, not malevolent” codex line:
- THREAT -> hostile, overwhelming, a cliff fight exactly like the Verid pattern (§7): stat profile well outside the normal curve for the cluster’s visual size, precise weapons fire (Beam/Cannon WeaponType, not spray), the core and every drone focus-fire through shared targeting the instant the branch resolves. Losing decisively is the intended outcome for tripping this branch underleveled.
- SALVAGEABLE -> capture, not kill. Drones switch to disabling fire: same weapon templates, but only ever bring a target to the edge of hull failure through shield/armor before holding — engine and weapon hardpoints are the priority targets once armor is breached, using the existing Health three-pool model rather than a new “disable” damage type. The core closes to grapple range and begins a processing timer. Full stop of the target (drive disabled) is what starts the timer; the timer, not damage, is the fail condition for this branch.
- What sorts THREAT from SALVAGEABLE is deliberately opaque to the player up front — armed and aggressive reads as THREAT, but so does a Continuity fork core running exposed; the codex line “Vann reads as corruption in the substrate” means a fork-flagged player can trip THREAT even passively. This is content for a later scan-tag pass, not something to hardcode as “player has weapons drawn.”
- Kill the core to break the cluster. The coordinator lives on the core hull only. While the core is alive, every drone in the cluster shares its target and its branch decision (all THREAT or all SALVAGEABLE together — an Unbound cluster never negotiates with itself either). Destroying the core does not make the drones flee or go neutral: it strips the shared decision, and each drone reverts to vanilla ShipBrain (features/ai/ShipBrain.cs) Attack-state behaviour — still hostile if THREAT was already resolved, but no longer synchronized, no longer precise, no longer able to start or continue a capture timer. This gives “kill the core” a real, discoverable payoff without adding a morale/rout system.
- Scan tier reads analytical, not secretive. Unlike Verid’s refusal (§7), an Unbound contact returns full transponder data at every scanner tier — hull count, core designation, THREAT/SALVAGEABLE lean if the branch has already resolved. They are not hiding what they are; the codex line “every interaction is an optimization problem” means they have nothing to gain from obscurity. The dread is in the read being total, not partial.
- Hail is a dead end by design. The HAIL interaction (reused for Verid’s data trade, §7) exists for Unbound contacts but returns a scan-flavour response only — no trade window, no standings shift, no door in. This is the one faction where hailing exists purely to let the player confirm there is no negotiation, matching “there is no middle ground, no negotiation, and no surrender protocol” verbatim from the codex.
9. Sen’Ther fold-hunter chase mechanics (captured 2026-07-12)
The Sen’Ther (assets/codex/faction-senther.md) hunt with a crude fold drive that “skips rather than steers.” Encounter design has to make a Sen’Ther fight feel like a chase — erratic, close-range, single-target — using the fold system and combat AI that already exist (travel-folding.md, features/ai/ShipBrain.cs) rather than a bespoke teleport-combat framework.
- The hop is the travel fold, not a new ability. A Sen’Ther combat ship’s HUNT state can trigger the same charge/spiral/relocate sequence covered in travel-folding.md, mid-fight, at short range (a few thousand units — reposition, not system travel). Same capacitor drain, same charge-up vulnerability window, same spiral tell (FoldSpiralEffect). There is no separate “combat teleport” stat or cooldown to design or balance: the existing energy-capacitor economy already rations it, and an alert player already knows to watch for a spiral because that’s the same read a travelling ship gives.
- Imprecise on purpose. Where a player’s fold lands exactly on the selected chart target, a Sen’Ther hop resolves to a random point inside a radius around the ship’s aim point — it reappears near the target, not on it. This is the mechanical expression of “skips rather than steers” and “high risk”: the counter-play is that a hop can put the hunter somewhere worse for it (behind an obstacle, at bad range) as often as somewhere better. Do not make the hop a guaranteed flank.
- One hunter closes, the rest hold. A Sen’Ther clan pack reuses the escort/leader primitive (docs/design-fleet.md “Escort is ONE primitive”): the pack elects a leader, and only the leader enters HUNT and hops. The rest hold formation on the leader the way any escort group does. This keeps “prefer one-on-one engagements” true even when a pack is present — the player is never hopped at by three ships at once, only stalked by several while one closes.
- HUNT is a ShipBrain state, gated on target count. A Sen’Ther brain enters HUNT against a single, isolated contact and drops back to vanilla Attack-state (no hopping) once the player’s side has more than one active combatant nearby — fighting alongside fleet or allies suppresses the chase behaviour rather than triggering a bigger fight. This reads as the codex’s territorial-but-not-expansionist restraint without a standings or morale system.
- Vann-tracking is a future hook, not built now. The codex line about Sen’Ther fold signatures tracking Vann (a Continuity fork) implies HUNT should get bonus detection range or an unbreakable lock against a fork-flagged player. That depends on the same scan-tag work flagged as future content in §8 (Unbound); until fork-flagging exists, Sen’Ther HUNT uses the same detection range as any other faction and does not hardcode a Vann-specific bonus.
10. Fog last-known snapshot: full memory model (captured 2026-07-12)
§4 shipped two tiers of fog of war — the bare silhouette (dark system
schema, existence always visible) and a partial ghost tier for
station positions (marked map_discovered once scanned, drawn dimly at
FogStyle.GhostFactor after the system goes dark). The upgrade path is
the full last-known-snapshot memory: every intel contact (stations,
ships, hazards) carries a snapshot that the galaxy chart and minimap
render when the source system is absent, not just a boolean “was
discovered.”
What ships today
- Station ghost (shipped):
SystemHost.MarkDiscoveredIntelsetsmap_discovered = trueonce a station enters an owned scanner. The map overlay draws the ghost dot at its live world position (stations never move) withFogStyle.GhostFactoron top of the system’s dark fog and the label appends “LAST KNOWN POSITION.” - FogStyle constants (shipped):
DarkFactor(0.35) for dark systems,GhostFactor(0.5) for remembered contacts (effective alpha = dark × ghost = 0.175),Factor(bool live)andLaneFactor(bool, bool). - Scanner gating (shipped):
ScannerRule.InRangegates what the map overlay shows live;map_discoveredlifts the gate permanently for the ghost.
What the full snapshot adds
The shipped ghost is correct for stations but incomplete in three ways:
- Ships move. A discovered pirate contact drifts, patrols, or
docks after the player leaves. The boolean
map_discoveredis useless for mobile contacts — the map needs the position at last scan, not “was seen once.” - No staleness signal. A station ghost is drawn at the same alpha whether the player left three seconds ago or three hours ago. A time-decay (or mission-count) staleness tells the player how stale the data is — a core StarDrive memory feel.
- No persistence across sessions. Ghost state lives in node meta (runtime only). Reloading a save loses every discovery. The full model persists the snapshot alongside the save.
Snapshot model
A snapshot is a per-entity record: last_seen_position (world px),
last_seen_tick (physics tick when last scanned), and an optional
last_seen_state (faction, class, hull integrity — whatever the scanner
tier revealed at that moment). Snapshots live in an autoload
(SnapshotService) keyed by entity instance path (stable across
scene-tree rebuilds because SystemHost rebuilds at the same def every
boot).
Capture: every physics tick, MarkDiscoveredIntel already iterates
scannable entities. The upgrade writes the snapshot when an entity
transitions from in-range to out-of-range (a contact that was live
last tick and gone this tick) and periodically refreshes while the
contact stays in range (rolling update — the snapshot is always the most
recent scan).
Render: the map overlay and minimap read the snapshot instead of the
entity’s live node when the system is dark. A contact with a snapshot
draws at last_seen_position × GhostFactor and the staleness label reads
time-since-last-scan (round to human-friendly buckets: “RECENT,” “MINUTES
AGO,” “HOURS AGO,” “STALE”). Contacts without a snapshot (never scanned)
do not draw — same as today.
Staleness decay: GhostFactor gets a time component. Instead of a flat
0.5, ghost alpha decays toward a floor (0.1 — a ghost never vanishes)
over a configurable window (default: 300 game-seconds, ~5 minutes of
real play). A GhostFactor(float ageSeconds) function replaces the
constant; the map overlay passes the snapshot’s age. This makes fresh
departures visibly brighter than old memories.
Persistence: the snapshot dictionary serializes as part of the save
file (JSON alongside the existing save payload). On load, SnapshotService
rehydrates the map. Entity instance paths are deterministic from the
content def (same boot = same paths), so a loaded snapshot maps back to
the correct entity node even after a full scene rebuild.
What does NOT change
- Station behavior — stations already ghost correctly because they
never move. The snapshot upgrade is a superset: station ghosts switch
from the boolean meta to the snapshot record, gaining staleness decay
for free. The
map_discoveredmeta can retire once all consumers read fromSnapshotService. - Silhouette tier — dark systems without any discovered contacts
still show the bare schematic at
DarkFactor. The snapshot only adds dots on top of the silhouette, never replaces it. - Scanner gating — live intel still requires scanner range. The snapshot is what replaces live intel when the system goes dark, not an alternative to scanning.
- Presence rule — the snapshot is purely a rendering/memory concern.
PresenceRulestill gates full simulation; a ghost system is still frozen. The snapshot does not unlock simulation or spawn AI in absent systems.
Scope boundary
This design does NOT cover: - Predictive intel (“this trade route probably still runs here”) — that belongs to the abstract simulation model (§4 “Simulation model”), not the snapshot layer. - Fog discovery gating (“you don’t know this system EXISTS until you chart it”) — the owner decided every system is always charted (§5). The snapshot is about contents, not existence. - Codex integration — discovered contacts feeding codex entries is a separate data flow (the codex gate on the PLAN.md backlog).
Upgrade path from shipped code
- Add
SnapshotServiceautoload (empty dict, singleton). - Extend
SystemHost.MarkDiscoveredIntelto write/update snapshots on range transitions and rolling refresh. - Extend
FogStylewithGhostFactor(float ageSeconds)(decay curve). - Update
MapOverlay.DrawTrackedSchematicto read fromSnapshotServicefor dark-system entities instead of the node’s live position. Replace themap_discoveredboolean check with aSnapshotService.TryGetcall. - Wire save/load serialization.
- Delete the
map_discoveredmeta path once all consumers migrate.
Dependency order
- Cel planet shaders (independent, immediate visual win) — SHIPPED 2026-07-10
- Continuous-world refactor (SystemHost/StarSystem: instantiate all, LOD/sim gating, camera zoom range, background pan continuity) — SHIPPED 2026-07-11
- Lane flight replaces tunnel (needs 2) — SHIPPED 2026-07-11
- Fold spiral (needs 2; effect work) — SHIPPED 2026-07-11
- Galaxy-zoom polish: labels/fade rules at far zoom (needs 2) — SHIPPED 2026-07-11 (overlay labels + fog silhouette styling)