What it does
You create an arena from a definition and tick it with the player's input: a move direction and a fire direction,
each in eight ways. The arena runs whole frames at a fixed 60 Hz, moves the player and every enemy, flies the shots,
and reports what happened as events: wave-start, killed, rescued, human-lost, reprogrammed, spawned,
fired, player-killed, extra-life, wave-clear, game-over and more. The state holds every actor, shot and
score for your game to draw.
A wave is a row of counts by kind with its own timings. Each opens with a moment of stillness, places its enemies
around the player, and ends shortly after the last required enemy goes. The enemies come in families with their own
behaviour: grunt walkers that close in faster as their numbers fall, hulk brutes that cannot be killed and crush
the people, brain enemies that reprogram people into prog chasers and fire missiles that rebound off the walls,
spheroid and quark spawners that drop shooters, enforcer sparks that curve and slide along walls, tank shells
banked off a wall, and electrode obstacles. People wander the arena, and each rescue since the wave began or the
player last died scores more than the one before.
Every shot is a projectile-patterns projectile, so swept hits, walls, lifetimes and snapshots come from that pack,
while the families steer their own shots each frame. Death costs a life and restarts the wave with the survivors. The
whole game is deterministic for a seed and an input sequence, runs headless, and saves and restores.
Features
- Eight-way move and fire — movement and firing directions held independently, with a laser count, speed and rate per game.
- Enemy families —
grunt,electrode,hulk,brain,prog,spheroid,enforcer,quarkandtank, each with its own movement, shots and parameter block. - People to rescue — the
humanfamily wanders, brains reprogram them and brutes crush them, and a rescue table pays a rising bonus. - Kinds as data — any number of kinds share a family with their own size, score and whether they must die to clear the wave, and a game may leave families out.
- Waves as data — authored rows of counts with per-wave timings, an optional safe box at the start, and a point to repeat from after the last.
- Difficulty — the authored tables by default, or
easyandnormalpresets and your own values for population, its ramp per wave, a cap per kind, speed, fire rate, a grace period and a safe radius at each wave start. - A classic preset —
robotronPresetwith 40 authored waves that repeat from 21, the original scores, rescue table, mercy table and extra lives, androbotronWaves,robotronWaveParamsandrobotronKindsto reuse its tables. - A second ruleset —
arenaSiegePreset, an arena you size with eight authored waves, drone swarms, mines to clear, brutes that hunt only the player, motherships, six lasers and its own rescue table. - Validation —
validateWaveArenareports a definition the arena cannot run. - Deterministic and snapshot-able — the same seed and inputs always play the same, with
snapshot,restoreandresetto any wave.
Good for
- Single-screen arena shooters with eight-way fire and people to rescue, in the style of Robotron: 2084.
- Wave-based arena games in the style of Smash TV, with your own enemy kinds and wave tables.
- Twin-stick survival modes, where the threat comes from every side and the waves keep coming.
- Shooters tuned for different players, with easier populations and a safe space at the start for a newcomer and the authored tables for a veteran.
- Bots, replays and tests, since the rules run headless and play identically from a seed.
Make it yours
The pack factory takes no options: everything is the definition passed to createWaveArena. robotronPreset takes
lives, extra-life score, laser count and rate, the rescue table and a seed, and then any field of the definition can
be replaced: the arena bounds, the player's size, speed and lives, the lasers, the kinds with their families, sizes
and scores, the waves and their timings, the repeat point, the rescue table, every family's parameter block,
projectile caps, the mercy table and the phase lengths.
Two very different games from the same rules: the classic preset, a small arena with four lasers, 40 waves and the
original's speeds, played on the authored tables; and the second ruleset, a wide arena with eight waves of drone
swarms, mines and brutes that hunt only the player, six lasers and a smaller rescue bonus, played on the easy
difficulty with fewer enemies, a grace period and 80 pixels kept clear at every wave start.
A quick look
The classic preset, ticked with the player's move and fire directions:
const wa = game.waveArena;
const g = wa.createWaveArena(wa.robotronPreset());
g.tick(dt, { move: { x: -1, y: 0 }, fire: { x: 0, y: 1 } }); // fixed 60 Hz frames inside
for (const e of g.drain()) { /* wave-start, killed, rescued, human-lost, wave-clear, game-over … */ }
const s = g.state; // actors, shots, player, score, lives, wave, status
g.shotPosition(shot.id); // where a shot is
Works with
projectile-patterns— required: every laser, spark, missile and shell is one of its projectiles.maze-rooms— for room-to-room play through lethal walls with a pursuer.scrolling-shooter,asteroid-field,marching-fleetandflight-formation— for scrolling, asteroid and formation shooters.
Good to know
- A wave may place at most 400 actors, and more is reported as an error.
- Actors collide as boxes and projectiles as circles, not pixel masks.
tickruns at most eight frames per call and drops the rest, so a long stall does not snowball.- Every actor dies to one hit or cannot be killed: there are no hit points or status effects.
- The pack draws nothing; your game reads the state, maps input and draws.






