What it does
A ruleset is data plus a few small functions: the well's size, the rotation system, the randomiser, the match rule,
the cascade mode, the timing, the scoring, the progression and the top-out, with optional viruses, a magic piece,
nuisance and an objective. createFaller(rules) returns a game, and you call frame(input) once per 60 Hz frame with
the buttons held. Timing is counted in frames, as the originals counted it, so auto-repeat, soft drop, lock delay and
entry delay feel as they should.
A move goes through phases you can see: the piece falls and locks, rows or matched cells flash, the cells above fall,
the next match flashes, and so on until the entry delay brings the next piece. Each phase reports its progress, and
every locked cell keeps a stable id through falls, so your presenter animates the whole chain, cell by cell,
instead of jumping to the result.
The game also gives you what a modern version needs around the rules: a ghost, a next queue and a hold, events for everything from a rotation to a level-up, snapshot and restore, every possible placement and a preview of any one for a bot, and hooks to queue nuisance or garbage rows from an opponent. Unsupported configurations throw an error that names the problem.
Features
- Rotation systems — the modern system with its full kick tables, the original home-console pivots, colour cycling, pairs with wall and floor kicks and a quick turn, two-cell capsules, and table-driven rotation for your own shapes.
- Randomisers — a 7-bag, the home-console reroll rule, colour pairs, a 128-capsule loop, uniform, and authored sequences.
- Handling — modern delayed auto-shift and repeat rate, or the home-console 16/6 counter; soft drop by factor, rate or the home-console rule; hard drop, hold and initial rotation during entry.
- Gravity and locking — gravity curves by level up to 20G, and lock delay with move resets, step resets or the lock-on-block rule.
- Matching — line clears, runs of a length in rows, columns and diagonals, and connected groups of a size.
- Cascades — whole rows, single cells, or linked halves that stay joined until a partner clears.
- Scoring — T-spins and minis, back-to-back, combos, perfect clears, chain power and colour and group bonuses.
- Extras — viruses placed by the original algorithm, a magic jewel, nuisance with all-clear bonuses, and garbage rows.
- Objectives — endless, lines, a chain, an all clear, clearing a colour or a score, each with an optional piece limit, and authored starting stacks for missions.
- Crash gems — a separate board on the same piece engine, with power gems, crash gems, a diamond and timed counter gems.
- Versus hooks and bots — queued nuisance and garbage, attack events,
placementsandpreviewfor AI search. - Deterministic — the same seed and inputs always play the same game, with snapshot, restore and reset.
Good for
- Line-clearing block games, in the style of Tetris, by the modern guideline or the original home-console rules.
- Jewel-column matching, in the style of Columns, with colour cycling, diagonal matches and the magic jewel.
- Capsule-and-virus puzzles, in the style of Dr. Mario, with viruses placed by level.
- Chaining blob games, in the style of Puyo Puyo, with chain power, nuisance and puzzle missions.
- Crash-gem versus games, in the style of Super Puzzle Fighter II Turbo.
- Sprint, marathon and mission modes for any of them, from an objective, a start stack and a fixed sequence.
- Your own falling-piece game: pentominoes, wider wells, new match rules or a hybrid of the families.
Make it yours
Every preset takes options, including a difficulty: arcade is the original tables, normal keeps the original handling and caps the top speed, and easy caps it lower. Any field of a preset's rules can then be overridden: the well's size and buffer rows, the rotation system, the deal, the number of previews, hold, hard drop, the match rule, the cascade mode, every timing, the scoring, the progression, the top-out rule, viruses, the magic jewel, nuisance, the objective and a starting layout.
Materially different games come from the same engine: a six-wide sprint of the line-clear game with three previews, no hold and a goal of 40 lines; a jewel-column game on an eight-by-sixteen well with four-jewel columns that clear in fours, no diagonals and four colours; a two-colour capsule game on a ten-by-twenty bottle; blobs that pop in threes; or pentominoes from a table-driven rotation system with your own shapes and kicks.
A quick look
Two variations through the same API:
// A 6-wide line-clear sprint with three previews and no hold, ending at 40 lines.
const sprint = createFaller({ ...tetrisGuideline({ cols: 6, rows: 12, previews: 3, hold: false }),
objective: { kind: 'lines', lines: 40 } });
// Four-jewel columns that clear in fours, no diagonals, four colours, on an 8 x 16 well.
const wide = createFaller(columnsArcade({ cols: 8, rows: 16, length: 4, match: 4, diagonals: false, colors: 4 }));
sprint.frame(input); // once per 60 Hz frame with the held buttons
for (const e of sprint.drain()) present(e);
Works with
versus-garbage— to seat two games against each other, with attacks sent through the nuisance and garbage hooks.typography— for the score, level and queue labels.placer— for tray-and-grid puzzles where pieces are placed rather than dropped.bubbleshooter— for firing bubbles into a hanging grid.catch-stack— for catching tiles on a paddle and stacking them in a bin.
Good to know
- Frames are 60 Hz;
advance(seconds)rounds to frames. placementslists drops from spawn height and does not search tucks, slides or spins; a bot that wants them can drive inputs and usepreviewon snapshots.- Some timings had no primary source and are estimates, such as several jewel-column and blob delays; every one is a
timingfield. - The home-console randomiser keeps the reroll rule and its distribution but draws from the engine's seeded generator, not the original hardware's.
- Two-player play is composed with
versus-garbagerather than built in, and there is no sound.






