SNAKE!

Remember the first time you played Snake on a tiny phone screen? If so, you might enjoy this nostalgia trip! Scroll donw if you haven’t already noticed: there’s a playable Snake game. Go ahead, give it a try, use your arrow keys to navigate the snake and devour those apples (without running into your tail!).
Play Snake!
Yep, a game, embedded right at the top of this blog post. No iframe. No external libraries. Just HTML, CSS, and vanilla JavaScript doing what they do best rendering a dynamic, fully-interactive mini-game straight into your browser.
What you are seeing it's in reality a small snippet of code, all packed inside a <details> tag, it loads with a click and runs seamlessly on an HTML <canvas>. It responds to your arrow keys, wraps around the edges, grows as it eats, and yes, crashes when it bites itself. Just like the one you played on your old Nokia or on your first PC.
But here’s the cool part: this isn’t just for fun. It’s a compact demo of how simple game logic, canvas rendering, and input handling can come together to build something that feels alive directly inside a blog post.
So if you’re into games, browser wizardry, or just love the idea of turning code into something playable, this breakdown is for you.
Let’s dive in.
Understanding the Code
<details>
<summary>Click to view the Snake code with comments</summary>
<!-- SNAKE GAME START -->
<div style="text-align: center; margin: 20px 0;">
<h3>Play Snake!</h3>
<!-- The canvas on which the snake game is rendered -->
<canvas
id="snakeCanvas"
width="400"
height="400"
style="border: 1px solid #444;">
</canvas>
<!-- Display game messages (like "Game Over") -->
<p id="snakeStatus" style="font-weight: bold; margin-top: 10px;"></p>
</div>
<script>
/***************************************************
* 1. Getting references to our HTML elements
***************************************************/
// Grab the <canvas> element by its ID
const canvas = document.getElementById("snakeCanvas");
// 2D context is needed to draw shapes on the canvas
const ctx = canvas.getContext("2d");
// Grab the paragraph element to show the game status
const statusText = document.getElementById("snakeStatus");
/***************************************************
* 2. Game configuration constants and variables
***************************************************/
// The size of each grid cell (a 20x20 cell for a 400x400 canvas)
const gridSize = 20;
// tileCount indicates how many cells fit across (and down) the canvas
const tileCount = canvas.width / gridSize;
// Initial snake position (x, y)
let snakePosX = 10;
let snakePosY = 10;
// Initial snake velocity (x, y) = (0, 0) means not moving
let velocityX = 0;
let velocityY = 0;
// This array will store the coordinates of each snake segment
let snakeTrail = [];
// Starting length of the snake
let snakeLength = 5;
// Apple (food) initial coordinates
let appleX = 15;
let appleY = 15;
/***************************************************
* 3. Game initialization
***************************************************/
// Listen for keyboard arrow keys to move the snake
window.addEventListener("keydown", keyPush);
// Set the main game loop to run every 120 milliseconds
// (faster or slower to adjust difficulty)
setInterval(gameLoop, 120);
/***************************************************
* 4. Main game loop
***************************************************/
function gameLoop() {
// Update the snake's head position by its velocity
snakePosX += velocityX;
snakePosY += velocityY;
// Handle "wrapping" around edges
if (snakePosX < 0) {
snakePosX = tileCount - 1;
} else if (snakePosX >= tileCount) {
snakePosX = 0;
}
if (snakePosY < 0) {
snakePosY = tileCount - 1;
} else if (snakePosY >= tileCount) {
snakePosY = 0;
}
// Clear the canvas each frame
// Here we set the background to black ("#000")
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw the apple in red
ctx.fillStyle = "red";
ctx.fillRect(appleX * gridSize, appleY * gridSize, gridSize - 2, gridSize - 2);
// Draw the snake in green
ctx.fillStyle = "green";
snakeTrail.forEach(segment => {
ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize - 2, gridSize - 2);
});
// Add the new head position to the snake's body (snakeTrail)
snakeTrail.push({ x: snakePosX, y: snakePosY });
// Trim the snakeTrail to match the snake's length
// If it grows too big, remove the oldest segment
while (snakeTrail.length > snakeLength) {
snakeTrail.shift();
}
// Check if the snake head is on the apple
if (snakePosX === appleX && snakePosY === appleY) {
// Grow the snake by one segment
snakeLength++;
// Randomly place the next apple
appleX = Math.floor(Math.random() * tileCount);
appleY = Math.floor(Math.random() * tileCount);
}
// Check for collision with the snake's own body
for (let i = 0; i < snakeTrail.length - 1; i++) {
const segment = snakeTrail[i];
// If the head overlaps any segment, the game is over
if (segment.x === snakePosX && segment.y === snakePosY) {
// Reset the snake
snakeLength = 5;
velocityX = 0;
velocityY = 0;
snakePosX = 10;
snakePosY = 10;
// Display a message to the player
statusText.textContent = "Game Over! Press any arrow key to start again";
return;
}
}
// If still alive, encourage the player to use arrow keys
statusText.textContent = "Use arrow keys to play!";
}
/***************************************************
* 5. Keyboard event handling
***************************************************/
function keyPush(evt) {
switch (evt.key) {
case "ArrowLeft":
if (velocityX !== 1) {
velocityX = -1;
velocityY = 0;
}
break;
case "ArrowUp":
if (velocityY !== 1) {
velocityX = 0;
velocityY = -1;
}
break;
case "ArrowRight":
if (velocityX !== -1) {
velocityX = 1;
velocityY = 0;
}
break;
case "ArrowDown":
if (velocityY !== -1) {
velocityX = 0;
velocityY = 1;
}
break;
}
}
</script>
<!-- SNAKE GAME END -->
</details>
HTML Structure
At the core of the Snake game, we have a straightforward HTML setup:
- Canvas Element: This is the visual playground where the snake moves and interacts with apples.
- Status Display: A simple paragraph element to communicate messages like "Game Over" or "Use arrow keys to play!"
JavaScript Initialization
JavaScript is essential for adding interactivity:
- Canvas Context (
ctx
): Provides tools to draw elements dynamically. - Event Listeners: Captures keyboard inputs to control snake movement.
- Game Loop (
setInterval
): Repeatedly updates the game's state approximately eight times per second, refreshing visuals and logic.
Variables and Their Roles
Let's briefly explore key variables:
snakePosX
,snakePosY
: Track the snake’s head position on the grid.velocityX
,velocityY
: Determine the snake's direction and speed.snakeTrail
: Holds the coordinates of the snake's segments.snakeLength
: Manages how long the snake grows when eating apples.appleX
,appleY
: Define apple positions that randomly change after each bite.
Game Loop Breakdown
Within the main loop, the following happens continuously:
- Position Update: Snake's position updates based on velocity, with boundary wrapping to seamlessly re-enter from the opposite side.
- Canvas Clearing and Redrawing: Each frame refreshes by clearing the canvas, then redrawing the snake and apple.
- Collision Detection: Checks if the snake has collided with an apple (to grow) or itself (ending the game).
- Growth Mechanics: Each apple eaten increases the snake's length, adding complexity to the game.
Keyboard Controls
The game listens for arrow key inputs to adjust the snake’s direction:
- Prevents direct reversal, adding strategic depth.
- Responsive controls ensure smooth gameplay.
Wrap Up
That’s all there is to it! The entire game is less than a hundred lines of JavaScript, making it an excellent learning project if you want to dabble in canvas-based animation or event handling.
Thanks for playing and reading! If you have questions or want to share your own Snake modifications (perhaps a rainbow snake or multiple apples?), drop a comment below.
Happy coding and happy gaming!