What it does
You start a run, tell it which way the hero walks and step it. The hero's weapons fire by themselves, each in its own way: a lash across the front and then behind, projectiles at the nearest enemies, projectiles the way the hero faces, damage to everything within an aura, orbs circling for a while, things thrown up that fall, and strikes on random enemies on screen. Each weapon has a table of levels setting its damage, cooldown, area and, where it applies, its amount, speed, duration, pierce and knockback.
Enemies spawn just beyond the screen from a wave table whose rates rise through each wave and whose mix changes as the run goes on, with a cap on how many are alive. Scheduled events bring elites with multiplied hit points and bosses, which drop chests. Enemies crowd apart, and stragglers left far behind are carried round to the front. Kills drop gems; the magnet draws in those within reach, and enough experience levels the hero up.
Each level pauses the run and offers a choice, three by default, of a new weapon, a new passive or a level of one
held, within the weapon and passive slots; further level-ups queue. Passives add to stats such as might, area,
cooldown, speed, magnet, health, armour and recovery. A chest evolves a weapon at its last level when its partner
passive is held, replacing it with the evolved form. Survive to the end of the run's time and it is won. view()
gives everything to draw, drain() the events, and the whole run saves to JSON and back.
Features
- Seven ways to fire — whip, seek, facing, aura, orbit, arc and strike, each with a level table.
- Evolutions — a maxed weapon plus its partner passive becomes a new weapon from a chest.
- Passives — twelve stats, from might and area to magnet, armour, recovery and growth.
- A spawn table — waves with weighted enemies, rising rates and caps, spawning just off screen.
- Elites and bosses — scheduled events with scaled hit points that drop chests.
- Gems and the magnet — experience pickups drawn in within reach, and an experience curve you can replace.
- Level-up drafts — a choice of new or upgraded weapons and passives within slots, with queued level-ups.
- A view for any renderer — the hero, enemies, shots, lashes, strikes, gems, chests and pickups.
- An autopilot — a fair player that dodges, collects and chooses, for an attract mode or a test.
- Saves and validation — snapshots as plain JSON, and every fault in the options named.
Good for
- Survivors-likes with auto-firing weapons, level-up drafts and evolutions, in the style of Vampire Survivors.
- Short-session horde games on mobile, where one stick or a touch moves the hero and the build does the rest.
- Themed variants with your own weapons, enemies and waves, from a wizard's spells to a robot's drones.
- Attract modes and balance tests, with the autopilot playing whole runs.
Make it yours
The pack has no options; createSurvivors takes the seed, the set, the starting weapon, the hero (health, speed,
size, magnet, armour, recovery and the grace time after a hit), the weapon and passive slots (six each by default),
the number of choices per level, the run's length (600 seconds by default), the size of the screen enemies spawn
beyond, the experience curve and a pace that multiplies every spawn rate. The set itself is
{ weapons, passives, enemies, waves, events }, and the built-in survivorSet (the whip, magic wand, knife, garlic,
an orbiting book, axe and lightning ring with their evolutions, twelve passives, eight enemy kinds, ten minutes of
waves, an elite every minute and a half, a giant bat at five minutes and the reaper at the end) can be kept, extended
or replaced.
Two different runs: the built-in ten-minute run with six weapon slots and three choices a level; and a fifteen-minute run with your own set of three weapons, two passive slots, two choices a level, a faster pace and a boss event every five minutes.
A quick look
A run started with the whip, walked by the player and drawn from its view:
const run = game.survivors.create({ seed: 4, start: 'whip', duration: 900 });
run.move(input.x, input.y);
run.step(dt);
if (run.state.choosing) showCards(run.state.choosing); // then run.choose(i)
const v = run.view();
for (const e of v.enemies) drawEnemy(e.id, e.kind, e.x, e.y, e.flash);
Works with
run-progression— a branching map, shops and unlocks around a series of runs.room-run— for rooms cleared one at a time, stopping to shoot.wave-arena— for twin-stick arena waves.wave-plan— for waves and difficulty in a game of your own design.
Good to know
- Bodies are circles and there is no physics engine; enemies crowd apart on a grid.
- A step's cost grows with the swarm: hundreds of enemies are fine, thousands are not.
- Gems are kept to the newest 400.
- Luck, curses, revivals, arcanas, stages and shops are not modelled.






