The backend holds persistent, authoritative state and exposes server-side reducers for game
actions. Clients subscribe to the rows they need and update reactively.
{[
{ name: 'connect_player(display_name)', trigger: 'Player opens app', resp: 'Create/update player row, spawn initial ship if needed.' },
{ name: 'set_destination(ship_id, x, y, z)', trigger: 'Click in space', resp: 'Validate ownership/status, update destination/vector.' },
{ name: 'dock(station_id)', trigger: 'Click dock', resp: 'Check distance, set ship docked, update location/state.' },
{ name: 'start_mining(asteroid_id)', trigger: 'Click mine', resp: 'Check range, asteroid quantity, ship status, create active action.' },
{ name: 'complete_mining(action_id)', trigger: 'Timer/event', resp: 'Transfer ore into inventory, reduce asteroid quantity.' },
{ name: 'sell_item(item_type, qty, station)', trigger: 'Sell from UI', resp: 'Validate inventory and station, exchange ore for ISK.' },
{ name: 'place_market_order(...)', trigger: 'Market UI', resp: 'Reserve inventory, create sell order.' },
{ name: 'send_chat(channel_id, body)', trigger: 'Chat box', resp: 'Validate/rate-limit, append chat message row.' },
{ name: 'world_tick(ctx)', trigger: 'Server timer (5 min)', resp: 'Evaluate galaxy state, player density, faction matrix. Conditionally spawn PvE events (faction conflicts, anomalies, migrations, raids). Propagate active events.' },
{ name: 'spawn_world_event(event_type, system_id, params)', trigger: 'World tick evaluation', resp: 'Create world_event row, generate story log entry, notify nearby players via sensors, set expiration timer.' },
{ name: 'resolve_world_event(event_id, outcome)', trigger: 'Event timer or player action', resp: 'Update galaxy state based on outcome, write story log chapter, adjust faction relations, trigger cascading events.' },
].map((row, i) => (
{row.name}
{row.trigger}
{row.resp}
))}
>
)}
{activeSection === 'movement' && (
<>
Movement Model
Avoid sending per-frame movement. Store destination and speed. Clients interpolate visually;
the backend periodically updates authoritative positions.
Movement Flow
1. Client calls set_destination(ship_id, x, y, z)
2. Server validates ownership + ship status
3. Server updates ships.destination + calculates velocity vector
4. Server broadcasts updated ship state to subscribers
5. Client interpolates visual position between last known + destination
6. Server periodically updates authoritative x/y/z position
Client-side interpolation
Smooth visual movement between authoritative position updates. Uses dead reckoning
with periodic server correction. Handles latency spikes gracefully.
Server authority
Backend is the source of truth for all positions. Clients never modify their own
position directly — they submit intentions and wait for confirmation.
Single galaxy, simulated world. The server maintains one persistent galaxy with a connected graph of star systems,
each containing planets, moons, asteroid belts, and stations. A world simulation layer runs on top, spawning dynamic PvE events
that create a unique story per server. This is not instanced content — every player in the galaxy shares the same world state.
Galaxy Topology
Galaxy → contains Regions (4–8 regions, each with distinct character) Region → contains Constellations (3–6 per region, connected clusters) Constellation → contains Systems (2–8 per constellation, gate-connected) System → contains Star + Planets + Moons + Belts + Stations + Anomalies Planet → has orbiting_objects (stations, moon mining outposts, customs offices)
World Simulation Tables
Overlap note:faction_relations, world_events, and galaxy_story_log also appear in the Tables tab with abbreviated field descriptions. The definitions below are the expanded versions with full field detail. Both tabs describe the same underlying tables.
// Runs every 5 minutes on the server reducerworld_tick(ctx) {'{'} // 1. Evaluate faction tension matrix for each faction_pair {'{'} if standing {'<'} -5 && random {'<'} tension_weight {'{'} spawn_event("faction_skirmish", contested_system); log_story({'"'}Hostilities erupt between {'{'}A{'}'} and {'{'}B{'}'} in {'{'}system{'}'}{'"'});
{'}'}
{'}'}
// 2. Check anomaly spawn slots if active_anomalies {'<'} max_anomalies {'{'}
pick random system weighted by distance_from_hub; spawn_anomaly(system, random_type);
{'}'}
// 3. Advance fauna migration routes for each fauna {'{'} if now {'>='} next_waypoint.arrival_at {'{'}
advance fauna to next system in route; log_story({'"'}{'{'}species{'}'} migration enters {'{'}system{'}'}{'"'});
{'}'}
{'}'}
// 4. Cascade: check if any active events should trigger follow-ons for each active_event near expiry {'{'}
evaluate_outcome(participants, event_state); resolve_event(event_id, outcome); // outcome may shift faction relations → future events
{'}'}
{'}'}
>)}
{galaxySubSection === 'galaxy-gen' && (<>
GALAXY-GEN
Galaxy Generation — Seeded Parameters & Algorithm
Every galaxy begins with a seed. The galaxy generation algorithm is deterministic: the same seed always produces
the same galaxy. This means server operators can share a seed for a known-good galaxy layout, or generate a unique one.
Generation runs once at server bootstrap and writes immutable topology tables (regions, constellations, systems, stargates,
planets, moons, stations, asteroid belts). Faction territories and NPC agent placement are also seeded at this stage.
Galaxy Parameters
Parameter
MVP Value
Full Launch
Rationale
{[
{ param: 'Regions', mvp: '4', full: '6–8', reason: 'Core, Frontier, Null, Deep Null for MVP. Add 2–4 faction-specific regions at launch.' },
{ param: 'Constellations per region', mvp: '3–4', full: '4–8', reason: 'Minimum 3 for gate connectivity. More in Core region, fewer in Deep Null.' },
{ param: 'Systems per constellation', mvp: '2–5', full: '3–8', reason: 'Density varies by region type. Core constellations are denser (trade hubs).' },
{ param: 'Total systems (MVP)', mvp: '~50', full: '~300–500', reason: '4 regions × 3.5 const × 3.5 sys ≈ 49 systems. Enough for economic loops without barren stretches.' },
{ param: 'Stargates per system', mvp: '1–4', full: '1–6', reason: 'Minimum 1 (no dead ends). Hub systems get 4+. Frontier gets 2–3.' },
{ param: 'Stations per system', mvp: '1–3', full: '1–6', reason: 'High-sec: 2–3 stations. Low-sec: 1–2. Null: 0–1 NPC stations. Stations are where the economy lives.' },
{ param: 'Planets per system', mvp: '1–5', full: '2–8', reason: 'Aesthetic + resource variety. Orbital mechanics run on a slow tick (no gameplay impact in MVP).' },
{ param: 'Asteroid belts per system', mvp: '1–3', full: '1–5', reason: 'Belts are where mining happens. More belts in lower-sec = better ore = risk/reward.' },
{ param: 'Factions', mvp: '4', full: '4–6', reason: 'One per region in MVP. Each has territory, ideology, and agent networks.' },
{ param: 'NPC agents per station', mvp: '1–2', full: '1–4', reason: 'Mission-givers. Specialty and quality randomized from seed.' },
].map((row, i) => (
{row.param}
{row.mvp}
{row.full}
{row.reason}
))}
Galaxy Shape & Layout
Spiral galaxy with 4 arms. The galaxy is rendered as a top-down 2D map (with a Z-depth dimension for 3D system
coordinates within each system). Regions are assigned to spiral arm segments:
Core (center), Frontier (inner arms), Null (outer arms), Deep Null (tips and gaps between arms).
Systems within a region are placed using a Poisson disk distribution to ensure minimum spacing while maintaining natural clustering.
Region Assignment Rules
Core (sec +0.8 → +1.0): Center of galaxy map. Dense, high station count, trade hub. Starter systems live here. 1 region.
Deep Null (sec −0.5 → −1.0): Tips and gaps. Very sparse. Wormhole connections only. Elite content. 1 region.
System Placement Algorithm
1. Place constellation centroids via Poisson disk (min 40px apart on map)
2. For each centroid, place 2–5 systems in a cluster (Gaussian offset from centroid, σ = 15px)
3. Assign security level band based on region assignment
4. Add jitter to security within band (±0.1 random) for natural variation
5. Place star type (O/B/A/F/G/K/M) weighted by frequency — G/K most common
6. System name generated from faction language + sequential number
Stargate Topology
No disconnected components. Every system must be reachable from every other system.
The stargate graph is the transportation backbone. If a system has only one gate, it\'s a dead-end —
risky because you can\'t flee without going back through the same gate. The algorithm ensures minimum 2 gates
per system (MVP) and creates "choke point" systems with 4+ gates that become natural trade hubs and conflict zones.
Stargate Connectivity Algorithm
Phase 1 — Minimum Spanning Tree: Compute MST over all systems using Euclidean distance. This guarantees full connectivity with minimum total gate length. Phase 2 — Intra-constellation edges: For each constellation, add 1–2 extra gates between systems within the constellation. This creates local redundancy and multiple routes within a cluster. Phase 3 — Inter-region choke points: Identify 2–4 systems on region boundaries. Add gates between them to create known choke points. These become strategic PvP locations. Phase 4 — Shortcut edges: Add 10–15% extra gates weighted toward connecting high-sec systems to create trade route variety. Never add shortcuts into/out of Deep Null (wormhole-only access preserved). Validation: After generation, verify: (a) graph is fully connected (BFS from any node reaches all), (b) no system has <2 gates, (c) Deep Null systems have no direct high-sec gates, (d) average path length <15 jumps for MVP galaxy.
Starter System Template
Starter System Layout
Security: +1.0 (maximum safety) Stations: 3 — Home Station, Trade Hub, Factory Belts: 3 — Veldspar/Scordite (easy ore) NPC agents: 2 — Tutorial agent + Level 1 kill agent Gates: 3 — connects to 3 adjacent high-sec systems NPC pirates: None (CONCORD-protected + no belt spawns in 1.0) Services: Refinery, Factory, Market, Fitting, Insurance, Medical
New Player Spawn Rules
New players always spawn in a starter system (sec 1.0)
Each faction has exactly 1 starter system in their Core region
Player receives a Rookie Frigate (free, uninsurable, untradeable)
Player receives the tutorial mission sequence from the tutorial agent
Starter system is guaranteed to have Veldspar and Scordite at NPC buy prices that make the first-30-minute walkthrough viable
Multiple new players can share the same starter system (no instancing)
Station & Belt Placement Rules
Entity
Placement Rule
Density by Sec
Notes
{[
{ entity: 'Station', rule: 'Orbiting a planet or moon. Placed at galaxy gen, never moved.', density: 'High-sec: 2–3/station. Low: 1–2. Null: 0–1 NPC. Player stations (post-MVP) can be anchored.', notes: 'Stations define where economy happens. Every station has a Market. Refinery and Factory depend on station size.' },
{ entity: 'Asteroid Belt', rule: 'Circular orbit around star. 3–5 asteroids per belt.', density: 'High-sec: 1–2. Low: 2–3. Null: 2–4. Deep Null: 3–5.', notes: 'Belt ore quality scales with sec level. High-sec: Veldspar/Scordite only. Null: adds Arkonor/Megacyte.' },
{ entity: 'Moon', rule: 'Orbiting planets. 0–3 moons per planet.', density: '1–3 moons per planet (uniform distribution).', notes: 'Moons have moon minerals (post-MVP). MVP: moons exist for visual flavor and as station anchors.' },
{ entity: 'Stargate', rule: 'At system edge, paired with gate in target system. Placed at fixed (x,y) = system edge toward destination.', density: 'Matches graph topology. 2–4 per system typically.', notes: 'Gates are always paired. Jumping gate A→B always works. No fuel cost for jumping (MVP).' },
{ entity: 'NPC Agent', rule: 'Located at a station. 1–2 per station in MVP.', density: 'High-sec stations: 2. Low-sec: 1. Null: 1 or 0.', notes: 'Agent specialty drawn from faction pool. Quality randomized from seed.' },
].map((row, i) => (
{row.entity}
{row.rule}
{row.density}
{row.notes}
))}
Faction Territory Seeding
Faction Assignment at Galaxy Gen
1. Assign regions: Each faction claims 1 region as home territory. The Core region is shared (contested). 2. Place capitals: Each faction gets a capital station in their home region — largest station, most agents, best services. 3. Seed diplomatic stance: Initial faction relations set to baseline matrix (allies: +5, neutral: 0, rivals: −3). This drifts via world simulation. 4. Distribute agents: NPC agents placed at stations within faction territory. Specialty weighted by faction ideology (militarist → kill agents, trader → trade/escort agents). 5. Set regional price seeds:regional_price_seeds table populated at gen time. Each region gets commodity modifiers (0.6–1.5) that create baseline price differences for traders to discover. 6. Faction military/economy: Initial military_strength and economy_strength set from faction template. These are the starting values the world simulation modifies.
Generation Pseudocode
Galaxy Generation — Pseudocode
fngenerate_galaxy(seed: u64) {'{'} let rng = SeededRng::new(seed);
// 1. Create regions let regions = ['{'Core, Frontier_A, Null, Deep_Null'}']; for region in regions {'{'}
insert region row (id, name, faction_id, security_profile);
{'}'}
// 2. Place constellation centroids (Poisson disk) let centroids = poisson_disk(min_dist=40, rng); for centroid in centroids {'{'} let region = assign_region(centroid.position);
insert constellation row (region_id, centroid.x, centroid.y);
{'}'}
// 3. Place systems within constellations (Gaussian cluster) for constellation in constellations {'{'} let count = rng.range(2..5); // MVP: 2–5 systems per constellation for i in 0..count {'{'} let offset = gaussian(σ=15, rng); let sec = assign_security(constellation.region) + rng.range(-0.1..+0.1);
insert system row (name, constellation_id, sec, star_type, x, y);
place_planets(system, rng);
place_stations(system, sec, rng);
place_belts(system, sec, rng);
{'}'}
{'}'}
// 4. Stargate topology let mst = minimum_spanning_tree(all_systems, euclidean_distance); for edge in mst {'{'} insert_gate(edge.a, edge.b); {'}'}
add_intra_constellation_edges(rng); // +1–2 per constellation
add_region_chokepoints(rng); // 2–4 cross-region gates
add_shortcut_edges(percentage=0.12, rng); // 12% extra high-sec shortcuts
validate_connectivity(); // BFS from node 0 reaches all?
Determinism guarantee: Given the same seed, generate_galaxy always produces identical topology.
This enables: (1) shared "known-good" galaxy seeds for competitive servers, (2) reproducible bug reports with exact galaxy layout,
(3) automated testing against fixed galaxy configurations. The seed is stored in a single galaxy_meta table row:
{'{'} seed: u64, generated_at: timestamp, system_count: u32, total_gates: u32 {'}'}.
MVP scope note: For Phase 0, the galaxy can be hand-authored (a 5–10 system "mini galaxy") as long as
it follows these rules. The procedural generator ships when the galaxy needs to scale beyond ~50 systems (Phase 7+).
Hand-authored galaxies must still pass the same connectivity validation.
>)}
{galaxySubSection === 'galaxy-events' && (<>
World Simulation Tables
Overlap note:faction_relations, world_events, and galaxy_story_log also appear in the Tables tab with abbreviated field descriptions. The definitions below are the expanded versions with full field detail.
50+ tables organized into 5 clusters. This diagram shows the core entity relationships
and how data flows between clusters. Each cluster is color-coded. Foreign key relationships shown as arrows.
Subscription patterns indicate which tables clients subscribe to for reactive updates.
Cross-cluster flows: The most important cross-cluster relationships are:
(1) players \u2192 market_orders \u2192 stations (the economic loop),
(2) ships \u2192 systems \u2192 chat_messages (the spatial-social loop),
(3) ship_ai_soul \u2192 market_orders (Zora reads market data for intelligence).
Every reducer call touches at least two clusters.