Files
casino/docs/superpowers/specs/2026-08-05-quantum-arcade-design.md
drjones 483ba9f2a2 Add Quantum Arcade design spec
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 01:54:01 +00:00

7.8 KiB

Quantum Arcade — Design Spec

Date: 2026-08-05 Status: Approved for planning Repo: https://gitea.thetempleofdoom.com/drjones/casino.git

1. Context and Scope

Quantum Arcade is a private, LAN-hosted physics gaming platform for the host and their friends, including at parties of up to ~100 people on phones. It runs entirely on a single Linux box owned by the host.

In scope: deterministic physics games (group and single-player), a provably-fair RNG, a double-entry ledger, Lightning deposits/withdrawals and peer-to-peer transfers, ephemeral chat, and a single-box Docker deployment.

Out of scope for this phase: public internet deployment, KYC/identity verification, geo-gating, and licensed real-money operation. The architecture keeps these as additive modules rather than rewrites, but they are not built here and this system is not to be exposed publicly as-is.

Success criteria:

  • A guest joins from a phone in under 5 seconds with no account creation.
  • 100 concurrent phones sustain a group round with no visible desync.
  • Any player can independently verify any round outcome on their own device.
  • End-of-night balances reconcile exactly, with a per-transaction explanation.

2. Identity

Identity is a keypair, not an account.

On first visit the browser generates an ed25519 keypair stored in IndexedDB and prompts for a nickname. The public key is the player ID: it is what the ledger posts against and what signs bet intents. There is no email, password, reset flow, or KYC.

Multi-device: a QR code exports the key from one device to another. Key loss means balance loss. This is accepted and stated plainly in the UI.

Nicknames are display-only and non-unique; the pubkey prefix disambiguates.

3. Architecture

One Go binary with enforced internal module boundaries, plus PostgreSQL, Redis, LND, and Caddy. Nine separate services on one machine would add latency and operational burden with no benefit at this scale.

Caddy (TLS termination, static assets, WebSocket upgrade)
  └── quantum-arcade (single Go binary)
        ├── ledger/   double-entry postings, append-only
        ├── rng/      commit-reveal seed lifecycle
        ├── sim/      deterministic physics core
        ├── room/     round lifecycle, tick broadcast
        ├── wallet/   Lightning in/out, P2P transfers
        └── chat/     ephemeral, in-memory only
PostgreSQL  ledger, rounds, seeds, results
Redis       live room state, presence, rate limits
LND         Lightning node, isolated wallet

Modules communicate only through Go interfaces defined by the consumer. No module imports another's internal types. Extracting a module into its own process later is a transport change at the call site, not a rewrite.

Scaling posture: 100 concurrent WebSocket clients is a small fraction of a single Go process's capacity. The genuine constraint is PostgreSQL write throughput at settlement, addressed by settling each round in exactly one transaction with batched postings.

4. Deterministic Simulation Core

The physics core is fixed-timestep and integer-seeded, using fixed-point arithmetic rather than floating point to guarantee bit-identical results across platforms. It is compiled twice from one source: natively for the authoritative server, and to WASM for the browser.

Consequences:

  • The server broadcasts a seed, not a position stream. Bandwidth per additional phone is negligible.
  • Any client can replay any historical round locally.
  • The public verifier is simply the sim run against published inputs.

Determinism is a hard invariant, enforced by test (§9), not a convention.

5. Provable Fairness

Per round:

  1. Commit. Server generates serverSeed, publishes SHA256(serverSeed) before the betting window opens.
  2. Client seed. Derived from the concatenated public keys of all participants in the round, in join order. The host cannot know the outcome in advance because the host does not control the inputs.
  3. Outcome. HMAC-SHA256(serverSeed, clientSeed || nonce) seeds the sim. The crash point / result is a pure function of that seed.
  4. Reveal. After settlement the server publishes serverSeed. Clients recompute the commitment hash, re-derive the seed, and re-run the WASM sim.

Verification runs on-device in roughly 400ms and requires trusting no server response. Seeds, commitments, and participant sets are retained permanently.

6. Games

All games share the sim core and the fairness pipeline.

Group rounds — a fixed ~5-minute cadence; all players watch the same simulation. Three crash variants rotate:

  • Rocket vs. gravity — multiplier is altitude; the craft visibly strains as fuel depletes toward the seeded crash point.
  • Orbital decay — multiplier is orbits completed, each pass dipping lower.
  • Stacking tower — multiplier is height; wobble grows until collapse.

Round lifecycle: betting_openlockedrunningsettled. Cash-out intents are signed by the player key and accepted only while running.

Single-player — always available between group rounds, ~10 seconds per play, one tap to start: gravity-slingshot targeting, physics drop, and a momentum/timing challenge. Same fairness proof, per-play nonce.

7. Ledger and Money

Double-entry, append-only. No row is ever updated or deleted; corrections are compensating entries.

Every posting records: transaction ID, timestamp, player pubkey, account, amount, round ID, balance before, balance after. Each transaction's postings sum to zero. Player balances may never go negative.

Accounts: per-player balances, house pot, and Lightning bridge accounts. The house pot balance is displayed in the UI to all players — the pool is never opaque.

Lightning: deposit and withdraw via invoice/QR against the on-box LND node. The LND wallet is isolated from application state, with its own credentials and backup path.

Peer-to-peer transfers: instant, purely internal ledger entries between two player accounts, signed by the sender's key. This is the primary way value moves between friends at a party.

8. Interface and Feel

Phone-first portrait layout; cash-out is thumb-reachable.

Deep obsidian and indigo ground, with dense ornate filigree etched into the background. Vibrant cyan and magenta are reserved exclusively for the live multiplier, the player's balance, and the cash-out control — everything that matters is luminous, nothing else is.

Ambient music is synthesized in WebAudio: endless, non-looping, and shipping with zero audio assets.

Chat is a compact sidebar, in-memory only, discarded when the round ends. Nothing is written to disk.

9. Testing

  • Ledger: property-based tests for the invariants in §7 — postings sum to zero, balances never negative, no value created or destroyed across arbitrary transaction sequences.
  • Sim determinism: identical seed produces identical output across 10,000 runs, and native output matches WASM output byte-for-byte.
  • Fairness: commitment always matches revealed seed; independent reimplementation of the verifier agrees with the server on recorded rounds.
  • Load: harness simulating 150 concurrent phone clients through a complete group round, asserting no desync and correct settlement.

10. Deployment

docker compose up on the single Linux box. Postgres and LND data on persistent volumes with scheduled backups. Caddy terminates TLS on the LAN. Prometheus and Grafana included for host and application metrics.

11. Explicit Non-Goals

  • Not exposed to the public internet in this phase.
  • No engagement mechanics designed to extend play beyond a player's intent: no loss-chasing prompts, no artificial near-miss tuning, no dark patterns on cash-out. Game feel comes from the physics being genuinely good.
  • No mixing or obfuscation of fund provenance. The ledger is the product.