๐ŸŽฎ Get a game ยท $19

๐Ÿ Free game ยท copy & paste

Free HTML Game Code (Copy and Paste): Snake

A complete Snake game in a single HTML file: no libraries, no images, no setup. Copy the code below, save it as snake.html and open it in any browser.

โ–ฒ Play it right here. Arrow keys, swipe, or the buttons.

What's in this free Snake game

The code (151 lines, one file)

snake.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>Snake Game</title>
<!--
  Free HTML Snake game โ€” one file, no libraries. Copy it, save as snake.html, open in a browser.
  From htmlgamescode.com (free to use in your own projects).
  Controls: arrow keys / WASD, swipe on phones, or the on-screen buttons. Space = pause.
-->
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
    background: #1b1446; color: #fff; font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    user-select: none; -webkit-user-select: none; touch-action: none; padding: 12px;
  }
  .bar { width: min(92vw, 420px); display: flex; justify-content: space-between; align-items: center; font-weight: 700; }
  .bar span { background: #2a2170; padding: 6px 12px; border-radius: 10px; }
  canvas { width: min(92vw, 420px); aspect-ratio: 1; border-radius: 16px; background: #120d35; box-shadow: 0 0 0 4px #382c8f, 0 18px 40px rgba(0,0,0,.4); }
  .pad { display: grid; grid-template-columns: repeat(3, 64px); gap: 8px; }
  .pad button {
    height: 56px; border: 0; border-radius: 14px; background: #382c8f; color: #fff; font-size: 24px; cursor: pointer;
    box-shadow: 0 4px 0 #20185a;
  }
  .pad button:active { transform: translateY(3px); box-shadow: 0 1px 0 #20185a; }
  .pad .up { grid-column: 2; } .pad .left { grid-column: 1; grid-row: 2; } .pad .down { grid-column: 2; grid-row: 2; } .pad .right { grid-column: 3; grid-row: 2; }
  .msg { position: fixed; inset: 0; display: grid; place-items: center; background: rgba(10, 6, 36, .7); }
  .msg[hidden] { display: none; }
  .card { text-align: center; background: #2a2170; padding: 26px 30px; border-radius: 20px; }
  .card h1 { font-size: 30px; margin-bottom: 6px; }
  .card p { opacity: .85; margin-bottom: 16px; }
  .card button { border: 0; border-radius: 14px; padding: 12px 28px; font-size: 18px; font-weight: 700; color: #fff; background: #36d35a; box-shadow: 0 4px 0 #1d9a3a; cursor: pointer; }
</style>
</head>
<body>
  <div class="bar"><span>Score: <b id="score">0</b></span><span>Best: <b id="best">0</b></span></div>
  <canvas id="game" width="400" height="400"></canvas>
  <div class="pad">
    <button class="up" data-dir="up" aria-label="Up">โ–ฒ</button>
    <button class="left" data-dir="left" aria-label="Left">โ—€</button>
    <button class="down" data-dir="down" aria-label="Down">โ–ผ</button>
    <button class="right" data-dir="right" aria-label="Right">โ–ถ</button>
  </div>
  <div class="msg" id="msg"><div class="card"><h1 id="title">๐Ÿ Snake</h1><p id="text">Eat the apples, don't hit the walls or yourself.</p><button id="play">Play</button></div></div>

<script>
  // ---- settings: change these to make it your own ----
  const GRID = 20;               // cells per side
  const START_SPEED = 140;       // ms per move (lower = faster)
  const SPEED_UP = 3;            // ms faster after each apple
  const MIN_SPEED = 60;          // fastest allowed
  const COLORS = { snake: "#36d35a", head: "#7dff5a", apple: "#ff5f8f", grid: "rgba(255,255,255,.04)" };

  const canvas = document.getElementById("game"), ctx = canvas.getContext("2d");
  const CELL = canvas.width / GRID;
  const $ = id => document.getElementById(id);
  const DIRS = { up: [0, -1], down: [0, 1], left: [-1, 0], right: [1, 0] };

  let snake, dir, nextDir, apple, score, speed, timer = null, paused = false;
  let best = Number(localStorage.getItem("snake-best") || 0);
  $("best").textContent = best;

  function reset() {
    snake = [{ x: 8, y: 10 }, { x: 7, y: 10 }, { x: 6, y: 10 }];
    dir = nextDir = "right";
    score = 0; speed = START_SPEED; $("score").textContent = 0;
    placeApple();
  }

  function placeApple() {
    do { apple = { x: Math.floor(Math.random() * GRID), y: Math.floor(Math.random() * GRID) }; }
    while (snake.some(s => s.x === apple.x && s.y === apple.y));
  }

  function turn(d) {
    const opposite = { up: "down", down: "up", left: "right", right: "left" };
    if (d && d !== opposite[dir]) nextDir = d;   // no instant reverse into yourself
  }

  function step() {
    dir = nextDir;
    const head = { x: snake[0].x + DIRS[dir][0], y: snake[0].y + DIRS[dir][1] };
    const hitWall = head.x < 0 || head.y < 0 || head.x >= GRID || head.y >= GRID;
    const hitSelf = snake.some(s => s.x === head.x && s.y === head.y);
    if (hitWall || hitSelf) return gameOver();
    snake.unshift(head);
    if (head.x === apple.x && head.y === apple.y) {
      score++; $("score").textContent = score;
      speed = Math.max(MIN_SPEED, speed - SPEED_UP);
      placeApple();
    } else snake.pop();
    draw();
    timer = setTimeout(step, speed);
  }

  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = COLORS.grid;                       // checkerboard
    for (let y = 0; y < GRID; y++) for (let x = (y % 2); x < GRID; x += 2) ctx.fillRect(x * CELL, y * CELL, CELL, CELL);
    ctx.fillStyle = COLORS.apple;                      // apple
    ctx.beginPath(); ctx.arc(apple.x * CELL + CELL / 2, apple.y * CELL + CELL / 2, CELL * 0.4, 0, Math.PI * 2); ctx.fill();
    snake.forEach((s, i) => {                          // snake
      ctx.fillStyle = i === 0 ? COLORS.head : COLORS.snake;
      ctx.beginPath();
      if (ctx.roundRect) ctx.roundRect(s.x * CELL + 1, s.y * CELL + 1, CELL - 2, CELL - 2, 5); else ctx.rect(s.x * CELL + 1, s.y * CELL + 1, CELL - 2, CELL - 2);
      ctx.fill();
    });
  }

  function start() { $("msg").hidden = true; paused = false; reset(); draw(); clearTimeout(timer); timer = setTimeout(step, speed); }

  function gameOver() {
    clearTimeout(timer); timer = null;
    if (score > best) { best = score; localStorage.setItem("snake-best", best); $("best").textContent = best; }
    $("title").textContent = "Game over";
    $("text").textContent = `You scored ${score}. Best: ${best}.`;
    $("play").textContent = "Play again";
    $("msg").hidden = false;
  }

  function togglePause() {
    if (!timer && !paused) return;
    paused = !paused;
    if (paused) { clearTimeout(timer); timer = null; } else timer = setTimeout(step, speed);
  }

  // keyboard
  document.addEventListener("keydown", e => {
    const map = { ArrowUp: "up", ArrowDown: "down", ArrowLeft: "left", ArrowRight: "right", w: "up", s: "down", a: "left", d: "right" };
    if (map[e.key]) { e.preventDefault(); turn(map[e.key]); }
    if (e.key === " ") { e.preventDefault(); $("msg").hidden ? togglePause() : start(); }
  });
  // on-screen buttons
  document.querySelectorAll(".pad button").forEach(b => b.addEventListener("pointerdown", e => { e.preventDefault(); turn(b.dataset.dir); }));
  // swipe
  let sx = 0, sy = 0;
  canvas.addEventListener("touchstart", e => { sx = e.touches[0].clientX; sy = e.touches[0].clientY; }, { passive: true });
  canvas.addEventListener("touchend", e => {
    const dx = e.changedTouches[0].clientX - sx, dy = e.changedTouches[0].clientY - sy;
    if (Math.max(Math.abs(dx), Math.abs(dy)) < 20) return;
    turn(Math.abs(dx) > Math.abs(dy) ? (dx > 0 ? "right" : "left") : (dy > 0 ? "down" : "up"));
  });
  $("play").addEventListener("click", start);

  reset(); draw();
</script>
</body>
</html>

How to use it

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

Make it your own

All the settings are at the top of the script:

SettingDefaultWhat it does
GRID20Cells per side of the board
START_SPEED140Milliseconds per move at the start (lower is faster)
SPEED_UP3How much faster after each apple
MIN_SPEED60The fastest the snake can go
COLORSsnake, head, apple, gridEvery color of the game

FAQ

Is this HTML game code really free?

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

How do I run the game?

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

Does it work on phones?

Yes. Swipe on the board or use the on-screen arrow buttons. On a computer use the arrow keys or WASD, and Space to pause.

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.