Skip to content

Instantly share code, notes, and snippets.

@nsdevaraj
Created July 18, 2026 03:04
Show Gist options
  • Select an option

  • Save nsdevaraj/cd4aae7cac68f2acc6cb0e94ae5934bd to your computer and use it in GitHub Desktop.

Select an option

Save nsdevaraj/cd4aae7cac68f2acc6cb0e94ae5934bd to your computer and use it in GitHub Desktop.
Snak.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Classic Snake Game</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background-color: #2c3e50;
color: white;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#score {
font-size: 28px;
font-weight: bold;
margin-bottom: 20px;
letter-spacing: 2px;
}
canvas {
background-color: #34495e;
border: 4px solid #ecf0f1;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
#instructions {
margin-top: 15px;
color: #bdc3c7;
font-size: 14px;
}
</style>
</head>
<body>
<div id="score">SCORE: 0</div>
<!-- The game board -->
<canvas id="gameCanvas" width="400" height="400"></canvas>
<div id="instructions">Use Arrow Keys to move. Refresh page to restart.</div>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
// Game settings
const gridSize = 20;
let score = 0;
let gameInterval;
// Snake configuration (starts in the middle of the board)
let snake = [
{ x: 200, y: 200 },
{ x: 200, y: 220 },
{ x: 200, y: 240 }
];
// Initial movement direction (moving UP)
let dx = 0;
let dy = -gridSize;
// Food configuration
let food = { x: 0, y: 0 };
// Randomly place food on the grid
function placeFood() {
food.x = Math.floor(Math.random() * (canvas.width / gridSize)) * gridSize;
food.y = Math.floor(Math.random() * (canvas.height / gridSize)) * gridSize;
// Ensure food doesn't spawn exactly where the snake currently is
snake.forEach(part => {
if (part.x === food.x && part.y === food.y) {
placeFood();
}
});
}
// Draw individual snake blocks
function drawSnakePart(snakePart, index) {
ctx.fillStyle = index === 0 ? "#2ecc71" : "#27ae60"; // Head is slightly lighter
ctx.strokeStyle = "#1e8449";
ctx.fillRect(snakePart.x, snakePart.y, gridSize, gridSize);
ctx.strokeRect(snakePart.x, snakePart.y, gridSize, gridSize);
}
// Draw the food block
function drawFood() {
ctx.fillStyle = "#e74c3c";
ctx.strokeStyle = "#c0392b";
ctx.fillRect(food.x, food.y, gridSize, gridSize);
ctx.strokeRect(food.x, food.y, gridSize, gridSize);
}
// Update snake's position based on velocity
function moveSnake() {
const head = { x: snake[0].x + dx, y: snake[0].y + dy };
snake.unshift(head); // Add new head
// Check if snake ate the food
if (head.x === food.x && head.y === food.y) {
score += 10;
document.getElementById("score").innerText = "SCORE: " + score;
placeFood();
} else {
snake.pop(); // Remove tail if no food eaten
}
}
// Check for game-ending collisions
function checkCollision() {
const head = snake[0];
// 1. Wall collision
if (head.x < 0 || head.x >= canvas.width || head.y < 0 || head.y >= canvas.height) {
return true;
}
// 2. Self collision (start checking from index 1, skip the head)
for (let i = 1; i < snake.length; i++) {
if (head.x === snake[i].x && head.y === snake[i].y) {
return true;
}
}
return false;
}
// The main game loop
function main() {
if (checkCollision()) {
clearInterval(gameInterval); // Stop the game loop
// Draw Game Over text
ctx.fillStyle = "rgba(0, 0, 0, 0.75)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "white";
ctx.font = "bold 36px 'Segoe UI'";
ctx.textAlign = "center";
ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 10);
ctx.font = "18px 'Segoe UI'";
ctx.fillText("Press F5 to Restart", canvas.width / 2, canvas.height / 2 + 30);
return;
}
// Clear the canvas for the next frame
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Render everything
drawFood();
moveSnake();
snake.forEach(drawSnakePart);
}
// Listen for keyboard arrow navigation
document.addEventListener("keydown", (event) => {
// Prevent default scrolling behavior when pressing arrows
if(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key)) {
event.preventDefault();
}
const goingUp = dy === -gridSize;
const goingDown = dy === gridSize;
const goingRight = dx === gridSize;
const goingLeft = dx === -gridSize;
// Update direction (preventing 180-degree self-reversals)
if (event.key === "ArrowLeft" && !goingRight) {
dx = -gridSize;
dy = 0;
}
if (event.key === "ArrowUp" && !goingDown) {
dx = 0;
dy = -gridSize;
}
if (event.key === "ArrowRight" && !goingLeft) {
dx = gridSize;
dy = 0;
}
if (event.key === "ArrowDown" && !goingUp) {
dx = 0;
dy = gridSize;
}
});
// Start the game
placeFood();
gameInterval = setInterval(main, 100); // Game speed (100ms per frame)
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment