A realtime collaborative whiteboard with offline support, version history, and AI-powered commands. Create stickies, shapes, connectors, and frames—together or alone—and never lose your work.
Live app · Source · AI cost analysis · AI dev log · Docs
| Demo | Description |
|---|---|
| General overview | A quick tour of the canvas: stickies, shapes, connectors, text editing, and more. |
| Multi-user collaboration | Live cursors, realtime syncing, and following another user's viewport. |
| Version history | Browse snapshots, restore to any point, and undo/redo with confidence. |
| Offline support | Edit without a connection; changes queue locally and sync when you're back online. |
| AI commands | Natural language to create layouts, SWOT analyses, and more—AI writes directly to the board. |
| Delightful extras | Themes, command palette, Konami easter egg, and other polish. |
- Next.js 16 · Supabase (auth, DB, realtime) · Konva (canvas) · Zustand · OpenAI (AI commands)
- Local-first sync with IndexedDB outbox and snapshot cache
- Supabase Realtime for presence, cursors, and board-object broadcasts
1. Local-first sync that survives offline
Every edit applies immediately to the UI, then goes into a persistent IndexedDB outbox. A 2-second send loop drains pending ops when online; on reconnect, the client fetches the latest snapshot and rebases local ops on top. Idempotent ops (deduped by opId) prevent double-apply on retries. The result: fast, uninterrupted editing with eventual consistency and no lost work.
2. Realtime collaboration without chaos
Multiple users edit the same board at once. We use Last-Write-Wins (LWW) per object: when two clients change the same sticky, the one with the newer updated_at wins. Cursor presence is throttled and interpolated for smooth motion. The server broadcasts committed ops; clients apply via applyRemoteObject and LWW—no CRDTs, no OT, just deterministic, predictable merging.
3. AI that writes to the board
The AI agent runs server-side (API keys stay secure) and writes directly to board_objects, then broadcasts on the same Realtime channel clients use. Tool executors (createStickyNote, moveObject, createFrame, etc.) feed getBoardState() for context, execute changes, and broadcast—so all users see AI edits in real time through the existing sync pipeline, with no client changes.
-
Copy environment variables
cp .env.example .env.local
-
Fill in Supabase URL/key and OpenAI API key.
-
Run migrations in your Supabase project:
supabase db push
-
(Optional) Enable Anonymous Sign-Ins for "Continue as Guest":
- Hosted Supabase: Authentication → Providers → enable anonymous sign-ins
- Local Supabase:
supabase/config.tomlhasenable_anonymous_sign_ins = true; use local URL and anon key fromsupabase status
-
Run the app
npm install npm run dev
Open http://localhost:3000.
npx playwright install # once
npm run test:e2e # run testsTests use the local /e2e/board harness and mock APIs. For debugging: npm run test:e2e:headed or npm run test:e2e:ui.