Quick start - JavaScript / TypeScript
Connect a browser or Node game to a running Asobi server in about five minutes. No server yet? Run the server quickstart first - it gives you a backend on localhost:8084 with a default match mode, which is what this page connects to.
1. Install
The package is @widgrensit/asobi. It is not on npm yet, so install it from GitHub (the prepare script builds it on install):
npm install github:widgrensit/asobi-jsIt is ESM-only and targets Node 22+ (it uses the global WebSocket and fetch). On Node 18/20, install ws and assign it to globalThis.WebSocket before importing. Browsers work as-is with any bundler (Vite, esbuild, Webpack).
2. Authenticate and open the socket
Create the client, get a guest session, then open the realtime socket - it reuses the stored access token automatically. You generate and persist the device_secret yourself (>= 32 random bytes, base64); the same device_id + secret resumes the same guest on the next launch.
import { Asobi } from "@widgrensit/asobi";
const asobi = new Asobi({ baseUrl: "http://localhost:8084" });
const session = await asobi.auth.guest({
device_id: deviceId, // stable per-device id
device_secret: deviceSecret // your >= 32-byte base64 secret
});
// session.player_id, session.access_token, session.created
const ws = asobi.websocket(); // derives ws://localhost:8084/ws + token
await ws.connect(); // sends session.connect and authenticates3. Join a match and exchange state
There is no join(mode) helper - you queue the matchmaker and the server pushes the match once it forms. Subscribe before you queue, then send input with the fire-and-forget sendFire:
ws.on("match.matched", (p) => console.log("in match", p.match_id));
ws.on("match.state", (s) => render(s.players)); // players keyed by player_id
ws.sendFire("matchmaker.add", { mode: "default" });
// later, each frame or on input:
ws.sendFire("match.input", { data: { move_x: 1, move_y: 0 } });mode must be a mode your server actually defines. The server quickstart ships default; a demo backend may serve demo instead.
Core API
new Asobi({ baseUrl, accessToken?, onTokens? })- root SDK (REST + realtime).asobi.auth.guest({ device_id, device_secret })- guest auth; alsoregister,login,upgradeGuest.asobi.websocket()thenws.connect()- open and authenticate the realtime socket.ws.on(event, cb)- subscribe to pushed events (returns an unsubscribe fn;"*"matches all).ws.sendFire(type, payload)- fire-and-forget (input);ws.send(type, payload)- RPC that awaits a reply (10s timeout).
Gotchas
- Tokens live in memory only. Pass
onTokensto persist them, and store your guestdevice_secretyourself - otherwise every launch creates a new account. - Handle auth expiry. On
invalid_token/ idle timeout the socket emitsauth_expiredand stops reconnecting - re-auth and reconnect. - Use wss in production. A browser on an
httpspage cannot openws://- serve the backend over TLS so the URL becomeswss://.
What's next
- Full JS/TS SDK reference
- WebSocket protocol - the message types behind
on/sendFire. - Authentication