Blog·Engineering··7 min read

Making an infinite canvas multiplayer (without losing anyone’s work)

MediaMint Engineering

The moment we shipped workspaces, the canvas stopped being a document and became a place — two designers arranging renders while a director drops notes between them. This post covers the three layers that make that work: presence, state sync, and the local cache that makes boards feel instant.

Presence is cheap — treat it that way

Cursors, selections, and “who’s here” ride Supabase Realtime’s presence channels: broadcast-only, never persisted, throttled to animation-frame rates. If a presence packet drops, nobody’s work is affected — the next one paints the cursor where it should be. Designing presence as loss- tolerant is what lets it feel live without ever competing with real data for reliability.

Board state syncs as operations, not snapshots

The board itself is different: it’s money — hours of curation and a pile of credits. Edits travel as small, targeted operations (“move item X to (2410, -80)”, “retag asset Y”) applied to the shared record and fanned out to every subscriber. Two rules keep merges sane:

  • Most edits don’t collide by construction. Items are independent rows, so you moving one clip while I caption another isn’t a conflict — it’s Tuesday.
  • When they do collide, last-writer-wins per field. For spatial arrangement, LWW loses at most a nudge — and never silently deletes anyone’s item. Deletions are explicit operations, so the destructive case is always intentional.

Media never rides the channel at all. Sync moves references; pixels come from Backblaze B2 on signed URLs. A board with two hundred renders syncs in kilobytes.

The cache that makes refresh free

Every board keeps a local copy in your browser (localStorage), stamped against server state. Reload and the canvas paints from cache immediately — your pan position, your arrangement, no spinner — then reconciles with the server and applies whatever teammates did while you were gone. The subjective result: boards open like local files but stay collectively true.

Generations are multiplayer too

Because every generation is a durable job, a render one person starts is visible to everyone: the placeholder appears on the shared board, ticks through its states, and resolves for the whole room at once. The person who prompted it doesn’t even need to stay online — the job belongs to the board, not the browser.

The stack is deliberately boring — presence for ephemera, operations for truth, cache for feel. The result isn’t a whiteboard with cursors; it’s a production surface a team can actually trust.

Try it on the canvas

100 free credits a day. Every model. No card.

Start creating