A 5-letter word guessing game with three difficulty levels, unlimited play, stats tracking, and daily streaks — no account, no app store, no daily limit.
Wordle is a genuinely good game, but the daily limit and the single difficulty level leave room. This was a focused exercise in Vue 3 Composition API — component design, reactive state, and event-driven architecture without a backend — and in implementing the core algorithm correctly.
The algorithm is the interesting part. The two-pass duplicate-letter resolution (greens before yellows) looks simple but has a real edge case: if the target is SPEED and the guess is EERIE, only the first two E's should get yellow — the third shouldn't, because the pool is exhausted. Getting that right without over-counting required careful testing. There are 65 unit tests covering the algorithm, storage, and word list logic.
After each guess, each tile is colored based on a two-pass algorithm.
| Color | Meaning |
|---|---|
| A Green | Letter is in the word and in the correct position |
| A Yellow | Letter is in the word but in the wrong position |
| A Gray | Letter is not in the word |
// Pass 1 — Exact matches (green)
for (let i = 0; i < WORD_LENGTH; i++) {
if (guess[i] === target[i]) {
statuses[i] = 'correct'
pool[i] = null // consume from the pool
}
}
// Pass 2 — Present letters (yellow), skipping greens
for (let i = 0; i < WORD_LENGTH; i++) {
if (statuses[i] === 'correct') continue
const idx = pool.indexOf(guess[i])
statuses[i] = idx !== -1 ? 'present' : 'absent'
if (idx !== -1) pool[idx] = null // consume so it can't be double-counted
}
Easy (common vocabulary), Medium (standard Wordle-style), Hard (uncommon and complex). Difficulty persists between sessions.
Words cycle through the full list before repeating. Solved words are tracked per difficulty so you never get the same word twice in a row.
Tracks total games, wins, losses, average guesses, average time, fastest win, current streak, and best streak. Daily streak uses calendar-day logic.
One-click share copies a result summary to the clipboard. Same emoji-grid format Wordle uses, readable without spoiling the word.
On-screen keyboard updates letter colors as you play. Physical keyboard also works. Designed for both desktop and mobile.
Instructions shown automatically on first visit; accessible any time from the menu. No account or sign-up prompt — ever.
Words are stored base64-encoded in the bundle — a light obfuscation layer to prevent trivial spoilers from inspecting source. Not a security measure, just a courtesy.
| Difficulty | Words | Description |
|---|---|---|
| Easy | 31 | Common, familiar words with simple vowel patterns |
| Medium | 49 | Standard Wordle-style vocabulary (default) |
| Hard | 24 | Uncommon or complex vocabulary |
When all words at a difficulty are exhausted, the solved list resets and the full pool becomes available again.
Five Vue components with logic split into standalone
modules — gameLogic.js, gameStorage.js, and words.js are all
pure functions with no Vue dependency, which is why they're easy to unit test in isolation.
src/
App.vue # Root: menu/game toggle, header, footer
gameConfig.js # Constants: WORD_LENGTH (5), MAX_GUESSES (6)
gameLogic.js # computeGuessStatuses() — pure two-pass algorithm
gameStorage.js # localStorage helpers: history, stats, streak info
words.js # Word lists (base64-encoded), difficulty management
components/
GameBoard.vue # Core game: grid, keyboard, guess submission, timers
GameMenu.vue # Landing: play, difficulty picker, instructions link
VictoryModal.vue # Win result, stats, share button, confetti
GameOverModal.vue # Loss result, target word reveal, play again
InstructionsModal.vue# How-to-play overlay
__tests__/
gameLogic.test.js # 15 tests for the guess-status algorithm
gameStorage.test.js # 25 tests for storage, stats, and streak logic
words.test.js # 25 tests for word lists, difficulty, and random draw
| Layer | Technology |
|---|---|
| Framework | Vue 3 (Composition API) |
| Build tool | Vite 6 |
| Testing | Vitest 4 + jsdom — 65 unit tests |
| Linting | ESLint 9 + eslint-plugin-vue |
| Formatting | Prettier |
| Deployment | Vercel |
| Confetti | canvas-confetti |