Сегодня сделаем очень простую слот-машину, которая будет показывать случайные эмодзи фруктов и овощей на трёх слотах. Проект поможет попрактиковаться в 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();
});