Developer Log
2026 update: CONTRABAND now ships as the official Steam PC release. The playable browser build has been retired from this site. Several posts below were written during the web prototype era and are kept as design history — check each article’s note for what still applies.
This section is for people curious about how CONTRABAND was made. It’s a solo project built in modular JavaScript, CSS, and HTML — no Unity or Godot — with Three.js handling real-time 3D combat and galaxy views.
Why no traditional engine?
The obvious choice would be Unity, Godot, or a full browser-game framework. I chose a custom JS stack because:
- Lean runtime. Core game logic stayed modular ES modules instead of a monolithic engine loop.
- Fast iteration. Hot-reload-friendly files during the long web prototype phase.
- Modular architecture. Each system is its own file with a clean boundary. Combat doesn’t know about stories. Stories don’t know about combat. They communicate via an EventBus.
- Portable stack. The same systems later wrapped into the Steam PC build without rewriting narrative or economy code.
Architecture
The game has five conceptual layers:
- Core — EventBus, State, Boot sequence.
- Data — Pure JS data files: ships, items, crew, story, achievements.
- Systems — Combat, Galaxy, Branch, Market, Story engine, Crew, Analytics, Audio.
- UI — HUD, modals, toasts, panels for each system.
- CSS — Design system + component styles.
Key design decisions
EventBus over direct coupling
Every system emits events (combat:victory, story:decision, galaxy:jump) instead of directly calling other systems. Adding a feature like Analytics is just “listen to existing events.”
State as single source of truth
There’s one GameState instance. Saving is JSON.stringify(state). Loading is JSON.parse + merge. No complex reducers.
Audio evolution
Early browser builds used procedural ambient layers via Web Audio API. The Steam release adds a 21-track authored soundtrack (Across the Silent Stars) while keeping lightweight synthesized SFX for combat and UI. See the Procedural Audio post for the original approach.
ASCII portraits
Character portraits are ASCII art, not images. Each NPC has a small pattern rendered in the gold accent color — zero portrait assets, instant load.
Development stats (current)
- 300+ authored narrative scenes
- 140 Steam achievements
- 42 flyable ships · 34 systems · 7 regions
- Solo developer · built in Texas
Individual devlog posts
- Why Vanilla JavaScript — Custom JS stack vs Unity/Godot; where Three.js fits.
- Designing the Rift branches — How the revisit mechanic evolved.
- Procedural Audio — Web Audio prototype era; how music evolved for Steam.
- ASCII Portraits — Why character portraits are text.
- Stripe & Firebase Integration — Browser-era entitlement architecture (archived reference).
- Three.js Lessons — Real-time 3D ship combat and GLB pipeline.
- Monetization Philosophy — Browser F2P + epilogues history; Steam pricing today.