Сегодня сделаем очень простую слот-машину (как в онлайн-казино), которая будет показывать случайные эмодзи фруктов и овощей на трёх слотах. Проект поможет попрактиковаться в CSS-анимациях, работе с DOM и массивами в JavaScript.

Логика проекта
На экране есть три вертикальных слота с эмодзи и кнопка перезапуска. При каждом клике по кнопке эмодзи крутятся, как в настоящем автомате, и меняются случайным образом. После того, как три эмодзи выстроились в ряд, можно нажать на кнопку и перезапустить игру.
Призов нет, зато фриспинов — сколько хочешь.
Как мы это сделаем:
- Создадим HTML-разметку с контейнером для барабанов и кнопкой управления.
- Добавим стили для фона, кнопки и создадим простую анимацию вращения.
- Напишем код функции, который будет случайным образом генерировать эмодзи.
- Напишем код для логики перезапуска игры.
- Поиграем бесплатно, без регистрации и СМС.
Готовим HTML-страницу
Создадим новый HTML-файл и добавим сразу в него основные элементы. Для эмодзи мы будем использовать Unicode-коды, а не сами символы, чтобы все браузеры могли корректно их отображать. Коды эмодзи можно взять из Википедии. Для HTML будем использовать HTML-формат с префиксом &#x.
По сути, всё, что нам нужно сделать, — добавить на страницу блоки:
- для логотипа;
- слотов с эмодзи;
- для кнопки перезапуска.
Всё остальное будем добавлять, настраивать и обрабатывать в скрипте и CSS-файле.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Веб-проект: Emoji Fruit Machine</title>
<!-- Создадим файл для стилей, позже сделаем всё красиво -->
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- Логотип -->
<div class="logo">🎰</div>
<!-- Основной контейнер -->
<div class="container">
<!-- Три слота -->
<div class="reel first"></div>
<div class="reel second"></div>
<div class="reel third"></div>
</div>
<!-- Кнопка управления -->
<div class="controls">🔄</div>
<!-- Сразу создадим и подключим файл со скриптом, код напишем позже -->
<script src="./script.js"></script>
</body>
</html>
Сюда мы добавили:
- Логотип в виде эмодзи игрового автомата.
- Контейнер с тремя слотами (
.reel
), где будут появляться случайные эмодзи. - Кнопку для перезапуска игры.

Добавляем стили
Берём созданный файл style.css — в него добавим стили и красиво оформим слот-машину. Для начала добавим общие настройки для страницы и контейнера:
body {
/* Тёмно-синий фон */
background: #293544;
/* Выравниваем весь текст по центру */
text-align: center;
}
/* Настраиваем контейнер для барабанов */
.container {
/* Фиксированная ширина */
width: 600px;
/* Фиксированная высота */
height: 200px;
/* Обрезаем содержимое, выходящее за границы */
overflow: hidden;
/* Позиционируем */
position: relative;
/* Сдвигаем контейнер на середину экрана */
left: 50%;
/* Компенсируем смещение, центрируя контейнер */
margin-left: -300px;
/* Закругляем углы */
border-radius: 30px;
/* Фон с радиальным градиентом*/
background: radial-gradient(ellipse at center, #2c7dfd 1%, #5d9bfd 65%);
/* Добавляем тень для объёма */
box-shadow: 10px 10px 50px rgba(255, 255, 255, 0.2);
}
Обновляем и видим что-то очень большое и синее.

Теперь оформляем кнопку и логотип:
/* Общие стили для кнопок */
.controls,
.logo {
/* Фиксированная ширина */
width: 80px;
/* Размер шрифта */
font-size: 40px;
/* Выравнивание содержимого по центру */
text-align: center;
/* Высота строки для центрирования */
line-height: 76px;
/* Серый фон */
background: #b5b5b5;
/* Отступы 0, автоцентрирование по горизонтали */
margin: 0 auto 0;
/* Эффект свечения */
box-shadow: 10px 10px 50px rgba(255, 255, 255, 0.2);
}
/* Кнопка перезапуска */
.controls {
/* Закругляем только нижние углы */
border-radius: 0 0 20px 20px;
/* Делаем курсор указателем, чтобы показать, что элемент кликабельный */
cursor: pointer;
}
/* Оформляем логотип */
.logo {
/* Отступ сверху */
margin-top: 50px;
/* Закругляем только верхние углы */
border-radius: 20px 20px 0 0;
}
Логотип и кнопка встали на место и получилось так. Уже похоже на то, что нам нужно:

Настройка барабанов
Продолжаем заниматься стилями и переходим к настройкам барабанов. Для начала нам нужно создать анимацию, которая будет их прокручивать вниз, а потом мы её применим к каждому слоту.
@keyframes reel {
0% {
/* В начале анимации слот находится в исходном положении */
top: 0;
}
100% {
/* Слот сдвигается вверх, создавая эффект прокрутки */
top: -1187%;
}
}
Теперь оформим сами слоты:
.reel {
/* Абсолютное позиционирование внутри контейнера */
position: absolute;
/* Фиксированная ширина слота */
width: 200px;
/* Высота больше контейнера для эффекта прокрутки */
height: 1800%;
/* Применяем анимацию прокрутки */
animation: reel 1.75s linear 2;
/* Обрезаем всё, что выходит за границы */
overflow: hidden;
}
Дальше стилизуем содержимое слота:
.inner {
/* Ширина слота */
width: 200px;
/* Высота элемента для корректного отображения эмодзи */
height: 66%;
/* Размер эмодзи */
font-size: 130px;
/* Высота строки для центрирования */
line-height: 216px;
/* Обрезаем всё, что выходит за границы */
overflow: hidden;
}
👉 Визуально на странице ничего пока не должно меняться — все стили будут работать уже с эмодзи.
Дальше нам нужно сделать позиционирование для слотов барабана и задать разную задержку анимации, чтобы эмодзи появлялись по очереди, слева направо. Поэтому на каждый слот добавим дополнительный стиль:
.first {
left: 0;
animation-delay: -0.5s;
}
.second {
left: 200px;
animation-delay: -0.2s;
}
.third {
left: 400px;
animation-delay: 0s;
}
Пока всё так же, потому что нет скрипта, который бы запускал всю написанную нами красоту:

Пишем скрипт
Сейчас мы напишем JavaScript-код, который будет:
- генерировать случайные эмодзи для каждого слота, используя список кодов фруктов и овощей;
- заполнять слоты эмодзи и создавать эффект вращения;
- запускать слот-машину при каждом нажатии кнопки;
- проигрывать анимацию, которая имитирует вращение барабанов перед остановкой.
Теперь разберёмся, как это реализовать, и начнём с функции генерации случайных эмодзи.Перед тем как добавить новые эмодзи, сначала удаляем все старые элементы с классом .inner
. Это нужно, чтобы при каждом запуске слот-машины не накапливались дублирующиеся эмодзи:
// очищаем предыдущие эмодзи
document.querySelectorAll(".inner").forEach((el) => el.remove());
Затем мы создаём три массива, по одному для каждого слота. Они будут хранить сгенерированные эмодзи, которые мы затем вставим в HTML:
// создаём массивы для хранения эмодзи
let emojiList01 = [];
let emojiList02 = [];
let emojiList03 = [];
После этого создаём массив с кодами фруктов, овощей и других эмодзи, которые будут выпадать в слот-машине. Мы храним эмодзи в виде строк в шестнадцатеричном формате, а когда подставляем в HTML, то будем добавлять префикс &#x
перед кодом, чтобы он превратился в настоящий эмодзи на странице:
// задаём список доступных эмодзи
const emojiValue = [
"1F95D", "1F34B", "1F350", "1F353", "1F34A",
"1F352", "1F348", "1F347", "1F349", "1F34F",
"1F34E", "1F34D", "1F345", "1F951", "1F34C",
"1F351", "1F346", "1F955", "1F344", "1F952",
];
Теперь напишем функцию, которая получает ссылку на массив, выбирает случайный эмодзи из массива emojiValue
, превращает его в HTML-код и добавляет в переданный массив:
function generateEmoji(emojiList) {
// Выбираем случайный код эмодзи из массива emojiValue
const emojiSingle =
emojiValue[Math.floor(Math.random() * emojiValue.length)];
// Преобразуем Unicode-код в HTML-символ и добавляем в массив
emojiList.push(`&#x${emojiSingle};`);
}
Далее с помощью цикла заполняем каждый из трёх массивов 11 случайными эмодзи, которые потом попадут в слоты.
// Количество эмодзи на каждом слоте
const n = 11;
for (let i = 0; i < n; i++) {
generateEmoji(emojiList01);
generateEmoji(emojiList02);
generateEmoji(emojiList03);
}
Затем сделаем вот что: вставим сразу два набора эмодзи на каждый слот, чтобы создать эффект плавного движения. Анимация, которую мы написали в CSS, смещает барабан вверх, но поскольку символы повторяются, кажется, что они вращаются по кругу.
Чтобы объединить все эмодзи в строку и удалить запятые между ними, используем метод join()
:
// находим первый слот и вставляем 2 набора эмодзи
document.querySelector(".first").innerHTML = `
<div class="inner">${emojiList01.join("")}</div>
<div class="inner">${emojiList01.join("")}</div>
`;
// находим второй слот и вставляем 2 набора эмодзи
document.querySelector(".second").innerHTML = `
<div class="inner">${emojiList02.join("")}</div>
<div class="inner">${emojiList02.join("")}</div>
`;
// находим третий слот и вставляем 2 набора эмодзи
document.querySelector(".third").innerHTML = `
<div class="inner">${emojiList03.join("")}</div>
<div class="inner">${emojiList03.join("")}</div>
`;
Итак. Мы написали функцию emojiCode()
, которая очищает старые эмодзи, случайным образом заполняет три слота и создаёт эффект вращения. Если сейчас запустить эту функцию, барабаны начнут крутиться и эмодзи будут появляться в случайном порядке:

Но игра сработает только один раз — без обновления страницы эмодзи больше не меняются. Поэтому следующий шаг — добавить логику кнопки для перезапуска игры.
Запускаем игру
Сделаем так, чтобы игра работала по такой логике:
- При загрузке страницы слот-машина запускается автоматически.
- При нажатии на кнопку старые слоты удаляются.
- Создаются новые слоты, в которые заново загружаются случайные эмодзи.
Когда страница загрузится, мы вызываем функцию emojiCode()
, чтобы сразу заполнить слоты эмодзи:
// Запускаем emojiCode при загрузке страницы
document.addEventListener("DOMContentLoaded", emojiCode);
Затем находим кнопку, по нажатию на которую игра будет запускаться заново:
// Получаем кнопку для перезапуска
const btnReload = document.querySelector(".controls");
Когда пользователь нажимает кнопку, мы предотвращаем стандартное действие:
// Добавляем обработчик события клика
btnReload.addEventListener("click", function (e) {
// Останавливаем стандартное поведение кнопки
e.preventDefault();
Затем удаляем все элементы .reel
, чтобы освободить место для новых слотов:
// Удаляем старые барабаны
document.querySelectorAll(".reel").forEach((el) => el.remove());
Добавляем заново три блока .reel
, которые будут крутиться и показывать новые эмодзи:
// Создаём новые барабаны
document.querySelector(".container").innerHTML = `
<div class="reel first"></div>
<div class="reel second"></div>
<div class="reel third"></div>
`;
Снова вызываем emojiCode()
, чтобы заполнить слоты случайными эмодзи:
// Перезапускаем слот-машину
emojiCode();
});
Теперь всё готово — можно играть и крутить барабаны бесконечно.
Мы сделали очень простую слот-машину, буквально прототип, и её в дальнейшем можно улучшить. Например:
- Добавить проверку совпадений (три одинаковых эмодзи = победа).
- Добавить звук вращения слотов.
- Сделать плавную остановку каждого слота с задержкой.
- Выдавать виртуальные призы за виртуальные комбинации в виртуальной слот-машине в виртуальном мире.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Emoji Fruit Machine</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- Логотип -->
<div class="logo">🎰</div>
<!-- Основной контейнер -->
<div class="container">
<div class="blur">
<div class="reel first"></div>
<div class="reel second"></div>
<div class="reel third"></div>
</div>
</div>
<!-- Кнопка управления -->
<div class="controls">🔄</div>
<!-- Подключение скриптов -->
<script src="./script.js"></script>
</body>
</html>
body {
/* Тёмно-синий фон */
background: #293544;
/* Выравниваем весь текст по центру */
text-align: center;
}
/* Настраиваем контейнер для барабанов */
.container {
/* Фиксированная ширина */
width: 600px;
/* Фиксированная высота */
height: 200px;
/* Обрезаем содержимое, выходящее за границы */
overflow: hidden;
/* Позволяем точно позиционировать элементы внутри */
position: relative;
/* Сдвигаем контейнер на середину экрана */
left: 50%;
/* Компенсируем смещение, центрируя контейнер */
margin-left: -300px;
/* Закругляем углы */
border-radius: 30px;
/* Фон с радиальным градиентом*/
background: radial-gradient(ellipse at center, #2c7dfd 1%, #5d9bfd 65%);
/* Добавляем тень для объёма */
box-shadow: 10px 10px 50px rgba(255, 255, 255, 0.2);
}
/* Общие стили для кнопок */
.controls,
.logo {
/* Фиксированная ширина */
width: 80px;
/* Размер шрифта */
font-size: 40px;
/* Выравнивание содержимого по центру */
text-align: center;
/* Высота строки для центрирования */
line-height: 76px;
/* Серый фон */
background: #b5b5b5;
/* Отступы 0, автоцентрирование по горизонтали */
margin: 0 auto 0;
/* Эффект свечения */
box-shadow: 10px 10px 50px rgba(255, 255, 255, 0.2);
}
/* Кнопка перезапуска */
.controls {
/* Закругляем только нижние углы */
border-radius: 0 0 20px 20px;
/* Делаем курсор указателем, чтобы показать, что элемент кликабельный */
cursor: pointer;
}
/* Оформляем логотип */
.logo {
/* Отступ сверху */
margin-top: 50px;
/* Закругляем только верхние углы */
border-radius: 20px 20px 0 0;
}
/* Оформляем барабаны */
.reel {
/* Абсолютное позиционирование внутри контейнера */
position: absolute;
/* Фиксированная ширина барабана */
width: 200px;
/* Высота больше контейнера для эффекта прокрутки */
height: 1800%;
/* Применяем анимацию прокрутки */
animation: reel 1.75s linear 2;
/* Обрезаем всё, что выходит за границы */
overflow: hidden;
}
/* Оформляем содержимое барабана */
.inner {
/* Ширина барабана */
width: 200px;
/* Высота элемента для корректного отображения эмодзи */
height: 66%;
/* Размер эмодзи */
font-size: 130px;
/* Высота строки для центрирования */
line-height: 216px;
/* Обрезаем всё, что выходит за границы */
overflow: hidden;
}
/* Позиционируем барабаны и задаём разную задержку анимации */
.first {
left: 0;
animation-delay: -0.5s;
}
.second {
left: 200px;
animation-delay: -0.2s;
}
.third {
left: 400px;
animation-delay: 0s;
}
/* Анимация вращения барабанов */
@keyframes reel {
0% {
/* В начале анимации барабан находится в исходном положении */
top: 0;
}
100% {
/* Барабан сдвигается вверх, создавая эффект прокрутки */
top: -1187%;
}
}
function emojiCode() {
// Удаляем все элементы с классом .inner
document.querySelectorAll(".inner").forEach((el) => el.remove());
// Создаём пустые массивы для хранения эмодзи
let emojiList01 = [];
let emojiList02 = [];
let emojiList03 = [];
// Массив с кодами эмодзи в формате Unicode
const emojiValue = [
"1F95D",
"1F34B",
"1F350",
"1F353",
"1F34A",
"1F352",
"1F348",
"1F347",
"1F349",
"1F34F",
"1F34E",
"1F34D",
"1F345",
"1F951",
"1F34C",
"1F351",
"1F346",
"1F955",
"1F344",
"1F952",
];
// Функция для генерации случайного эмодзи и добавления его в массив
function generateEmoji(emojiList) {
// Выбираем случайный код эмодзи из массива emojiValue
const emojiSingle =
emojiValue[Math.floor(Math.random() * emojiValue.length)];
// Добавляем эмодзи в массив, используя HTML-код &#x...; для отображения Unicode-символов
emojiList.push(`&#x${emojiSingle};`);
}
// Количество эмодзи, которые нужно сгенерировать для каждого списка
const n = 11;
// Заполняем каждый массив 11 случайными эмодзи
for (let i = 0; i < n; i++) {
generateEmoji(emojiList01);
generateEmoji(emojiList02);
generateEmoji(emojiList03);
}
// Обновляем содержимое элементов с классами .first, .second и .third,
// вставляя внутрь два дива с классом .inner, содержащие эмодзи из соответствующих массивов
document.querySelector(".first").innerHTML = `
<div class="inner">${emojiList01.join("")}</div>
<div class="inner">${emojiList01.join("")}</div>
`;
document.querySelector(".second").innerHTML = `
<div class="inner">${emojiList02.join("")}</div>
<div class="inner">${emojiList02.join("")}</div>
`;
document.querySelector(".third").innerHTML = `
<div class="inner">${emojiList03.join("")}</div>
<div class="inner">${emojiList03.join("")}</div>
`;
}
// Запуск функции emojiCode после полной загрузки документа
document.addEventListener("DOMContentLoaded", emojiCode);
// Получаем кнопку с классом .controls для управления процессом
const btnReload = document.querySelector(".controls");
// Добавляем обработчик события клика на кнопку
btnReload.addEventListener("click", function (e) {
// Предотвращаем стандартное поведение кнопки
e.preventDefault();
// Удаляем все элементы с классом .reel, если есть
document.querySelectorAll(".reel").forEach((el) => el.remove());
// Добавляем в .container три новых div-элемента с классами .reel (first, second, third),
// которые затем будут заполнены эмодзи в emojiCode()
document.querySelector(".container").innerHTML = `
<div class="reel first"></div>
<div class="reel second"></div>
<div class="reel third"></div>
`;
// Повторно запускаем emojiCode для обновления эмодзи
emojiCode();
});