Interactive demo of Conflict-free Replicated Data Types using Yjs.
Two simulated peers edit shared data structures in real-time. Toggle them offline, make conflicting edits, then reconnect — CRDTs merge everything automatically, no conflicts.
demo.mp4
| CRDT Type | What you see |
|---|---|
| Y.Text | Two textareas sharing the same text — character-level merging via the YATA algorithm |
| Y.Map | A shared counter where each peer owns its own key — increments never conflict |
- Toggle each peer offline independently
- While offline, edits are queued (shown as amber in the sync log)
- On reconnect, state-vector-based reconciliation syncs only the missing deltas
The visualization section shows Yjs internals in real time:
- Each character as a linked-list node with its unique
(client:clock)ID - Tombstones (deleted characters still preserved in the structure)
- State vectors tracking each peer's known history
npm install
npm run devOpen http://localhost:5173.
src/
├── crdt/
│ ├── peer.ts # CRDTPeer — wraps Y.Doc with typed accessors
│ └── sync-engine.ts # Simulated network sync between peers
├── ui/
│ ├── peer-panel.ts # Per-peer UI (text editor, counter)
│ ├── algorithm-viz.ts # YATA algorithm visualization
│ ├── network-controls.ts # Online/offline toggles
│ └── update-log.ts # Scrolling log of sync events
├── utils/
│ └── escape-html.ts # HTML escaping utility
├── main.ts # Entry point — wires everything together
└── style.css # Dark theme
This demo runs entirely in the browser with an in-memory sync engine. To ship real multi-device collaborative editing, swap the sync engine for a persistence + network layer:
- Persist Yjs updates as rows in a local SQLite table via a sync engine like PowerSync
- Sync — the engine replicates rows to your backend DB and fans them out to other clients
- Apply — a watch query detects new rows, decodes them, and applies to the in-memory
Y.Doc - Origin tracking prevents infinite loops (don't re-persist updates loaded from the DB)
Other viable sync layers: y-websocket, y-indexeddb, Liveblocks, PartyKit.
- Yjs — CRDT library (YATA algorithm for sequences, LWW-Register for maps)
- TypeScript — Strict mode, zero
any - Vite — Build tool + dev server
- Vanilla DOM — No framework, ~700 lines of source
MIT