noteloom

Canvas

A freehand drawing surface — pen, two eraser modes, resizable text, and six shape tools, each with independent color and fill pickers. A pure widget block like Embed or Divider: contentIds is always empty, and everything lives in props.

Toolbar

ToolWhat it does
PenFreehand strokes, pressure-aware where the input device reports pressure.
EraserTwo modes, in a popover: Object (removes a whole stroke/shape on contact) and Precise (erases only the part of a stroke actually under the cursor).
SelectMove, resize, and rotate existing strokes/shapes/text; also exposes Bring to front / Send to back for overlapping shapes.
TextDrop resizable text anywhere on the canvas, with its own font-size control.
ShapeRectangle, Ellipse, Arrow, Diamond, Triangle, Star — one popover, remembers the last shape you used.
Color / FillSwatch pickers plus a custom-color swatch for stroke and fill independently; shapes support "no fill" (outline only).
Stroke sizeLine/shape-outline thickness.
ZoomZoom in / reset to 100% / zoom out, for working on a larger drawing than the block's own rendered size.
Export as PNGRasterizes the current drawing to a downloadable PNG, independent of the document's own SVG export (see Export below).

JSON shape

json
{
  "id": "c1",
  "type": "canvas",
  "contentIds": [],
  "props": {
    "strokes": [
      { "id": "s1", "color": "#6c5ce7", "size": 4, "points": [[100, 100, 0.6], [140, 160, 0.7]] }
    ],
    "shapes": [
      { "id": "sh1", "type": "rect", "x": 300, "y": 60, "width": 160, "height": 100, "color": "#1971c2", "strokeWidth": 2 }
    ],
    "width": 480,
    "height": 320
  }
}
PropTypeNotes
strokes{ id, points, color, size }[]Freehand pen strokes. points is an array of [x, y, pressure] triples.
shapes{ id, type, ... }[]type is one of rectangle, ellipse, diamond, triangle, star, or arrow. Every type except arrow shares { type, x, y, width, height, color, strokeWidth, fillColor? }; arrow instead uses { type: 'arrow', x1, y1, x2, y2, color, strokeWidth }. The arrowhead itself is derived at render/export time, not stored. fillColor is omitted (renders as outline-only) when the "no fill" option was chosen.
width / heightnumberThe block's own rendered pixel size, default 480 × 320. Resizable by dragging, like Embed.
Every point/shape coordinate is authored in a fixed 0–1000 normalized space, independent of width/height — resizing the canvas changes how big that fixed space is drawn, it never touches or rescales the stroke/shape data itself.

Using it in your editor

useEditor() registers every built-in block by default, canvas included — most apps need nothing extra here. Canvas is a single block type — no companion group like Table's TABLE_BLOCKS — so register it on its own if opting in manually:

jsx
import { useEditor, NoteloomEditor, registerBlocks, paragraphBlockType, canvasBlockType } from 'noteloom';

function Editor() {
  const editor = useEditor({
    registerBlocks: (registry) => registerBlocks(registry, { paragraph: paragraphBlockType, canvas: canvasBlockType }),
  });
  return <NoteloomEditor editor={editor} />;
}

See Picking only the blocks you want for combining this with other types.

canvasBlockType requires a noteloom version where it's exported from the package root — if it imports as undefined, update noteloom, or use registerBuiltInBlocks in the meantime (it already wires canvas in internally, opt-in or not).

Export

A canvas bakes down to a self-contained inline <svg> as part of the document's normal HTML export (toHTML / exportDocumentHTML / clipboard copy) — no canvas-to-image conversion step, and no extra asset to host. An empty canvas (no strokes or shapes yet) exports as an empty <p></p>, the same convention Embed uses for "nothing meaningful here yet."

Known limitations (v1)

  • No plain-text representation — toPlainText returns an empty string, the same as a divider's decorative "---". There is no OCR or auto-generated description of what was drawn.
  • A canvas can only be created via its own slash command. Pasting foreign SVG markup back in doesn't reverse-parse into editable stroke/shape data (reconstructing normalized points from arbitrary path d data is out of scope) — it falls through to whatever the paste pipeline does for an unrecognized node.

Slash command

Canvas — keywords: canvas, draw, drawing, sketch, freehand.

Styling

.be-canvas-toolbar and its .be-canvas-toolbar-btn/.be-canvas-picker family style the pen/eraser/text/shape/color controls — all covered by the default theme (Theming & styling) like every other block.