LixSketch uses Cloudflare Durable Objects for real-time collaboration. Each canvas room is a single Durable Object instance that coordinates all connected users via WebSockets.
Why Durable Objects?
Traditional WebSocket servers have a problem: if you have multiple server instances, you need a pub/sub layer (Redis, NATS, etc.) to broadcast messages between them. Durable Objects solve this by guaranteeing that all connections to a room are handled by a single instance.
This means:
- No external pub/sub needed
- No message ordering issues
- State is always consistent
- Automatic scaling per room
The Architecture
When a user joins /room/{roomId}:
- 1.WebSocket upgrade — the browser opens a WebSocket to the Cloudflare Worker
- 2.Routing — the Worker routes the connection to the Durable Object for that
roomId - 3.State sync — the DO sends the current canvas state to the new user
- 4.Broadcasting — any change from one user is broadcast to all others in the room
Message Protocol
Each WebSocket message is a JSON object with a type field:
join— user enters the room (includes guest profile)leave— user disconnectssync— full state snapshot (sent to new joiners)delta— incremental change (shape added/moved/deleted)cursor— cursor position update (throttled to 60fps)presence— list of active users in the room
Deltas are the key to performance. Instead of sending the full canvas state on every change, we send only what changed:
{
"type": "delta",
"action": "move",
"shapeId": "rect-abc123",
"data": { "x": 150, "y": 200 }
}Conflict Resolution
Since all messages go through a single Durable Object, ordering is guaranteed. The DO processes messages sequentially, so there are no conflicts. If two users move the same shape simultaneously, the last write wins — which is the expected behavior for a visual canvas.
Presence & Cursors
Each user's cursor position is broadcast to the room at up to 60fps. The Durable Object doesn't persist cursor data — it's ephemeral, only forwarded to other connected users.
User presence (who's in the room) is tracked by the DO and broadcast whenever someone joins or leaves.
