Back to docsRecipe

Realtime collab cursors

Broadcast live cursor positions across connected clients using a lightweight WebSocket relay. Each remote cursor renders as a floating caret with the user's name and a unique color derived from their session ID.

1

Cursor broadcast

Each client emits a cursor-move event containing {x, y, userId}. The server fans out to all other peers, skipping the sender.

2

Color assignment

Hash the user ID into a hue offset. Use HSL with fixed saturation and lightness so every cursor pops against dark backgrounds without clashing.

3

Caret rendering

Render a small triangular caret above the coordinate point and a label badge below. Use CSS transform with a smooth transition so cursors glide rather than jump.

4

Cleanup & stale removal

Set a 3-second TTL on each remote cursor entry. If no update arrives within the window, fade the cursor out and remove it from the DOM to avoid ghost artifacts.

Minimal server snippet

wss.on('connection', (ws) => {
  ws.on('message', (raw) => {
    const data = JSON.parse(raw);
    if (data.type === 'cursor-move') {
      broadcast(data, ws);
    }
  });
});
Tags:websocketrealtimecollaboration