๐ŸŽฎ Get a game ยท $19

๐Ÿน Free game 13 of 20 ยท copy & paste

Whack-a-Mole Game in HTML & JavaScript: Free Code + Demo

Hit as many moles as you can in 30 seconds, but watch out for bombs. It is built with plain HTML elements and CSS transitions, which makes it a great first game. Copy the code below, save it as whack-a-mole.html and open it in any browser.

Type
Word & quick
Level
Beginner
Code
109 lines, 1 file
Libraries
None
Works on
Phones & computers
You learn
Timers (setTimeout / setInterval) and DOM events

โ–ฒ Play it right here. Click or tap the moles.

What's in this free Whack-a-Mole game

The code (109 lines, one file)

whack-a-mole.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>Whack-a-Mole Game</title>
<!--
  Free HTML Whack-a-Mole game โ€” one file, no libraries, no images. Save it as whack-a-mole.html and open it in a browser.
  From htmlgamescode.com (free to use in your own projects).
  Tap the moles before they hide. Don't hit the bombs!
-->
<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: 16px;
    background: linear-gradient(#5ec8ff, #3fa66b 55%); color: #fff; font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    user-select: none; -webkit-user-select: none; touch-action: manipulation; padding: 12px;
  }
  .bar { width: min(92vw, 400px); display: flex; justify-content: space-between; gap: 6px; font-weight: 800; }
  .bar span { background: rgba(0,0,0,.3); padding: 6px 12px; border-radius: 10px; }
  .field { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; width: min(92vw, 380px, calc(100vh - 90px)); }
  .hole { position: relative; aspect-ratio: 1; border-radius: 50%; overflow: hidden; background: radial-gradient(ellipse at 50% 70%, #3b2412 55%, #5a3a1c 56%); cursor: pointer; }
  .hole span { position: absolute; left: 0; right: 0; bottom: -100%; text-align: center; font-size: min(17vw, 70px, calc((100vh - 90px) / 5.5)); line-height: 1; transition: bottom .12s ease-out; pointer-events: none; }
  .hole.up span { bottom: 10%; }
  .hole.hit span { filter: grayscale(1) brightness(1.5); transform: scale(.85); }
  .msg { position: fixed; inset: 0; display: grid; place-items: center; background: rgba(10, 6, 36, .6); }
  .msg[hidden] { display: none; }
  .box { text-align: center; background: #2a2170; padding: 26px 30px; border-radius: 20px; }
  .box h1 { font-size: 30px; margin-bottom: 6px; }
  .box p { opacity: .85; margin-bottom: 16px; }
  .box button { border: 0; border-radius: 14px; padding: 12px 28px; font: 700 18px system-ui, sans-serif; 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>โฑ <b id="time">0</b>s</span><span>Best: <b id="best">0</b></span></div>
  <div class="field" id="field"></div>
  <div class="msg" id="msg"><div class="box"><h1 id="title">๐Ÿ”จ Whack-a-Mole</h1><p id="text">Hit as many moles as you can. Bombs cost 2 points!</p><button id="play">Play</button></div></div>

<script>
  // ---- settings: change these to make it your own ----
  const GAME_SECONDS = 30;       // length of one game
  const HOLES = 9;               // number of holes (3 per row)
  const UP_TIME = 900;           // ms a mole stays up at the start (gets shorter)
  const SPAWN_EVERY = 650;       // ms between new moles at the start (gets shorter)
  const BOMB_CHANCE = 0.15;      // chance that a bomb pops up instead of a mole
  const MOLE = "๐Ÿน", BOMB = "๐Ÿ’ฃ"; // what pops up

  const $ = id => document.getElementById(id);
  const load = k => { try { return Number(localStorage.getItem(k)) || 0; } catch { return 0; } };
  const save = (k, v) => { try { localStorage.setItem(k, v); } catch {} };
  let score = 0, timeLeft = 0, playing = false, spawner, clock, best = load("mole-best");
  $("best").textContent = best;

  const holes = [...Array(HOLES)].map(() => {
    const h = document.createElement("div");
    h.className = "hole"; h.innerHTML = "<span></span>";
    h.addEventListener("pointerdown", e => { e.preventDefault(); whack(h); });
    $("field").appendChild(h);
    return h;
  });

  function popUp() {
    if (!playing) return;
    const free = holes.filter(h => !h.classList.contains("up"));
    if (free.length) {
      const h = free[Math.floor(Math.random() * free.length)];
      const bomb = Math.random() < BOMB_CHANCE;
      h.dataset.kind = bomb ? "bomb" : "mole";
      h.firstChild.textContent = bomb ? BOMB : MOLE;
      h.classList.remove("hit"); h.classList.add("up");
      const progress = 1 - timeLeft / GAME_SECONDS;               // 0 at the start, 1 at the end
      clearTimeout(h.hide);
      h.hide = setTimeout(() => h.classList.remove("up"), UP_TIME * (1 - progress * 0.45));
    }
    spawner = setTimeout(popUp, SPAWN_EVERY * (1 - (1 - timeLeft / GAME_SECONDS) * 0.5));
  }

  function whack(h) {
    if (!playing || !h.classList.contains("up") || h.classList.contains("hit")) return;
    h.classList.add("hit");
    score = Math.max(0, score + (h.dataset.kind === "bomb" ? -2 : 1));
    $("score").textContent = score;
    clearTimeout(h.hide);
    h.hide = setTimeout(() => h.classList.remove("up"), 250);
  }

  function start() {
    score = 0; timeLeft = GAME_SECONDS; playing = true;
    $("score").textContent = 0; $("time").textContent = timeLeft; $("msg").hidden = true;
    holes.forEach(h => h.classList.remove("up", "hit"));
    clock = setInterval(() => { timeLeft--; $("time").textContent = timeLeft; if (timeLeft <= 0) end(); }, 1000);
    popUp();
  }

  function end() {
    playing = false; clearInterval(clock); clearTimeout(spawner);
    holes.forEach(h => h.classList.remove("up"));
    const record = score > best;
    if (record) { best = score; save("mole-best", best); $("best").textContent = best; }
    $("title").textContent = "โฐ Time's up!";
    $("text").textContent = `You whacked ${score} point${score === 1 ? "" : "s"}.${record ? " New best! ๐Ÿ†" : ""}`;
    $("play").textContent = "Play again"; $("msg").hidden = false;
  }

  $("play").addEventListener("click", start);
  $("time").textContent = GAME_SECONDS;
</script>
</body>
</html>

How to use it

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

How the code works

Popping up

A mole is an emoji inside a hole. Adding the up class slides it into view with a CSS transition.

Timing

setTimeout picks a random free hole again and again; the delays get shorter as the clock runs down.

Scoring

pointerdown on an up mole adds a point, a bomb takes two away.

Make it your own

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

SettingDefaultWhat it does
GAME_SECONDS30length of one game
HOLES9number of holes (3 per row)
UP_TIME900ms a mole stays up at the start (gets shorter)
SPAWN_EVERY650ms between new moles at the start (gets shorter)
BOMB_CHANCE0.15chance that a bomb pops up instead of a mole
MOLE"๐Ÿน"what pops up
BOMB"๐Ÿ’ฃ"what pops up

Put it on your website

Upload whack-a-mole.html next to your page and add this where the game should appear:

<iframe src="whack-a-mole.html" width="460" height="620" style="border:0;max-width:100%" title="Whack-a-Mole game"></iframe>

FAQ

Is this Whack-a-Mole 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 Whack-a-Mole game?

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

What are the controls?

Click or tap the moles.

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 whack-a-mole.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