TinyGames · how it works

Palisade

A tower defence. Creeps walk a fixed road; you build alongside it and stop them. Three towers, three levels each, twenty lives.

Open index.html. No build step, no dependencies, no images — the map is drawn.

palisade/
  index.html      markup
  style.css       the frame around the canvas
  js/engine.js    copied unchanged from Overdrive - the eighth game on it
  js/td.js        the road, the tower table and the arithmetic
                  - no pixels, no engine, no DOM
  js/palisade.js  the playable layer
  test-td.js      node test-td.js

The part that matters is the road

Not the towers. Creeps have to walk it at a genuinely constant speed, and the obvious way to write that is wrong:

t += speed * dt;                            // t runs 0..1 along THIS segment
pos = lerp(waypoints[i], waypoints[i + 1], t);

That advances the same fraction of every segment per second, so a creep crosses a two-cell corner at the same rate as a nine-cell straight — visibly sprinting down the short legs and crawling along the long ones. Every tower's damage-per-creep then depends on which leg it happens to overlook, and the game becomes unbalanceable for a reason nobody watching it can name.

So the road is measured once and addressed by distance, not by segment. The test walks the whole path in equal 3-pixel steps and measures how far the point actually moved each time:

$ node test-td.js
71 passed, 0 failed

Every step covers equal ground, corners included. A companion test builds the naive per-segment version on the same road and confirms it varies by more than between its shortest and longest step — the bug is real, not hypothetical, and the test says so out loud.


Placement is worth five times everything else

The clearest measurement in this project. Two bots, the same money, the same towers, the same upgrade policy — differing only in where they put things:

waves held
builds on the squares nearest the road (which clusters them all in one corner) 4
spreads the same towers evenly along the road 21

Doing nothing at all reaches wave 3. So a clustered defence is worth almost exactly one wave more than no defence; a spread one is worth eighteen. That is the whole game, and it fell straight out of a bot that was originally written badly.

It is also the reason buildability is measured against the road itself rather than a list of "path cells" — the clearance is then the same on a diagonal as on a straight, and the buildable area looks deliberate instead of blocky. 75% of the map takes a tower.


Towers

Bolt 60 Fast single shots. Cheap, and the backbone of any line.
Mortar 105 Slow, heavy, hits everything near where it lands.
Frost 80 Barely scratches anything. Makes everything else land twice.

Each has three levels. The tests hold the table to properties rather than to numbers: damage and range never fall on an upgrade, total spend only climbs, a tower never sells for what it cost, and — the one that actually matters — a level 3 tower must buy more damage per second than it costs, or upgrading is a trap dressed up as a choice.

Frost's slow deepens with each level but is asserted to stay below 1, because a tower that can stop a creep dead is a tower that ends the game.

Each tower is a different shape as well as a different colour, and that was verified by reading the rendered pixels back off the canvas.


The economy

You start with 190 — three Bolts, and deliberately not four. Wave 1 pays 42, which is less than a Bolt costs, so the opening is spent from the stake rather than from income and the first placements are the decision the rest of the map is built around.

From wave 2 on, every wave is asserted to fund at least one more tower, and twenty waves of income is asserted to fund a real defence. Sending a wave early pays 3 per second of the break you skip, which is the only way to get ahead of the curve.


Targeting

A tower shoots the creep furthest along the road that is in range — not the nearest. Furthest-along concentrates fire on whatever is closest to escaping, so a creep that gets past a tower is not then saved by a fresh one wandering into range behind it. That is checked against an independent search over 2,000 random arrangements.

A shot chases the creep it was fired at. If that creep dies on the way, the shot carries on to where it last was and still splashes — so a mortar shell aimed at something a Bolt happens to finish first is not simply deleted in mid-air.


Controls

Tap a tower button, then tap the map build
Tap a tower select it, then Upgrade or Sell
1 2 3 pick a tower to build
U upgrade the selected tower
Space send the next wave early
Esc deselect
R new game

While a tower is selected or a build is pending, its range is drawn — and every square is shaded green or red so nobody has to guess where a tower will go.


Performance

Twenty-five towers and twenty-eight creeps: 0.005 ms a tick, 0.22 ms a frame to draw.


Things deliberately left undone