The core and editor packages

The framework-free engine (@opendrawjs/core) and editor (@opendrawjs/editor): scene document, history, export, commands and persistence.

@opendrawjs/core

The engine has no framework or DOM requirement. OpenDrawDocument holds the elements, the app state and history; every change goes through it, so undo, redo and change events always agree. Elements are plain, immutable objects, the shapes of the whiteboard (rectangle, diamond, ellipse, arrow, line, freedraw, text, image, frame, sticky note).

core.ts
import {
  OpenDrawDocument,
  newRectangleElement,
  exportToSvg,
  parseFile,
  serializeToJSON,
} from '@opendrawjs/core'

const doc = new OpenDrawDocument()
doc.addElement(newRectangleElement({ x: 0, y: 0, width: 160, height: 90 }))

// Every write is one undoable step; listeners hear each change.
doc.subscribe((state) => console.log(state.elements.length))
doc.undo()

// Export without a browser canvas:
const svg = exportToSvg(doc.getElements(), '#ffffff', { padding: 16 })
const json = serializeToJSON(doc.serialize())
const restored = parseFile(JSON.parse(json))
  • Factories: newRectangleElement, newLinearElement, newTextElement, newStickyNoteElement, newFrameElement, …
  • Export: exportToSvg, exportToDataURL (PNG), with padding, scale, theme and background options.
  • Files: parseFile validates untrusted JSON and drops malformed elements; serializeToJSON writes the .opendraw format.
  • Rendering: renderScene and renderOverlay paint onto any 2D canvas context.

@opendrawjs/editor

The whole interactive editor without a UI framework: createEditor() returns a controller (state getters plus commands), and mountCanvas() wires every gesture, shortcut, the text editor and rendering onto three DOM elements. subscribe() announces each change, that is all a UI layer needs.

editor.ts
import { createEditor, mountCanvas, runAction } from '@opendrawjs/editor'

const editor = createEditor({ appState: { theme: 'light' } })

const session = mountCanvas(editor, {
  host,          // a positioned element the canvases fill
  staticCanvas,  // the scene
  overlayCanvas, // selection chrome, stacked on top
})

editor.subscribe((ed) => renderMyToolbar(ed.activeTool, ed.canUndo))
editor.setActiveTool('rectangle')
runAction(editor, 'undo')

// later
session.dispose()
  • Tools: TOOLS lists every tool with its icon name, label and keys, render your toolbar from it.
  • Actions: ACTIONS / runAction / isActionEnabled, the commands behind menus and shortcuts, with labels and key hints.
  • Icons: actions and tools name a semantic IconName; your adapter maps each name to any icon set.

Persistence

persistence.ts
import { attachScenePersistence } from '@opendrawjs/editor'

const persistence = attachScenePersistence(editor, { storageKey: 'my-board' })
persistence.restore()  // load the saved scene, if any
// ...
persistence.dispose()  // flushes the last save