Skip to content

Sessions ​

What a player goes through from the main menu to a game and back, mode by mode: a single player's game (solo), a mission played together (co-op), and one played against each other (versus). Each diagram is the real flow of the web client's pages (apps/client/src/ui: GamePage.tsx, LobbyPage.tsx, run-view.ts, the page header's Back, nav.ts), the API's lobbies (apps/api/src/lobbies.ts, lobby-routes.ts) and runs (runs.ts), and a run's room on the game server (apps/server/src/run-host.ts).

The path is the same in every mode: the main menu, the page of games or the creation page, a game's page, then a room of one's own, a run of one, or a lobby and its runs, the results and the vote, and back. Nothing dead-ends: every state has a way out, every page a Back to its logical parent that never needs the browser's history (the header of every game page, Esc too), and every failure (the city busy, a kick, a lobby closed, a dropped seat, the API restarted, a player who never came) lands somewhere that says what happened and offers the next step.

Every state in the diagrams is a row of the table under them, with the end-to-end tests that prove it (tests/e2e/TEST-PLAN.md, whose rows name the states). A unit test (apps/client/src/ui/sessions.test.ts) parses these diagrams and fails when a state has no way out, has no row here, or names a test the plan does not have.

Solo ​

A single player's game (rules.mode: "solo") plays in a room of the player's own; a solo mission of any game in a run of one. Back from a run of one, the game's page shows what it paid.

Co-op ​

A co-op mission never starts in a level's room: its Play opens a lobby (the player its host, their party with them), Quick play and the Play together screen find one, and its runs play in rooms of their own for the lobby's roster.

Versus ​

The same lobby, its teams balanced by the players' hidden skill; a run ends when a team wins, the clock runs out, or every other team is left empty (a forfeit).

The states ​

StateWhat the player seesIts ways outE2E
MenuThe main menu over the burning car, the account in its cornerCommunity, Create, Play online, QuitE2E-439, E2E-780, E2E-784
BrowseThe page of games (?browse), its header's brand and Back to the menuA game's card, Play together, BackE2E-170, E2E-780
CreateThe creation page (?create, one creation &job=)Open in the studio, Publish, Back to the menuE2E-714, E2E-780
StudioThe studio on a draft (?studio=<draft>)Back to its creation (&job=), else to Your games; PublishE2E-686, E2E-762, E2E-780
GamePageA game's page (?game=<id>), what a run paid after one (&run=)Play, a mission's Play, Join, Back to the page of gamesE2E-172, E2E-780
RefusedThe game's page saying why Play was refused, Rejoin for a seat still held, the error with Try againRejoin, Try again, BackE2E-744, E2E-742
SoloRoomA single player's game in a room of the player's own: nobody else joinsThe pause menu's Quit to the main menuE2E-742, E2E-442
TogetherThe Play together screen (?together): Quick play, the playlists, the public lobbies, the invitationsA lobby, Back to the page of gamesE2E-660, E2E-683, E2E-780
LobbyGatheringA lobby gathering (data-state="gathering"): the mission's card, the teams' slotsReady check, Start with AI players, Leave; told when goneE2E-658, E2E-659, E2E-669
LobbyReadyThe ready check (data-state="ready"): every team at its minimum, Ready and the host's StartThe countdown, back to gathering when a member leavesE2E-658, E2E-659
StartWithAIUnder the minimum for 20 s: the host's Start with AI players enabledAI stand-ins and the countdown, a player joiningE2E-740, E2E-741
LobbyCountdownThe countdown (#lobby-countdown), the run's room warmingThe run, the city busy, back to gatheringE2E-658, E2E-649
CityBusyThe countdown waiting for a game server (#lobby-notice, busy)The run once a server takes it, gathering again, LeaveE2E-786
RunGatheringA run's room gathering its seats (__poc().run.phase: gathering)The countdown once every seat came, or 20 s after the firstE2E-649, E2E-787
RunCountdownThe run's countdown, every car heldLiveE2E-649
RunLiveThe run under way: the mission's objectives, the teams' scoresIts result, Leave the run, a dropped connectionE2E-649, E2E-653, E2E-680
DroppedA seat whose connection was lost: its minute (60 s) to come backBack into the seat, or the seat given up (filled under always)E2E-651, E2E-680, E2E-681
RunEndedThe run's results in its room (#run-results: complete, failed, a team's win)Back to the lobby, or to the game's page for a run of oneE2E-650, E2E-652, E2E-655
LobbyRunningThe lobby while its run plays (data-state="running"), the way back into the seatRejoin, the run's resultE2E-743
LobbyResultsThe lobby's results and the vote (data-state="results")Replay, the next mission, LeaveE2E-661, E2E-662, E2E-663
LobbyGoneThe lobby gone for the reader (#lobby-gone: kicked, closed, the API restarted), its header's BackBack to its game (opened from it) or to Play togetherE2E-659, E2E-785

The failure edges ​

What happensWhere it landsE2E
The city busyThe countdown says so and asks again every 5 s for two minutes, then gathers again: the lobby is never lost (CityBusy)E2E-786
KickedThe page says the host removed them, its buttons gone, Back to the game or Play together (LobbyGone)E2E-659
The lobby closedThe same page, closed (LobbyGone)E2E-785
A dropped seatIts player has 60 s to come back to the same seat (Dropped); past it the seat is given up, filled under always, a team left empty forfeitsE2E-651, E2E-680
The API restartedLobbies live in the API's memory: the page finds its lobby gone (LobbyGone, closed), the session kept, and the game's page opens anotherE2E-785
A player who never cameThe run starts 20 s after the first seat came, the no-show's seat gone for good; a room nobody came to closes 60 s after it was readyE2E-787
Seated in another runThe game's page offers Rejoin (Refused)E2E-744