Demos
Real-time Collaboration with PartyKit
Stream and replay MobX patches to sync Polotno stores across clients
Polotno’s SDK is single‑user by design, but because the document state lives in a MobX‑State‑Tree store you can stream patches and replay them elsewhere. That’s exactly what PartyKit does in the demo below: every user who joins the same room sees edits appear in under a second.
Sample code: https://github.com/polotno-project/polotno-partykit
Demo page: https://polotno-partykit.lavrton.partykit.dev/
How it works
- Each client joins a PartyKit room (example-room).
- On first load it asks the room for the current state:
{ type: 'request-state' }
. - The first peer to answer sends back a full snapshot:
{ type: 'reset-state', state: … }
. - After that we only ship incremental MobX patches:
{ type: 'patch', patch: … }
. - Every receiver applies the patch with
applyPatch(store.pages, patch)
and the canvas updates instantly.
The tiny guard ignorePathRef
prevents echo loops while a patch is replaying.
const socket = usePartySocket({
room: 'example-room',
onMessage(evt) {
const event = JSON.parse(evt.data);
if (event.type === 'patch') {
console.log('patch received');
ignorePathRef.current = true;
applyPatch(store.pages, event.patch);
ignorePathRef.current = false;
}
if (event.type === 'reset-state') {
console.log('reset-state received');
ignorePathRef.current = true;
store.loadJSON(event.state);
ignorePathRef.current = false;
}
if (event.type === 'request-state') {
console.log('request-state received');
socket.send(
JSON.stringify({
type: 'reset-state',
state: store.toJSON(),
})
);
}
},
});
React.useEffect(() => {
// ask for the current state
socket.send(JSON.stringify({ type: 'request-state' }));
// stream local edits
onPatch(store.pages, (patch) => {
if (ignorePathRef.current) return;
socket.send(JSON.stringify({ type: 'patch', patch }));
});
}, []);
A few notes
- Not part of core SDK – Polotno doesn’t ship server code or conflict resolution; we simply forward MobX patches.
- Latency‑tolerant – patches are small JSON objects, so even high‑latency networks feel snappy.
- Conflict strategy – the demo is last‑write‑wins. For richer docs you might add per‑element locks or OT/CRDT.