LiveBoard / docsProject documentation

Reference

Editor Geometry and Interaction Model

Look up syntax, contracts, layouts, algorithms, and exact behavior.

The editor uses SVG as the scene representation. The canvas viewport is effectively infinite by rendering a very large background rectangle and treating the SVG viewBox as the camera window. Wheel input changes zoom around the cursor. Middle-button or background drag changes the viewport origin.

  • Toolbar tools include select, rectangle, ellipse, line, text, and paint bucket.
  • The header shows canvas metadata, revision state, active presence, navigation, and sharing controls.
  • Mouse wheel zooms around the pointer, and middle-button dragging pans without touching shared canvas state.
  • Select-tool background drag draws a box selection; dragging selected artwork moves selected units.
  • Delete/Backspace removes selected unlocked shapes; Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z, and Cmd/Ctrl+Y call server undo/redo.
  • Right-click shape menus expose z-order actions, group/ungroup, and delete.
  • The paint bucket can apply fill style to a shape or update the canvas background color.

Using SVG keeps the editor close to the document model. Rectangles, ellipses, lines, text, selection outlines, and handles are all inspectable vector elements rather than pixels in a canvas bitmap. The cost is that geometry has to be explicit: zoom, rotation, hit targets, transformed bounds, and text editing all need careful coordinate conversion.

screen(p)=zoom⋅(p−camera)screen(p) = zoom \cdot (p - camera)
Viewport transform. The whiteboard treats the SVG viewBox as camera state; shapes remain in shared canvas coordinates.

Selection behavior distinguishes object editing from viewport movement. Left-dragging the background with the select tool draws a box selection. Dragging any selected object moves the whole selection. Combined selection handles scale selected units, and the rotation handle rotates every selected unit around the selection center.

idle
  -> background pointer down with select tool: box-selecting
  -> drawing tool pointer down: drawing draft shape
  -> selected shape pointer down: moving
  -> resize handle pointer down: resizing
  -> rotation handle pointer down: rotating
  -> middle button down: panning local viewport

pointer up
  -> local preview becomes one durable operation when the gesture changed shared canvas state
Pointer interaction states. The frontend keeps local interaction state explicit so it can decide which gestures are local-only, transient previews, or durable history entries.

The interaction model tries to make the same gesture mean the same thing for one object, many objects, and a grouped unit. A drag moves the selected unit, a corner handle scales it, and the rotation handle rotates it. The implementation may produce one shape patch or a batch of many shape patches, but the user's mental model stays centered on the visible selection box.

p′=c+Rθ(p−c)p' = c + R_\theta(p-c)
Rotation transform. Lines rotate by transforming endpoints. Rect-like shapes rotate by moving their center and updating their stored rotation angle.

Selection overlays are not the stored axis-aligned boxes. Single rotated shapes compute rendered corners from the stored rotation so the outline and handles remain aligned with the visual object. Multi-selection and group overlays compute the axis-aligned bounds of each member's rendered corners, producing a combined box that wraps what the user actually sees.

Toolbar synchronization follows the same respect for selection state. When every selected relevant shape shares a value, that value appears in the toolbar. If selected shapes disagree, the control remains useful as a next action but does not pretend there is one current value. Text controls stay visible so users can discover them, but they are muted and disabled unless the selection contains only unlocked text shapes.

  • Stroke controls: color, opacity, width.
  • Fill controls: color and opacity.
  • Text controls: text color, text opacity, pixel font size with increase/decrease buttons, and left/center/right alignment.
  • Slider controls commit on release rather than on every movement.
  • Color controls preview locally while the picker is moving and commit once the color rests or the picker blurs.
  • Grouped members are locked from direct style, text, bucket, and delete mutations, while the group can still move, scale, rotate, or be nested into a parent group.
boundsrendered(s)=AABB({Rθqi}i=14)bounds_{rendered}(s) = AABB(\{R_\theta q_i\}_{i=1}^{4})
Rendered bounds. The overlay uses the axis-aligned bounding box of rotated corners for wrapping selected artwork.

The canvas is visually infinite and operationally finite only in the mathematical sense that coordinates must be valid finite numbers. The backend does not validate movement against the initial viewport dimensions, so dragging far left, right, up, or down can still produce a durable operation that every client will converge on.

valid(p)⇔isFinite(px)∧isFinite(py)valid(p) \Leftrightarrow isFinite(p_x) \land isFinite(p_y)
Coordinate validity. Durable movement validation follows the infinite-canvas model by rejecting non-finite values rather than rejecting coordinates outside the starting view.

Read-only canvas text is not browser-selectable, which keeps object drags from turning into accidental text selection. The one exception is the active inline text editor: while editing a text shape, that shape's editor allows normal browser text selection, caret movement, and typing.