To add some cool 'enhancements' to your Javascript Game you could include some of the following:
Keyboard typing support
Sound effects
Difficulty levels
Score tracking
Animations
Mobile layout
Dark mode
Word packs
I have described how to add SOME of the above features but you, of course, could add in a whole collection of new ones or look up how to add the rest that are described above.
Good luck and have fun! :)
Goal: control word length + lives.
Add above your buttons:
<select id="difficulty">
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
Inside play():
var difficulty = document.getElementById("difficulty").value;
var settings = {
easy: { lives: 12, min: 3, max: 6 },
medium: { lives: 9, min: 6, max: 9 },
hard: { lives: 6, min: 9, max: 20 }
};
var config = settings[difficulty];
lives = config.lives;
Filter your category words:
var filtered = chosenCategory.filter(word =>
word.length >= config.min && word.length <= config.max
);
word = filtered[Math.floor(Math.random() * filtered.length)];
Goal: reward wins + speed + accuracy.
At top:
var score = 0;
var roundStart;
Inside play():
roundStart = Date.now();
Inside your win check:
var timeBonus = Math.max(0, 30 - Math.floor((Date.now() - roundStart) / 1000));
var lifeBonus = lives * 5;
score += 50 + timeBonus + lifeBonus;
document.getElementById("score").innerHTML =
"Score: " + score;
Add to HTML:
<p id="score">Score: 0</p>
localStorage.setItem("hangmanScore", score);
Load on start:
score = parseInt(localStorage.getItem("hangmanScore")) || 0;
You can animate UI, not just the stickman.
CSS:
.guess {
transform: scale(0);
transition: transform 0.3s;
}
.guess.reveal {
transform: scale(1);
}
JS (when correct guess):
geusses[i].classList.add("reveal");
CSS:
.shake {
animation: shake 0.4s;
}
@keyframes shake {
0%,100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
JS:
document.body.classList.add("shake");
setTimeout(() => document.body.classList.remove("shake"), 400);
Instead of drawing instantly:
setTimeout(drawArray[drawMe], 200);
Creates a staged hangman build.
<button id="themeToggle">Dark Mode</button>
:root {
--bg: #c1d72e;
--text: #fff;
}
.dark {
--bg: #111;
--text: #eee;
}
body {
background: var(--bg);
color: var(--text);
}
document.getElementById("themeToggle").onclick = () => {
document.body.classList.toggle("dark");
localStorage.setItem(
"theme",
document.body.classList.contains("dark")
);
};
Load saved theme:
if (localStorage.getItem("theme") === "true") {
document.body.classList.add("dark");
}
Goal: expandable categories.
var wordPacks = {
movies: ["alien", "jaws"],
sports: ["everton", "chelsea"],
cities: ["madrid", "prague"],
animals: ["elephant", "giraffe"]
};
<select id="pack">
<option value="movies">Movies</option>
<option value="sports">Sports</option>
<option value="cities">Cities</option>
<option value="animals">Animals</option>
</select>
var pack = document.getElementById("pack").value;
chosenCategory = wordPacks[pack];
You can load JSON files:
fetch("animals.json")
.then(res => res.json())
.then(data => wordPacks.animals = data);
This makes the game expandable without editing code.
You could also add:
Level progression
Combo bonuses
Sound effects
Timer mode
Multiplayer turns
Animated hangman drawing
Keyboard typing
Achievements
Daily challenge word
Here are a few possibilities that I've outlined
HTML:
<p id="timer">Time: 60s</p>
You can place this near your score or lives.
JS (at the top of your script):
var timerDuration = 60; // seconds per round
var timerInterval;
var timeLeft;
Inside play():
// Clear previous timer if exists
clearInterval(timerInterval);
timeLeft = timerDuration;
document.getElementById("timer").innerHTML = "Time: " + timeLeft + "s";
// Count down every second
timerInterval = setInterval(function() {
timeLeft--;
document.getElementById("timer").innerHTML = "Time: " + timeLeft + "s";
if (timeLeft <= 0) {
clearInterval(timerInterval);
showLives.innerHTML = "Time's up! Game Over";
// Optionally disable letters
var letters = document.querySelectorAll("#alphabet li");
letters.forEach(letter => letter.onclick = null);
}
}, 1000);
Inside comments() or your win/loss check:
if (lives < 1 || counter + space === geusses.length) {
clearInterval(timerInterval);
}
Instead of drawing instantly, we can animate each body part using setTimeout for a smooth effect.
Instead of calling drawArray[drawMe]() instantly:
var animate = function() {
var drawMe = 10 - lives; // assuming lives decrease from 10
drawPart(drawMe);
}
// Draw one part at a time with animation
function drawPart(i) {
if (i < 0 || i >= drawArray.length) return;
// Animate stroke
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "#fff";
// Call the original draw function
drawArray[i]();
// Optional: animate the next part after delay
// setTimeout(() => drawPart(i+1), 200);
}
For example, modify your draw function:
function draw(fromX, fromY, toX, toY) {
let steps = 20;
let dx = (toX - fromX)/steps;
let dy = (toY - fromY)/steps;
let i = 0;
function animateLine() {
if (i > steps) return;
context.moveTo(fromX, fromY);
context.lineTo(fromX + dx * i, fromY + dy * i);
context.stroke();
i++;
requestAnimationFrame(animateLine);
}
animateLine();
}
Now every line of the hangman draws gradually instead of appearing instantly.
Timer runs independently.
When a wrong guess happens:
lives -= 1;
comments();
animate(); // animated drawing of the next part
Timer stops automatically on win/loss.