Как создать клон Wordle на JavaScript
Короткое описание и цель
Wordle — простая словесная игра, где игрок отгадывает секретное пятибуквенное слово за шесть попыток. Цель этого материала — помочь начинающим JavaScript-разработчикам понять механику игры и реализовать рабочую версию с понятной архитектурой, тест-кейсами и рекомендациями по улучшению.
Важно: этот материал сосредоточен на учебной реализации. Он не копирует оригинальный сайт Wordle, а объясняет принцип и даёт практический пример реализации.
Основные идеи игры
- Секретное слово состоит из пяти букв. Игроку даётся шесть попыток.
- После каждой попытки буквы получают цветовую подсветку: зелёный — буква на правильной позиции, жёлтый — буква есть в слове, но в другой позиции, серый — буквы нет в слове.
- В интерфейсе есть виртуальная клавиатура, кнопки перезапуска и показа ответа, уведомления для пользователя.
Что вам потребуется
- Node.js (рекомендуется актуальная стабильная версия)
- Yarn установлен локально (можно заменить на npm с соответствующими командами)
- Редактор кода (VS Code или другой)
- Доступ в Интернет для загрузки слов с внешнего API (в примере используется Random Word API)

Быстрый старт: настройка проекта
- Создайте проект через Vite (в терминале):
yarn create viteВыберите framework: Vanilla, вариант: JavaScript.
- Установите зависимости:
yarn- Запустите dev-сервер:
yarn devЕсли вы предпочитаете npm, используйте аналогичные команды npm init vite, npm install и npm run dev.
Структура проекта и начальная разметка
Откройте проект в редакторе, очистите файл main.js и убедитесь, что структура папок похожа на изображение ниже.
Замените содержимое index.html на этот шаблон:
JS Wordle
Wordle Clone
Please wait. The Game is loading...
Стили возьмите из репозитория проекта: скопируйте файл style.css и поместите его в корень проекта.
Установите Toastify для уведомлений:
yarn add toastify -SПодключите стили и Toastify в main.js:
import "./style.css"
import Toastify from 'toastify-js'Инициализация DOM-элементов и переменных
Определите переменные для упрощённого доступа к элементам DOM и клавишам:
let board = document.querySelector("#board");
let message = document.querySelector("#message");
let keys = "QWERTYUIOPASDFGHJKLZXCVBNM".split("");
let restartBtn = document.querySelector("#restart-btn");
let showBtn = document.querySelector("#show-btn");
showBtn.setAttribute("disabled", "true");
keys.push("Backspace");
let keyboard = document.querySelector(".keyboard");Локализуйте метки интерфейса, если необходимо (например, заменить “Replay” на “Перезапустить”).
Подготовка игрового поля
Определите структуру данных для поля — массив из шести строк по пять ячеек и индексы текущей строки и ячейки:
let boardContent = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
];
let currentRow = 0;
let currentBox = 0;
let secretWord;Отрисуйте DOM-структуру для игрового поля (6 строк по 5 ячеек):
for (let i = 0; i <= 5; i++) {
let row = document.createElement('div')
for (let y = 0; y <= 4; y++) {
let box = document.createElement('span');
row.appendChild(box);
row.className = `row-${i + 1}`
}
board.appendChild(row);
}Создание виртуальной клавиатуры и событие клика
Генерация кнопок клавиатуры и привязка обработчиков:
keys.forEach(entry => {
let key = document.createElement("button");
if (entry === "*") {
key.innerText = "Backspace";
} else {
key.innerText = entry;
}
key.className = "key";
key.setAttribute("data-key", entry.toUpperCase());
key.addEventListener("click", () => {
insertKey(entry.toUpperCase())
setTimeout(() => {
document.querySelector(`button[data-key=${entry.toUpperCase()}]`).blur();
}, 250)
})
keyboard.append(key);
})Совет: при создании кнопок можно заменить текст кнопки Backspace на иконку, но тогда лучше сохранить data-key=”Backspace” для совместимости с логикой.
Получение случайного слова через API
При загрузке игры нужно получить новое пятибуквенное слово и сохранить его в secretWord:
function getNewWord() {
async function fetchWord() {
try {
const response = await fetch("https://random-word-api.herokuapp.com/word?length=5");
if (response.ok) {
const data = await response.json();
return data;
} else {
throw new Error("Something went wrong!")
}
} catch (error) {
message.innerText = `Something went wrong. \n${error}\nCheck your internet connection.`;
}
}
fetchWord().then(data => {
secretWord = data[0].toUpperCase();
main();
})
}Опции улучшения: вместо публичного API можно хранить локальный список слов и выбирать из него — это удобно для оффлайн-режима и для контроля над словарём.
Главная функция и подготовка интерфейса
Создайте функцию main, которая подготовит список всех ячеек и добавит обработчики событий:
function main(){
}Примеры шагов внутри main:
- собрать список rows и boxes
- добавить класс empty всем ячейкам
- скрыть сообщение о загрузке
- добавить слушатель keyup на window для обработки аппаратной клавиатуры
- привязать клики к showBtn и restartBtn
Фрагмент кода для инициализации ячеек и скрытия сообщения:
rows.forEach(row => [...row.children].forEach(child => boxes.push(child)))
boxes.forEach((box) => {
box.classList.add("empty");
})
message.style.display = "none";Добавьте обработчик аппаратной клавиатуры, который симулирует клик по соответствующей кнопке виртуальной клавиатуры:
window.addEventListener('keyup', (e) => {
if (isValidCharacter(e.key)) {
document.querySelector(`button[data-key=${e.key.toUpperCase()}]`).focus();
document.querySelector(`button[data-key=${e.key.toUpperCase()}]`).click();
setTimeout(() => {
document.querySelector(`button[data-key=${e.key.toUpperCase()}]`).blur();
}, 250)
}
})Обработчики кнопок:
showBtn.addEventListener('click', () => {
Toastify({
text: `Alright fine! the answer is ${secretWord}`,
duration: 2500,
className: "alert",
}).showToast();
})
restartBtn.addEventListener('click', () => {
location.reload();
})
function isValidCharacter(val) {
return (val.match(/^[a-zA-Z]+$/) && (val.length === 1 || val === "Backspace"))
}Отрисовка содержимого ячейки
Функция renderBox оформляет букву в указанной ячейке:
function renderBox(row, box, data) {
[...document.querySelector(`.row-${row}`).children][box].innerText = data;
}Обработка ввода с клавиатуры
Функция insertKey отвечает за удаление и добавление букв, переход между строками и запуск оценки строки:
function insertKey(key) {
if (key === "Backspace".toUpperCase() && currentRow < boardContent.length) {
boardContent[currentRow][currentBox] = 0;
if (currentBox !== 0) {
currentBox--;
renderBox(currentRow + 1, currentBox, "");
}
} else {
if (currentRow < boardContent.length) {
boardContent[currentRow][currentBox] = key;
renderBox(currentRow + 1, currentBox, key);
currentBox++;
}
if (currentRow < boardContent.length && boardContent[currentRow][currentBox] !== 0) {
evaluate(currentRow, key);
currentBox = 0;
currentRow++;
}
}
}Совет: можно улучшить логику так, чтобы оценка запускалась только при нажатии Enter и только если строка заполнена, а Backspace работал обычным образом.
Оценка попытки игрока
Создайте функцию evaluate, которая принимает номер строки и вычисляет цвета для каждой буквы:
function evaluate(row){
}Показ кнопки Show Answer после четырёх попыток:
if (currentRow === 4) {
showBtn.removeAttribute('disabled')
}Подготовка guess и answer:
let guess = boardContent[row].join('').toUpperCase();
let answer = secretWord.split("");Алгоритм подсветки с учётом повторяющихся букв:
let colors = guess
.split("")
.map((letter, idx) => letter == answer[idx] ? (answer[idx] = false) : letter)
.map((letter, idx) =>
letter
? (idx = answer.indexOf(letter)) < 0
? "grey"
: (answer[idx] = "yellow")
: "green"
);Затем примените цвета к буквам на клавиатуре и плиткам:
function setColor(colors) {
colors.forEach((color, index) => {
document.querySelector(`button[data-key=${guess[index].toUpperCase()}]`).style.backgroundColor = color;
document.querySelector(`button[data-key=${guess[index].toUpperCase()}]`).style.color= "black";
[...document.querySelector(`.row-${row + 1}`).children][index].style.backgroundColor = color;
})
}После того как игрок отгадал слово или исчерпаны попытки, можно показать финальное сообщение и предложить перезапустить игру.
Финальная инициализация
Запустите загрузку нового слова:
getNewWord();Поздравляем — базовая версия готова.
Альтернативные подходы и улучшения
- Локальный словарь вместо внешнего API — надёжнее и даёт контроль над валидными словами.
- Хранение словаря в виде JSON и выбор слов с учётом частоты употребления.
- Поддержка многоязычности: загрузка словаря под регион (ru, en, es).
- Добавление таймера и статистики (количество побед, среднее число ходов).
- Анимации при подсветке плиток для улучшения UX (CSS transitions).
Когда этот подход не подходит
- Если вам нужна масштабируемая онлайн-версия с мультиплеером — потребуется серверная часть и управление пользователями.
- Для поддержки мобильных приложений лучше использовать гибридные или нативные решения.
- Когда нужен строгий контроль словаря (например, для тестирования знаний) — публичное API может возвращать редкие или неподходящие слова.
Ментальные модели и эвристики
- Модель «проверка позиций → проверка наличия»: сначала помечаем точные соответствия, затем помечаем оставшиеся совпадения, чтобы корректно обрабатывать повторяющиеся буквы.
- Отделяйте представление (DOM) от состояния (boardContent). Все изменения сначала обновляют состояние, затем DOM.
Критерии приёмки
- Игрок может ввести буквы и удалять их клавишей Backspace.
- После заполнения строки запускается оценка и применяются цвета.
- Кнопка Show Answer активируется после четырёх ходов.
- При повторном запуске состояние сбрасывается.
Тест-кейсы и сценарии приёмки
- Ввод непечатного символа (например, цифры) — система игнорирует ввод.
- Неполная строка и Enter — оценка не запускается.
- Полная строка и Enter — отображаются цвета и клавиша Show Answer активируется после 4 попыток.
- Повторы букв в слове — подсветка учитывает количество вхождений.
- Клик по Show Answer — показывается верное слово в тосте.
Чек-лист для ролей
Разработчик:
- Инициализация проекта и dev-сервер.
- Реализация логики ввода и оценки.
- Юнит-тесты для функции evaluate.
Тестировщик:
- Выполнить тест-кейсы из предыдущего раздела.
- Проверить поведение при отсутствии сети.
Дизайнер:
- Проверить читаемость цветов на разных экранах.
- Убедиться, что кнопки доступны для касания на мобильных устройствах.
Шаблон структуры проекта
- index.html
- main.js
- style.css
- /assets — изображения
- /data — (опционально) локальный словарь words.json
Отладочные советы
- Для проверки secretWord временно логируйте его в консоль или активируйте кнопку Show Answer сразу.
- Если API недоступен, поддержите fallback на локальный список слов.
- Используйте DevTools для отслеживания классов и стилей плиток.
Совместимость и миграция
- Vite + Yarn подходят для быстрой разработки. При миграции на npm замените команды yarn на npm и убедитесь в корректности package.json.
- Для продакшн-сборки используйте vite build и размещайте статические файлы на CDN или в статическом хостинге.
Безопасность и приватность
- Игра не обрабатывает чувствительные данные. Если вы добавляете статистику или авторизацию, используйте HTTPS и защищённое хранение токенов.
Короткое объявление для соцсетей
Создал простой клон Wordle на чистом JavaScript с Vite и Toastify. Пошаговое руководство: от структуры проекта до алгоритма подсветки и тестов. Идеально для начинающих.
Социальный предпросмотр (OG)
Предлагаемые заголовок и описание для превью:
- OG заголовок: Клон Wordle на JavaScript — пошагово
- OG описание: Учебная реализация Wordle: установка, логика подсветки, обработка клавиатуры и тесты.
Короткая глоссарий в одну строку
- boardContent — состояние игрового поля (6×5).
- currentRow/currentBox — указатели текущей строки и ячейки.
- secretWord — загаданное слово.
- Toastify — библиотека для тост-уведомлений.
Резюме
- Реализовать клон Wordle можно на чистом JavaScript с небольшим набором зависимостей.
- Ключевые части: состояние поля, отрисовка DOM, обработка ввода, алгоритм подсветки с учётом повторяющихся букв.
- Для продакшн-версии рекомендуется локальный словарь, аналитика и адаптация под мобильные устройства.
Ключевые выводы:
- Простая версия Wordle помогает понять работу со state и DOM.
- Алгоритм подсветки требует двух проходов для корректной обработки повторяющихся букв.
- Рекомендуется предусмотреть fallback для API и тестовый словарь.
Похожие материалы
Разгон GPU в Windows 10 с ASUS GPU Tweak II
Вход в Xbox через microsoft.com/link — быстрое руководство
Как скачать игры с Xbox Game Pass
Browser-in-the-Browser: как защититься
Как получить Fortnite CourageJD Icon Skin бесплатно