logo
Build a Bird Game Using HTML, CSS & JavaScript – Complete Tutorial

Step 1: Create a Project Folder

Create a new folder on your system. You can name it anything, for example:

bird-game

 

Step 2: Create index.html

Inside the folder, create a file named:

index.html 

 

Step 3: Copy & Paste the Code

Now copy the complete bird game code (given below) and paste it into index.html.

 Make sure you paste the entire code, including <html>, <style>, and <script> sections.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Simple Bird Game</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(#4facfe, #00f2fe);
      font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    }

    .game-wrapper {
      background: #222;
      padding: 8px;
      border-radius: 16px;
      box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
    }

    #gameCanvas {
      display: block;
      background: linear-gradient(#87ceeb, #e0f7ff);
      border-radius: 12px;
    }

    .info {
      text-align: center;
      margin-top: 8px;
      color: #f5f5f5;
      font-size: 14px;
    }

    .info span.key {
      padding: 2px 6px;
      border-radius: 4px;
      background: rgba(255, 255, 255, 0.12);
      border: 1px solid rgba(255, 255, 255, 0.2);
      font-size: 12px;
    }
  </style>
</head>
<body>
  <div class="game-wrapper">
    <canvas id="gameCanvas" width="420" height="600"></canvas>
    <div class="info">
      Press <span class="key">SPACE</span> / <span class="key">↑</span> or click / tap to jump
    </div>
  </div>

  <script>
    (function () {
      const canvas = document.getElementById("gameCanvas");
      const ctx = canvas.getContext("2d");

      const WIDTH = canvas.width;
      const HEIGHT = canvas.height;

      // Bird properties
      const bird = {
        x: WIDTH * 0.25,
        y: HEIGHT / 2,
        radius: 14,
        vy: 0,
        gravity: 0.5,
        jumpStrength: -8,
      };

      // Pipes
      const pipes = [];
      const PIPE_WIDTH = 70;
      const PIPE_GAP = 140;
      const PIPE_SPEED = 2.5;
      const PIPE_INTERVAL = 180; // frames between pipes

      let frameCount = 0;
      let score = 0;
      let bestScore = 0;

      let gameState = "start"; // "start", "play", "gameover"

      function resetGame() {
        bird.y = HEIGHT / 2;
        bird.vy = 0;
        pipes.length = 0;
        frameCount = 0;
        score = 0;
        gameState = "start";
      }

      function spawnPipe() {
        const minGapY = 80;
        const maxGapY = HEIGHT - 80;
        const gapY = Math.random() * (maxGapY - minGapY) + minGapY;

        pipes.push({
          x: WIDTH + PIPE_WIDTH,
          gapY: gapY,
          passed: false,
        });
      }

      function updateBird() {
        bird.vy += bird.gravity;
        bird.y += bird.vy;

        // Limit fall speed
        if (bird.vy > 12) bird.vy = 12;

        // Prevent going off top
        if (bird.y - bird.radius < 0) {
          bird.y = bird.radius;
          bird.vy = 0;
        }

        // Hit ground
        if (bird.y + bird.radius > HEIGHT) {
          bird.y = HEIGHT - bird.radius;
          gameOver();
        }
      }

      function updatePipes() {
        for (let i = pipes.length - 1; i >= 0; i--) {
          const p = pipes[i];
          p.x -= PIPE_SPEED;

          // Passed the bird (score)
          if (!p.passed && p.x + PIPE_WIDTH < bird.x) {
            p.passed = true;
            score++;
            if (score > bestScore) bestScore = score;
          }

          // Remove offscreen pipes
          if (p.x + PIPE_WIDTH < 0) {
            pipes.splice(i, 1);
          }
        }

        // Spawn new pipes
        if (frameCount % PIPE_INTERVAL === 0) {
          spawnPipe();
        }
      }

      function checkCollisions() {
        for (const p of pipes) {
          const inXRange = bird.x + bird.radius > p.x && bird.x - bird.radius < p.x + PIPE_WIDTH;
          if (!inXRange) continue;

          const topPipeBottom = p.gapY - PIPE_GAP / 2;
          const bottomPipeTop = p.gapY + PIPE_GAP / 2;

          if (bird.y - bird.radius < topPipeBottom || bird.y + bird.radius > bottomPipeTop) {
            gameOver();
            return;
          }
        }
      }

      function jump() {
        if (gameState === "start") {
          gameState = "play";
        }
        if (gameState === "play") {
          bird.vy = bird.jumpStrength;
        } else if (gameState === "gameover") {
          resetGame();
        }
      }

      function gameOver() {
        if (gameState !== "gameover") {
          gameState = "gameover";
        }
      }

      function drawBackground() {
        // Sky is already gradient via canvas background.
        // Draw ground
        const groundHeight = 80;
        ctx.fillStyle = "#5c913b";
        ctx.fillRect(0, HEIGHT - groundHeight, WIDTH, groundHeight);

        // Ground detail
        ctx.fillStyle = "#4a7a30";
        for (let i = 0; i < WIDTH; i += 24) {
          ctx.fillRect(i, HEIGHT - groundHeight + 40, 16, 40);
        }
      }

      function drawPipes() {
        for (const p of pipes) {
          const topPipeBottom = p.gapY - PIPE_GAP / 2;
          const bottomPipeTop = p.gapY + PIPE_GAP / 2;

          // Pipe body
          ctx.fillStyle = "#2ecc71";

          // Top pipe
          ctx.fillRect(p.x, 0, PIPE_WIDTH, topPipeBottom);

          // Bottom pipe
          ctx.fillRect(p.x, bottomPipeTop, PIPE_WIDTH, HEIGHT - bottomPipeTop);

          // Pipe edges
          ctx.fillStyle = "rgba(0,0,0,0.15)";
          ctx.fillRect(p.x, topPipeBottom - 12, PIPE_WIDTH, 12); // top lip
          ctx.fillRect(p.x, bottomPipeTop, PIPE_WIDTH, 12); // bottom lip
        }
      }

      function drawBird() {
        // Bird body
        ctx.beginPath();
        ctx.arc(bird.x, bird.y, bird.radius, 0, Math.PI * 2);
        ctx.fillStyle = "#f1c40f";
        ctx.fill();
        ctx.closePath();

        // Eye
        ctx.beginPath();
        ctx.arc(bird.x + 6, bird.y - 4, 4, 0, Math.PI * 2);
        ctx.fillStyle = "#fff";
        ctx.fill();
        ctx.closePath();

        ctx.beginPath();
        ctx.arc(bird.x + 7, bird.y - 4, 2, 0, Math.PI * 2);
        ctx.fillStyle = "#000";
        ctx.fill();
        ctx.closePath();

        // Beak
        ctx.beginPath();
        ctx.moveTo(bird.x + bird.radius, bird.y);
        ctx.lineTo(bird.x + bird.radius + 10, bird.y - 4);
        ctx.lineTo(bird.x + bird.radius + 10, bird.y + 4);
        ctx.closePath();
        ctx.fillStyle = "#e67e22";
        ctx.fill();

        // Wing
        ctx.beginPath();
        ctx.ellipse(bird.x - 4, bird.y + 2, 8, 6, 0, 0, Math.PI * 2);
        ctx.fillStyle = "#f39c12";
        ctx.fill();
      }

      function drawText() {
        ctx.textAlign = "center";

        // Score top center
        ctx.fillStyle = "rgba(0,0,0,0.3)";
        ctx.font = "bold 32px system-ui, sans-serif";
        ctx.fillText(score, WIDTH / 2 + 2, 52 + 2);
        ctx.fillStyle = "#ffffff";
        ctx.fillText(score, WIDTH / 2, 52);

        if (gameState === "start") {
          ctx.font = "bold 28px system-ui, sans-serif";
          ctx.fillStyle = "#ffffff";
          ctx.fillText("Tap or Press SPACE to Start", WIDTH / 2, HEIGHT / 2 - 20);

          ctx.font = "16px system-ui, sans-serif";
          ctx.fillText("Avoid the pipes and stay in the air!", WIDTH / 2, HEIGHT / 2 + 10);
        } else if (gameState === "gameover") {
          // Overlay
          ctx.fillStyle = "rgba(0,0,0,0.45)";
          ctx.fillRect(0, 0, WIDTH, HEIGHT);

          ctx.fillStyle = "#ffffff";
          ctx.font = "bold 36px system-ui, sans-serif";
          ctx.fillText("Game Over", WIDTH / 2, HEIGHT / 2 - 30);

          ctx.font = "20px system-ui, sans-serif";
          ctx.fillText("Score: " + score, WIDTH / 2, HEIGHT / 2 + 5);
          ctx.fillText("Best: " + bestScore, WIDTH / 2, HEIGHT / 2 + 32);

          ctx.font = "16px system-ui, sans-serif";
          ctx.fillText("Click / Tap / Press SPACE to restart", WIDTH / 2, HEIGHT / 2 + 65);
        }
      }

      function loop() {
        ctx.clearRect(0, 0, WIDTH, HEIGHT);

        drawBackground();

        if (gameState === "play") {
          frameCount++;
          updateBird();
          updatePipes();
          checkCollisions();
        }

        drawPipes();
        drawBird();
        drawText();

        requestAnimationFrame(loop);
      }

      // Input handlers
      document.addEventListener("keydown", function (e) {
        if (e.code === "Space" || e.code === "ArrowUp") {
          e.preventDefault();
          jump();
        }
      });

      canvas.addEventListener("mousedown", function () {
        jump();
      });

      canvas.addEventListener("touchstart", function (e) {
        e.preventDefault();
        jump();
      });

      // Start game
      resetGame();
      loop();
    })();
  </script>
</body>
</html>

 

Step 4: Run the Game Using Live Server

To play the game in your browser:

  1. Open the folder in VS Code
  2. Install the Live Server extension (if not installed)
  3. Right-click on index.html
  4. Click “Open with Live Server”

Your game will open in the browser 

 

How to Play the Game

  • Press SPACE or ↑ Arrow key to make the bird jump
  • Click or Tap on the screen to jump
  • Avoid hitting the pipes
  • Try to beat your best score

 

Features of This Bird Game

  • Smooth canvas animation
  • Gravity & jump physics
  • Random pipe generation
  • Score & best score tracking
  • Works on desktop and mobile
  • Built with pure JavaScript

 

Conclusion

This is a great beginner project to understand:

  • HTML Canvas
  • Game loops
  • Collision detection
  • JavaScript physics logic

You can later enhance it by adding:

  • Sound effects
  • Levels
  • Mobile full-screen mode
  • High-score storage using localStorage
     

 Preview : 
 

Build a Bird Game Using HTML, CSS & JavaScript – Complete Tutorial

I'm a dedicated full-stack developer with expertise in building and managing dynamic web applications across both frontend and backend.

Yash Patel