(Part 1) Building Tetris in TypeScript: Setting Up the Game Structure and Rendering the Grid
Learn how to build the foundation of a Tetris game using TypeScript and the Canvas API. In this first tutorial, you'll set up the project, render a 10x20 game grid, and structure your code for maintainability—all without using any frameworks.
Introduction
Tetris is a classic puzzle game that provides an excellent challenge for game development using TypeScript and the HTML5 Canvas API. In this tutorial series, we will build a fully functional Tetris game step by step. By the end of this tutorial, you'll have:
- A working TypeScript setup that compiles to JavaScript
- A modular folder structure with separate responsibilities
- A rendered Tetris grid using the Canvas API
We’ll keep the setup minimal: no frameworks or build tools — just pure TypeScript compiled via tsc
and referenced in HTML.
Project Structure
Let’s begin by organizing our project:
tetris-ts/
├── dist/
│ └── main.js # Output JS from TypeScript
├── src/
│ ├── grid.ts # Grid rendering and logic
│ └── main.ts # Entry point
├── index.html # Game canvas + script reference
├── package.json # NPM metadata and scripts
├── tsconfig.json # TypeScript config
Step 1: Initialize NPM and Install TypeScript
On terminal, navigate to your project directory and initialize an NPM project:
mkdir tetris-ts && cd tetris-ts
npm init -y
Install TypeScript as a local development dependency:
npm install typescript --save-dev
Create a tsconfig.json
file:
{
"compilerOptions": {
"target": "ES6",
"module": "ES6",
"outDir": "./dist",
"rootDir": "./src",
"strict": true
},
"include": ["src"]
}
Create a build script on your package.json
,under the scripts
section:
"scripts": {
"build": "tsc"
}
You can now compile your TypeScript code by running on your terminal:
npm run build
Step 2: Setting Up HTML
Create a new index.html
file:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tetris in TypeScript</title>
<style>
html, body {
margin: 0;
padding: 0;
background: #1c1818;
}
canvas {
border: 1px solid #000;
background: #000;
display: block;
margin: 20px auto;
}
</style>
</head>
<body>
<canvas id="tetris"></canvas>
<script type="module" src="./dist/main.js"></script>
</body>
</html>
Step 3: Creating the Grid Renderer
Create src/grid.ts
to define the Tetris grid and drawing logic:
export const COLS = 10;
export const ROWS = 20;
export const BLOCK_SIZE = 40;
export class Grid {
private context: CanvasRenderingContext2D;
constructor(context: CanvasRenderingContext2D) {
this.context = context;
this.context.canvas.width = COLS * BLOCK_SIZE;
this.context.canvas.height = ROWS * BLOCK_SIZE;
this.context.scale(BLOCK_SIZE, BLOCK_SIZE);
}
clear(): void {
this.context.fillStyle = '#000';
this.context.fillRect(0, 0, COLS, ROWS);
}
drawMatrix(matrix: number[][], offset: { x: number; y: number }): void {
matrix.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
this.context.fillStyle = '#444'; // Placeholder color for grid
this.context.fillRect(x + offset.x, y + offset.y, 1, 1);
}
});
});
}
}
Step 4: Entry Point - main.ts
Create src/main.ts
as the starting point of the game source:
import { Grid, COLS, ROWS } from './grid';
function createMatrix(w: number, h: number): number[][] {
const matrix = [];
for (let i = 0; i < h; i+=1) {
matrix.push(new Array(w).fill(0));
}
return matrix;
}
const canvas = document.getElementById('tetris') as HTMLCanvasElement;
const context = canvas.getContext('2d')!;
const grid = new Grid(context);
const arena = createMatrix(COLS, ROWS);
function draw() {
grid.clear();
grid.drawMatrix(arena, { x: 0, y: 0 });
requestAnimationFrame(draw);
}
draw();
Step 5: Compile and Run
To compile your code:
npm run build
Then open index.html
in your browser. You should see a black canvas with a 10x20 grid (empty, for now). You can optionally mark test blocks in the matrix to see rendering, like so:
arena[0][0] = 1;
arena[0][1] = 1;
Summary and Next Steps
In this tutorial, you:
- Initialized a TypeScript NPM project
- Set up a build script for easy compilation
- Built a reusable
Grid
class to manage rendering - Rendered the Tetris arena using the Canvas API
- Externalized and modularized the code from the original
tetris.html
On our Part 2, we’ll introduce Tetrominoes, movement, and collision detection. You’ll learn how to:
- Define and draw Tetromino shapes
- Move them left, right, and down
- Handle boundary and collision logic cleanly in TypeScript
Stay tuned — we're just getting started!
Read for Part 2?

Discussion