Lobby
GET /v1/lobby tells the game client, in one request, what Play will start for the current player: the display mode, the project's game, the next level, an unfinished run, and the result of the last run. The server decides all of it — the embed snippet on your site does not change, and the browser never decides progress or rewards.
Keyboard navigation
Use Tab to enter the iframe and reach Play, settings or the daily-wheel button. Enter and Space activate those controls. Match3 and Memory expose a card/cell grid: arrow keys move focus; Enter or Space sends the corresponding semantic game action. Parcel exposes a flight control for launch and flaps. Escape opens the pause menu; menu and result buttons use the same keyboard activation. Controls respect each mechanic's pending and pause states; Memory can buffer one additional flip as described in game runs. The server still determines every result, level and reward.
Safari on Mac can require Option+Tab to reach buttons when keyboard navigation is disabled in its settings. Use Shift+Option+Tab to move backwards in that mode. Apple's Safari guide explains the keyboard-navigation setting.
Display modes
entry_mode | Project setting | play block | Starting a run |
|---|---|---|---|
lobby | play_mechanic is set | present | POST /v1/game-runs starts the game in play.mechanic |
legacy | play_mechanic is empty | absent (wheel too) | The active template's own flow |
wheel_only | Site wheel; saving requires a ready wheel client and a published site table | absent | 409 mechanic_not_enabled |
Projects that ran match3_v1 as their active template were given play_mechanic = "match3_v1" automatically. play_mechanic is set with PATCH /v1/admin/projects/{id}; the API reference lists the checks it runs.
GET /v1/lobby
- Auth: the player's session token (
Authorization: Bearer); anonymous sessions only infree_play. - The call does not change progress or claims; exceeding its limit records a
rate_exceededfraud flag. Responses useCache-Control: no-store; the size budget is 8 KiB (the server logs a warning if exceeded). - Limit: 60 requests per minute per player.
Example response:
{
"assets": {
"lobby_background": null
},
"config_revision": 1,
"entry_mode": "lobby",
"last_result": {
"level_number": 1,
"mechanic": "match3_v1",
"reward": {
"status": "pending"
},
"run_id": "00000000-0000-0000-0000-000000000007",
"status": "won"
},
"play": {
"active_run": null,
"available": true,
"levels_total": 15,
"mechanic": "match3_v1",
"next_level": {
"cycle_round": null,
"id": "score_intro",
"number": 2,
"preview": {
"goals": [
{
"target": 1000,
"type": "score"
}
],
"moves": 12,
"tier": "intro"
}
},
"title": "Ночной рынок",
"track_complete": false,
"unavailable_reason": null
},
"schema": 1,
"server_time": "2026-10-01T12:00:00.123Z",
"theme": {
"accent": "#d79a3c"
},
"viewport": {
"height": 760,
"width": 420
},
"wheel": {
"enabled": false,
"entitlement": null,
"pending": null,
"version": null,
"wheel_id": null
}
}| Field | Meaning |
|---|---|
schema | Version of this response shape — not the same as config_revision |
config_revision | Grows on every change of the project's game settings; compare it to notice changes |
entry_mode | See display modes |
server_time | Server clock at response time; base countdowns on it |
viewport | Logical size of the game area (420×760) |
theme.accent | Always a lowercase #rrggbb string. The project's brand color if set with at least 3:1 contrast against #0a1226; otherwise the game's accent. The default primary color #6c5ce7 counts as not set |
assets.lobby_background | A normalized WebP copy840×1520, up to220 KiB, with a service URL and dimensions; null if absent or uploaded before normalization |
play.mechanic, play.title | The game behind Play and its player-facing title |
play.available, play.unavailable_reason | false with not_built, disabled, plan_limit or unsupported_version — show the game as temporarily unavailable |
play.next_level | number, id, cycle_round и серверное preview: цели и ходы, для уровней Match3 v2 также tier и при введении элемента new_element. Поле и seed не передаются |
play.levels_total, play.track_complete | Track size, and whether every level is completed |
play.active_run | The player's unfinished, not expired run of this game; resumable: false means it cannot be continued after a reload |
last_result | The player's last won or lost game run, excluding wheel outcomes, with reward.status when the run has a reward claim |
wheel | An enabled wheel includes wheel_id (daily or site), published version, entitlement and an unrevealed pending result when present. A disabled wheel has enabled: false and null summary fields; its wheel_id is null in lobby mode and "site" in wheel_only mode |
What the player sees
The lobby displays Play with the next server-selected level, Continue for an active resumable run, or Play for a run that must be closed before restarting. A run without a level number has no numeric subtitle. A completed track without a next level shows “Все уровни пройдены”. An unavailable mechanic shows a neutral card without exposing internal plan restrictions. Offline mode disables Play and preserves only previously confirmed information.
An enabled daily wheel opens in a sheet over the lobby. wheel_only opens the site wheel directly, without Play or a game engine. Rights and countdowns come from the server; the full wheel view supplies the published ticket_cost used to decide whether the ticket balance can pay for a spin. Changing to wheel_only prevents new game starts; reads and commands for previously created game runs still follow those runs' own mechanics.
Settings control sound and reduced motion. The widget refreshes lobby state when the network returns, when the tab becomes visible, on a persisted pageshow, and when returning from an activity. Failed loads retry after 5, 15, 30 and then 60 seconds while online and visible. The lobby_shown parent event is emitted after the lobby becomes ready, only to the handshake origin listed in allowed_parent_origins.
From the lobby to a run
- Play:
POST /v1/game-runswith a freshstart_id,intent: "next",expected_mechanic: play.mechanicand the rule versions your client supports. Ifplay.active_runis present, the same call returns that run withresumed: true. - Continue after a reload:
GET /v1/game-runs/{play.active_run.run_id}. 409 mechanic_changed: the project switched games; the body carries the newplayblock andconfig_revision. Load that game and retry once with a newstart_idandexpected_mechanic; if it happens again, re-read the lobby.409 client_outdated: reload the page.409 level_locked: re-read the lobby.503 mechanic_unavailableand402 plan_limit_exceeded: show the game as temporarily unavailable, without automatic retries.429 rate_limited: the start created nothing; do not repeat it automatically.
All codes: Game runs → Errors.
The shared transition controller covers Play with an accent-colored medallion and a level card. It shows “Готовим поле…” after one second and “Подождать / В лобби” after ten seconds. Returning to the lobby leaves an in-flight start request running; a late successful response refreshes the lobby so the player can continue the run. A return with no confirmed lobby response hides the level number and disables Play until fresh state arrives.
The shared result window uses server scores, stars and progress. A restored result has no celebration. Reward status is fetched at opening and, while pending or checking, at 1, 2, 4, 8, 23 and 38 seconds; updates stop at 60 seconds or when the window closes. A network error says the reward will be checked when connectivity returns. The run_finished parent event carries mechanic and status, only to the approved handshake origin. Match3 использует общий MechanicModule, переходы и окно результата. Клиент поддерживает версии правил [1, 2]; прежние партии v1 восстанавливаются с их серверными целями и результатом.
Лобби загружает фон и эмблему только активного мира. lobby.background имеет приоритет над его стандартным фоном; фон механики из верхнего блока оформления используется отдельно при открытии игры. При скрытии лобби изображения и декоративные canvas освобождаются и восстанавливаются при возврате.
Memory использует атласы лиц и карточек, Parcel Pilot — слои небесного мира, колесо — собственный набор фона, обода и смысловых значков. Эти изображения загружаются при открытии соответствующего экрана. Подписи, доступные кнопки, правила и награды берутся из прежних контрактов; декоративные сундук и подарок не меняют вид награды. Окно результата загружается отдельным модулем при завершении партии. Ошибка загрузки предлагает обновить страницу, а закрытие виджета не создаёт запоздалое окно.
После 15-го уровня Match3 повторяет позиции 11–15. play.next_level.cycle_round описывает следующий старт; в текущей партии её круг берётся из сохранённого level.cycle_round. Лобби и карточка запуска показывают, например, «Уровень 13 · круг 2». preview.tier задаёт отметку сложности, а preview.new_element — отметку нового элемента (rocket, bomb, chain, ice, hole или sphere); браузер не определяет их по номеру уровня.
Noticing configuration changes
config_revision grows whenever the project's game settings change. A client that keeps the lobby open re-reads GET /v1/lobby (for example when the tab becomes visible again) and compares. A start with a stale expected_mechanic gets 409 mechanic_changed and creates no run. Runs started before a switch can still be finished: commands and reads follow the run's own game. The lobby of the new game does not show them as active_run; they close on expiry.
The current lobby document uses the same wasm CSP profile for Match3, Memory and Parcel Pilot. Switching between these games does not require weakening its policy or replacing the iframe. A change that requires a different document profile asks the player to reload; JavaScript cannot change an HTTP CSP header on the already open document. Wheel-only and the legacy entry use base.
After the single permitted retry, a second mechanic_changed returns to refreshed lobby state. It does not cause a third start request. Continuing an existing resumable run reads its run_id instead of silently creating another attempt.
Progress and identity
- Level progress lives on the server, per project, player (
external_user_id) and game. Switching the project's game does not reset it. - Anonymous players (
free_play) are identified by an anonymous id the loader keeps in your site'slocalStorage. Clearing site data or switching devices starts again at level 1, and anonymous progress is not merged into an identified user.
Analytics
The game-run path records server events: game.started, game.game_won, game.game_lost and game.abandoned (with end_reason). They come from the server's own transactions, not from the browser.
Not a reward channel
Nothing in the lobby response grants a reward. Rewards are confirmed only by the signed webhook; the player-facing status is GET /v1/game-runs/{run_id}/reward. Общее лобби отображается при entry_mode: "lobby"; Match3 запускается через общие переходы и окно результата. В цикле is_replay: true исключает промо-награды.