Cross-Tab Sync
Keep multiple tabs, iframes, or workers on the same origin in sync without a server. @oh-just-another/network's BroadcastChannelTransport wraps the native BroadcastChannel API and plugs straight into the collaboration layer.
The transport on its ownβ
BroadcastChannelTransport implements the generic Transport interface (send / onMessage / close) over a named channel. It carries raw binary payloads.
import { BroadcastChannelTransport } from "@oh-just-another/network";
const transport = new BroadcastChannelTransport("editor-room");
const off = transport.onMessage((bytes) => console.log("got", bytes));
transport.send(new Uint8Array([1, 2, 3]));
// β¦later
off();
transport.close();
The transport uses the platform's native BroadcastChannel β no polyfill or extra dependency.
Cross-tab collaborationβ
Pair the transport with @oh-just-another/collab to mirror a scene across tabs. Every tab opening the same channel name shares one CRDT document β edits and cursors propagate instantly.
import * as Y from "yjs";
import { BroadcastChannelTransport } from "@oh-just-another/network";
import { SceneDoc, TransportProvider, bindEditor } from "@oh-just-another/collab";
const doc = new Y.Doc();
const sceneDoc = new SceneDoc(doc);
const transport = new BroadcastChannelTransport("my-doc");
const provider = new TransportProvider({ doc, transport });
const unbind = bindEditor(editor, sceneDoc, { waitForSyncMs: 200 });
waitForSyncMs makes a newly opened tab wait briefly for the room's state before seeding the doc from its own scene β without it (default 0) a joiner with a non-empty editor can clobber the shared document.
Notesβ
- No reconnect logic β the browser keeps a
BroadcastChannelalive for the page lifetime. - Same-origin only. For cross-machine sync use
WebSocketTransportfrom the same package; the rest of the wiring is identical. - Presence (peer cursors) rides the same channel when you pass
awarenesstoTransportProvider.