Странствующий техник
Подкинуть работёнку
Назад к статьям
DEV30 июня 2026·5 MIN

Telegram Mini App за один день: клон River Raid на Canvas и React

Как собрать браузерную аркаду на Canvas и задеплоить её как Telegram Mini App за сутки — стек, три сюрприза Telegram WebApp API и баг с пропажей рекордов в Docker volume.

Собрал браузерный клон River Raid — аркады Activision для Atari 2600 1983 года — на Canvas и React, задеплоил как Telegram Mini App за сутки. Ниже — минимальный стек без игровых движков, три сюрприза Telegram WebApp API, которые ломают UX без явной ошибки, и баг с пропажей рекордов после каждого деплоя.

Была пятница вечером, и захотелось сделать что-то просто потому что интересно — без задачи, без продуктового смысла. Через сутки игра уже работала. Вот что я узнал по пути.

Стек — проще чем кажется

River Raid — это Canvas. Никакой физики, никаких игровых движков — просто цикл requestAnimationFrame, который рисует пиксели.

Фронтенд я собрал без сборки: React прямо с CDN, Tailwind тоже с CDN. Vite подключил только для dev-сервера — удобно. В продакшене отдаётся один HTML файл.

Бэкенд — Node.js + Fastify. Единственная задача: хранить топ-10 рекордов и отдавать их по запросу. База данных — JSON файл на диске. Для 10 записей это достаточно.

Шрифт — Press Start 2P. Без него ретро-эстетики не было бы.

Telegram Mini App — три сюрприза

Первый. Telegram требует HTTPS. Обязательно, без вариантов. Локальный http://localhost не откроется в боте. Нужен реальный домен с сертификатом.

Второй. Идентификация пользователя работает через window.Telegram.WebApp.initDataUnsafe.user. Имя, юзернейм, ID — всё там. Но это поле есть только внутри Telegram. На десктопе в браузере — undefined. Пришлось везде добавить ?. и fallback на "Guest".

Третий. WebApp.ready() нужно вызвать как можно раньше — иначе Telegram показывает лоадер поверх игры. Одна строчка, но без неё UX сломан.

Управление на мобиле — итерации

На десктопе управление простое — стрелки и пробел. На мобиле пришлось думать.

Первый вариант: кнопки на экране. Неудобно — пальцы закрывают игру.

Второй: тап по экрану = выстрел, свайп = движение. Лучше, но реакция тупила.

Итоговый вариант: тилт-управление через гироскоп телефона. Наклоняешь устройство — самолёт летит в ту сторону. Тап в любом месте = огонь. Звучит странно, но работает неожиданно хорошо — особенно для аркады где надо лавировать между берегами реки.

Баг: рекорды пропадали при каждом деплое

Это был самый обидный момент. Игра работала, Hall of Fame заполнялся — а после следующего docker compose up таблица обнулялась.

Причина: в server.js файл читался из /app/backend/highscores.json, а Docker volume был смонтирован на /app/data. При каждом деплое пересобирался образ — и файл, который лежал внутри контейнера, уходил вместе с ним.

Фикс простой: перенести путь к файлу в /app/data/highscores.json и убедиться, что volume смонтирован именно туда. Один коммит. Два часа отладки до него.

Итог

Игра живёт по адресу t.me/riveraid_bot/game — открывается прямо в Telegram, без установки. Можно поиграть прямо сейчас.

Что мне понравилось в этом проекте: минимум абстракций. Canvas рисует пиксели. Fastify отдаёт JSON. Telegram открывает HTML. Между идеей и рабочим результатом — один день и несколько сотен строк кода.

Иногда лучший способ изучить технологию — просто что-то с ней сделать. Похожая история про баг, вылезший именно из-за особенностей Docker-деплоя, — в посте про деплой на Coolify с pnpm 11, только там проблема была не с volume, а с rate limit AI-моделей.

Pro Tips: Как получить максимум

  • Проверяй пути Docker volume до деплоя, а не после. Файл внутри образа и файл в смонтированном томе — разные вещи; если путь в коде не совпадает с точкой монтирования, данные будут молча теряться при каждой пересборке.
  • Для несложных данных (топ-10 рекордов) JSON-файл на диске проще базы данных. Не усложняй стек ради небольшого объёма данных — минимум абстракций ускоряет разработку без потери надёжности на таком масштабе.
  • Проверяй window.Telegram.WebApp на undefined с самого начала. Это поле доступно только внутри Telegram — при разработке в обычном браузере получишь ошибку, если не добавить fallback заранее.

Common Pitfalls: Где люди ошибаются

  • Забывают вызвать WebApp.ready() как можно раньше. Без этого Telegram показывает лоадер поверх уже готового интерфейса — простая строчка, без которой UX выглядит сломанным.
  • Тестируют Docker volume только локально без имитации пересборки образа. Проблема с путём к файлу не проявляется, пока не случится реальный docker compose up с пересозданием контейнера.
  • Выбирают сложное управление для мобильных устройств с первой попытки. Кнопки на экране и свайпы могут казаться очевидным решением, но реальное тестирование на устройстве быстро покажет, что они неудобны.

Идентификация

Денис Заплахов

Исследую Пустоши рутинных задач: настраиваю AI-инструменты, создаю скиллы и тестирую нейросети на реальных кейсах.

Досье в Pip-Boy 3000
© 2026 79z.ru · Странствующий техник