VOOZH about

URL: https://dev.to/dev48v/i-built-tetris-in-150-lines-of-javascript-7-pieces-rotation-line-clear-3d63

โ‡ฑ I Built Tetris in 150 Lines of JavaScript โ€” 7 Pieces, Rotation, Line Clear - DEV Community


๐ŸŒ Live demo (LOOK ยท UNDERSTAND ยท BUILD): https://dev48v.infy.uk/game/day3-tetris.html

Day 3 of my GameFromZero series. 50 playable browser games in 50 days. All open the page โ†’ play instantly.

Today: Tetris. Iconic. Older than most readers. Famously simple to start, infinitely deep to master.

The whole game is 150 lines of vanilla JS โ€” same game-loop skeleton as Snake (Day 1) and Pong (Day 2), just with a richer state and a rotation algorithm.


The 4 ideas

Idea 1 โ€” Board is a 2D grid of color numbers

10 columns ร— 20 rows. Each cell holds 0 (empty) or 1-7 (the color of the tetromino that landed there).

let board = Array.from({ length: 20 }, () => Array(10).fill(0));

That's the whole world state. Every piece eventually merges into this grid.

Idea 2 โ€” 7 tetrominoes as little matrices

Each piece is a small 2D array of 0s and the piece's color number. Rotate the matrix to rotate the piece.

const SHAPES = [
 [[1,1,1,1]], // I (cyan)
 [[2,0,0],[2,2,2]], // J (blue)
 [[0,0,3],[3,3,3]], // L (orange)
 [[4,4],[4,4]], // O (yellow)
 [[0,5,5],[5,5,0]], // S (green)
 [[0,6,0],[6,6,6]], // T (purple)
 [[7,7,0],[0,7,7]], // Z (red)
];

Idea 3 โ€” Matrix rotation by transpose

To rotate a matrix 90ยฐ clockwise: column k of the original becomes row k of the rotated. Five lines:

function rotate(s) {
 const N = s.length, M = s[0].length;
 const out = Array.from({ length: M }, () => Array(N).fill(0));
 for (let r = 0; r < N; r++)
 for (let c = 0; c < M; c++)
 out[c][N - 1 - r] = s[r][c];
 return out;
}

Idea 4 โ€” Line clear

After a piece merges, scan rows bottom-up. Any row that's fully non-zero gets splice()'d out and replaced with an empty row at the top. Award points.

for (let y = ROWS - 1; y >= 0; y--) {
 if (board[y].every(v => v)) {
 board.splice(y, 1);
 board.unshift(Array(COLS).fill(0));
 cleared++;
 y++; // re-check same index
 }
}

// Original NES scoring
score += [0, 40, 100, 300, 1200][cleared];

Four lines at once = "Tetris" = 1200 points. The exponential reward is what makes the game tense.


Collision check

Before any move (left/right/down/rotate), check if the resulting position overlaps the board or goes out of bounds:

function collide(p, dx = 0, dy = 0, shape = null) {
 const s = shape || p.shape;
 for (let r = 0; r < s.length; r++)
 for (let c = 0; c < s[r].length; c++) {
 if (!s[r][c]) continue;
 const x = p.x + c + dx, y = p.y + r + dy;
 if (x < 0 || x >= COLS || y >= ROWS) return true;
 if (y >= 0 && board[y][x]) return true;
 }
 return false;
}

Same function handles all four motions because we pass dx/dy and optionally a rotated shape to "preview" the move.


The game loop

Same pattern as every game in this series. requestAnimationFrame for smooth rendering + a gravity tick at fixed intervals.

let last = 0;
function loop(t) {
 if (!gameOver) {
 if (t - last > 600) {
 softDrop(); // try to move down 1
 last = t;
 draw();
 }
 }
 requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

softDrop() either moves the piece down by 1 OR (if it can't) merges into the board, clears any complete lines, and spawns the next piece.


Hard drop (the satisfying one)

Space = drop piece as far as it goes in a single tick. The most-used shortcut in competitive Tetris.

function hardDrop() {
 while (!collide(piece, 0, 1)) piece.y++;
 softDrop(); // triggers merge + line-clear
}

Two lines. Maximum drama.


What this unlocks

Same skeleton works for every falling-block puzzle:

  • Puyo Puyo โ€” swap rectangular shapes for paired blobs, add cascade physics
  • Dr. Mario โ€” different piece set, color-matching match-3
  • Columns โ€” vertical-only pieces, match-3 instead of full rows
  • Lumines โ€” Tetris with a beat-synced "timeline" sweeper

Board + pieces + collide + rotate + line-clear + gravity tick. That's the pattern. Everything else is variation.


Try it now

Three tabs on one page:
https://dev48v.infy.uk/game/day3-tetris.html

  • LOOK โ€” playable Tetris (with next-piece preview + scoring)
  • UNDERSTAND โ€” 9 click-through steps with diagrams + WHY for each piece of math
  • BUILD โ€” copy the HTML, save, open, play

What's next in GameFromZero

Day 4: Breakout. Same loop, one paddle, replace right wall with a brick grid.

Series: 50 playable browser games ยท zero install ยท open + play.

๐ŸŒ All games: https://dev48v.infy.uk/gamefromzero.php