Add design spec for probability-based space trading sim
This commit is contained in:
@@ -0,0 +1,161 @@
|
|||||||
|
# Probability — design spec
|
||||||
|
|
||||||
|
A single-player space trading simulation in the browser. Inspired by Space Rangers.
|
||||||
|
The core conceit: NPC ships in systems the player cannot see exist as probability
|
||||||
|
clouds, not concrete positions. Entering a system collapses the clouds in it.
|
||||||
|
Probability is visible gameplay, not just an engine optimization: the player sees
|
||||||
|
clouds, stale prices, and aging intel, and trades on imperfect information — exactly
|
||||||
|
like every NPC does.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- A complete, playable trading loop: fly, dock, buy low, sell high, reach a credit target.
|
||||||
|
- The probability mechanic is visible and legible: clouds on the map, intel that ages.
|
||||||
|
- A living galaxy of 100–200 NPC traders at near-zero simulation cost while unobserved.
|
||||||
|
- Deterministic, headless-testable simulation core.
|
||||||
|
|
||||||
|
## Non-goals (v1)
|
||||||
|
|
||||||
|
- Combat, named pirate units, missions, factions, sound, save/load.
|
||||||
|
(Pirates exist only as hazard fields. localStorage save is a v1.5 candidate.)
|
||||||
|
- Free 2D flight. All movement is graph-based, including inside systems.
|
||||||
|
- Multiplayer, server, persistence beyond a session.
|
||||||
|
|
||||||
|
## World model
|
||||||
|
|
||||||
|
- **Galaxy**: an undirected graph of ~25 systems connected by jump lanes, generated
|
||||||
|
from a seed with a roughly planar layout.
|
||||||
|
- **System contents**: one star, 1–3 planets, one jump gate per lane. Inside a system,
|
||||||
|
ships move along straight legs between gate(s) and planets — still a graph
|
||||||
|
(nodes: gates, planets; edges: legs).
|
||||||
|
- **Commodities**: 6 goods. Each planet produces some and consumes others at fixed
|
||||||
|
rates. Price is a deterministic curve over current stock (low stock → high price).
|
||||||
|
- **Hazard fields**: each lane has a pirate danger rating in [0, 1]. Danger feeds the
|
||||||
|
probabilities of bad branches for ships using that lane: delay, cargo loss, or
|
||||||
|
destruction. No individual pirate units exist in v1.
|
||||||
|
|
||||||
|
## NPC model
|
||||||
|
|
||||||
|
NPC traders (100–200) alternate between two states:
|
||||||
|
|
||||||
|
- **Docked (concrete decision point)**: the NPC picks the best arbitrage opportunity
|
||||||
|
it knows about and plans a route. Decisions use *stale news*, not live state:
|
||||||
|
price snapshots propagate through the galaxy at a fixed speed (a few lanes per
|
||||||
|
game-day). This bounds decision cascades — an NPC's plan depends only on committed
|
||||||
|
history at planning time — and makes NPCs fallible the same way the player is.
|
||||||
|
- **In transit (branch tree)**: the plan is a tree of possible histories. Branch
|
||||||
|
points: route choice (weighted by NPC caution vs. lane danger), hazard outcomes
|
||||||
|
per lane (safe / delayed / cargo lost / destroyed), and fuzzy arrival times
|
||||||
|
(a time distribution per leg whose spread grows with legs traveled since the NPC
|
||||||
|
was last observed).
|
||||||
|
|
||||||
|
**Hidden-variable determinism**: every NPC has a seed. Every branch outcome is drawn
|
||||||
|
deterministically from (seed, branch id). Outcomes are therefore fixed-but-unknown
|
||||||
|
from the moment a plan is made; observation merely reveals them. This guarantees
|
||||||
|
observation-order consistency (seeing a market first or the ship first always yields
|
||||||
|
the same history) and makes the sim reproducible for tests.
|
||||||
|
|
||||||
|
## Probability clouds
|
||||||
|
|
||||||
|
Because movement is graph-based, a cloud is one-dimensional: a weighted set of
|
||||||
|
lane/leg segments, derived analytically from the plan and elapsed time (no per-tick
|
||||||
|
integration). Properties:
|
||||||
|
|
||||||
|
- Total mass is 1 across all branches/segments (invariant, asserted).
|
||||||
|
- Spread grows with time/legs since last observation.
|
||||||
|
- Observation that excludes branches (e.g., "the ore never arrived at B, so the
|
||||||
|
safe-and-on-time branch is dead") renormalizes the remainder — observing a market
|
||||||
|
sharpens the cloud of every ship entangled with it.
|
||||||
|
|
||||||
|
## Markets and probabilistic trades
|
||||||
|
|
||||||
|
Markets in unobserved systems hold **pending probabilistic transactions**
|
||||||
|
("+50 ore, 85% likely, arriving t=10–18") instead of applying trades on a schedule.
|
||||||
|
Anything needing a price meanwhile (NPC planning, news snapshots) uses the
|
||||||
|
expected (probability-weighted) market state. The concrete price exists only after
|
||||||
|
resolution.
|
||||||
|
|
||||||
|
## Observation and collapse
|
||||||
|
|
||||||
|
The player's current system is a **classical bubble** — fully concrete and simulated
|
||||||
|
in real time. All conversion happens at its boundary:
|
||||||
|
|
||||||
|
- **Player enters a system**: every cloud with mass inside is sampled (from its seed):
|
||||||
|
the ship spawns concrete, or is excluded and its remaining cloud renormalized
|
||||||
|
outside.
|
||||||
|
- **While the player stays**: an **arrival queue** holds potential arrival events for
|
||||||
|
this system — every branch in every NPC tree that routes through it, plus new
|
||||||
|
plans made elsewhere as they are created. When an event comes due, roll it: ship
|
||||||
|
materializes at the gate, or the branch silently didn't happen. Traffic volume
|
||||||
|
emerges from trade-route topology; nothing is scripted.
|
||||||
|
- **Docking at a planet**: resolve that market's pending transactions in
|
||||||
|
chronological order → concrete stock and price.
|
||||||
|
- **A concrete ship jumps out / the player leaves**: concrete state re-fuzzes into a
|
||||||
|
tight cloud anchored at the last known position and time, spreading thereafter.
|
||||||
|
|
||||||
|
## Time
|
||||||
|
|
||||||
|
Real-time with pause and ×1 / ×4 / ×16 speed. Internally: a global event queue
|
||||||
|
(arrivals, plan completions, news propagation) plus a fixed sim tick (~10 Hz,
|
||||||
|
scaled by game speed) for in-system ship motion. Clouds cost nothing between
|
||||||
|
observations.
|
||||||
|
|
||||||
|
## Player gameplay (v1)
|
||||||
|
|
||||||
|
- Fly between systems via gates, dock at planets, buy/sell on a market screen,
|
||||||
|
manage credits and cargo capacity. Win: reach a credit target (e.g., 100,000 cr).
|
||||||
|
- Player ship is subject to the same lane hazards (cargo loss / delay; destruction
|
||||||
|
= game over).
|
||||||
|
- **Galaxy map intel layer**:
|
||||||
|
- Lanes tinted by hazard rating.
|
||||||
|
- Last-known prices per planet, displayed with their age ("ore 12 cr — 3 days old").
|
||||||
|
The player's price knowledge updates by visiting or as news reaches their location.
|
||||||
|
- Probability clouds rendered as glowing smears along lanes — only for ships the
|
||||||
|
player has personally observed at least once.
|
||||||
|
|
||||||
|
## Rendering
|
||||||
|
|
||||||
|
- **PixiJS v8** on a single canvas, WebGL backend.
|
||||||
|
- **Two views**: galaxy map (systems = bright circles, lanes = dim lines, clouds =
|
||||||
|
bloomed smears) and system view (star = large bright circle, planets = circles,
|
||||||
|
ships = triangles sliding along legs, gates marked at the rim).
|
||||||
|
- **Neon look**: `AdvancedBloomFilter` (pixi-filters) over the world container;
|
||||||
|
simple flat-color geometry underneath.
|
||||||
|
- **UI as DOM overlay** (not canvas): market table, cargo panel, time controls,
|
||||||
|
hover tooltips.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
sim/ pure JS, zero rendering imports; deterministic given a seed
|
||||||
|
galaxy generation, economy, news propagation, NPC planning,
|
||||||
|
branch trees, clouds, observation/collapse, event queue, seeded RNG
|
||||||
|
render/ Pixi scene graph, two views, bloom, motion interpolation
|
||||||
|
ui/ DOM panels and tooltips
|
||||||
|
main.js game loop: advance sim, project state into render/ui
|
||||||
|
```
|
||||||
|
|
||||||
|
The sim exposes a small read API (system contents, cloud segments, market views,
|
||||||
|
player state) and a small command API (depart, dock, buy, sell, set speed). The
|
||||||
|
renderer and UI never mutate sim state directly.
|
||||||
|
|
||||||
|
Plain JavaScript (ES modules), Vite for dev server and bundling, Vitest for tests.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Headless tests against `sim/`:
|
||||||
|
|
||||||
|
- Cloud invariants: mass sums to 1; renormalization after exclusion is correct.
|
||||||
|
- **Observation-order independence**: observing market-then-ship produces the same
|
||||||
|
committed history as ship-then-market (the per-seed hidden-variable guarantee).
|
||||||
|
- Economy sanity: prices respond to stock; NPC arbitrage narrows price gaps over time.
|
||||||
|
- Event queue: chronological resolution; arrival events match branch probabilities
|
||||||
|
over many seeds (statistical test).
|
||||||
|
- Determinism: same galaxy seed + same player inputs → identical end state.
|
||||||
|
|
||||||
|
## Error handling
|
||||||
|
|
||||||
|
Single-player browser game: invariant assertions in `sim/` (probability mass,
|
||||||
|
non-negative stock, queue ordering) that throw in dev builds. No network, no I/O
|
||||||
|
beyond the page.
|
||||||
Reference in New Issue
Block a user