TinyGames · how it works

Strata

Falling blocks. Stack them, complete rows, watch the floor come up to meet you.

Open index.html. No build step, no dependencies, no images.

strata/
  index.html      markup
  style.css       the frame around the canvas
  js/engine.js    copied unchanged from Overdrive - the fourteenth game on it
  js/tetro.js     the well, the pieces, the kick tables and the bag
                  - no pixels, no engine, no DOM
  js/strata.js    the playable layer
  test-tetro.js   node test-tetro.js

Rotation is the whole game

Falling and line-clearing are easy. What separates a falling-block game that feels right from one that feels broken is what happens when you try to rotate against a wall.

The naive answer — rotate, and if it collides, refuse — means an I-piece flat against the left wall simply cannot be stood up. The player does not read that as a rule. They read it as the game ignoring them.

So rotation is not one test. It is a short ordered list of nudges: try the rotation where it is, then one square left, then one left and one up, and so on. The first that fits wins. Those lists are the Super Rotation System's kick tables, they are different for the I piece, and they are why a piece can be screwed into a slot it could never simply drop into.

The test tries every piece, in every rotation, in both directions, flush against both walls — 56 cases — and asserts none of them is ever stuck:

$ node test-tetro.js
99 passed, 0 failed

A second test fires 3,000 random rotations into randomly littered wells and asserts a kick never leaves a piece overlapping anything — a kick may only ever move a piece somewhere it genuinely fits.

The tables are written with y upward, as published. Every y in this file is the negation of the published value, because screen y goes down. Getting that sign wrong produces a game that kicks pieces into the floor instead of out of it, and looks like gravity has gone mad.


Four turns must return the piece exactly

Storing four hand-typed orientations per piece is how that quietly stops being true. Here each piece is defined once, in spawn orientation, inside a square box, and rotation turns the cells within the box — so the property holds by construction, and the test proves it rather than trusting it.

That construction has a consequence worth stating: the I-piece occupies four different positions inside its box (row 1, column 2, row 2, column 1) while having only two distinct silhouettes. That is not a bug — it is exactly what the kick tables are written against — and the tests assert both numbers so neither can drift.


The bag

Pure random dealing produces droughts, and a drought is indistinguishable from bad luck you cannot plan around. So pieces come from a shuffled bag of all seven, refilled when it empties.

The guarantee: at most twelve other pieces between one appearance and the next. The test checks all 700 deals and confirms the worst case is exactly that, so the bound is tight — and then runs plain random dealing on the same generator to show it leaves much longer droughts.


Lock delay

A piece that has landed gets half a second before it sets, and moving or turning it refreshes that — which is what lets you slide a piece along the floor into a gap. Without it, the game is far harsher than it looks.

But only fifteen refreshes, or a piece can be juggled forever and never lock at all.

Topping out is "the new piece has nowhere to appear", not "the stack reached the top". Checking the stack height instead ends the game a piece too early or too late depending on which piece is next.


Controls

move (hold to repeat)
/ X rotate clockwise
Z rotate the other way
soft drop
Space hard drop
C / Shift hold
R new game

On a touch screen: drag sideways to move a column at a time, drag down to soft drop, flick down to hard drop, tap to rotate, flick up to hold. A d-pad drawn on the glass would cover a third of the well.


Scoring

100 / 300 / 500 / 800 for one to four rows, multiplied by the level — so four at once beats four singles by a distance. Soft drop pays 1 a row, hard drop 2. A level every ten lines, and gravity bottoms out at 45 ms a row rather than reaching zero.


Things deliberately left undone