Dev Log · Build Notes · August 10, 2026

Iron Shore build notes: our first 3D game, and Three.js in two files

Iron Shore is a beach-defense shooter: you're the last gunner in a sandbagged nest, landing craft keep motoring out of the fog, and the barrel jams if you never let go of the trigger. It's also the arcade's first fully 3D game — which meant breaking our own "no libraries" streak, carefully.

Three.js, vendored as two files

This site's rule is no frameworks and no build step: every game is one HTML file you can View-Source. A software 3D renderer on a 2D canvas would have blown that budget on math instead of game, so we allowed exactly one library — but on our terms. No npm, no bundler, no CDN. Modern Three.js ships as a real ES module split into two files, so we copied three.module.min.js and three.core.min.js (about 700KB together) next to the game and wrote import * as THREE from './three.module.min.js' in a plain <script type="module">. The browser resolves the second file itself. That's the whole toolchain: two static files, first-party, pinned forever. Everything else — models, animation, particles, sound — is still hand-written in the page.

The beach is a math function

There are no model files and no textures. The terrain is one plane (110×84 segments) displaced by an analytic function groundH(x, z): two sine products for dunes, a squared ramp from the waterline up to the trench, and eight shell craters subtracted as Gaussian dents. Because the height is a function rather than baked geometry, the game sim shares it — soldiers, the supply crate, and even bullet impacts all ask the same equation where the ground is, so nothing ever floats or sinks. Color is painted per-vertex at startup: wet sand lerps to dry up the slope, crater rims darken, and a tiny sine-noise lightness wobble fakes grain. The battleships are eight boxes each; the sandbag wall is squashed spheres.

No shadow maps, blob shadows

Real-time shadow maps are the classic phone killer, so the lighting is one hemisphere light plus one directional sun and nothing casts anything. Each soldier instead carries a flat dark circle that hugs the ground — the trick every PS1-era game used, and it still reads perfectly at this art style. Same discipline everywhere: device pixel ratio is capped at 1.75, tracers are 16 pooled boxes stretched from muzzle to impact for 55 milliseconds, and all sand puffs, sparks, and steam live in a single 240-slot THREE.Points ring buffer. The soldiers themselves are pooled too — 30 riflemen and 6 heavies built from boxes, their run cycle just sine waves rotating arm and leg meshes in code.

Shooting without a physics engine

Firing is hitscan, but we never raycast against actual meshes. Each soldier is one invisible sphere, and the hit radius grows with distance — a soldier 200 meters out is fractionally easier to hit than geometry says he should be. That's aim assist hiding inside the collision test, and it's what makes a touchscreen drag feel like marksmanship instead of luck. If the ray misses everyone, we march it forward in 3-unit steps until it dips below groundH (sand puff) or hits the water past the shoreline (white splash), so every shot lands somewhere visible.

Overheat is the anti-autofire

Nova Strike taught us autofire frees a thumb — Iron Shore deliberately takes the trigger back and taxes it. Holding fire builds heat faster than idling sheds it, and a full bar jams the gun for 2.5 seconds, which is precisely how long a sprinting rifleman needs to reach the wire. Inputs follow our standing rule that every option ships on day one: touch-drag on the battlefield (the gun follows your finger and fires while you touch), an arrow pad with a FIRE button sitting below the play field so thumbs never cover the action, and mouse or arrow keys plus Space on desktop.

Testing 3D without a GPU

Our headless test browser renders WebGL in software, where 60fps doesn't exist. So the game has a hidden rig: ?autostart&ff=N starts a run and synchronously ticks the simulation N seconds forward with rendering skipped, then writes wave, kills, trench HP, and enemy state into the page title. One flag turned "watch it play for five minutes" into a half-second assertion.

Man the gun — and remember the tip on the cabinet: short bursts keep the barrel ice cold.


All dev log entries · Play the games