What it does
The runner races down parallel lanes. A swipe changes lane, and swipes queue, so two swipes cross two lanes, while a swipe against a change in progress turns it back. A jump needs the ground; a roll ducks on the ground and, in the air, drives the runner down and rolls on landing. Trains stand in lanes or come at the runner, ramps lead up onto their roofs, and the runner can run along a line of roofs and jump the gaps. Barriers must be jumped, rolled under, or either.
What a collision means depends on how it happens. A train head-on ends the run. A scrape down a train's side is a stumble: a chaser closes in, and a second stumble inside the window means it catches the runner. A hoverboard, started from those in hand, takes one hit, and a head-on hit it takes lets the runner through that train.
The track is endless, built from chunks of lane items on runner-core, and the built-in set works for any number of
lanes, getting harder further along. Every chunk begins with clear track wide enough to cross every lane at top speed.
Each frame, view() says where every train, barrier, coin and pickup is, with ids that stay stable for pooling meshes,
and how close the chaser is; drain() gives events such as jump, land, scrape, crash and pickup.
Features
- Lane swipes — queued swipes, turn-backs mid-change, and a
bumpevent for a swipe off the edge. - Jump, roll and fast-fall — with the body's height, rolled height, jump height and time, roll time and lane-change time all options.
- Trains and roofs — standing and oncoming trains, ramps up to the roof, roof runs with gaps to jump.
- Barriers — slabs to pass over or under, named for your drawing, that crash or only stumble.
- Stumbles and a chaser — a side scrape brings the chaser, and a second one in the window ends the run.
- Power-ups as data — a hoverboard shield, a magnet with its reach, a jetpack flight with its height, super sneakers with their jump, and a doubler, each retunable, and your own added beside them.
- Any number of lanes — from 1 to 12, with the built-in track laid out for the count you choose.
- An autopilot — tries lanes, jumps and rolls on copies of the run and plays the plan that lives longest, for an attract mode, a demo or a test.
- Saves and clones — the run as plain JSON and back, and a separate copy at the same point to try moves on.
Good for
- Endless lane runners in the style of Subway Surfers, with trains, roofs and a chaser.
- Highway dodgers, where traffic comes at you lane by lane.
- Ski or snowboard runs in lanes, with barriers to jump and duck.
- Mobile games driven by swipes, since every move is a lane change, a jump, a roll or a board.
- 2D games seen from behind, since nothing in the rules depends on how it is drawn.
- Attract modes and level testing, with the autopilot proving that authored chunks can be passed.
Make it yours
The number of lanes and their width, the starting lane, the train height and width, the runner's body and timings, the track's chunks and opening, the hoverboards in hand and the power-up a board starts, the power-ups themselves, the coin radius and the run's speed ramp, stumble and grace rules are all options. A chunk is a list of trains, barriers, coin runs and power-ups placed along it, so a hand-made stretch of track is plain data.
Two very different runs: the built-in three-lane track at the default ramp from 13 to 26 units a second, with three hoverboards and every power-up; or a five-lane run of your own chunks with low barriers that only stumble, longer jumps, a stronger magnet and no jetpack, so the game is about weaving rather than flying.
A quick look
Start a run, turn a key into a swipe, step it and place the meshes:
const run = game.laneRunner.create({ run: { seed: 7 } });
if (game.input.keyPressed('ArrowLeft')) run.input('left');
run.step(dt);
const v = run.view();
for (const t of v.trains) placeTrain(t.id, t.x, t.front, t.length, t.height, t.ramp);
hero.x = v.runner.x; hero.y = v.runner.y; hero.z = v.runner.z;
for (const e of run.drain()) if (e.kind === 'over') showGameOver(run.run.state.score);
Works with
runner-core— the endless run underneath, imported rather than composed; use it alone for a runner of your own.render-3d— meshes for the trains, barriers and runner.turn-runner-3d— for a path that turns at corners with free steering across it.jetpack-runner-2d— for a side-on jetpack corridor.
Good to know
- Collisions are boxes: a train is a block a lane wide with a sloped ramp, a barrier a slab across one lane, and the runner a box that shortens when it rolls. There is no physics engine.
- A scrape is decided by where the runner came from; a train that moves into a runner beside it counts as head-on.
- Oncoming trains are timed to meet the runner at the speed when their chunk is laid, so a speed change on the way moves the meeting a little.
- The built-in chunks are proved passable at top speed; authored chunks are yours to check, with the autopilot.
- The autopilot runs about 30 short copies of the run for each decision, so it costs far more than the run it plays.






