This is the "one billion checkboxes" idea from Anders Murphy's hyperlith, done the way this whole site works: CQRS over one SQLite database, and the server rendering again whatever a change touched.
1. The board is one attribute
The state of all 2,304 pixels is one string on the element: cells, a hex digit (palette index) per pixel, row by row. The server renders it like any other markup. When a new frame morphs in, the attribute changes and the component repaints its canvas. The component never owns the board. It only draws what the server says, plus your own pixels in flight, drawn faded.
<!-- rendered by the board's view, one frame for every viewer -->
<sb-pixel-board id="board" size="48" cells="0000…5ff5…0d00"
data-on:sb-paint="@post('/cmd/paint', {
payload: {color: evt.detail.color, cells: evt.detail.cells},
requestCancellation: 'disabled'
})"></sb-pixel-board>
2. Painting is a command
A stroke emits sb-paint every 80 ms, with the cells it crossed; fast drags are interpolated so there are no gaps. Each batch is a short POST that answers 204 No Content and returns no HTML. requestCancellation: 'disabled' matters here: by default Datastar cancels an in-flight request when a new one goes to the same URL, which would drop pixels mid-stroke. A per-session token bucket (20 pixels per second, bursts up to 60) keeps any one painter from flooding the board.
// internal/commands/board.go: runs inside the single writer's batch.
func (c PaintPixels) Apply(tx *writer.Tx) error {
tx.Touch(TopicBoard) // the board's view renders again once the batch commits
for _, i := range c.Cells {
tx.Exec(`INSERT INTO board_cells (board, idx, color, painted_at)
VALUES (?, ?, ?, ?) ON CONFLICT (board, idx) DO UPDATE
SET color = excluded.color, painted_at = excluded.painted_at`,
c.Board, i, c.Color, now)
}
// bump the board's version, which its encoded cells are cached by
...
}
A single writer goroutine drains the command queue. Everyone's strokes that arrive together are applied in one SQLite transaction, each in its own savepoint, and committed once.
3. One render for every viewer
After the commit, the writer tells the render loop what the batch touched, and a paint touches only the board. The board (the header above and the canvas) is a view of its own that everyone on this page shares. In its next tick (at most one every 50 ms, however many strokes came in) the loop renders it once, from a fresh read snapshot, and sends the same frame to every viewer. The encoded board is cached per version, so the cells are read once after each paint, however many people load the page. No one's page renders. The rest of this page is your tab's own view, which renders when something of yours changes, such as the flight plan below. Its frames carry the board as the board's view last sent it, so the morph leaves the board alone.
Sending the whole board after every paint sounds wasteful until you look at the wire. The stream is compressed with zstd (Brotli in browsers without it), and the compressor keeps its window across frames. The board's frame is about 3 KB, and after a paint it costs about 40 bytes on the wire (about 20 with Brotli). There is no diffing code anywhere: Datastar morphs the DOM, and compression takes care of the network.
4. Presence
"Watching" counts the open render streams on this page. The number is part of the board's view: when someone joins or leaves, the render loop renders the board again, once, and sends it to every viewer.