WARPATH: NEON FRONTIER — Technical Architecture
Hard requirements: one codebase → web desktop, mobile browsers, Android, iOS, tablets; touch + keyboard/mouse + gamepad; offline play; installable PWA; credible path to Steam. 2D top-down, heavy particles/glow, deterministic sim for daily seeds & future co-op.
1. Camera decision (design-technical joint call)
| Option | Verdict |
|---|---|
| Pure top-down ✅ | Recommended. Instantly reads as Warpath; aim direction, bullet paths, and orbit lines are unambiguous — critical in a momentum shooter; touch aiming maps 1:1 to screen space; art pipeline is single-angle sprites (solo-dev scale); minimap and main view share a mental model. Depth comes from parallax starfield layers, scale, glow, and shadows — not projection. |
| Slight isometric | Prettier ships at rest, but bullet trajectories and collision circles stop matching their visuals, touch aim degrades, and every sprite needs directional art or 3D renders. Wrong trade for an aim-based game. |
| Angled perspective (3D tilt) | Maximum spectacle, maximum cost: 3D assets, readability loss at screen edges, motion-sickness risk on phones. This is how you accidentally spend a year on a camera. |
Top-down with juice: 3-layer parallax stars, 5–10% zoom-out when boosting, zoom-in pulse + shake on big kills, slight camera lead in aim direction.
2. Engine comparison
| Stack | Web payload / iOS-Safari fit | Native mobile | Steam | Verdict for this game |
|---|---|---|---|---|
| PixiJS v8 (TS) ✅ | ~450 KB gz core; instant load; WebGPU with WebGL2 fallback; excellent on iOS Safari | Capacitor wrapper, WKWebView is fast for 2D | Electron/Tauri | Chosen — full renderer control for the glow aesthetic, smallest payload, web-first by nature |
| Phaser ¾ | Fine (~1 MB), proven | Capacitor | Electron | Honorable runner-up: more batteries (input, tweens, arcade physics) but opinionated scene/game-object model fights a custom deterministic ECS; we'd bypass half of it |
| Godot 4 | 30–50 MB wasm export, iOS Safari memory pressure + threading (SharedArrayBuffer/COOP-COEP) headaches, weak PWA story | First-class native | First-class | Best engine, wrong first platform. Runner-up if priorities ever flip to native-first |
| Unity | 30+ MB web builds, WebGL mobile officially "not supported," licensing noise | First-class | First-class | Overkill + web-hostile for 2D indie |
| Unreal | Web export effectively dead; 3D-first | Heavy | First-class | Not applicable |
| React + Pixi | React for menus is tempting, but reconciler in the game loop is a perf/complexity trap | — | — | Take the idea, not the framework: plain TS UI layer (or Preact for menus only, isolated) |
| BabylonJS | 3D-first; capable 2D but heavier mental model | Capacitor | Electron | No 3D need |
| PlayCanvas | Great 3D web engine, editor-centric, cloud workflow lock-in | Capacitor | Electron | Editor lock-in, 3D-first |
Recommendation: TypeScript + PixiJS v8, with a deliberately thin custom layer. We are building a game, not an engine — but the sim/render split below is non-negotiable.
3. Architecture
┌────────────────────────────────────────────────────────────┐
│ apps/ │
│ web/ Vite + PWA (Workbox) ← canonical build │
│ mobile/ Capacitor (Android + iOS) wraps web build │
│ desktop/ Electron (+ steamworks.js) or Tauri │
├────────────────────────────────────────────────────────────┤
│ packages/ │
│ sim/ Deterministic game core (ZERO DOM/Pixi deps)│
│ ECS, fixed 30 Hz tick, integer/fixed-point │
│ math, seeded PRNG (PCG32), galaxy-gen, │
│ economy/allegiance sim, combat, AI │
│ render/ PixiJS v8 view of sim state; interpolation │
│ between ticks; particles, bloom, camera │
│ ui/ HUD + menus (plain TS components; DOM for │
│ menus, Pixi for in-world UI) │
│ input/ Unified intents ← KB/M, touch (sticks, │
│ gestures), Gamepad API; remapping │
│ audio/ Howler.js; adaptive-layer music conductor │
│ data/ Content as typed JSON: hulls, modules, │
│ empires, biomes, campaign chapters │
│ save/ IndexedDB (idb) + schema-versioned │
│ migrations; cloud-sync adapter later │
└────────────────────────────────────────────────────────────┘
Key decisions & why
- Sim/render separation with fixed tick (30 Hz sim, interpolated 60/120 fps render). Buys: determinism (daily seeds = same galaxy for everyone; recap = replayable event log; regression tests = recorded replays), battery-friendly phone mode (render 30), and the lockstep door for post-1.0 co-op without a rewrite.
- Determinism discipline: all sim math in integers/fixed-point (no float drift across devices), PCG32 seeded RNG streams (gen/combat/AI separated so one system's rolls don't perturb another), sim package has zero platform imports — it runs headless in Node for tests and for a future server.
- ECS, hand-rolled (~300 lines) or bitecs: entity counts are modest (hundreds, not 100k); we need cache-friendly iteration for particles/projectiles and clean save/replay serialization more than a framework.
- UI split: menus/dock/settings in DOM (accessibility, text rendering, localization for free) — styled to the art direction; in-world HUD (bars, radio ticker, minimap) in Pixi for frame-sync. One design-token CSS/TS file feeds both.
- PWA: Workbox precache of the full bundle + content JSON → true offline;
beforeinstallpromptflow on desktop/Android; iOS PWA supported but the Capacitor store build is the first-class iOS citizen (iOS PWAs suffer storage eviction and audio-session quirks). - Capacitor over Cordova/Flutter-webview: maintained, thin, native plugins for haptics, Game Center/Play Games, IAP (single non-consumable unlock), and keeps the single codebase promise.
- Steam: Electron + steamworks.js (achievements, overlay, cloud saves). Tauri is lighter but Steamworks bindings are less proven — decide at Phase 5; nothing upstream depends on it.
- Gamepad: browser Gamepad API abstracted in
input/as intents; the same mapping file drives Steam Input glyphs later. - Perf budget: 3.5 ms sim + 8 ms render on a 2019 mid Android @ 60 fps target (30 fps fallback tier); particle pool caps per device tier; single bloom pass at half-res; texture atlas ≤ 2×2048².
- Telemetry (opt-in only): run recaps + settings snapshots to a tiny endpoint for balance; fully functional offline/never-consented.
4. Testing & tooling
- Vitest for sim unit tests; replay-based golden tests (recorded input → expected end-state hash) as the determinism tripwire in CI.
- Playwright smoke on the web build (boot, start run, dock, save/load).
- Device lab minimum: 1 low Android (2019), 1 recent iPhone, 1 iPad, 1 desktop each browser engine.
- Content hot-reload:
data/JSON watched in dev — balance without rebuilds.
5. Networking (future-proofing only, not built now)
Deterministic lockstep is the plan of record for 2–4 co-op: inputs-only over WebRTC data channels (or a thin relay), sim already deterministic, drop-in handled as bot-takeover/hand-back (directly fixing 1997's "join = spectate" flaw). Nothing in Phases 0–5 may violate sim determinism — that's the only rule co-op imposes today.