Why Vanilla JavaScript
The most common question about CONTRABAND's tech stack: why not a game engine? The answer turned out to be about tradeoffs I didn't fully appreciate when I started.
The question
Every time someone looks at CONTRABAND's architecture, they ask the same thing: "Why not Unity? Godot? Phaser? Why build all this from scratch?" It's a fair question. A game engine would have given me sprite rendering, audio management, input handling, and scene transitions for free. Instead, I built all of that.
The honest answer is that I started with vanilla because I wanted to learn, and I kept with vanilla because it turned out to be the right choice for this particular game. Not all games. Not all developers. This one.
What vanilla gave me
File size
The entire CONTRABAND game is under 120KB of code. Including assets (audio is procedural, portraits are ASCII, only ship models are GLB files), the full payload a user downloads is around 2-3MB — most of which is Three.js itself. A Unity WebGL build for an equivalent game would be 20-50MB. That size difference means my game loads in seconds on a phone. A Unity game loads in 15-30 seconds, which is enough time for a player to close the tab and never come back.
Startup speed
From URL click to playable in under 2 seconds on a modern phone. No engine warmup. No asset streaming. No shader compilation. The player clicks a link and the game starts. This is the single biggest gameplay advantage of vanilla over engines: players who cannot install anything on their device can still play. That matters for a browser game.
Modular architecture
Each system in CONTRABAND is its own file with a clean boundary. Combat doesn't know about stories. Stories don't know about combat. They communicate through an EventBus. When I added the monetization system at v3.0, I did not modify combat or story at all — I just subscribed to existing events. That's not a vanilla-only benefit, but vanilla forces you into it by default. In an engine, the path of least resistance is tight coupling through shared singletons.
Zero vendor lock-in
If Unity changes its pricing model, raises licensing fees, or (hypothetically) goes out of business, my game is unaffected. Web standards do not break. The JavaScript I wrote in 2024 will run in browsers in 2034. This matters more than it seems. Several indie games built on Flash became unplayable when Flash died. Games built on discontinued engines are in museum mode. Games built on web standards are timeless.
What vanilla cost me
Everything takes longer
Writing a sprite renderer, an audio system, and a save system is work an engine would do for free. I spent approximately 30% of development time on infrastructure that any engine would have provided. For a first-time developer, this was learning — valuable. For someone who already knows engines, it would be waste.
No community knowledge
If I get stuck on a Unity problem, I search the Unity forums and find someone who solved it. If I get stuck on a vanilla-JavaScript browser-game problem, I often find that no one else is building what I'm building, so there are no answers. I had to figure out most things alone.
Debugging is harder
Browser dev tools are excellent for web apps, okay for game code, and painful for Three.js-specific issues. Unity has a profiler that tells you exactly which frames are slow and why. Chrome's profiler gives you a flame graph that requires interpretation. I got better at reading flame graphs, but it took time.
What I learned about the tradeoff
The vanilla-vs-engine tradeoff is essentially: startup speed and portability (vanilla wins) vs development speed and tooling (engine wins). For most games, engine wins. For a browser game where the audience may have slow devices, may be on metered mobile data, and will abandon anything that doesn't load in 3 seconds — vanilla can win.
CONTRABAND specifically benefits from vanilla because:
- Its visuals are not a bottleneck. I do not need a render pipeline.
- Its gameplay is text-and-menu-driven. No physics engine needed.
- Its economics depend on casual players who might try it on a phone during a commute. Fast startup matters.
Would I do it again
For this game: yes, absolutely. The architecture fits the content. For my next game, if it has different requirements — real-time physics, complex graphics, multi-platform deployment — I would use an engine. Vanilla is a scalpel, not a hammer. Know when to use which.