Build a 2D Breakout Game with Pure JavaScript

Create a classic arcade game from scratch using only JavaScript and HTML5 Canvas--no external libraries required. Master game development fundamentals.

Why Build Games with Pure JavaScript

Creating games is one of the most engaging ways to learn JavaScript, and building a classic Breakout game provides the perfect foundation for understanding game development fundamentals. In this comprehensive guide, we'll walk through creating a fully functional 2D Breakout game using only pure JavaScript and the HTML5 Canvas API--no external libraries or frameworks required. Master game loops, collision detection, and user input handling to build interactive web experiences that captivate users.

The approach we'll take emphasizes learning the core concepts that power every game, from simple animations to complex collision systems. Starting with pure JavaScript gives you a deep understanding of how game mechanics actually work, making it easier to transition to any game framework later if you choose. These fundamentals also apply when you learn to code a website, as the same event-driven patterns and DOM manipulation skills transfer across all JavaScript projects.

The HTML5 Canvas API provides a powerful, hardware-accelerated surface for rendering 2D graphics directly in the browser. As documented in the MDN 2D Breakout Game tutorial, working with pure JavaScript and Canvas gives you complete control over every aspect of your game's behavior. This direct access means you can optimize exactly where needed and build a mental model of game development that scales to any technology stack.

Modern browsers have optimized Canvas rendering to leverage GPU acceleration, making it surprisingly performant for 2D games. The requestAnimationFrame API synchronizes your game loop with the browser's refresh rate, typically 60 frames per second, ensuring smooth animations without the complexity of managing timing manually. For more advanced animation techniques, explore the Web Animations API which provides complementary tools for declarative animations.

What You'll Learn

  • HTML5 Canvas setup and configuration
  • Drawing shapes (rectangles, circles) on canvas
  • Implementing game loops with requestAnimationFrame
  • Ball movement and trajectory physics
  • Collision detection with walls, paddle, and bricks
  • User input handling (keyboard and mouse)
  • Score tracking and game state management
  • Best practices for game performance

Setting Up Your Development Environment

The game's HTML document structure is minimal because the entire game renders on the canvas element. Your HTML file needs a charset declaration for proper character encoding, a title, basic CSS styling, and a canvas element with an ID for JavaScript access. The canvas element requires width and height attributes to define its pixel dimensions, which become the coordinate system for all drawing operations.

As covered in the MDN Canvas tutorial, understanding these fundamentals is essential before building more complex game mechanics. If you're new to HTML, our guide on HTML websites provides a solid foundation for understanding document structure and semantic markup.

index.html - HTML Structure
1<!DOCTYPE html>2<html lang="en-US">3 <head>4 <meta charset="utf-8" />5 <title>Gamedev Canvas Workshop</title>6 <style>7 * {8 padding: 0;9 margin: 0;10 }11 canvas {12 background: #eeeeee;13 display: block;14 margin: 0 auto;15 }16 </style>17 </head>18 <body>19 <canvas id="myCanvas" width="480" height="320"></canvas>20 <script>21 // JavaScript code goes here22 </script>23 </body>24</html>

Understanding the Canvas Coordinate System

The canvas uses a coordinate system where the origin (0, 0) is at the top-left corner of the canvas. X values increase to the right, and Y values increase downward. This is different from traditional Cartesian coordinates where Y increases upward, but it's the standard for computer graphics because it matches how screens draw pixels from top to bottom.

  • Origin (0, 0): Top-left corner
  • X-axis: Increases to the right
  • Y-axis: Increases downward

When specifying coordinates for drawing operations, all positions are relative to the canvas's coordinate system. A point at (100, 50) would be 100 pixels from the left edge and 50 pixels from the top edge. Understanding this coordinate system is essential because it affects every drawing and collision detection operation in your game.

Drawing on the Canvas

Before you can draw on the canvas, you need to obtain a reference to the canvas element and its 2D rendering context. The context provides all the methods and properties needed for drawing shapes, text, images, and other graphical elements. This two-step process separates canvas creation from drawing operations, allowing for flexible and organized code.

The CanvasRenderingContext2D API provides the complete reference for all 2D drawing operations available in the browser.

Getting the Canvas Context
1const canvas = document.getElementById("myCanvas");2const ctx = canvas.getContext("2d");
Canvas Drawing Fundamentals

Drawing Rectangles

Use rect() to define rectangles, fillRect() to fill, or strokeRect() for outlines.

Drawing Circles

Use arc() method with radius, start angle, and end angle parameters.

Color Specification

Support for named colors, hex, RGB, RGBA, and modern CSS color syntax.

Path Management

Use beginPath() and closePath() to properly manage drawing state.

Drawing a Rectangle
1ctx.beginPath();2ctx.rect(20, 40, 50, 50); // x, y, width, height3ctx.fillStyle = "red";4ctx.fill();5ctx.closePath();
Drawing a Circle
1ctx.beginPath();2ctx.arc(240, 160, 20, 0, Math.PI * 2, false);3ctx.fillStyle = "green";4ctx.fill();5ctx.closePath();6 7// Parameters:8// - x, y: Center coordinates9// - radius: Circle radius10// - startAngle: Starting angle in radians11// - endAngle: Ending angle in radians12// - counterclockwise: true/false (optional)

Creating the Game Loop

A game loop is the heartbeat of any game, continuously updating game state and rendering graphics. In modern JavaScript game development, the requestAnimationFrame API is the preferred method for implementing game loops because it synchronizes with the browser's refresh rate (typically 60Hz), pauses when the tab is inactive to save battery, and provides smooth, consistent animations.

As explained in the MDN animation guide, this approach provides significant advantages over older techniques like setInterval.

Basic Game Loop
1function gameLoop() {2 // Update game state3 update();4 5 // Render graphics6 draw();7 8 // Schedule next frame9 requestAnimationFrame(gameLoop);10}11 12// Start the loop13requestAnimationFrame(gameLoop);
Clearing the Canvas
1function draw() {2 // Clear the entire canvas before each frame3 ctx.clearRect(0, 0, canvas.width, canvas.height);4 5 // Draw game elements6 drawBall();7 drawPaddle();8 drawBricks();9 drawScore();10}

Implementing Ball Movement

A ball in a Breakout game requires several properties: position (x, y), velocity (dx, dy), radius, and color. Defining these as a consistent structure helps organize code and makes it easy to modify ball behavior. Starting the ball near the bottom center of the canvas, with a slight upward velocity (negative dy because Y increases downward), creates a natural starting position for gameplay.

Ball Properties
1let ball = {2 x: canvas.width / 2,3 y: canvas.height - 30,4 dx: 2,5 dy: -2,6 radius: 10,7 color: "#0095DD"8};
Updating Ball Position
1// On each frame, update position by adding velocity2ball.x += ball.dx;3ball.y += ball.dy;4 5// The order matters:6// Update position first, then check for collisions7// This allows accurate boundary detection

Implementing Collision Detection

Collision detection is crucial for any game. The ball needs to bounce off walls, the paddle, and destroy bricks when hit. Each type of collision has its own logic. This collision logic uses the ball's radius to detect when the ball's edge touches a wall, not just its center point, creating more accurate collision detection.

The MDN Breakout game tutorial provides comprehensive coverage of these collision patterns and their implementation.

Wall Collision Detection
1function checkWallCollisions() {2 // Right and left walls3 if (ball.x + ball.dx > canvas.width - ball.radius ||4 ball.x + ball.dx < ball.radius) {5 ball.dx = -ball.dx;6 }7 8 // Top wall9 if (ball.y + ball.dy < ball.radius) {10 ball.dy = -ball.dy;11 }12 13 // Bottom wall - game over condition14 else if (ball.y + ball.dy > canvas.height - ball.radius) {15 // Check if paddle hit16 if (ball.x > paddle.x && ball.x < paddle.x + paddle.width) {17 ball.dy = -ball.dy;18 }19 else {20 // Ball hit bottom without paddle - lose life21 lives--;22 if (!lives) {23 gameOver();24 }25 else {26 resetBall();27 }28 }29 }30}
Brick Collision Detection
1function checkBrickCollisions() {2 for (let c = 0; c < brickColumnCount; c++) {3 for (let r = 0; r < brickRowCount; r++) {4 const brick = bricks[c][r];5 if (brick.status === 1) { // Only check active bricks6 if (ball.x > brick.x &&7 ball.x < brick.x + brickWidth &&8 ball.y > brick.y &&9 ball.y < brick.y + brickHeight) {10 ball.dy = -ball.dy;11 brick.status = 0; // Mark brick as destroyed12 score++;13 14 // Check win condition15 if (score === brickRowCount * brickColumnCount) {16 winGame();17 }18 }19 }20 }21 }22}

Adding User Controls

Responding to keyboard input requires listening for keydown and keyup events. Store the state of relevant keys in boolean variables that your game loop can check. Using boolean flags for key states creates smooth, responsive movement. The paddle continues moving as long as the key remains pressed, and stops immediately when released. This approach handles multiple keys being pressed simultaneously and avoids the key-repeat delay.

Keyboard Controls
1let rightPressed = false;2let leftPressed = false;3 4document.addEventListener("keydown", keyDownHandler, false);5document.addEventListener("keyup", keyUpHandler, false);6 7function keyDownHandler(e) {8 if (e.key === "Right" || e.key === "ArrowRight") {9 rightPressed = true;10 }11 else if (e.key === "Left" || e.key === "ArrowLeft") {12 leftPressed = true;13 }14}15 16function keyUpHandler(e) {17 if (e.key === "Right" || e.key === "ArrowRight") {18 rightPressed = false;19 }20 else if (e.key === "Left" || e.key === "ArrowLeft") {21 leftPressed = false;22 }23}
Mouse Controls (Alternative)
1document.addEventListener("mousemove", mouseMoveHandler, false);2 3function mouseMoveHandler(e) {4 const relativeX = e.clientX - canvas.offsetLeft;5 if (relativeX > 0 && relativeX < canvas.width) {6 paddle.x = relativeX - paddle.width / 2;7 }8}

Tracking Game Progress

Display and track the player's score and remaining lives. This creates engagement and gives players clear goals to work toward. When a life is lost, reset both the ball and paddle to their starting positions, giving the player a fresh attempt. When lives reach zero, trigger the game-over sequence and offer the option to restart.

Score and Lives System
1let score = 0;2let lives = 3;3 4function drawScore() {5 ctx.font = "16px Arial";6 ctx.fillStyle = "#0095DD";7 ctx.fillText("Score: " + score, 8, 20);8}9 10function drawLives() {11 ctx.font = "16px Arial";12 ctx.fillStyle = "#0095DD";13 ctx.fillText("Lives: " + lives, canvas.width - 65, 20);14}15 16function resetBall() {17 ball.x = canvas.width / 2;18 ball.y = canvas.height - 30;19 ball.dx = 2;20 ball.dy = -2;21 paddle.x = (canvas.width - paddle.width) / 2;22}

Best Practices for JavaScript Game Performance

Building performant games requires attention to several key areas. Here are essential practices for smooth gameplay and optimal resource usage. The game loop is where most of your game's computational work happens--keep it lean by separating update logic from rendering, minimizing object creation within the loop, and using requestAnimationFrame for consistent frame timing.

Performance Optimization Tips

Optimize Game Loop

Keep the loop lean by separating update logic from rendering.

Efficient Collision

Skip collision checks for destroyed bricks using status flags.

Avoid Garbage

Don't create new objects in the game loop to reduce GC pauses.

Handle Edge Cases

Test on different browsers, handle resize events gracefully.

Extending Your Game

Once the basic Breakout game is working, consider adding features to enhance gameplay and create a more complete experience. These extensions build on the fundamental concepts covered in this guide and demonstrate how to expand a simple game into a polished interactive application. Whether you're building for fun or as a portfolio piece, these additions show advanced understanding of game development principles.

Power-ups

Add special bricks that grant abilities like multi-ball, paddle expansion, or score multipliers.

Levels

Create progressive difficulty with faster ball speed, more brick rows, or moving obstacles.

Sound Effects

Add audio feedback for paddle hits, brick destruction, and game events.

Particle Effects

Create visual flair when bricks are destroyed for a more polished feel.

High Scores

Implement localStorage-based persistent high score tracking.

Animation Effects

Add smooth transitions, screen shake, or slow-motion effects.

Complete Code Overview

The complete Breakout game combines all the elements covered in this guide into a cohesive implementation. This structure--setup, update, draw, repeat--is the foundation of most games and will serve you well as you explore more complex game development projects.

Complete Breakout Game
1// Canvas setup2const canvas = document.getElementById("myCanvas");3const ctx = canvas.getContext("2d");4 5// Game variables6let x = canvas.width / 2;7let y = canvas.height - 30;8let dx = 2;9let dy = -2;10const ballRadius = 10;11 12// Game loop13function draw() {14 ctx.clearRect(0, 0, canvas.width, canvas.height);15 drawBall();16 drawPaddle();17 drawBricks();18 drawScore();19 drawLives();20 21 // Collision detection22 checkWallCollisions();23 checkBrickCollisions();24 25 // Update position26 x += dx;27 y += dy;28 29 requestAnimationFrame(draw);30}31 32// Start the game33draw();

Conclusion

Building a 2D Breakout game with pure JavaScript teaches fundamental game development concepts that transfer to any technology stack or framework. You've learned how to:

  • Set up a rendering canvas and obtain the 2D context
  • Draw shapes using the Canvas API
  • Implement smooth animations with requestAnimationFrame
  • Detect collisions with walls, paddle, and bricks
  • Handle user input for keyboard and mouse controls
  • Track game progress with score and lives
  • Structure code for maintainability and performance

The pure JavaScript approach gives you complete control over every aspect of your game's behavior and a deep understanding of how game mechanics actually work. Whether you continue building games with JavaScript or move to other languages and engines, the concepts covered here will serve as a valuable foundation for your development journey.

Start with the basic implementation and gradually add features as you become more comfortable with the code. Game development is a creative process, and there's no single "right" way to build a game. Experiment, iterate, and most importantly--have fun bringing your ideas to life!

Ready to Build More Web Experiences?

Our team of JavaScript experts can help you create interactive web applications, games, and custom solutions tailored to your business needs. From simple interactive components to complex web applications, we bring your vision to life.

Frequently Asked Questions

Do I need any external libraries to build this game?

No, this entire game can be built using only pure JavaScript and the HTML5 Canvas API. No external libraries or frameworks are required, making it perfect for learning game development fundamentals.

What's the difference between setInterval and requestAnimationFrame?

requestAnimationFrame synchronizes with the browser's refresh rate for smooth animations, pauses when the tab is inactive to save resources, and provides better performance overall. setInterval runs at a fixed interval regardless of display refresh rate.

How do I make the ball bounce at different angles?

You can modify the ball's horizontal velocity (dx) based on where it hits the paddle. Hitting the edge of the paddle can increase horizontal speed, while hitting the center keeps it steady, adding strategic depth to gameplay.

Can I use this code in a production project?

Absolutely! This code demonstrates production-ready patterns for game development. The collision detection, game loop, and input handling patterns are all applicable to real-world projects.

Sources

  1. MDN Web Docs: 2D Breakout Game Pure JavaScript - Official step-by-step tutorial for building a complete Breakout game
  2. MDN: Create the Canvas and draw on it - Foundation lesson covering HTML structure and basic drawing operations
  3. MDN: Move the ball - Animation fundamentals including game loops and ball movement logic
  4. MDN Canvas API Reference - Complete reference for all 2D drawing operations
  5. MDN requestAnimationFrame API - API documentation for smooth, performance-optimized animations