Skip to content

Entry points ​

All modules are ES modules with TypeScript declarations. Browser code never imports the server entry.

ImportRuns inWhat's in it
twinwire/clientBrowserGameClient, EventClient, createEventClient, StateReceiver, LobbyClient, BrowserRtcPeer, StateTraceBuffer, BulkClient, BrowserWebTransportPeer
twinwire/serverNode 22+createGameServer, createEventServer, GameServer, GameSession, Lobby, Room, createNativeRtcFactory, turnCredentials, cloudflareTurn
twinwire/workerWorker / Durable ObjectStandard-WebSocket SocketSessionServer, GameSession; no Node/native imports
twinwire/netcodeBothClock, timing, interpolation, prediction, inputs, snapshots, replication, codecs, spatial
twinwire/browserBrowserOne file with the client, the lobby client and the netcode, for a script tag (window.Twinwire) or an import
twinwireBothThe wire protocol (encodeFrame, decodeFrame, FrameKind, VERSION), Endpoint, ReliableEvents, TokenBucket, TrafficBudget, StateTraceBuffer, estimateEgress, and the lobby's shared helpers

The server needs ws (installed with Twinwire). WebRTC on the server needs node-datachannel 0.33.x, which is optional. WebTransport is a separate optional HTTP/3 provider. Without a proven datagram path, sessions use WebSocket.

For named JSON APIs and retained room membership, start with named channels. For a complete runnable game, use the starter.

Messages, in one table ​

sendEvent(json)sendState(stream, bytes, options?)
DeliveryOrdered, acknowledged, deduplicated, replayed after reconnectsLatest wins per stream (0 to 65535); older ones dropped
SizeJSON up to 64 KiBUp to maxStateBytes (64 KiB; one datagram up to 1086 bytes)
PathWebSocket, with a copy on the datagrams while they are provenDatagrams while proven, else the WebSocket; over 8 KiB always the WebSocket
ReceiveronEvent(data, seq): each event once, in orderonState({ stream, seq, time, data, via }): newer than any seen on that stream
OptionsttlMs (100), priority (1), ack (false)

Limits worth knowing ​

  • No order holds between events and states. Stamp events with the server tick or a map generation when a snapshot depends on them.
  • An event is acknowledged when your callback returns, not when a database commits. Give purchases an action id and make handlers idempotent.
  • Sessions live in the server's memory: a restart starts everyone on a new session.

Optional WebTransport, bounded state tracing and independent HTTP resources explain the provider requirements, path selection, payload limits and measurement boundaries introduced in 3.0.

Twinwire is MIT licensed. Source on GitHub, package on npm. Made by Studio Kimeiga.

MIT licensed. Source on GitHub, package on npm.