๐น 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
- 30-second rounds
- Bombs that cost points
- Gets faster towards the end
- Best score saved in the browser
- Pure DOM + CSS, no canvas
The code (109 lines, one file)
<!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
- Click Copy code (or Download).
- Paste it into any text editor and save it as
whack-a-mole.html. - 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:
| Setting | Default | What it does |
|---|---|---|
GAME_SECONDS | 30 | length of one game |
HOLES | 9 | number of holes (3 per row) |
UP_TIME | 900 | ms a mole stays up at the start (gets shorter) |
SPAWN_EVERY | 650 | ms between new moles at the start (gets shorter) |
BOMB_CHANCE | 0.15 | chance 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.