Skip to content

Instantly share code, notes, and snippets.

@geekygeeky
Created August 12, 2025 02:10
Show Gist options
  • Select an option

  • Save geekygeeky/f565e25c76621b1a306a27d55dd96f92 to your computer and use it in GitHub Desktop.

Select an option

Save geekygeeky/f565e25c76621b1a306a27d55dd96f92 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tetris Game</title>
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #222;
}
canvas {
border: 2px solid #fff;
}
</style>
</head>
<body>
<canvas id="tetris" width="300" height="600"></canvas>
<script>
const canvas = document.getElementById("tetris");
const context = canvas.getContext("2d");
const rows = 20;
const cols = 10;
const blockSize = 30;
context.scale(blockSize, blockSize);
const tetrominos = [
{ shape: [[1, 1, 1, 1]], color: "cyan" }, // I
{ shape: [[1, 1, 1], [0, 1, 0]], color: "yellow" }, // T
{ shape: [[1, 1], [1, 1]], color: "red" }, // O
{ shape: [[1, 1, 0], [0, 1, 1]], color: "green" }, // S
{ shape: [[0, 1, 1], [1, 1, 0]], color: "blue" }, // Z
{ shape: [[1, 0, 0], [1, 1, 1]], color: "orange" }, // L
{ shape: [[0, 0, 1], [1, 1, 1]], color: "purple" }, // J
];
let board = Array.from({ length: rows }, () => Array(cols).fill(null));
let currentPiece = randomTetromino();
let gameOver = false;
document.addEventListener("keydown", handleKeyDown);
function randomTetromino() {
const tetromino = tetrominos[Math.floor(Math.random() * tetrominos.length)];
return { shape: tetromino.shape, color: tetromino.color, x: Math.floor(cols / 2) - 1, y: 0 };
}
function rotate(piece) {
const rotated = piece.shape[0].map((_, i) => piece.shape.map(row => row[i]));
piece.shape = rotated.reverse();
}
function handleKeyDown(e) {
if (gameOver) return;
if (e.key === "ArrowLeft") {
if (canMove(currentPiece, -1, 0)) currentPiece.x -= 1;
} else if (e.key === "ArrowRight") {
if (canMove(currentPiece, 1, 0)) currentPiece.x += 1;
} else if (e.key === "ArrowDown") {
if (canMove(currentPiece, 0, 1)) currentPiece.y += 1;
} else if (e.key === "ArrowUp") {
rotate(currentPiece);
if (!canMove(currentPiece, 0, 0)) rotate(currentPiece); // Undo if rotation is not valid
}
render();
}
function canMove(piece, dx, dy) {
for (let y = 0; y < piece.shape.length; y++) {
for (let x = 0; x < piece.shape[y].length; x++) {
if (piece.shape[y][x]) {
const newX = piece.x + x + dx;
const newY = piece.y + y + dy;
if (newX < 0 || newX >= cols || newY >= rows || board[newY] && board[newY][newX]) {
return false;
}
}
}
}
return true;
}
function placePiece(piece) {
for (let y = 0; y < piece.shape.length; y++) {
for (let x = 0; x < piece.shape[y].length; x++) {
if (piece.shape[y][x]) {
board[piece.y + y][piece.x + x] = piece.color;
}
}
}
clearRows();
currentPiece = randomTetromino();
if (!canMove(currentPiece, 0, 0)) gameOver = true;
}
function clearRows() {
for (let y = rows - 1; y >= 0; y--) {
if (board[y].every(cell => cell !== null)) {
board.splice(y, 1);
board.unshift(Array(cols).fill(null));
}
}
}
function render() {
context.clearRect(0, 0, canvas.width, canvas.height);
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
if (board[y][x]) {
context.fillStyle = board[y][x];
context.fillRect(x, y, 1, 1);
}
}
}
for (let y = 0; y < currentPiece.shape.length; y++) {
for (let x = 0; x < currentPiece.shape[y].length; x++) {
if (currentPiece.shape[y][x]) {
context.fillStyle = currentPiece.color;
context.fillRect(currentPiece.x + x, currentPiece.y + y, 1, 1);
}
}
}
if (gameOver) {
context.fillStyle = "white";
context.font = "30px Arial";
context.fillText("Game Over", 3, 10);
}
}
function gameLoop() {
if (gameOver) return;
if (canMove(currentPiece, 0, 1)) {
currentPiece.y += 1;
} else {
placePiece(currentPiece);
}
render();
setTimeout(gameLoop, 500);
}
gameLoop();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment