Atlas of Systems Atlas
MMXXVI
sun 120 round 1 lawn 10 trees 0/3
Plant something. They come from the left.

Watch Your Grass

A browser arena defense on a 6×6 grid, drawn up on paper first — ten plant and terrain types, six player classes, one lawn to lose.

a.k.a. Arm A Garden / Arena Garden · vanilla JS · Cloudflare Quick Tunnel
Watch Your Grass — a look inside, on desktop and phone
on desktop and phone
Softlocks

Enemies that could be walled in forever

Wall off every adjacent tile and a unit has nowhere legal to step. It doesn't die, doesn't reroute, doesn't time out — it just stops, and the round can never end.

The fix

getNextMove got a fallback: zero valid moves triggers a scan of adjacent tiles and removes one non-boulder plant to force a path open, logged so it's visible.

The related one

clearSpawnTile runs before every spawn. Trees, honey locust and boulders get cleared off the landing tile so nothing ever materialises inside a wall.

Tree cap

PLANT_CAPS.trees = [3, 0] — the zero increment means it never grows with the round. Honey locust and regular trees share the cap.

Animation timing

Every duration doubled. Humans 0.35→0.7s, runners 0.4→0.8s, grass 2.5→5s, roses 1.4→2.8s. The board stopped feeling frantic.

Palette

It was too gloomy

The original background sat at #060e0c — near-black with a green cast that read as sickly rather than lush. Every surface value shifted warmer and brighter, and the text came up with it.

#060e0c
before
#0b1510
after
#ceeace
before
#d6eed6
after

Small numbers, big difference. The shop icons also needed work — Rose Vines, Mushroom and Mint all use animation strips, so the shop clips to the first frame via overflow hidden plus a full-width image trick rather than maintaining separate static art.

Build

No engine, no bundler

Rendering

DOM grid with CSS transitions. Sprite strips animate by stepping background-position, not by swapping images.

Layout

Three-column: board centre, shop left, log right. CSS-driven filters on the event log so you can mute spawn spam.

Scaling

Enemy stats and plant caps both scale per round from a single table, so difficulty is one place to tune.

Sharing

A Cloudflare Quick Tunnel launcher — no account needed, Ctrl+C to stop. Hand someone a URL and they're playing.

Also known as Arm A Garden. Same game, two names, depending on how much the joke is landing that day.

On paper first

It started as handwritten notes

The design existed as pen on paper before any of it existed as code — arena dimensions, plant table, class stats, movement rules. Digitising it into a formal spec came before the first line of JavaScript.

The arena

A 6×6 grid. Small enough that every tile placement is a real decision and a bad wall can strand you.

Ten types

Plants and terrain in one table, each with its own effect — offensive, blocking, slowing, or purely structural.

Six classes

Each with HP, speed and an ability. The player is a piece on the board, not a disembodied cursor.

Movement rules

Written before implementation, which is why the pathfinding edge cases were findable rather than mysterious.

Damage model

Effects that wouldn't stop stacking

Exponential per plant

Damage tracked per plant and scaled exponentially, so a plant that survives contributes more the longer it holds.

Frost per step

Frost recalculates per step rather than per turn, which is the only way slow reads correctly against variable enemy speeds.

Effect locking

Flags added to stop the same effect applying twice in one resolution — the stacking bug that made frost look like an instant kill.

Combo plants

Adjacency-triggered combinations, which is where most of the balance work went and where most of the bugs lived.