Краткое руководство: как собрать игру на Pygame в версию для браузера и что нужно для публикации на Яндекс Игры и CrazyGames.
Игры на Pygame в браузер обычно переносят не в WebGL, а через WebAssembly (WASM):
- Код Python и Pygame компилируется/запускается в браузере как WASM (через CPython-WebAssembly).
- Рендер по‑прежнему идёт через Pygame (в браузере это бэкенд на Canvas/WebGL внутри движка), то есть вы не переписываете игру на чистом WebGL.
Основной инструмент: pygbag.
- Сайт и вики: pygame-web.github.io, pygbag wiki.
- Репозиторий: github.com/pygame-web/pygbag.
pip install pygbag --user --upgrade
# или из репозитория:
pip install git+https://github.com/pygame-web/pygbag --user --upgradeЕсли игра использует SpritePro и в папке проекта есть конфиг webgl.json (размер, заголовок, сцена, список файлов), веб-сборку можно подготовить так:
pip install spritepro[web]
spritepro --webgl путь/к/папке/игры
# или из папки игры:
spritepro --webgl .Папка сборки по умолчанию: <папка_игры>/web_build. Запуск: python -m pygbag <путь_к_web_build>.
Пример webgl.json в папке игры (минимальный — размер/заголовок/фон подтягиваются из config.py):
{
"scene_import": "from scene import PingPongScene",
"scene_var": "PingPongScene",
"py_files": ["scene.py", "objects.py", "config.py"],
"extra_setup": ""
}Размер окна, заголовок и цвет фона можно задать один раз в коде игры — в config.py (или в модуле из config_module в webgl.json). Сборка подставит их в get_screen(...) и update(fill_color=...). Поддерживаемые имена в config: для размера — WINDOW_SIZE, SIZE, SCREEN_SIZE, GAME_SIZE; для заголовка — TITLE, GAME_TITLE, WINDOW_TITLE; для фона — FILL_COLOR, BACKGROUND_COLOR, BG_COLOR. Если задать их в config.py, в webgl.json можно не дублировать size, title, fill_color.
Установка через pip: после pip install spritepro[web] команда spritepro --webgl . копирует пакет из site-packages в папку сборки — поведение такое же, как при разработке в репозитории библиотеки.
В браузере Pygbag поддерживает в основном OGG. Файлы MP3/WAV при подготовке сборки исключаются. Подключайте звуки в формате OGG или конвертируйте их для веб-версии.
- Точка входа — главный файл с игровым циклом должен называться
main.py. - Асинхронный цикл — игровой цикл должен быть в
async def main()и где‑то внутри содержатьawait asyncio.sleep(0)(отдаёт управление браузеру). - Запуск — в конце файла:
asyncio.run(main()).
Пример минимального main.py:
import asyncio
import pygame
pygame.init()
pygame.display.set_mode((320, 240))
clock = pygame.time.Clock()
async def main():
while True:
# ваша логика, отрисовка
pygame.display.update()
await asyncio.sleep(0) # обязательно, аргумент 0
clock.tick(60)
asyncio.run(main())Из каталога выше папки с игрой:
pygbag my_game_folder
# или
python -m pygbag my_game_folderОткрыть в браузере: http://localhost:8000. Первая загрузка может быть долгой (загрузка Python WASM и ассетов).
- Только сборка (без локального сервера):
pygbag my_game_folder --build - Самодостаточный HTML с ассетами:
pygbag my_game_folder --html - Архив для загрузки (Яндекс Игры, itch.io, CrazyGames):
pygbag my_game_folder --archive
Создаётся, например,build/web.zip.
Через SpritePro CLI (одной командой):
pip install spritepro[web]
spritepro --webgl путь/к/игре --archiveБудет подготовлена веб-сборка и создан ZIP в <папка_сборки>/build/web.zip. В архиве в корне лежит index.html и все файлы билда (JS, WASM, ассеты) — такой формат принимают Яндекс Игры и большинство площадок HTML5-игр.
| Что | Рекомендация |
|---|---|
| Аудио | Только OGG (сжатый). WAV/MP3/M4A в веб-сборке не подходят. На десктопе можно по sys.platform != "emscripten" подгружать WAV/MP3. |
| Изображения | PNG / WebP / JPG. Избегать сырых форматов (BMP). |
| Пути | Только прямые слэши /, все ассеты внутри папки проекта. |
| GUI / I/O | Не использовать tkinter, синхронные сетевые вызовы и т.п. Для GUI поверх Pygame — pygame-ce, pygame_gui и т.д. |
| Доп. модули | Сложные пакеты (numpy и т.д.) объявлять в PEP 723 в main.py или через доступные wheels для pygbag. |
| Мультиплеер | Встроенный spritePro.networking (TCP-сокеты) в браузере не работает: в WASM нет обычных TCP-сокетов. См. ниже. |
Для SpritePro: потребуется адаптировать главный цикл под async def main() и await asyncio.sleep(0), а также проверить, что все ресурсы лежат в папке проекта и используют OGG для звука.
Встроенный мультиплеер SpritePro (NetServer / NetClient, multiplayer.MultiplayerContext) использует TCP-сокеты и потоки. В браузере (Pygbag/WASM) стандартные сокеты недоступны или работают иначе, поэтому такой мультиплеер в веб-сборке работать не будет.
Что использовать для мультиплеера в браузере:
- WebSocket — подключение к внешнему серверу по
wss://. Нужен свой бэкенд (Node.js, Python и т.д.) или сервис (Firebase, PlayFab, Nakama и т.п.), который принимает WebSocket и обменивается сообщениями с клиентами. - Вызовы к WebSocket из Python в Pygbag возможны через JS-мост (например,
platform.windowи свой JS-обёртка надWebSocket) или через библиотеки, поддерживающие WASM/браузер. - Или использовать режим без сети в веб-версии (например,
if sys.platform == "emscripten":— показывать заглушку «мультиплеер только на десктопе» или офлайн-режим).
Площадки принимают HTML5-игры: страница с игрой (часто в iframe), которая загружается по URL. Сборка pygbag как раз даёт такой контент (HTML + JS + WASM + ассеты). Дальше нужно выполнить требования площадки и, при необходимости, встроить их SDK.
- Документация: yandex.com/dev/games.
- Консоль и тест: Yandex Games Console.
Формат загрузки: архив ZIP, в корне архива — index.html и все необходимые файлы (JS, WASM, данные). Сборка spritepro --webgl . --archive даёт именно такой архив (web_build/build/web.zip).
Обязательно:
- Подключить Yandex Games SDK в игре (скрипт и вызовы API).
- Платежи и реклама — только через SDK Яндекса.
- Авторизация только после явного действия пользователя и с понятным объяснением.
- Звук должен приглушаться/останавливаться при сворачивании вкладки (desktop и mobile).
Устройства:
- Мобильные: полноэкранный режим, виртуальная клавиатура для полей ввода, адаптив при смене ориентации, управление жестами (и/или акселерометр), без лишних уведомлений WebGL и долгого контекстного меню по долгому тапу.
- Десктоп: игровая область масштабируется под окно, соотношение сторон не хуже 1:2, мышь/клавиатура.
Дополнительно: гостевой режим или игра без обязательной авторизации с сохранением прогресса; модерация по заявленным браузерам и ОС (обычно 3–5 рабочих дней).
Интеграция с pygbag: сборка pygbag даёт HTML/JS. SDK Яндекса подключается в шаблоне страницы (кастомный шаблон pygbag --template) или на странице, которая встраивает iframe с игрой. Вызовы SDK — из JavaScript; при необходимости можно вызывать их из Python через JS‑мост (если pygbag/среда это позволяют).
- Документация: docs.crazygames.com, в т.ч. Technical requirements.
- SDK: HTML5 v2 SDK.
Размер и загрузка:
- Начальная загрузка до первого игрового кадра: ≤ 50 MB (для мобильной главной — ≤ 20 MB).
- При интеграции SDK размер считают до события «Gameplay start» (момент, когда пользователь уже в игре).
- Всего: до 250 MB, до 1500 файлов.
- Внешние файлы: до игрового процесса желательно укладываться в ≤ 20 секунд.
Устройства и браузеры:
- Работа в Chrome и Edge; Safari проверяется.
- Удобная работа на Chromebook (4 GB RAM).
- Управление: мышь, клавиатура, тач (если заявлена мобильная версия).
- На десктопе — ландшафт; портретные игры допустимы с чёрными полосами или фоном.
- Только относительные пути к файлам в бандле.
Мобильная версия: в CSS для body добавить отключение выделения и двойного зума, например:
-webkit-user-select: none;
user-select: none;SDK:
- Basic Launch (первые 2 недели, без монетизации): достаточно события Gameplay start для замера начальной загрузки.
- Full Launch: полная интеграция SDK (реклама, события Gameplay start/stop, при необходимости User и Data для аккаунта и сохранений).
Интеграция с pygbag: подключается скрипт CrazyGames SDK в шаблоне или на странице-обёртке; событие «Gameplay start» вызывается из JS в момент, когда игра перешла в игровой экран (при кастомном шаблоне pygbag можно вызывать из Python через JS‑мост при первом кадре геймплея).
- Вынести точку входа в
main.pyс циклом вasync def main()иawait asyncio.sleep(0)(например, обёртка над текущимs.update()). - Собрать проект через pygbag и проверить в браузере:
pygbag <папка_игры>, затем--build/--archive. - Разместить полученный билд на своём хостинге или, например, itch.io (через
--archive). - Для Яндекса: зарегистрироваться в Yandex Games, добавить SDK в шаблон/страницу, реализовать паузу звука при сворачивании, адаптив и мобильные требования, отправить на модерацию.
- Для CrazyGames: зарегистрироваться как разработчик, интегрировать SDK (минимум — Gameplay start), соблюсти лимиты по размеру и путям, отправить билд на проверку.
Итог: Pygame-игры превращаются в веб не в «чистый WebGL», а в браузерный билд на Pygbag (Python WASM + Pygame). Этого достаточно для площадок в формате HTML5; для Яндекс Игр и CrazyGames нужно дополнительно подключить их SDK и выполнить технические и контентные требования площадки.