Sixty frames, deterministic: inside the Bulwark engine

2026-06-08 · 4 min read · The Bulwark Studio

Bulwark runs entirely in your browser. There is no install, no plugin, no multi-hundred-megabyte download. You click play and you are defending the Core within a second. Keeping a game that responsive while it simulates hundreds of enemies, dozens of turrets, projectiles, beams, and particles takes a bit of engineering. Here is how the pieces fit.

A fixed timestep, decoupled from your screen

The most important decision in the engine is also the least visible: the simulation advances in fixed steps of one sixtieth of a second, no matter what your monitor or browser is doing.

A naive game loop ties the simulation to the frame: it asks "how much time passed since the last frame?" and moves everything by that amount. That seems fine until your frame rate stutters. A long frame produces a giant time step, an enemy teleports through a wall, and a fast turret skips its shot. Worse, the game plays differently on a 60Hz laptop than on a 144Hz desktop.

Bulwark instead accumulates real time and spends it in fixed one-sixtieth-second chunks. Render as often as the browser will let it; simulate in exact, identical ticks. The result is that a run is reproducible: the same inputs produce the same outcome, frame rate be damned. It also makes the speed controls honest. When you hit 2x, the engine runs two simulation steps per chunk instead of one. Two times means exactly two times, and three times means exactly three times. Not "roughly faster."

This matters for a leaderboard. A score should reflect how you played, not how fast your laptop happened to render.

React for the HUD, canvas for the war

The interface and the battlefield are drawn by two different systems, on purpose.

The gold counter, the build menu, the upgrade panel, the wave preview: those are React components. They are crisp, accessible, and easy to lay out. But React is the wrong tool to redraw three hundred glowing enemies sixty times a second. So the battlefield itself is painted on an HTML canvas, by hand, every frame.

The trick is keeping them from fighting. The mutable game state lives in one place and is never handed to React directly. Instead the engine emits a small, immutable snapshot of just the HUD numbers about a dozen times a second. React re-renders from that. So a sixty-frame battle drives at most a dozen React updates, and the heavy per-frame drawing stays on the canvas where it belongs.

Everything in the simulation is stored in cell units rather than pixels. An enemy at column four, row two is at four-and-a-half, two-and-a-half, regardless of how big your screen is. The renderer owns the single transform that turns cell units into pixels, so the exact same run looks identical whether you are playing on a phone or a 4K monitor. The simulation never thinks about pixels at all.

Neon without a sprite sheet

Bulwark does not ship a single image asset for its gameplay. Every turret, enemy, projectile, beam, and explosion is drawn with canvas primitives: polygons, arcs, lines, and the browser's own glow via shadow blur. That neon look you see is real light bloom rendered on the fly, not a baked-in texture.

This keeps the download tiny and lets the whole game recolor from three brand values. It also means the visual language is data driven: a turret's color comes from the same config that defines its damage, so design and art never drift.

Sound out of thin air

There are no sound files either. Every effect, the kinetic thump of a Blaster, the crack of a Railspike, the alarm when the Core takes damage, is synthesized at runtime with the Web Audio API: a few oscillators and noise bursts shaped by tight volume envelopes. The audio context warms up on your first click (browsers require a gesture before they make noise), and each sound has a minimum re-trigger interval so a wall of rapid-firing turrets cannot smear into a clipping mess.

The payoff is the same as the visuals: nothing to download, nothing to buffer, and a soundtrack that stays responsive even when the screen is full of explosions.

The board is the opponent

The final piece lives in the cloud. When a run ends, your score streams to a global leaderboard over a websocket and appears, ranked, the instant it lands. Open the board while you play and you will watch other people's runs slot in above and below you in real time.

Anyone can post a run, logged in or not, by choosing a handle. Submission goes through a server function that sanitizes the handle and clamps the numbers, so a tampered client cannot inject a billion-point run. Sign in and your best runs are attributed to you and saved across devices.

That is the whole stack: a deterministic simulation, a split render path, procedural art and audio, and a live board. None of it is exotic on its own. Put together, it is a tower defense that feels like a real game and runs anywhere you have a browser.

Go hold the line, and try to get your handle near the top.