How Plot games work
A Plot game is an independent browser app made from HTML, CSS, JavaScript, and any other assets the browser can load. Use plain JavaScript, a web framework, or a game engine that exports for the web. The result must be a client-side build that works in modern phone and desktop browsers and uses the Plot Game SDK for Plot features.
When a group starts a game, Plot loads one copy for each participating player. Each person uses their own phone or computer, so the same app can give people different information and controls while they work toward one shared outcome. Plot runs exactly one active game iframe for each player at a time and the SDK exposes only that iframe's current game session. Your game does not receive a party or session ID, and it never needs to find, filter, or clear data left by a different party or game; Plot owns that scoping and cleanup.
What your game owns
Your game is responsible for:
- its visuals, sound, interaction, rules, and pacing;
- its layout on phone and desktop screens;
- its bundled assets and normal browser compatibility;
- game-specific logic and presentation state;
- clear loading, unavailable, and error states.
The initial creator format is a client-side web app deployed as static assets. Do not assume that server code is included with a game upload.
What Plot provides
Plot brings the party into a game and gives each running copy the current
Plot.party, one shared
Plot.gameState, synchronized
Plot.playerData,
Plot.realtime.channels, and a
synchronized Plot.time clock. Your game
receives only the information and abilities documented by the SDK.
Each game copy calls Plot.ready() when it is ready to participate. A player
may already appear to other copies as joining. Plot installs a complete
synchronized view before changing that player to connected and allowing game
traffic. A game can safely treat every connected player as ready to
participate through the SDK without adding its own connection flag.
Do not read Plot page data, credentials, or private platform APIs. If your game needs something from Plot, use a documented SDK feature.
One app, one player view
The party's players list
contains every person admitted during this game session, including players who
are still joining or who have left. Each
PartyPlayer has a stable numeric
playerId; player 0 is the
host. A player remains in the list
after disconnecting or leaving, so IDs and array positions never move. A
non-host rejoin reuses that slot but resets that player's
Player Data and pending transient
messages. Use the player's
state to decide whether to show or
include them.
The host is the natural gameplay coordinator because their Plot session owns the game's lifetime. Many games will run shared rules on the host's copy and publish results for everyone else. Plot never runs a second active game iframe for that same host, so the coordinator does not need to elect between duplicate local host game copies. It should still store every decision that must survive a reload in synchronized state rather than ordinary JavaScript variables.
The host may disconnect temporarily or refresh and return to the same active
session. A refreshed iframe calls Plot.ready() and resumes from restored
state. A page that remains open is resynchronized automatically and does not call
ready() again. In either case, host logic must resume from synchronized state
rather than page-local variables. The host cannot leave while keeping the party
open. If the host leaves, closes the party, or ends the game,
Plot ends the game session for everyone and clears that session's state. Its
Plot.gameState and
Plot.playerData stop updating and
cannot accept writes. Cached snapshots may remain readable for a final screen,
but they are no longer live session state and are never exposed to a later game.
A platform-level restart or reset ends the old session, clears its synchronized
state, replaces the iframe, and starts a fresh session whose new page
initializes from Plot.ready(). This is different
from an in-session resynchronization, where Plot installs one authoritative
replacement snapshot without reloading the iframe. Plot.onLifecycleChange()
reports connected after Party and all state are installed, before retained
channel events. Focused state listeners handle ordinary data changes. Normal
reconnects and completed planned service updates preserve current state; an
unexpected service crash can restore an older snapshot or lose a new game before
its first snapshot. See Lifecycle and recovery.
Choose state by its lifetime
Use four separate kinds of state:
- Game State is one shared session object that everyone can read and only the host can write. Put the current phase, round, solved puzzles, shared deadline, and other shared facts here so a late joiner can reconstruct the game.
- Player Data is additional session state that belongs to one player and is replicated to everyone. Use it for a role, score, clue, hand, ready-to-start choice, or another fact owned by that player.
- Realtime channel messages are transient. Use them for effects and replaceable high-rate values such as cursor movement or player positions.
- Local UI state belongs only to one running page, such as an open panel or animation. Keep it inside your app.
Default to Plot.gameState for common
session state, and reach for
Plot.playerData only when a fact
belongs to an individual player. Do not use either for high-frequency realtime
data; that belongs in
Plot.realtime.channels.
Store each player's current answer or vote in Player Data. The host reads those values and publishes shared results in Game State. A temporary host absence pauses its game logic; Plot does not migrate that logic to another player or run it in the background while the host browser is suspended.
Plot.realtime.latest separately reports whether replaceable messages are
available and how large a payload can be. Shared state and reliable messages can
keep working during a latest-transport interruption.
Game State and Player Data are scoped to one game session, not permanent saved games. While that session remains active, startup and recovery install its current synchronized values. Games must not use either store for account data or saved progress.
Plot.time is a shared reference rather than
another kind of state. Give a timer a game-time deadline and send that deadline
to the party; every screen can then render the same remaining time even when the
message arrives at different moments. See
Synchronized time.
Every game copy can read Plot.gameState
and every player's Player Data. Your
interface may reveal a role or clue only on its owner's screen, but modified
game code can still inspect it. Plot games use a cooperative trust model for
their own rules: clients may submit their own actions, gameplay timestamps, and
scores, and Plot does not make those values anti-cheat proof. That is appropriate
for social play, but do not put credentials, purchases, personal information,
or anything that needs security-grade secrecy in synchronized game data.
Start with Getting started, or read the API reference for the exact TypeScript interface.