Party and players
Plot.party is the latest immutable view of
everyone in the game session:
get() is synchronous after readiness. During a temporary disconnection it
keeps returning the latest cached snapshot, which may be stale.
The party snapshot
PartySnapshot contains:
A captured snapshot never changes. Call get() again for the latest one or use
subscribe() to render updates. Plot does not expose its platform party ID to
games; use each player's session-scoped playerId.
Each PartyPlayer is also an immutable
plain value:
Names, colors, and icons can change and are not unique identities. Use
playerId for UI keys, maps, Player Data lookups, and channel recipients. The
exported PartyPlayerState and
PlayerIcon values avoid string literals in
game code.
Get the party join URL
Use Plot.party.getJoinUrl() when
your game wants to render its own invite link or QR code:
Call it after Plot.ready() resolves. It returns the current authoritative,
absolute party URL from the trusted Plot host; it is not a field in the cached
Party snapshot. Each call asks Plot again, so do not construct a URL from player
data or an assumed join-code format. Production URLs use HTTPS. HTTP is accepted
only for loopback development.
Retrieving the URL is read-only and does not require a player gesture. The URL contains no embedded credentials and does not bypass Plot's normal join and admission checks. Browser features you use afterward, such as native sharing, may impose their own gesture requirements.
A call before readiness rejects with PlotNotReadyError; a call during a
disconnection rejects with not-connected. service-unavailable,
communication-failed, internal-error, and operation-timeout are also
possible. Because retrieval has no remote side effect, you may deliberately try
again when the runtime is connected and the link is still useful. See
Error handling for the common error pattern.
Stable IDs and player states
Player IDs are zero-based array indexes, assigned in order and never reused for
another person during the session. Player 0 is always the host.
The player list is append-only:
Joiningmeans Plot has assigned the player a stable slot, but their game copy has not installed its complete synchronized view and been activated yet.Connectedmeans their game copy has installed the complete synchronized state and can participate.Disconnectedmeans a previously connected game copy was interrupted or is resynchronizing and may return.Leftmeans a non-host player left but remains in the session history.
These states describe whether a game copy can participate through the SDK.
Connected does not promise that the player's React tree has rendered,
animations have finished, or every
optional asset has loaded. If a game needs everyone to confirm a rule or finish
a game-specific preparation step, model that separately.
Plot may show an incoming person in its own party interface before the game sees
them. Once admitted to the game, other game copies see the player as Joining
with a stable ID and an initial {} Player Data object. Plot changes that same
player to Connected only after their copy has installed a complete
synchronized view and can receive game traffic. On that player's device,
Plot.ready() resolves after the final connected snapshot and initial snapshot
callbacks are installed. Several players can join at once without IDs moving.
You do not need a Player Data flag or channel message to decide whether a connected player has a usable SDK snapshot. Add a player-owned flag only when the game itself asks for a deliberate action such as reading the rules and tapping Ready to start.
A disconnected player keeps the same slot and Player Data if they reconnect. A
refreshed iframe calls Plot.ready() again as a new page; a page
that stays open during a temporary interruption is resynchronized automatically
and does not call it again.
To rebuild from Party and every synchronized record after startup or recovery,
read their getters in the connected
Plot.onLifecycleChange() callback. Normal browser
reconnects preserve current state; unexpected service crashes can restore an
older checkpoint, identified by Plot.connection.recovery.kind.
A non-host player who leaves and later rejoins also keeps the slot. Plot changes
them from Left to Joining, resets only their
Player Data to {}, clears their old transient delivery state, and later changes
them to Connected once the new copy is synchronized. This is a player change,
not a second onPlayerAdded() event.
The host may be joining or disconnected but never becomes left while the
party is open. A temporary host disconnect or refresh preserves the active
session and its synchronized state. If the host leaves, Plot closes the party
and ends the game session.
Use Plot.party.getPlayer(playerId) when you have stored an ID. It returns the
latest player or undefined for an unknown valid slot. IDs must be integers from
0 through 1023; any other value throws TypeError.
Open Plot's Profile or Party UI
Profile editing and party controls belong to Plot outside the game iframe. A game can direct a player to either trusted surface without recreating it:
Call showSystemUi() directly from the click, tap, or keyboard handler. Do not
delay it behind a timer or unrelated asynchronous work: Plot verifies the
player interaction before opening parent UI. Await Plot.ready() during normal
startup before enabling the control.
SystemUi.Profileopens the player's Profile, where they can update their display name, color, and icon or log in to Plot.SystemUi.Partyopens the Party surface with the join code and link, voice-chat controls, and the party-management controls available to that player's role.
The promise resolves when Plot accepts the request and invokes the surface. It does not wait for the surface to close and does not report what the player did there. The player remains in control of dismissal. Your game receives no profile record, account action, parent-page access, or party-management API.
Keep an in-game fallback when the runtime is disconnected or Plot reports
user-activation-required or service-unavailable. Do not automatically retry
an operation-timeout: the requested surface may already have opened before
its confirmation was lost. Plot also limits rapid repeats to at most one
accepted request per second, so call from deliberate controls rather than an
update loop. See Error handling for the complete failure
model.
When a player changes their display name, color, or icon, Plot publishes the
accepted fields through the normal Party replica in real time. Every active game
copy in the party receives the updated snapshot; subscribe() and
onPlayerChanged() run with the corresponding fields. Render those public
fields from the latest snapshot instead of caching them as permanent identity.
Logging in and other account details stay private to Plot.
Subscribe to complete snapshots
Use subscribe() as the main source
for party UI:
A subscription registered before startup receives its first snapshot as Plot
finishes startup, just before ready() resolves. One registered later receives
the current snapshot immediately.
Later revisions arrive in order, and the returned unsubscribe function is safe
to call more than once.
SnapshotReason is
SnapshotReason.Initial for that first delivery, SnapshotReason.Change for a
normal party update, and SnapshotReason.Resync when Plot replaces its cached
state during recovery. A resync is delivered even when the values happen to
compare equal, so stateful UI can rebuild from the complete snapshot.
Subscribe to focused events
Use focused callbacks for effects tied to one normal party transition:
onPlayerAdded() runs only when a slot first enters the list. It does not replay
players from an initial or resynchronized snapshot. onPlayerChanged() supplies
the previous and current player plus all changed fields: state, displayName,
color, and icon. If one update affects several players, focused events run
in player-ID order.
Plot installs a complete party update before invoking any callback. Inside a
listener, Plot.party.get() and the event's party already contain the new
values. For a new or rejoining player, their Player Data is also installed
first. A newly added player is still Joining and cannot receive game messages
yet. Their later change to Connected means the copy can participate; no
additional SDK connection flag is required in game code.
If an update changes the current player from Connected to Disconnected or
Left, Plot changes Plot.connection
to Disconnected before running Party callbacks. Reads inside those callbacks
already show the complete new Party. Cached state may be stale while Plot
recovers; see Error handling for write and send behavior.
Subscriptions stay registered through recoverable disconnections. If Plot
cannot prove every individual transition, it emits one complete Resync
snapshot rather than inventing player-added or player-changed events.
All party subscription methods throw TypeError for a non-function listener
and return an idempotent unsubscribe function. An exception in game listener
code is reported to the browser without stopping other listeners or SDK
cleanup.