SpawnWeaver has a small number of moving parts. This page gives you the mental model; each concept links to a guide with the details.
Project and keys
A project is one game. It has two keys:
| Key | Where it lives | What it can do |
|---|---|---|
Public key pk_… |
Inside your game client (spawnweaver.cfg) |
Open realtime connections; identify the project. Safe to ship. |
Secret key sk_… |
Your own servers/tools only — never in the game | Full HTTP access to every player's storage; shown once at creation. |
Game clients only ever need the public key. If a secret key leaks, regenerate it from the dashboard.
Player identity
Players are anonymous-first: no accounts, no login screens. The first time a client
connects, the server mints a new player id (player_…) and hands back a signed
player token. The SDK persists that token in user:// and presents it on every
later connect — so SpawnWeaver.player.id is stable across app restarts. A fresh token
is issued on each successful connect (sliding expiration).
await SpawnWeaver.start()
print(SpawnWeaver.player.id) # same id tomorrow, on this machine
SpawnWeaver.set_display_name("Ada") # what other players see
Identity is scoped per project (and per server URL), so one machine has an independent identity in each of your games. See Players & identity.
Connection and session
await SpawnWeaver.start() opens one WebSocket to the server and resolves when the
session is welcomed. From then on the SDK:
- keeps
SpawnWeaver.statusup to date (OFFLINE/CONNECTING/ONLINE), - heartbeats and measures
SpawnWeaver.latency_ms, - reconnects forever after drops (exponential backoff, capped at 30s) until you call
SpawnWeaver.stop().
Every request method is awaitable and returns an SWResult — result.ok,
result.value (or a typed accessor like result.room), and result.error. You never
need to connect a signal to learn a request's outcome.
Rooms
A room is where players meet: it has a short join code (e.g. 4V8772), a
roster, a host, and optional attributes (name, max_players, metadata).
- Visibility:
"private"rooms are joinable by code only;"public"rooms also appear inlist_rooms()and can be joined by id. A "lobby" is just a public room. - One room per connection — you are in at most one room at a time.
- Host: the creator (or first matched player). Only the host can
update_room()and write room-level state. If the host disconnects or leaves, the server promotes the earliest-joined connected player — host migration is automatic. - Disconnect grace: if a player's connection blips, their seat (and their entities) are kept for a grace window (default 60s). They resume exactly where they were.
SpawnWeaver.room is maintained for you: roster, host, code, metadata, and live state.
See Rooms.
Matchmaking
Instead of sharing codes, players can queue: await SpawnWeaver.find_match("duel")
resolves when the server has filled a bucket of players with the same mode, region, and
size — the result is a normal room with a host. See
Matchmaking.
Events vs. state sync
Two ways to communicate inside a room — use both, for different jobs:
| Events | State sync | |
|---|---|---|
| Call | send_event("fired", {...}) |
set_entity() / patch_entity() / set_room_state() |
| Nature | Transient message, relayed once | Persistent value, kept by the server |
| Who receives | Other room members (not you) | Everyone, including you (as the ack) |
| Late joiners | Never see past events | Get the full state snapshot on join |
| Good for | Shots, chat, emotes, "round started" pings | Positions, health, scores, game phase |
Rule of thumb: if a player joining late needs to know it, it's state. If only players present right now care, it's an event.
State has two levels: room state (one shared object, host-writable) and
entities (per-object state, writable only by the owning player). The SpawnSync
node automates entity sync for transforms. See State sync and
Events.
Player storage
Per-player key-value storage that persists across sessions — save games, unlocks, settings — with no server of your own:
await SpawnWeaver.storage_set("save", {"level": 3, "gold": 120})
var save := await SpawnWeaver.storage_get("save")
The same data is reachable over HTTP (with the secret key, or the player's own token) for tooling and dashboards. See Player storage.
The debugger
When something goes wrong, the dashboard explains why:
- Session inspector — a per-connection timeline: connect, auth, every action, every rejection, the disconnect reason.
- Error explorer — protocol errors aggregated by code, each with a suggested fix.
- Debug bundle viewer — paste a client's
SpawnWeaver.create_debug_report_string()output to inspect its state offline.
See Debugging.
Putting it together
A typical casual game uses: start() once at boot → a menu that calls create_room()
/ join_room() / find_match() → a level with a PlayerSpawner (avatars + movement
sync, zero code) → send_event() for one-shot actions → set_room_state() from the
host for the game phase → storage_set() for progression. That's the whole stack.