A multiplayer infinite-canvas board where workshop attendees enter their name, drop sticky-note cards with their best Cursor / agentic-engineering tips, heart each other's notes, and see each other's live cursors.
Built with React + Vite + tldraw (canvas + live cursors) and Convex (realtime backend / single source of truth), styled to a clean "eggshell" editorial aesthetic.
- Identity: no login. You type a name once; a
sessionId+ color is stored inlocalStorage. Ownership is enforced server-side by matchingauthorSessionId(spoofable, but fine for a workshop). - Notes: stored in Convex. Rendered as a custom tldraw shape (
tip). You can edit/move/delete only your own notes; everyone can heart any note. - Hearts: one per person per note (toggle). The number is the count of unique people.
- Cursors: your pointer position is streamed to Convex (throttled) and other people are rendered as native tldraw cursors with name chips.
convex/ # Backend (single source of truth)
schema.ts # notes, hearts, presence tables
notes.ts # list / create / update / remove (owner-checked)
hearts.ts # toggle (one per person per note)
presence.ts # heartbeat / list / leave (live cursors)
src/
App.tsx # identity gate -> board
main.tsx # ConvexProvider
components/
NameModal.tsx # name entry
TopBar.tsx # wordmark, online count, "+ Add note"
board/
Board.tsx # mounts tldraw + hooks
NoteShapeUtil.tsx # the custom note card (heart, owner edit, delete)
useSyncNotes.ts # reconciles Convex notes <-> tldraw shapes
usePresence.ts # streams + renders live cursors
lib/ # identity, throttle, constants
context/IdentityContext.tsx
You need Node 20+ and a (free) Convex account.
- Install dependencies:
npm install
- Start Convex (first run logs you in, creates a dev deployment, and writes
.env.local):Leave this running.npx convex dev
- In a second terminal, start the frontend:
Open http://localhost:5173.
npm run dev
Or run both at once:
npm run dev:allOpen the app in two different browsers (or one normal + one incognito window — a single browser shares localStorage, so two normal tabs become the same user). Join with two names and confirm:
- both cursors move live (with name chips),
- a new note appears in both windows,
- hearts update live and the count = unique people,
- you can't edit or move the other person's note (no textarea / delete on theirs).
- Push to GitHub and import the repo in Vercel.
- Set the build command to
npx convex deploy --cmd 'npm run build'(seevercel.json), or usenpm run buildwithVITE_CONVEX_URLset manually. - Add Vercel environment variables:
CONVEX_DEPLOY_KEY— production deploy key (prod:...|...)VITE_TLDRAW_LICENSE_KEY— tldraw license (required on HTTPS; without it the canvas blanks after ~5s)
- Connecting
maingives auto-deploys; pull requests get preview URLs.
- tldraw works on localhost without a key; production requires
VITE_TLDRAW_LICENSE_KEY(trial or hobby license from tldraw.dev). - Identity is browser-local and not authenticated; ownership is best-effort (good enough for a trusted workshop crowd).