Retro Snake Game in JavaScript: 5 Easy Steps to Build Your Fun 2025 Tutorial

Retro Snake Game in JavaScript: 5 Easy Steps to Build Your Fun 2025 Tutorial

Have you ever wanted to build a retro snake game in JavaScript? 🐍 It’s one of the best beginner-friendly projects to learn HTML, CSS, and JS. This tutorial will guide you step-by-step, with space to add your own code snippets, images, and videos.

Fun fact: The original Snake game was launched in 1976 and became popular on Nokia phones in the late ’90s. Imagine creating your own modern version in 2025!

By the end, you’ll have a fully playable game that’s responsive, mobile-friendly, and ready for customization.

Click Here to check the live demo

Setting Up Your HTML Structure

Overview: Prepare the HTML skeleton for the game.

  • Create a basic HTML5 document with semantic tags

  • Add a <canvas> element for the game

  • Include placeholders for score display and game messages

  • Add buttons for mobile controls

HTML Code Placeholder:

				
					<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Retro Snake</title>
    <script src="https://cdn.tailwindcss.com"></script>
    </head>
<body>
    <div class="game-container">
        <div class="game-info">Score: <span id="score">0</span></div>
        <canvas id="gameCanvas" width="400" height="400"></canvas>
        <div id="gameMessage" class="game-message hidden">Press any arrow key or button to start!</div>

        <!-- Mobile Controls -->
        <div class="control-buttons">
            <button class="control-button up" data-direction="UP">▲</button>
            <button class="control-button left" data-direction="LEFT">◀</button>
            <button class="control-button right" data-direction="RIGHT">▶</button>
            <button class="control-button down" data-direction="DOWN">▼</button>
        </div>
    </div>
    </body>
</html>
				
			

Styling the Game with CSS

Overview: Make your game visually appealing and retro.

  • Set background and canvas colors

  • Style the snake, food, and borders

  • Make the game responsive for mobile screens

  • Add glow and shadow effects for a retro feel

CSS Code Placeholder:

				
					    <style>
        body {
            font-family: 'Inter', sans-serif;
            background-color: #1a202c; /* Dark background */
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            overflow: hidden; /* Prevent scrollbars */
        }
        canvas {
            background-color: #2d3748; /* Slightly lighter dark for canvas */
            border: 4px solid #4a5568; /* Retro border */
            border-radius: 8px;
            box-shadow: 0 0 20px rgba(0, 255, 255, 0.5); /* Glowing effect */
            display: block;
            touch-action: manipulation; /* Allow touch events for mobile controls */
        }
        .game-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 16px;
            padding: 20px;
            background-color: #2d3748;
            border-radius: 12px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        }
        .game-info {
            color: #e2e8f0;
            font-size: 1.25rem;
            font-weight: bold;
            text-align: center;
        }
        .game-message {
            color: #e2e8f0;
            font-size: 1.5rem;
            font-weight: bold;
            text-align: center;
            margin-top: 10px;
        }
        .control-buttons {
            display: grid;
            grid-template-areas:
                ". up ."
                "left . right"
                ". down .";
            gap: 10px;
            margin-top: 20px;
        }
        .control-button {
            background-color: #4a5568;
            color: #e2e8f0;
            padding: 15px 20px;
            border-radius: 8px;
            font-size: 1.2rem;
            font-weight: bold;
            cursor: pointer;
            transition: background-color 0.2s, transform 0.1s;
            box-shadow: 0 4px #2d3748;
            border: none;
            user-select: none; /* Prevent text selection */
        }
        .control-button:active {
            transform: translateY(2px);
            box-shadow: 0 2px #2d3748;
        }
        .control-button.up { grid-area: up; }
        .control-button.left { grid-area: left; }
        .control-button.right { grid-area: right; }
        .control-button.down { grid-area: down; }

        @media (max-width: 600px) {
            .game-container {
                padding: 10px;
                gap: 10px;
            }
            .game-info {
                font-size: 1rem;
            }
            .game-message {
                font-size: 1.2rem;
            }
            .control-button {
                padding: 10px 15px;
                font-size: 1rem;
            }
        }
    </style>
				
			

Writing the JavaScript Logic

Overview: Make the snake move, eat food, and detect collisions.

  • Define game variables: snake, food, direction, score

  • Draw snake and food on the canvas

  • Update game state with a game loop

  • Handle keyboard and mobile button input

  • Detect collisions (walls and self)

JavaScript Code Placeholder:

				
					    <script>
        // Get canvas and its 2D rendering context
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const scoreDisplay = document.getElementById('score');
        const gameMessage = document.getElementById('gameMessage');
        const controlButtons = document.querySelectorAll('.control-button');

        // Game constants and variables
        const gridSize = 20; // Size of each "pixel" block
        let snake = [{ x: 10, y: 10 }]; // Initial snake position
        let food = {}; // Food position
        let direction = 'RIGHT'; // Initial direction
        let score = 0;
        let gameOver = true;
        let gameInterval; // To hold the game loop interval ID

        // Function to generate random coordinates for food
        function generateFood() {
            food = {
                x: Math.floor(Math.random() * (canvas.width / gridSize)),
                y: Math.floor(Math.random() * (canvas.height / gridSize))
            };
        }

        // Function to draw a single game block (snake segment or food)
        function drawBlock(x, y, color) {
            ctx.fillStyle = color;
            ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
            ctx.strokeStyle = '#2d3748'; // Darker border for pixel effect
            ctx.strokeRect(x * gridSize, y * gridSize, gridSize, gridSize);
        }

        // Main drawing function
        function drawGame() {
            ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas

            // Draw snake
            snake.forEach((segment, index) => {
                drawBlock(segment.x, segment.y, index === 0 ? '#48bb78' : '#68d391'); // Head is darker green
            });

            // Draw food
            drawBlock(food.x, food.y, '#f6e05e'); // Yellow food
        }

        // Main game update logic
        function updateGame() {
            if (gameOver) return;

            // Move the snake's head
            const head = { x: snake[0].x, y: snake[0].y };
            switch (direction) {
                case 'UP': head.y--; break;
                case 'DOWN': head.y++; break;
                case 'LEFT': head.x--; break;
                case 'RIGHT': head.x++; break;
            }

            // Check for game over conditions
            // Wall collision
            if (head.x < 0 || head.x >= canvas.width / gridSize ||
                head.y < 0 || head.y >= canvas.height / gridSize) {
                endGame();
                return;
            }

            // Self-collision
            for (let i = 1; i < snake.length; i++) {
                if (head.x === snake[i].x && head.y === snake[i].y) {
                    endGame();
                    return;
                }
            }

            // Add new head
            snake.unshift(head);

            // Check if food is eaten
            if (head.x === food.x && head.y === food.y) {
                score++;
                scoreDisplay.textContent = score;
                generateFood(); // Generate new food
            } else {
                snake.pop(); // Remove tail if no food eaten
            }

            drawGame(); // Redraw game elements
        }

        // Function to handle game over
        function endGame() {
            gameOver = true;
            clearInterval(gameInterval); // Stop the game loop
            gameMessage.textContent = `Game Over! Score: ${score}. Press any arrow key or button to restart!`;
            gameMessage.classList.remove('hidden');
        }

        // Function to reset and start a new game
        function resetGame() {
            snake = [{ x: 10, y: 10 }];
            direction = 'RIGHT';
            score = 0;
            scoreDisplay.textContent = score;
            gameOver = false;
            gameMessage.classList.add('hidden');
            generateFood();
            drawGame();
            if (gameInterval) clearInterval(gameInterval); // Clear any existing interval
            gameInterval = setInterval(updateGame, 150); // Start game loop (adjust speed here)
        }

        // Event listener for keyboard input
        document.addEventListener('keydown', e => {
            if (gameOver) {
                resetGame();
                return;
            }
            const newDirection = e.key.replace('Arrow', '').toUpperCase();
            // Prevent snake from reversing directly
            if ((newDirection === 'UP' && direction !== 'DOWN') ||
                (newDirection === 'DOWN' && direction !== 'UP') ||
                (newDirection === 'LEFT' && direction !== 'RIGHT') ||
                (newDirection === 'RIGHT' && direction !== 'LEFT')) {
                direction = newDirection;
            }
        });

        // Event listeners for mobile control buttons
        controlButtons.forEach(button => {
            button.addEventListener('click', () => {
                if (gameOver) {
                    resetGame();
                    return;
                }
                const newDirection = button.dataset.direction;
                if ((newDirection === 'UP' && direction !== 'DOWN') ||
                    (newDirection === 'DOWN' && direction !== 'UP') ||
                    (newDirection === 'LEFT' && direction !== 'RIGHT') ||
                    (newDirection === 'RIGHT' && direction !== 'LEFT')) {
                    direction = newDirection;
                }
            });
        });

        // Initial setup when the window loads
        window.onload = function() {
            generateFood();
            drawGame();
            gameMessage.textContent = "Press any arrow key or button to start!";
            gameMessage.classList.remove('hidden');
            // Game starts only when user presses a key/button
        };
    </script>
				
			

Conclusion

Building a retro snake game in JavaScript is a fun and educational project! 🕹️ You now have a full tutorial structure with placeholders for HTML, CSS, and JS code, plus SEO-friendly content.

Experiment with speed, colors, and mobile controls to make your game unique. Share your creation and continue learning!

 

Find Out Our more Simple Amazing Projects 

SHARE

Leave a Reply

Your email address will not be published. Required fields are marked *