Quickstart
Scaffold an app
The fastest start is the template — a working shared-cursor app with burner-wallet onboarding already wired:
npm create solsocket my-app
cd my-app && npm install && npm run devOr add the SDK to an existing project:
npm install solsocketConnect
import { SolSocket } from "solsocket";
const sock = SolSocket.connect({
wallet, // wallet adapter (browser) or Keypair (node)
cluster: "devnet", // "devnet" (default), "local", or { rpc, er } endpoints
region: "eu", // devnet ER region: "asia" (default) | "eu" | "us"
});The wallet signs one base-layer transaction (create/join + delegate) and needs a little devnet SOL for it — get some at faucet.solana.com. Everything after that is signed by an auto-managed session key and costs nothing.
Regions
A room lives on the region it was created on. Everyone joining it must connect with the same region — put it in your invite links.
Join a room
// Named room: every client asking for "lobby" lands in the same room
const room = await sock.joinOrCreate("lobby");
// Or explicitly:
const created = await sock.createRoom({ maxPlayers: 8 });
const joined = await sock.joinRoom(address); // from an invite link or listRooms()The three channels
Every room gives you three independent realtime channels:
// 1. Presence — your per-player slot (cursor, avatar, …). Fire-and-forget, ~50ms.
await room.broadcast({ x: 0.4, y: 0.7 });
room.onPresence(({ player, data }) => draw(player, data));
// 2. Messages — ephemeral events in transaction logs. No state write.
await room.emit("chat", { text: "gm" });
room.onMessage("chat", ({ player, data }) => bubble(player, data));
// 3. Shared state — one account the whole room reads and writes.
await room.setState({ doorOpen: true });
room.onStateChange(({ state }) => setDoor(state.doorOpen));Leave
await room.leave(); // commit + undelegate your presence slot
await room.closeToBase(); // creator only: commit + undelegate the room itselfAfter leave()/closeToBase() the accounts are back on the base layer — inspect them on any explorer.
Discover live rooms
const rooms = await sock.listRooms(); // busiest first
for (const r of rooms) console.log(r.address.toBase58(), `${r.players} players`);Run against a local stack
The repo ships scripts/local-stack.sh, which boots a local validator plus a local ephemeral rollup. Connect with cluster: "local" — useful for tests and offline dev.
Next: Concepts for how it works under the hood, or Build a tiny Gather for the full walkthrough.