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