webdevpuneet.com

Word Unscramble Puzzle Game — Free HTML CSS JS Snippet

Word Unscramble Puzzle Game · Games · Plain HTML, CSS & JS · Live preview

CategoryGames

For supporters

Source Code

Want the source code?

Play the game for free. Become a WebDevPuneet supporter to unlock the complete HTML, CSS and JavaScript source code, the exports (HTML, React, Vue, Angular, Tailwind) and Fork.

Play freeSource code: Patreon

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Fisher-Yates shuffle: scrambleWord() produces a uniformly random letter permutation, retried if it matches the original word
Sequential word pool: shuffled once per pass via refillPool() so no word repeats until the full list has been seen
Hint system: hintedPositions Set reveals one letter at a time in a dedicated answer-key row without reordering the puzzle tiles
Dynamic scoring: Math.max(100 - hintsUsed * 25, 25) rewards hint-free solves while flooring the minimum per-round score
Cosmetic Shuffle button: re-scrambles the same target word for a fresh visual arrangement without affecting score or hints
CSS shake animation on incorrect guesses, forced reflow via offsetWidth so the animation restarts on repeated wrong answers
aria-live="polite" feedback region so screen readers announce correct/incorrect results automatically
New game control fully resets score, round count, and word pool for unlimited replayability

About this UI Snippet

Word Unscramble Puzzle Game — Letter Tiles, Scoring, Hints & Vanilla JS Word Logic

Screenshot of the Word Unscramble Puzzle Game snippet rendered live

Word unscramble puzzles are one of the oldest and most durable casual game formats because the core loop is instantly understandable — look at a jumble of letters, rearrange them mentally, type the word you see. This snippet implements a complete, replayable version of that loop entirely in vanilla JavaScript: a hardcoded word list, a real Fisher-Yates shuffle algorithm, a scoring system that rewards unaided solves, and a hint mechanic that trades points for help. There is no backend and no dependency — everything runs client-side against a plain JavaScript array.

How the scrambling actually works

The word pool is a flat array of 15 lowercase words of varying length (six to seven letters each, chosen so the puzzle is neither trivially short nor frustratingly long). scrambleWord() splits the target word into a character array and runs the classic Fisher-Yates shuffle: iterate from the last index down to the first, swapping each element with a randomly chosen earlier (or equal) element. This produces a mathematically uniform random permutation, unlike naive sort(() => Math.random() - 0.5) shuffles which are provably biased. Because a truly random shuffle can occasionally return the original word unchanged, the function retries up to ten times if the scrambled result matches the source word exactly.

Rounds, the word pool, and avoiding repeats

Rather than picking a random word from the full list on every round (which can repeat the same word twice in a row), the game shuffles the entire word list once per pass and walks through it sequentially with a poolIndex pointer. When the pointer reaches the end of the shuffled pool, refillPool() reshuffles the same 15 words into a fresh random order and resets the index to zero, so the game stays endlessly replayable while guaranteeing every word is seen once before any repeats.

The hint system and its effect on scoring

Clicking Hint does not spoil the puzzle outright — it reveals exactly one additional letter in its correct position, tracked in a hintedPositions Set keyed by character index. A separate row of boxes beneath the scrambled tiles mirrors the target word's length; unrevealed boxes stay blank while hinted ones display the letter with an accent-coloured underline. Crucially, the scrambled letter tiles themselves are never reordered by a hint — hints only affect the answer-key row, so the player still has to do the unscrambling work for the remaining letters. Because hintedPositions.size is read directly when a correct guess is submitted, scoring naturally and transparently reflects how much help was used.

Scoring formula and the shuffle button

A correct guess awards Math.max(100 - hintsUsed * 25, 25) points — a flawless, no-hint solve is worth 100 points, each hint costs 25, and the score floors at 25 so no correct answer is ever worth zero. The separate Shuffle button is purely cosmetic: it re-runs scrambleWord() on the same target word and re-renders the letter tiles in a new random order, giving players who feel visually "stuck" on one arrangement a fresh look at the same letters without changing the underlying answer or resetting any hint progress.

Feedback, state resets, and accessibility

Submitting the form (via the Submit button or pressing Enter) compares the trimmed, lowercased input against currentWord. A correct match adds a green .correct class to the input, disables further guessing, and reveals the full hint row as confirmation; an incorrect guess triggers a CSS shake keyframe animation on the input by removing and re-adding the class (forcing a reflow with void guessInput.offsetWidth so the animation restarts on consecutive wrong guesses) alongside a red error message. The aria-live="polite" attribute on the feedback paragraph means screen readers announce the result without needing focus to move. New game fully resets score, round count, and the word pool for a clean restart at any time.

Step by step

How to Use

  1. 1
    Unscramble and submit a guessRead the scrambled letter tiles at the top of the card, type the word you think they spell into the input, and press Enter or click Submit. handleSubmit() compares your trimmed, lowercased guess against currentWord and shows a green success state or a red shake animation.
  2. 2
    Use Shuffle for a fresh lookClick "Shuffle" to re-run scrambleWord() on the same target word, producing a new random letter order with a pop-in tile animation. This is purely visual — it never changes the answer or affects your score, it just gives you a different arrangement to look at if you feel stuck.
  3. 3
    Reveal letters with HintClick "Hint" to reveal one additional random letter in its correct position within the answer-key boxes beneath the tiles, tracked in the hintedPositions Set. Each hint reduces the points you can earn for that round from a maximum of 100 down to a floor of 25, so use them sparingly for a higher score.
  4. 4
    Advance rounds and track your scoreAfter a correct guess, click "Next word →" to call pickWord() again, which pulls the next word from the shuffled pool, resets hints, and generates a new scramble. The Score, Round, and Hints used counters in the stat row update live via updateStats().
  5. 5
    Start a clean run with New gameClick "New game" in the header to reset score to 0, round to 1, and reshuffle the entire 15-word pool via refillPool() before picking the first word — useful for demoing the game from a fresh state or starting a new competitive round.
  6. 6
    Customise the word list and difficultyEdit the WORDS array in the JS panel to add your own theme (countries, animals, tech terms). Adjust the scoring formula in handleSubmit() — Math.max(100 - hintsUsed * 25, 25) — to change how steeply hints reduce points, or add difficulty tiers by filtering WORDS by length.

Real-world uses

Common Use Cases

Vocabulary and spelling practice for language learning apps
Unscramble games are a proven format for reinforcing spelling and vocabulary recall because the player must actively reconstruct the word rather than passively recognise it. Swap the WORDS array for vocabulary from a specific language course or spelling curriculum, and the hint system doubles as a built-in scaffolding mechanism for learners who need partial support without giving away the full answer.
Daily mini-game or engagement feature on a content site
Embed this as a lightweight daily puzzle on a blog, newsletter landing page, or community site to increase time-on-page and repeat visits. Because the word pool reshuffles endlessly via refillPool(), the same component works as a bottomless casual game or, with a date-seeded random function, a shareable "word of the day" challenge similar to Wordle-style daily puzzles.
Onboarding or loading-screen filler for productivity tools
Drop this into an app loading state, empty dashboard, or "nothing to show yet" screen to give users something engaging to interact with instead of a static spinner. The self-contained scoring and round system means it needs no backend or account system to feel like a real, complete mini-game.
Teaching UI feedback states: success, error, and progressive reveal
The correct/shake/hint states make this a compact reference for building clear, immediate input feedback — a pattern also useful in form validation, quiz interfaces, and the Quick Math Arithmetic Game. Swap the accent colour #6366f1 and tile styling to match your design system while keeping the underlying interaction logic intact.
Learn the Fisher-Yates shuffle and Set-based state tracking
This snippet is a clean, real-world example of implementing an unbiased shuffle algorithm from scratch instead of relying on a library, plus using a native JavaScript Set to track sparse, order-independent state (which letter positions have been hinted) rather than a boolean array. Both patterns generalise well beyond games — the shuffle applies to any randomised list, and Set-based tracking applies to any "which items are unlocked/visited/selected" UI state.
Portfolio or interview demo of vanilla JS game-state management
The snippet manages several interdependent pieces of state — current word, scrambled order, hinted positions, score, round, and solved flag — using nothing but plain variables and DOM APIs, no framework or state library. It is a compact, readable demonstration of manual state management discipline, useful as a code sample when discussing vanilla JS architecture in interviews or portfolio reviews.

Got questions?

Frequently Asked Questions

Fisher-Yates produces a genuinely uniform random permutation, so for short words there is a real (if reduced) chance that only two or three letters swap position, making the scramble look deceptively close to the answer. The scrambleWord() function retries up to ten times only when the shuffle produces an exact match to the original word — near-misses are intentionally left alone, since eliminating them would bias the randomness and make the puzzle less fair.

Yes — in giveHint(), the unrevealed positions are currently chosen with Math.floor(Math.random() * unrevealed.length). Replace that line with unrevealed[0] to always reveal the leftmost unrevealed letter first, which some players find more intuitive since it lets them build the word left-to-right rather than getting scattered hints.

Add a difficulty selector that filters the WORDS array by string length before calling refillPool() — for example const easyWords = WORDS.filter(w => w.length <= 5) for an easy mode and a longer-word filter for hard mode. You could also maintain three separate arrays (easy/medium/hard) and swap which one populates the pool when the difficulty control changes.

No, this snippet keeps score, round, and the word pool entirely in memory via plain JavaScript variables, so a page reload resets everything. To persist a best score across sessions, add a localStorage.getItem/setItem call similar to the pattern used in the Quick Math Arithmetic Game snippet, storing the highest score achieved in a single New game run.

Yes — add a countdown timer using setInterval alongside the existing round logic, similar to the timer pattern in the Quick Math Arithmetic Game snippet, and call a game-over routine when it reaches zero instead of waiting indefinitely for the next correct guess. You would disable the guess form and hint/shuffle buttons on timeout and show a final score summary.