BoardAPI Documentation

JavaScript API exposed on window.BoardAPI for programmatic control of the board editor. Designed for AI agents, browser extensions, and automation scripts.

Overview

BoardAPI provides full control over the board editor: authentication, board management, element creation/modification, viewport control, and export. All functions are synchronous unless noted with async.

All data is stored locally in the browser using localStorage via js-doc-store. No server required. Multiple users can share the same browser with isolated data.

Quick Start

Open the browser console on board-editor.pages.dev and run:

// Register and create a flowchart in 10 lines
await BoardAPI.register('agent@ai.com', 'password123', 'AI Agent')

BoardAPI.createBoard('My Flowchart')

const start = BoardAPI.addShape('roundedRect', 100, 100, {text: 'Start', fill: '#A5D6A7'})
const check = BoardAPI.addShape('diamond', 300, 80, {text: 'OK?', fill: '#FFF176'})
const done = BoardAPI.addShape('circle', 500, 100, {text: 'End', fill: '#F48FB1'})

BoardAPI.addConnector(start.id, check.id)
BoardAPI.addConnector(check.id, done.id)

BoardAPI.addFrame(50, 30, 600, 250, {label: 'Validation'})
BoardAPI.saveBoard()

How to Access

The API is available in any of these ways:

Auth

Authentication is local (PBKDF2 + JWT stored in localStorage). Each user sees only their own boards.

register(email, password, name) async

Create a new user account and auto-login.

await BoardAPI.register('user@test.com', 'mypass123', 'Alice')
// → { ok: true, email: 'user@test.com', id: '...' }

login(email, password) async

Login to an existing account. Clears the current board and updates the UI.

await BoardAPI.login('user@test.com', 'mypass123')
// → { ok: true, email: 'user@test.com', id: '...' }

logout()

Sign out. Clears the canvas and session.

BoardAPI.logout()
// → { ok: true }

me()

Get the current logged-in user info, or null if not logged in.

BoardAPI.me()
// → { email: 'user@test.com', id: '...', roles: ['user'] }

Boards

createBoard(name)

Create a new empty board and set it as the active board.

BoardAPI.createBoard('Architecture Diagram')
// → { ok: true, name: 'Architecture Diagram' }

saveBoard(name?)

Save the current board. Uses the current name if none provided.

BoardAPI.saveBoard()          // save with current name
BoardAPI.saveBoard('v2')     // save as new name

loadBoard(name)

Load a saved board by name. Replaces the current canvas.

BoardAPI.loadBoard('Architecture Diagram')
// → { ok: true, elements: 15 }

listBoards()

List all boards for the current user.

BoardAPI.listBoards()
// → [{ name: 'Board 1', savedAt: '...', _id: '...' }, ...]

deleteBoard(name)

BoardAPI.deleteBoard('Old Board')

Elements

addShape(shapeType, x, y, opts?) returns {ok, id}

Add a geometric shape to the canvas.

ParamTypeDescription
shapeTypestringOne of: rectangle, roundedRect, circle, diamond, parallelogram, cylinder, hexagon, triangle, cloud
x, ynumberWorld coordinates (top-left corner)
opts.textstringText inside the shape
opts.fillstringFill color (hex). Default: #ffffff
opts.strokestringStroke color. Default: #1a1a18
opts.strokeWidthnumberStroke width. Default: 2
opts.w, opts.hnumberSize. Defaults vary by shape type
opts.fontSizenumberFont size. Default: 12
opts.boldbooleanBold text. Default: false
BoardAPI.addShape('diamond', 200, 100, {
  text: 'Is valid?',
  fill: '#FFF176',
  w: 140,
  h: 110
})
// → { ok: true, id: 'el_abc123' }

addSticky(x, y, opts?)

Add a sticky note (post-it).

ParamTypeDescription
opts.textstringNote text
opts.colornumberColor index (0-11). See Colors
opts.wnumberWidth. Default: 150
opts.boldbooleanBold text
BoardAPI.addSticky(100, 300, {text: 'Remember this', color: 4})

addFrame(x, y, w, h, opts?)

Add a frame/section to group elements visually.

ParamTypeDescription
x, y, w, hnumberPosition and size
opts.labelstringSection label. Default: 'Section'
opts.colorIdxnumberColor index (0-5). See Frame Colors
BoardAPI.addFrame(50, 30, 500, 300, {label: 'Phase 1', colorIdx: 3})

addConnector(fromId, toId, opts?)

Connect two elements with a Bezier curve.

ParamTypeDescription
fromId, toIdstringElement IDs to connect
opts.fromSidestringtop, bottom, left, right. Default: right
opts.toSidestringDefault: left
opts.colorstringStroke color. Default: #1a1a18
opts.dashedbooleanDashed line. Default: false
opts.arrowbooleanArrow head. Default: true
opts.widthnumberStroke width. Default: 2
BoardAPI.addConnector(start.id, end.id, {
  fromSide: 'bottom',
  toSide: 'top',
  color: '#c62828',
  dashed: true
})

addLabel(x, y, opts?)

Add free-floating text.

BoardAPI.addLabel(100, 50, {text: 'Title', fontSize: 24, bold: true})

updateElement(id, props)

Update any property of an existing element.

BoardAPI.updateElement('el_abc123', {text: 'Updated!', fill: '#F48FB1'})

deleteElement(id)

Delete an element. Also removes any connectors referencing it.

BoardAPI.deleteElement('el_abc123')

listElements(filter?)

List all elements, optionally filtered by properties.

BoardAPI.listElements()                     // all elements
BoardAPI.listElements({type: 'shape'})       // only shapes
BoardAPI.listElements({type: 'connector'})   // only connectors

batch(elements[]) bulk

Add multiple elements at once. Each element must have a type field. IDs are auto-generated if missing.

BoardAPI.batch([
  {type: 'shape', shapeType: 'circle', x: 100, y: 100, w: 80, h: 80, text: 'A', fill: '#A5D6A7'},
  {type: 'shape', shapeType: 'rectangle', x: 250, y: 100, w: 120, h: 60, text: 'B'},
  {type: 'sticky', x: 100, y: 250, text: 'Note', color: 1},
])
// → { ok: true, added: 3, elements: [...] }

Viewport

zoomTo(scale)

Set zoom level (0.1 to 3.0). 1.0 = 100%.

BoardAPI.zoomTo(1.5)  // 150%

panTo(wx, wy, scale?)

Animate the view to center on world coordinates, optionally setting zoom.

BoardAPI.panTo(400, 300, 1.0)

fitToFrame(frameName)

Zoom to fit a frame by its label name.

BoardAPI.fitToFrame('Phase 1')

resetView()

Reset to default zoom (60%) and position.

Export

exportJSON()

Get the board as a JSON object (for saving to file or sending to another system).

const data = BoardAPI.exportJSON()
// → { format: 'miro-board-editor', version: 1, name: '...', elements: [...], viewport: {...} }

exportHTML()

Get the board as a standalone HTML string with built-in pan/zoom.

const html = BoardAPI.exportHTML()

Also available: BoardAPI.downloadJSON() and BoardAPI.downloadHTML() to trigger file downloads.

GitHub Sync

Sync your boards across devices using GitHub Gists as storage. No server required — works 100% client-side using the GitHub Device Flow.

How it works: Your boards are exported as a JSON file and stored in a secret GitHub Gist linked to your account. When you sync from another device, boards are pulled from the Gist and merged with your local data. Cost: $0 (Gists are free and unlimited).

Connecting GitHub

Click the "GitHub" button in the top bar. A modal will appear with:

After you authorize, the app detects it automatically (no redirect needed). A "Sync" button appears in the top bar.

// Flow:
// 1. Click "GitHub" in topbar
// 2. Modal shows code: ABCD-1234
// 3. Go to github.com/login/device
// 4. Enter code, authorize
// 5. App auto-detects → "Sync" button appears

Syncing Boards

Click "Sync" to push local boards to GitHub and pull remote boards. The sync is bidirectional:

ActionWhat happens
PullDownloads boards from Gist. New boards are added locally. Existing boards are updated if the remote version is more recent.
PushUploads all local boards to the Gist (creates one if it doesn't exist).
SyncPull first, then push. Ensures both sides have the latest data.

Cross-device workflow

// Device A:
// 1. Register / Login
// 2. Connect GitHub
// 3. Create boards, edit, save
// 4. Click "Sync" → boards pushed to Gist

// Device B:
// 1. Login (same email/password)
// 2. Connect GitHub (same GitHub account)
// 3. Click "Sync" → boards pulled from Gist
// 4. Continue editing

Merge Strategy

When the same board exists both locally and remotely:

ScenarioResult
Board only exists locallyPushed to remote on next sync
Board only exists remotelyAdded locally on pull
Both exist, remote is newerRemote version overwrites local
Both exist, local is newerLocal version kept, pushed to remote

Merge is based on the savedAt timestamp of each board. The most recent version always wins.

Security

API (window.GitHubSync)

The GitHub sync module is also accessible programmatically:

// Check connection status
GitHubSync.isConnected()    // → true/false

// Push local boards to Gist
await GitHubSync.push()

// Pull remote boards from Gist
await GitHubSync.pull()
// → { added: 2, updated: 1, total: 5 }

// Pull + Push (bidirectional sync)
await GitHubSync.sync()

// Disconnect
GitHubSync.disconnect()

// Get last sync time
GitHubSync.getLastSync()   // → '2026-04-07T...' or null

// Get connected GitHub user
await GitHubSync.getUser()  // → { login: 'username', ... }

Storage format (Gist content)

{
  "format": "board-editor-sync",
  "version": 1,
  "exportedAt": "2026-04-07T...",
  "boards": [
    {
      "name": "My Flowchart",
      "elements": [...],
      "viewport": { "tx": 200, "ty": 200, "scale": 0.6 },
      "savedAt": "2026-04-07T..."
    }
  ]
}

Limits

LimitValue
Max Gist size10 MB (~200+ boards)
GitHub API rate limit5,000 requests/hour (authenticated)
Sync typeManual (click "Sync"), not real-time
CollaborationSingle-user per Gist (no shared editing)

Shape Types

TypeUse caseDefault size
rectangleProcess / generic120 x 80
roundedRectActivity / start-end120 x 80
circleStart / end node100 x 100
diamondDecision (if/else)120 x 100
parallelogramInput / output140 x 80
cylinderDatabase / storage100 x 120
hexagonPreparation / subprocess130 x 100
triangleAlert / note110 x 100
cloudExternal service / API140 x 100

Colors

Sticky Note Colors (index 0-11)

IndexNameBackground
0Yellow#FFF176
1Amber#FFD54F
2Orange#FFCC80
3Orange Light#FFF3E0
4Pink#F48FB1
5Pink Light#FCE4EC
6Green#A5D6A7
7Green Light#E8F5E9
8Blue#90CAF9
9Blue Light#E3F2FD
10Purple#CE93D8
11Purple Light#F3E5F5

Frame Colors (index 0-5)

IndexBorder
0#F0997B Coral
1#CE93D8 Purple
2#90CAF9 Blue
3#A5D6A7 Green
4#FFD54F Amber
5#FFCC80 Orange

Data Model

Each board is stored as a document with an elements[] array. Each element has:

{
  id: 'el_abc123',        // unique ID
  type: 'shape',           // sticky | shape | frame | connector | label | draw
  x: 100, y: 100,          // world position
  w: 120, h: 80,           // size
  // ... type-specific properties
}

Board Editor — Built with vanilla JS, zero dependencies. Powered by js-doc-store.