Skip to content

Real-Time Collaboration

NodeUI supports real-time multi-user editing through WebSocket connections backed by Cloudflare Durable Objects. Multiple users can work on the same graph simultaneously, with node operations, edge changes, and subgraph updates synced in real time.

How It Works

 User A (browser)              Cloudflare              User B (browser)
 +--------------+     wss://    +-----------+    wss://  +--------------+
 | Collaboration|<------------>| Durable   |<---------->| Collaboration|
 | module       |   WebSocket  | Object    |  WebSocket | module       |
 +--------------+              | (room)    |            +--------------+
       |                       +-----------+                  |
       v                                                      v
  events.publish()                                     events.publish()
  (local changes)                                      (remote changes)
  1. A user starts or joins a session identified by a memorable three-word code (e.g., NOVA-WOLF-BLAZE)
  2. The browser opens a WebSocket connection to a Cloudflare Pages Function at /collab/{SESSION_ID}
  3. The Pages Function routes the connection to a Durable Object that acts as the room
  4. The Durable Object broadcasts messages to all connected clients in that room
  5. Each client's Collaboration module translates local events into WebSocket messages and remote messages into local events

Synced Events

These events are automatically broadcast to all users in a session:

EventWhat Syncs
node:updateTitle, content, color, pin state, and custom properties
node:movedNode position after drag
node:resizedNode dimensions after resize
node:deleteNode removal
edge:createNew edge connections
edge:updateEdge label and routing point changes
edge:deleteEdge removal
subgraph:updateInternal graph state of SubGraphNodes

TIP

Node creation (node:create) is handled separately from the sync event list. It is dispatched directly during state sync to prevent duplication loops.

Session Management

Starting a Session

Click the status indicator in the bottom-left corner to start a new session. NodeUI generates a three-word session code and connects automatically.

Programmatically:

javascript
const sessionId = nodeUI.collaboration.startSession();
// Returns something like 'NOVA-WOLF-BLAZE'

Joining a Session

Share the session code with a collaborator. They enter it through the join dialog or pass it as part of their workflow:

javascript
nodeUI.collaboration.joinSession('NOVA-WOLF-BLAZE');

Leaving a Session

javascript
nodeUI.collaboration.leaveSession();

This closes the WebSocket, clears the session ID, and removes all nodes from the canvas.

Session Info

javascript
const info = nodeUI.collaboration.getSessionInfo();
// {
//   sessionId: 'NOVA-WOLF-BLAZE',
//   userId: 'flux-ember_m4k7x9',
//   isConnected: true,
//   connectedUsers: ['flux-ember_m4k7x9', 'dark-wolf_p2j8q1'],
//   userCount: 2
// }

State Synchronization

When a new user joins an existing session, the system syncs the current graph state:

  1. The new user sends a request-state message
  2. An existing user responds with a state-response containing all nodes and edges
  3. The new user loads the remote state, clearing their local canvas first
  4. A hasLoadedState flag prevents processing duplicate state responses

WARNING

State sync transfers the full graph as JSON. Large graphs with embedded image data (ImageSequenceNodes) can produce messages over 10MB. The system logs warnings for payloads exceeding this size.

Presence

Each user gets a randomly generated display name made of two words (e.g., flux-ember). Connected users appear in the top-right corner of the screen.

The status indicator in the bottom-left shows:

StateDisplayClick Action
No sessionSession: noneStart a new session
ConnectedSession: NOVA-WOLF-BLAZECopy session ID to clipboard
DisconnectedSession: NOVA-WOLF-BLAZE (offline)Attempt reconnection

Reconnection

If the WebSocket connection drops, NodeUI automatically attempts to reconnect with exponential backoff:

  • Retry intervals: 1s, 2s, 4s, 8s, 16s, 30s (capped)
  • Maximum attempts: 10
  • After max attempts, the user sees an error prompting a page refresh

A keep-alive ping is sent every 30 seconds to prevent idle connection timeouts.

Architecture Details

See the following pages for setup and deployment:

Released under the MIT License.