Skip to main content

Realtime Editing

Real-time multi-peer editing is provided by @oh-just-another/collab, a CRDT layer built on Yjs. It mirrors the scene into a Y.Doc, syncs over a pluggable @oh-just-another/network transport, and carries presence (cursors, selections) alongside the document.

Wire an editor to a shared documentโ€‹

SceneDoc is the CRDT-backed scene mirror; bindEditor keeps an Editor and a SceneDoc in sync (self-origin filtered). TransportProvider ferries Yjs updates over a transport.

import * as Y from "yjs";
import { BroadcastChannelTransport } from "@oh-just-another/network";
import {
SceneDoc,
CollabAwareness,
TransportProvider,
bindEditor,
bindAwareness,
} from "@oh-just-another/collab";

const doc = new Y.Doc();
const sceneDoc = new SceneDoc(doc);
const awareness = new CollabAwareness(doc);

const transport = new BroadcastChannelTransport("room-foo");
const provider = new TransportProvider({ doc, transport, awareness: awareness.awareness });

const unbindScene = bindEditor(editor, sceneDoc, { waitForSyncMs: 200 });
const unbindPresence = bindAwareness(editor, awareness, {
user: { id: "me", name: "Alice", color: "#1a73e8" },
});

waitForSyncMs (default 0) makes a joiner wait for the room's state before seeding the doc from its own scene โ€” set it on async transports (BroadcastChannel, WebSocket). yjs and y-protocols ship as regular dependencies of @oh-just-another/collab.

Transportsโ€‹

Pick a @oh-just-another/network transport for your topology: BroadcastChannelTransport for tabs on the same origin, WebSocketTransport for cross-machine rooms (auto-reconnect with exponential backoff, onStatusChange for connection badges). Any transport implementing the Transport interface works.

Teardownโ€‹

The bind functions and provider each return / expose a cleanup path. Call them on unmount:

unbindPresence();
unbindScene();
provider.destroy();
awareness.destroy();
transport.close();
doc.destroy();

Beyond the basicsโ€‹

@oh-just-another/collab also exports extractMentions / resolveMentions / notifyMention for @handle mentions, BranchDoc for branch-and-merge, CollabHistory for Yjs-aware undo, and an EncryptedTransport (client-side AES-GCM) for blind-relay servers.