🎮 Get a game · $19

🧱 Free game 7 of 20 · copy & paste

Breakout Game in HTML & JavaScript (Brick Breaker): Free Code

Breakout, the brick breaker classic: bounce the ball off your paddle and break every brick. Levels get faster, and the bounce angle depends on where the ball hits the paddle. Copy the code below, save it as breakout.html and open it in any browser.

Type
Arcade
Level
Intermediate
Code
140 lines, 1 file
Libraries
None
Works on
Phones & computers
You learn
Ball physics and circle–rectangle collision

▲ Play it right here. Move the mouse or drag your finger (or ← →). Click, tap or Space to launch.

What's in this free Breakout game

The code (140 lines, one file)

breakout.html⬇ Download
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Breakout Game</title>
<!--
  Free HTML Breakout (brick breaker) game — one file, no libraries. Save it as breakout.html and open it in a browser.
  From htmlgamescode.com (free to use in your own projects).
  Controls: move the mouse or drag your finger to move the paddle (or use the arrow keys). Click / tap / Space to launch.
-->
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #1b1446;
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif; user-select: none; -webkit-user-select: none; touch-action: none;
  }
  canvas { display: block; width: min(96vw, 400px, calc((100vh - 16px) * 2 / 3)); aspect-ratio: 2 / 3; border-radius: 18px; background: #120d35; box-shadow: 0 0 0 4px #382c8f, 0 18px 40px rgba(0,0,0,.4); }
</style>
</head>
<body>
<canvas id="game" width="360" height="540"></canvas>

<script>
  // ---- settings: change these to make it your own ----
  const ROWS = 6;                // rows of bricks
  const COLS = 7;                // bricks per row
  const LIVES = 3;               // balls you start with
  const BALL_SPEED = 5;          // starting ball speed (+10% every level)
  const PADDLE_WIDTH = 80;       // paddle size in pixels
  const ROW_COLORS = ["#ff4d6d", "#ff8a3d", "#ffd23f", "#36d35a", "#3fa6ff", "#b46bff"];   // one color per row

  const canvas = document.getElementById("game"), ctx = canvas.getContext("2d");
  const W = canvas.width, H = canvas.height, PADDLE_Y = H - 40, BW = (W - 20) / COLS, BH = 20;
  const load = k => { try { return Number(localStorage.getItem(k)) || 0; } catch { return 0; } };
  const save = (k, v) => { try { localStorage.setItem(k, v); } catch {} };

  let bricks, ball, paddleX, lives, score, level, state, best = load("breakout-best");
  const keys = {};

  function buildBricks() {
    bricks = [];
    for (let r = 0; r < ROWS; r++) for (let c = 0; c < COLS; c++)
      bricks.push({ x: 10 + c * BW, y: 60 + r * (BH + 6), alive: true, color: ROW_COLORS[r % ROW_COLORS.length], points: (ROWS - r) * 10 });
  }
  function newGame() { lives = LIVES; score = 0; level = 1; paddleX = W / 2; buildBricks(); serve(); }
  function serve() { state = "ready"; ball = { x: paddleX, y: PADDLE_Y - 10, vx: 0, vy: 0, r: 8 }; }
  function launch() {
    if (state === "over" || state === "won") return newGame();
    if (state !== "ready") return;
    const speed = BALL_SPEED * (1 + (level - 1) * 0.1), angle = -Math.PI / 2 + (Math.random() - 0.5) * 0.8;
    ball.vx = Math.cos(angle) * speed; ball.vy = Math.sin(angle) * speed; state = "play";
  }

  function update() {
    if (keys.ArrowLeft) paddleX -= 7;
    if (keys.ArrowRight) paddleX += 7;
    paddleX = Math.max(PADDLE_WIDTH / 2, Math.min(W - PADDLE_WIDTH / 2, paddleX));
    if (state === "ready") { ball.x = paddleX; return; }
    if (state !== "play") return;

    ball.x += ball.vx; ball.y += ball.vy;
    if (ball.x < ball.r || ball.x > W - ball.r) { ball.vx *= -1; ball.x = Math.max(ball.r, Math.min(W - ball.r, ball.x)); }
    if (ball.y < ball.r) { ball.vy = Math.abs(ball.vy); }

    // paddle: where the ball lands decides the bounce angle
    if (ball.vy > 0 && ball.y + ball.r >= PADDLE_Y && ball.y < PADDLE_Y + 12 && Math.abs(ball.x - paddleX) < PADDLE_WIDTH / 2 + ball.r) {
      const hit = (ball.x - paddleX) / (PADDLE_WIDTH / 2), speed = Math.hypot(ball.vx, ball.vy);
      const angle = -Math.PI / 2 + hit * 1.05;
      ball.vx = Math.cos(angle) * speed; ball.vy = Math.sin(angle) * speed;
      ball.y = PADDLE_Y - ball.r;
    }

    for (const b of bricks) {
      if (!b.alive) continue;
      const nx = Math.max(b.x, Math.min(ball.x, b.x + BW - 4)), ny = Math.max(b.y, Math.min(ball.y, b.y + BH));
      if ((ball.x - nx) ** 2 + (ball.y - ny) ** 2 > ball.r ** 2) continue;
      b.alive = false; score += b.points;
      // bounce off the side we hit most squarely
      const overlapX = Math.min(Math.abs(ball.x - b.x), Math.abs(ball.x - (b.x + BW - 4)));
      const overlapY = Math.min(Math.abs(ball.y - b.y), Math.abs(ball.y - (b.y + BH)));
      if (overlapX < overlapY) ball.vx *= -1; else ball.vy *= -1;
      break;
    }

    if (bricks.every(b => !b.alive)) { level++; buildBricks(); serve(); }
    if (ball.y > H + ball.r) {
      lives--;
      if (lives > 0) serve();
      else { state = "over"; if (score > best) { best = score; save("breakout-best", best); } }
    }
  }

  function draw() {
    ctx.clearRect(0, 0, W, H);
    for (const b of bricks) if (b.alive) {
      ctx.fillStyle = b.color; ctx.beginPath();
      ctx.roundRect ? ctx.roundRect(b.x, b.y, BW - 4, BH, 5) : ctx.rect(b.x, b.y, BW - 4, BH);
      ctx.fill();
      ctx.fillStyle = "rgba(255,255,255,.25)"; ctx.fillRect(b.x + 3, b.y + 3, BW - 10, 4);
    }
    ctx.fillStyle = "#fff"; ctx.beginPath();
    ctx.roundRect ? ctx.roundRect(paddleX - PADDLE_WIDTH / 2, PADDLE_Y, PADDLE_WIDTH, 12, 6) : ctx.rect(paddleX - PADDLE_WIDTH / 2, PADDLE_Y, PADDLE_WIDTH, 12);
    ctx.fill();
    ctx.fillStyle = "#ffd23f"; ctx.beginPath(); ctx.arc(ball.x, ball.y, ball.r, 0, 7); ctx.fill();

    ctx.fillStyle = "#fff"; ctx.font = "700 16px system-ui, sans-serif";
    ctx.textAlign = "left"; ctx.fillText(`Score ${score}`, 12, 30);
    ctx.textAlign = "center"; ctx.fillText(`Level ${level}`, W / 2, 30);
    ctx.textAlign = "right"; ctx.fillText("❤".repeat(Math.max(0, lives)), W - 12, 30);
    ctx.textAlign = "center";
    if (state === "ready") { ctx.font = "700 20px system-ui, sans-serif"; ctx.fillText("Tap or press Space to launch", W / 2, H / 2 + 60); }
    if (state === "over") {
      ctx.fillStyle = "rgba(10,6,36,.75)"; ctx.fillRect(0, 0, W, H); ctx.fillStyle = "#fff";
      ctx.font = "900 38px system-ui, sans-serif"; ctx.fillText("Game over", W / 2, H / 2 - 20);
      ctx.font = "700 20px system-ui, sans-serif"; ctx.fillText(`Score ${score} · Best ${best}`, W / 2, H / 2 + 20); ctx.fillText("Tap to play again", W / 2, H / 2 + 60);
    }
  }

  let last = 0, acc = 0;
  function loop(t) {
    acc += Math.min(100, t - (last || t)); last = t;
    while (acc >= 1000 / 60) { update(); acc -= 1000 / 60; }
    draw();
    requestAnimationFrame(loop);
  }

  const toCanvasX = e => { const r = canvas.getBoundingClientRect(); return (e.clientX - r.left) * W / r.width; };
  canvas.addEventListener("pointermove", e => { paddleX = toCanvasX(e); });
  canvas.addEventListener("pointerdown", e => { e.preventDefault(); paddleX = toCanvasX(e); launch(); });
  document.addEventListener("keydown", e => {
    if (e.key === " ") { e.preventDefault(); launch(); }
    if (e.key.startsWith("Arrow")) { e.preventDefault(); keys[e.key] = true; }
  });
  document.addEventListener("keyup", e => { keys[e.key] = false; });
  newGame();
  requestAnimationFrame(loop);
</script>
</body>
</html>

How to use it

  1. Click Copy code (or Download).
  2. Paste it into any text editor and save it as breakout.html.
  3. Open the file in Chrome, Safari, Firefox or Edge. That's it, it runs offline.

How the code works

Moving the ball

The ball has a speed on x and y. Hitting a wall flips one of them.

Paddle angle

Where the ball lands on the paddle (−1 at the left edge, +1 at the right) sets the bounce angle, so you can aim.

Brick collision

For each brick the code finds the closest point of the rectangle to the ball's centre. If it is closer than the radius, the brick breaks and the ball bounces off the side it hit.

Make it your own

All the settings are at the top of the script. Change a value, save and reload:

SettingDefaultWhat it does
ROWS6rows of bricks
COLS7bricks per row
LIVES3balls you start with
BALL_SPEED5starting ball speed (+10% every level)
PADDLE_WIDTH80paddle size in pixels
ROW_COLORSa listone color per row

Put it on your website

Upload breakout.html next to your page and add this where the game should appear:

<iframe src="breakout.html" width="460" height="620" style="border:0;max-width:100%" title="Breakout game"></iframe>

FAQ

Is this Breakout code really free?

Yes. Copy it and use it in your own website, school project or app, change it as much as you like and publish it, even commercially. A link back to HTML Games Code is welcome but not required.

How do I run the Breakout game?

Copy the code, paste it into a text editor, save the file as breakout.html and double-click it. It opens in your browser and works offline; there is nothing to install.

What are the controls?

Move the mouse or drag your finger (or ← →). Click, tap or Space to launch.

Does it work on phones?

Yes. It has touch controls and fits a phone screen, and it works with a keyboard and mouse on a computer.

Can I put it on my website?

Yes. Upload breakout.html and link to it, or show it inside an iframe on any page (see "Put it on your website" above).

Can I turn it into an Android app?

Yes. Any HTML game can be packaged as an Android APK. Our HTML Games APK Builder does it for our premium games, or you can use a tool like htmltoapk.com for this file.

More free HTML games