Public: anyone can read this; the crew can change it.

Build canvas #2

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

canvas is now a real whiteboard: an infinite sheet with freehand ink, rectangles, ellipses, lines, arrows, text and sticky notes, pan and zoom (wheel, pinch, two fingers), live cursors and presence over server-sent events, per-person undo, SVG and PNG export, and boards that are shared by URL with an optional edit password. The starter's notes table is gone; boards and shapes replace it.

shipped production is serving it for issue #1 deploy 89346db

opened this

canvas is now a real whiteboard: an infinite sheet with freehand ink, rectangles, ellipses, lines, arrows, text and sticky notes, pan and zoom (wheel, pinch, two fingers), live cursors and presence over server-sent events, per-person undo, SVG and PNG export, and boards that are shared by URL with an optional edit password. The starter's notes table is gone; boards and shapes replace it.

The design worth looking at is src/shape.ts: one vocabulary imported by both halves, so the boundary validation, the server's SVG and the browser's DOM nodes are the same code and cannot drift — colours are indexes into a palette, so no colour string from the network can ever reach an attribute. src/db.ts gives each board a revision counter and stamps every shape it touches, with deletes as tombstones, so GET /b/<id>/events can hand a reconnecting stream exactly what it missed via Last-Event-ID. Cursors and shape changes travel together in one throttled POST /b/<id>/sync, and presence is coalesced and flushed at 15 Hz per board so the fan-out stays bounded. src/watch.ts is the one piece of polling: once a second, and only for boards someone is actually watching, it notices a change made in the terminal and streams it on.

In the preview: make a board on /, open it in two windows and draw in one — the stroke grows live in the other, and the cursors carry names. Try SVG and PNG in the bar, then make a board with a password and open it in a private window: the board is readable, the tools are gone, and the banner trades the password for an HttpOnly cookie scoped to that one board. Over FORGE_APP_SSH (printed on the front page), press n for a board, a to stick a note on it, and watch it land on the open web page within a second.

What I chose not to do: undo is per person and per tab — the browser sends the inverse of what it did, and a reload empties the stack; there is no server-side history, because a shared undo that reverses a colleague's stroke is worse than none. There is no selection rectangle, no resize handles, no z-order controls and no image paste — select moves one shape at a time. The board is rendered twice into the first response (as SVG for the no-JavaScript first paint, as JSON for the client's model), which roughly doubles the HTML for a very busy board; I kept it because a board that is readable before any script runs is worth the bytes. bun test is 26 tests, all passing, covering validation, escaping, the export, locks, cross-site posts, the stream's catch-up and the terminal bridge.

Closes #1

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs