---
title: "How to make Snake Game in JavaScript"
description: "Learn how to build a classic Snake game using JavaScript and HTML5 Canvas in this detailed, step-by-step guide. Full source code available also!!"
author: "Tajammal Maqbool"
last_updated: "2024-12-07"
---

# How to make Snake Game in JavaScript

> Learn how to build a classic Snake game using JavaScript and HTML5 Canvas in this detailed, step-by-step guide. Full source code available also!!

**Author:** Tajammal Maqbool  
**Published:** December 7, 2024  
**Tags:** javascript, game code, game development

The Snake game is one of the most beloved classics in the world of video games. Its simple yet addictive gameplay makes it an ideal project for developers looking to sharpen their skills in [JavaScript](https://tajammalmaqbool.com/pages/categories/javascript.md), **HTML5**, and [CSS](https://tajammalmaqbool.com/pages/categories/css.md). In this guide, we’ll walk through **how to create a fully functional Snake game**, explain every part of the code, and discuss key concepts such as the HTML5 Canvas, event handling, game loops, collision detection, and more.

Let’s get started!

## What Is the HTML5 Canvas?
[HTML5 CANVAS](https://tajammalmaqbool.com/pages/blogs/html5-canvas-with-examples.md) is a powerful element that allows you to draw graphics, animations, and interactive content directly in the browser using JavaScript. It provides a raster-based drawing surface where you can dynamically render shapes, text, images, and more.

```html
<canvas width="300" height="150" ></canvas>
```

### How Does It Work With JavaScript?
JavaScript gives life to the canvas. It provides a **"context"** that holds drawing methods. The most common context is the 2D context. With this context, you can draw shapes, set colors, and more.

```html
<script>
  // Get the canvas element by its ID.
  var canvas = document.getElementById('myCanvas');
  
  // Get the 2D drawing context.
  var ctx = canvas.getContext('2d');
  
  // Set the fill color to red.
  ctx.fillStyle = "red";
  
  // Draw a red rectangle.
  ctx.fillRect(20, 20, 150, 100);
</script>
```
In this example, we set up a canvas with a border. JavaScript finds the canvas using its ID. Then, we get the 2D drawing context and use it to draw a red rectangle.

## Project Setup
Before jump into the JavaScript code, let’s set up project structure. Create a new folder for Snake game project, and inside it, create a subfolder named src. Within this folder, create the following three essential files:
* index.html – This file contains the main HTML structure for the game.
* styles.css – This stylesheet will be used to style the game canvas, buttons, and overlays.
* index.js – This is the JavaScript file that will hold all the game logic and interactive functionality.

Your project structure should look something like this:
```bash
snake-game/
├── src/
|   ├── assets/
│   ├── index.html
│   ├── styles.css
│   └── index.js
```

This structure helps keep the code modular and easier to maintain. Later on, we’ll see how these files interact to create a seamless gaming experience.

### Understanding the Code
The HTML file structures the webpage by defining elements and layout, the CSS file styles these elements to enhance visual appeal, and the JavaScript file adds interactivity by handling events and dynamic updates. Checkout result:

<Image 
  src="/images/blogs/snake-game-in-javascript.gif"
  alt="Snake Game using HTML Canvas & JavaScript"
  title="Snake Game using HTML Canvas & JavaScript"
  className="object-center object-cover"
  width="600"
  height="600"
></Image>

#### 1. HTML (Defining Structure)
The HTML file structures the webpage using elements like div, button, and canvas. It provides a basic layout for user interaction, including buttons and an area to display dynamic content. The HTML links to the CSS for styling and the JavaScript for functionality.
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Snake Game</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <div id="game-container">
      <canvas id="gameCanvas" width="600" height="400"></canvas>
      <div id="score">Score: 0</div>
      <div id="game-over">
        <h2>Game Over</h2>
        <p>Your final score: <span id="final-score"></span></p>
        <button id="restart-btn">Restart Game</button>
      </div>
    </div>
    <button id="start-btn">Start Game</button>

    <!-- Sound Effects -->
    <audio id="eat-sound" src="/src/assets/sounds/eat-food.mp3"></audio>
    <audio id="gameover-sound" src="/src/assets/sounds/game-over.mp3"></audio>

    <script src="./index.js"></script>
  </body>
</html>
```

#### 2. CSS (Adding Styles)
The CSS file enhances the visual appearance of the webpage by styling elements with colors, fonts, spacing, and layouts. It ensures a responsive and user-friendly interface. Additionally, it may include animations or hover effects to improve user interaction.

```css
/* Reset */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  background: #6a8a38;
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}

/* Game container (no border) */
#game-container {
  position: relative;
  width: 600px;
  height: 400px;
  /* border removed */
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

/* The canvas will be drawn dynamically with a tiled background */
canvas {
  display: block;
}

/* Score display */
#score {
  position: absolute;
  top: 10px;
  right: 15px;
  font-size: 18px;
  background: rgba(0, 0, 0, 0.5);
  padding: 5px 10px;
  border-radius: 5px;
}

/* Start button styling */
#start-btn {
  margin-top: 20px;
  padding: 12px 24px;
  font-size: 18px;
  border: none;
  padding-top: 14px;
  border-radius: 5px;
  background: rgb(106, 106, 255);
  color: #fff;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.3s ease;
}

#start-btn:hover {
  background: rgb(93, 93, 253);
}

/* Game Over overlay styling */
#game-over {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.85);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s ease;
}

#game-over.active {
  opacity: 1;
  visibility: visible;
}

#game-over h2 {
  font-size: 36px;
  margin-bottom: 10px;
}

#game-over p {
  font-size: 20px;
  margin-bottom: 20px;
}

#game-over button {
  padding: 10px 20px;
  font-size: 16px;
  padding-top: 12px;
  border: none;
  border-radius: 5px;
  background: rgb(106, 106, 255);
  color: #fff;
  cursor: pointer;
  transition: background 0.3s ease;
}

#game-over button:hover {
  background: rgb(93, 93, 253);
}
```

#### 3. JavaScript (Adding Logic and Interactivity)
The JavaScript file adds interactivity to the webpage by handling events like button clicks and animations. It manipulates the DOM, updates elements dynamically, and controls any logic or data processing required for the app. It ensures smooth functionality and enhances user experience.

##### **i. UI Elements & Global Variables**
First, we capture references to key HTML elements and set up variables that will track the snake’s state, movement, score, and more. This initialization ensures everything is ready for when the game starts.

```js
// UI Elements
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const startBtn = document.getElementById("start-btn");
const scoreElement = document.getElementById("score");
const gameOverScreen = document.getElementById("game-over");
const finalScoreElement = document.getElementById("final-score");
const restartBtn = document.getElementById("restart-btn");

// Sound Effects
const eatSound = document.getElementById("eat-sound");
const gameoverSound = document.getElementById("gameover-sound");

// Game variables
const gridSize = 20;
let snake = [];
let food = null;
let dx = gridSize;
let dy = 0;
let score = 0;
let gameInterval = null;
let gameStarted = false;
```

##### **ii. Preloading Game Assets**
To ensure smooth gameplay, preload all the images for the snake’s head, body, tail, and food before the game begins. The loadImages function does exactly that by counting the loaded assets and triggering a callback when they’re all ready.

```js
// Preload images for snake parts and food.
const images = {};
function loadImages(callback) {
  let loaded = 0;
  const total = 15; // Total number of images to load

  function onLoad() {
    loaded++;
    if (loaded === total) {
      callback();
    }
  }

  images.head_right = new Image();
  images.head_right.onload = onLoad;
  images.head_right.src = "/src/assets/head_right.avif";

  images.head_left = new Image();
  images.head_left.onload = onLoad;
  images.head_left.src = "/src/assets/head_left.avif";

  images.head_up = new Image();
  images.head_up.onload = onLoad;
  images.head_up.src = "/src/assets/head_up.avif";

  images.head_down = new Image();
  images.head_down.onload = onLoad;
  images.head_down.src = "/src/assets/head_down.avif";

  images.tail_right = new Image();
  images.tail_right.onload = onLoad;
  images.tail_right.src = "/src/assets/tail_right.avif";

  images.tail_left = new Image();
  images.tail_left.onload = onLoad;
  images.tail_left.src = "/src/assets/tail_left.avif";

  images.tail_up = new Image();
  images.tail_up.onload = onLoad;
  images.tail_up.src = "/src/assets/tail_up.avif";

  images.tail_down = new Image();
  images.tail_down.onload = onLoad;
  images.tail_down.src = "/src/assets/tail_down.avif";

  images.body_vertical = new Image();
  images.body_vertical.onload = onLoad;
  images.body_vertical.src = "/src/assets/body_vertical.avif";

  images.body_horizontal = new Image();
  images.body_horizontal.onload = onLoad;
  images.body_horizontal.src = "/src/assets/body_horizontal.avif";

  images.body_topright = new Image();
  images.body_topright.onload = onLoad;
  images.body_topright.src = "/src/assets/body_topright.avif";

  images.body_topleft = new Image();
  images.body_topleft.onload = onLoad;
  images.body_topleft.src = "/src/assets/body_topleft.avif";

  images.body_bottomright = new Image();
  images.body_bottomright.onload = onLoad;
  images.body_bottomright.src = "/src/assets/body_bottomright.avif";

  images.body_bottomleft = new Image();
  images.body_bottomleft.onload = onLoad;
  images.body_bottomleft.src = "/src/assets/body_bottomleft.avif";

  images.food = new Image();
  images.food.onload = onLoad;
  images.food.src = "/src/assets/apple.avif";
}
```

##### **iii. Drawing the Game Elements**
Your game’s canvas is where the magic happens. Here, we create functions to draw the background grid, randomly place and draw the food, and render the snake based on its current state.

###### a. Drawing the Background
A checkered background gives the game a classic, polished look by alternating colors in a grid pattern. The function loops through rows and columns, filling each cell with a different shade based on its position.

```js
function drawBackground() {
  const rows = canvas.height / gridSize;
  const cols = canvas.width / gridSize;
  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      ctx.fillStyle = (row + col) % 2 === 0 ? "#b2d14f" : "#b9d757";
      ctx.fillRect(col * gridSize, row * gridSize, gridSize, gridSize);
    }
  }
}
```

###### b. Creating and Drawing the Food
The food appears at a random position on the grid, ensuring it aligns perfectly with the game's layout. When the snake eats the food, a sound effect plays, the score increases, and a new food item is generated at a different random location. The createFood function calculates a valid position within the canvas, while drawFood renders the food image at that position.

```js
function createFood() {
  const maxX = canvas.width - gridSize;
  const maxY = canvas.height - gridSize;
  food = {
    x: Math.floor(Math.random() * ((maxX + 1) / gridSize)) * gridSize,
    y: Math.floor(Math.random() * ((maxY + 1) / gridSize)) * gridSize,
  };
}

function drawFood() {
  ctx.drawImage(images.food, food.x, food.y, gridSize, gridSize);
}
```

###### c. Drawing the Snake
The snake is made up of multiple segments. The first segment is the head (which changes its image based on the movement direction), the last segment is the tail, and the middle segments form the body. This function determines which image to use for each segment.

```js
function drawSnake() {
  snake.forEach((segment, i) => {
    let img;
    if (i === 0) {
      // Head: choose image based on movement direction.
      if (dx === gridSize) img = images.head_right;
      else if (dx === -gridSize) img = images.head_left;
      else if (dy === gridSize) img = images.head_down;
      else if (dy === -gridSize) img = images.head_up;
    } else if (i === snake.length - 1) {
      // Tail: choose image based on the previous segment.
      const prev = snake[i - 1];
      const diffX = segment.x - prev.x;
      const diffY = segment.y - prev.y;
      if (diffX === gridSize) img = images.tail_right;
      else if (diffX === -gridSize) img = images.tail_left;
      else if (diffY === gridSize) img = images.tail_down;
      else if (diffY === -gridSize) img = images.tail_up;
    } else {
      // Body: decide between straight or turning.
      const prev = snake[i - 1];
      const next = snake[i + 1];
      if (prev.x === next.x) {
        img = images.body_vertical;
      } else if (prev.y === next.y) {
        img = images.body_horizontal;
      } else {
        let fromAbove = prev.y < segment.y || next.y < segment.y;
        let fromBelow = prev.y > segment.y || next.y > segment.y;
        let fromLeft = prev.x < segment.x || next.x < segment.x;
        let fromRight = prev.x > segment.x || next.x > segment.x;
        if (fromAbove && fromRight) img = images.body_topright;
        else if (fromAbove && fromLeft) img = images.body_topleft;
        else if (fromBelow && fromRight) img = images.body_bottomright;
        else if (fromBelow && fromLeft) img = images.body_bottomleft;
      }
    }
    ctx.drawImage(img, segment.x, segment.y, gridSize, gridSize);
  });
}
```

##### **iv. The Game Loop: Movement, Collision, and Score Updates**
The heart of our game is the update loop. In each iteration, we calculate the snake’s new head position, check for collisions with walls or the snake itself, update the score if food is eaten, and then redraw the entire game state.

```js
function update() {
  const head = snake[0];
  const newHead = { x: head.x + dx, y: head.y + dy };

  // Check for wall collision
  if (
    newHead.x < 0 ||
    newHead.x >= canvas.width ||
    newHead.y < 0 ||
    newHead.y >= canvas.height
  ) {
    return gameOver();
  }

  // Check for self-collision
  if (snake.some((segment) => segment.x === newHead.x && segment.y === newHead.y)) {
    return gameOver();
  }

  // Move snake: add new head to the beginning of the array
  snake.unshift(newHead);

  // Check for food collision
  if (newHead.x === food.x && newHead.y === food.y) {
    eatSound.play();
    score += 10;
    scoreElement.textContent = `Score: ${score}`;
    createFood();
  } else {
    // Remove tail if no food is eaten
    snake.pop();
  }

  // Redraw game elements
  drawBackground();
  drawFood();
  drawSnake();
}
```

##### **v. Handling Game Over and Restart**
When the snake crashes into a wall or itself, the game stops, a sound plays, and an overlay appears showing the final score. The following functions handle game over logic and starting/restarting the game.

```js
function gameOver() {
  gameoverSound.play();
  clearInterval(gameInterval);
  finalScoreElement.textContent = score;
  gameOverScreen.classList.add("active");
}

function startGame() {
  gameStarted = true;
  snake = [
    { x: gridSize * 3, y: 0 },
    { x: gridSize * 2, y: 0 },
    { x: gridSize * 1, y: 0 },
    { x: gridSize * 0, y: 0 },
  ];
  dx = gridSize;
  dy = 0;
  score = 0;
  scoreElement.textContent = "Score: 0";
  gameOverScreen.classList.remove("active");
  startBtn.style.display = "none";
  createFood();

  // Draw initial game state
  drawBackground();
  drawFood();
  drawSnake();

  if (gameInterval) clearInterval(gameInterval);
  gameInterval = setInterval(update, 200);
}

function restartGame() {
  startGame();
}
```

##### **vi. Event Listeners: Controlling the Snake**
The game is controlled via the arrow keys, and you start or restart the game with on-screen buttons. Add these event listeners to make your game interactive:

```js
// Start and restart button event listeners
startBtn.addEventListener("click", startGame);
restartBtn.addEventListener("click", restartGame);

// Listen for arrow key presses to change the snake's direction
document.addEventListener("keydown", (e) => {
  switch (e.key) {
    case "ArrowUp":
      if (dy !== gridSize) {
        dx = 0;
        dy = -gridSize;
      }
      break;
    case "ArrowDown":
      if (dy !== -gridSize) {
        dx = 0;
        dy = gridSize;
      }
      break;
    case "ArrowLeft":
      if (dx !== gridSize) {
        dx = -gridSize;
        dy = 0;
      }
      break;
    case "ArrowRight":
      if (dx !== -gridSize) {
        dx = gridSize;
        dy = 0;
      }
      break;
  }
});
```

##### **vii. Initializing the Game**
Finally, once all images have loaded, initialize the game to display a static snake, background, and food—ready for you to hit “Start!”

```js
function initGameState() {
  snake = [
    { x: gridSize * 3, y: 0 },
    { x: gridSize * 2, y: 0 },
    { x: gridSize * 1, y: 0 },
    { x: gridSize * 0, y: 0 },
  ];
  dx = gridSize;
  dy = 0;
  createFood();
  drawBackground();
  drawFood();
  drawSnake();
}

loadImages(function () {
  if (!gameStarted) {
    initGameState();
  }
});
```

Do you want to see the results in real-time, checkout this sandbox project with full source code and also all things are attached there like images, sounds etc.

<iframe src="https://codesandbox.io/embed/92lsty?view=preview"
      width="100%" height="620"
     title="snake-game-javascript"
     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
   ></iframe>

## FAQs
1. **What is the Snake Game?** The Snake game is a classic arcade-style game where a player controls a growing snake, navigating a grid to eat food while avoiding collisions with the walls or itself.
2. **What technologies are used in this project?** This project uses HTML5, CSS, and JavaScript. The game canvas is created using the HTML5 Canvas API, and JavaScript is used for game logic, rendering, and user interactions.
3. **Can I modify the game?** Yes! The game is fully customizable. You can modify the snake's speed, grid size, colors, or add new features like obstacles or different food types.
4. **What happens when the game ends?** When the game ends, a Game Over screen appears, displaying your final score. You can restart the game by clicking the Restart Game button.
5. **What is the role of the canvas in the game?** The HTML5 Canvas is used to render the game graphics. It provides a drawing surface where the snake, food, and game elements are dynamically drawn and updated using JavaScript.

## Conclusion
The Snake game is a fun and interactive way to learn JavaScript while improving your game development skills. By using [HTML5 Canvas](https://tajammalmaqbool.com/pages/blogs/html5-canvas-with-examples.md), [CSS](https://tajammalmaqbool.com/pages/categories/css.md) for styling, and [JavaScript](https://tajammalmaqbool.com/pages/categories/javascript.md) for logic, this project covers essential programming concepts such as event handling, game loops, collision detection, and user interaction.

This gudie provides a solid foundation for building more advanced games. Feel free to experiment with new features, improve the game's mechanics, or even integrate sound effects and animations for a more engaging experience. Happy coding!

> Follow and Support me on [Medium](https://medium.com/@tajammalmaqbool11) and [Patreon](https://www.patreon.com/TajammalMaqbool). Clap and Comment on Medium Posts if you find this helpful for you. Thanks for reading it!!!

---

## Related Articles

- [Learn addEventListener and removeEventListener in JavaScript](https://tajammalmaqbool.com/pages/blogs/addeventlistener-and-removeeventlistener-in-javascript.md)
- [Godot Array - A Comprehensive Guide (GDScript 4.x)](https://tajammalmaqbool.com/pages/blogs/godot-array-a-comprehensive-guide.md)
- [Godot Dictionary - A Comprehensive Guide (GDScript 4.x)](https://tajammalmaqbool.com/pages/blogs/godot-dictionary-a-comprehensive-guide.md)
- [Godot Enum - A Comprehensive Guide (GDScript 4.x)](https://tajammalmaqbool.com/pages/blogs/godot-enum-a-comprehensive-guide.md)
- [Godot vs Unity - A Comprehensive 2025 Guide](https://tajammalmaqbool.com/pages/blogs/godot-vs-unity-a-comprehensive-comparison.md)

## Sitemap

See the full [sitemap](https://tajammalmaqbool.com/sitemap.md) for all pages.
