ReadonlyBoardAFTER event: Clear removed everything from the board (one undo step).
ReadonlyBoardAFTER event: LoadFromJSON rehydrated a persisted board into this instance.
ReadonlyChanged$Fires after every mutation (including undo/redo 'replace' events).
ReadonlyContentAFTER event: an item's content fields changed (markdown / html / text edits).
ReadonlyContentCancelable BEFORE event raised — in addition to ItemUpdating$ — when an
UpdateItem patch touches CONTENT fields (Text / Label / Sub / Markdown /
Html / Title). The dedicated hook for content governance: set Cancel = true
synchronously to veto the whole update.
ReadonlyItemAFTER event: an item was added (fires once per applied AddItem).
ReadonlyItemCancelable BEFORE event of AddItem (and Highlight /
DuplicateItem, which add through it). Set Cancel = true synchronously to
veto the add — AddItem then returns null and nothing changes.
ReadonlyItemAFTER event: an item was removed from the board.
ReadonlyItemCancelable BEFORE event of RemoveItem. Set Cancel = true synchronously to
keep the item — RemoveItem then returns false and nothing changes.
ReadonlyItemAFTER event: an item changed (patch applied / moved / z-reordered).
ReadonlyItemCancelable BEFORE event of UpdateItem (Operation: 'update'),
MoveItem ('move') and BringToFront / SendToBack
('reorder'). Set Cancel = true synchronously to veto — the mutator returns false.
ReadonlyPageAFTER event: a page was added (and became the active page).
ReadonlyPageReadonlyPageAFTER event: a page (and all of its items) was removed from the board.
ReadonlyPageCancelable BEFORE event of RemovePage (never raised for the guarded
last-page case). Set Cancel = true synchronously to keep the page.
ReadonlyPageAFTER event: a page was renamed.
ReadonlyPageCancelable BEFORE event of RenamePage. Handlers may rewrite NewName; set
Cancel = true synchronously to veto — RenamePage then returns false.
ReadonlyPageAFTER event: the active page changed via SwitchPage.
ReadonlyPageCancelable BEFORE event of SwitchPage. Set Cancel = true synchronously to
stay on the current page — SwitchPage then returns false.
ReadonlySelectionAFTER event: the single selection changed — via Select or implicitly (the selected item was removed / dropped by a restore). Selection is transient UI state, so this is a notification only (never cancelable, never journaled).
ID of the active page (every item operation targets this page).
Display name of the active page.
Current sequence number — use as the sinceToken for the next BuildSceneDelta.
ACTIVE-page "elements" as the status footer reports them (transient highlights excluded).
All items on the ACTIVE page in render order (ascending Z).
The ordered page list (read-only snapshots — see WhiteboardPageInfo).
The PRIMARY selected item's ID (the most recently selected member of the multi-selection), or null when nothing is selected. Selection is UI state — not persisted. For the full multi-selection see SelectedIDs.
All selected item IDs in selection order (last = primary). Returns a copy.
Total item count summed across ALL pages (the active-page count is ElementCount).
Add an item; the engine stamps ID, Z and Author and emits one change.
Raises the cancelable ItemAdding$ BEFORE event first — when a handler
cancels, nothing changes and null is returned. On success the stamped item is
returned and ItemAdded$ fires after the journal/Changed$ emission.
Add a new page and SWITCH to it. name is trimmed; when omitted (or blank) the page
auto-names itself "Page N" from the monotonic page counter, so auto-names never
repeat even after removals.
Raises the cancelable PageAdding$ BEFORE event (handlers may rewrite the
name) — returns null when vetoed; fires PageAdded$ after. One undoable
step; journals a 'replace' op (the agent's visible scene swaps to the new, empty
page), so perception consumers re-read the scene.
Optionalname: stringProtectedapplySwap the multi-selection and fire SelectionChanged$ when it differs.
ProtectedbeforePre-mutation bookkeeping shared by every committed mutation: pushes the undo snapshot (unless inside a RunBatch, which snapshotted at batch start) and invalidates the redo branch. Subclasses extending the mutation paths should call this exactly once per logical change, AFTER any cancelable before-event survived.
Raise an item above everything else. Follows the engine's existing Z handling:
++zCounter is by construction greater than every assigned Z (max + 1), exactly how
AddItem stamps new items. Journals as an 'update'.
Raises the cancelable ItemUpdating$ BEFORE event (Operation: 'reorder') —
returns false when vetoed or the ID is unknown; fires ItemUpdated$ after.
Build the coalesced scene delta of everything that changed AFTER sinceToken
(a previously observed CurrentSeq; defaults to 0 = everything).
Coalescing: per item, the NET effect wins — N moves → one moved entry at the current
position; add+move → one added entry (current state); add+remove → nothing;
update+move → one updated entry. When the window contains a 'replace' (undo/redo/load)
or the journal no longer reaches the token, the delta carries reset: true plus the full
compact items array — replace-current-state semantics, never an append-only log.
Full compact scene + counts — the popover's stats and the delta-reset payload.
ProtectedchangeApply a SINGLE-or-clear selection change (legacy internal path).
Remove EVERYTHING from the ACTIVE page as ONE undoable operation (other pages are
untouched). Journals a single 'replace' op (perception consumers re-read the
now-empty scene) and fires BoardCleared$. Clears the selection (firing
SelectionChanged$ when one existed). Returns false when the active page was
already empty.
ProtectedcompactProject one item to its compact, model-facing representation (deltas / summaries).
ProtectedcomposeThe page-aware scene sentence shared by every delta / summary tail line.
ProtectedcomposeCompose the human-readable tail line of deltas / summaries ("2 added, 1 moved. …"), including which page is active and the full page list — so the model always knows pages exist and which one its item entries describe.
Bounding box of all items (null when the board is empty). Powers fit-to-content + minimap.
Active-page elements by author (highlights excluded, same basis as ElementCount).
Duplicate an item: a DEEP clone (ink points included) with a fresh engine-stamped
identity, offset +16/+16 from the source so the copy is visibly distinct. Connectors
(which reference other items) and transient highlights cannot be duplicated — returns
null without mutating. The clone lands through AddItem, so it journals as a
normal 'add', is one undo step, and raises the ItemAdding$ /
ItemAdded$ pair (a canceled add also returns null).
Tolerant page lookup: by exact ID first, then by case-insensitive, trimmed name
(first match wins on duplicate names). Returns undefined when nothing matches.
Look up one ACTIVE-page item by ID (items on other pages are not visible here).
Convenience: add a pulsing highlight region (agent "pointing without touching").
Adds through AddItem, so the ItemAdding$ / ItemAdded$ pair
fires — returns null when a handler canceled the add.
Whether an item is part of the current (single or multi) selection.
Axis-aligned bounds for any item (estimates for content-sized kinds).
All ACTIVE-page items whose axis-aligned bounds intersect the given rectangle — the marquee (rubber-band) hit test, in render order. Transient highlight regions are excluded: they are "pointing" chrome dismissed by click, never selected. Edge-touching items (zero overlap area) do NOT count as intersecting.
Rehydrate THIS instance in place from ToJSON output — used by the channel's
RestoreState hook so existing subscriptions (perception feed, save pipeline) and any
bound surface keep pointing at the same engine. TOLERANT: malformed input returns
false and leaves the current state untouched (never throws).
On success the undo/redo stacks and journal are cleared (restored state is the new
baseline), stale delta tokens force reset semantics, one 'replace' change is
emitted so consumers re-read the full scene, and BoardLoaded$ fires.
Move an item to an absolute board position. Positioned kinds move their origin; ink strokes translate every point; connectors translate their floating endpoints.
Raises the cancelable ItemUpdating$ BEFORE event (Operation: 'move',
Position = the requested top-left) — returns false when vetoed or the ID is
unknown; fires ItemUpdated$ after an applied move.
Move EVERY selected item by the same delta as ONE undo step (the multi-select group
drag). Internally one RunBatch of per-item MoveItem calls, so each
member still raises its own cancelable 'move' BEFORE event (a veto skips just that
member) and journals normally — but a single Undo reverts the whole group move.
Returns how many items actually moved (0 when nothing is selected or the delta is 0).
ProtectednextMint the next stable item ID for a kind (sticky-3, shape-7, …).
ProtectedpageProject a live page record to its public read-only descriptor.
ProtectedpushPush the current scene onto the undo stack (bounded) and drop the redo branch.
ProtectedraiseRaise the cancelable 'reorder' BEFORE event; returns false when a handler vetoed.
ProtectedrecordPost-mutation bookkeeping shared by every committed mutation: bumps the sequence, appends the journal entry (bounded — trimming forces reset deltas for stale tokens) and emits the Changed$ notification.
Re-apply the most recently undone snapshot. Emits a 'replace' change.
Remove an item. Connectors that referenced it survive: their endpoint freezes to the removed item's last center (the floating-endpoint fallback).
Raises the cancelable ItemRemoving$ BEFORE event — returns false when vetoed or the ID is unknown; fires ItemRemoved$ after an applied removal.
Remove a page AND all of its items (tolerant lookup, same as SwitchPage).
The LAST remaining page can never be removed (false, no events). Removing the
ACTIVE page activates a neighbor — the next page when one exists, otherwise the
previous one.
Raises the cancelable PageRemoving$ BEFORE event — returns false when
vetoed or the page is unknown; fires PageRemoved$ after (with the activated
neighbor when the active page was removed). One undoable step; journals a
'replace' op.
Remove EVERY selected item as ONE undo step (the multi-select Delete key). One RunBatch of per-item RemoveItem calls — each member still raises its cancelable ItemRemoving$ BEFORE event (a veto keeps just that member), and a single Undo restores the whole group. The selection empties as items are removed. Returns how many items were actually removed.
Rename a page (tolerant lookup, same as SwitchPage). The new name is
trimmed; an empty result returns false. Renaming to the current name is a
successful no-op (no events, no journal entry).
Raises the cancelable PageRenaming$ BEFORE event (handlers may rewrite
NewName) — returns false when vetoed; fires PageRenamed$ after. One
undoable step; journals a 'replace' op so the agent's page list stays current.
Resolve one connector endpoint: anchored to the referenced item's bounds-center when the item still exists, otherwise the absolute fallback point (floating endpoint).
ProtectedrestoreSwap the whole board to a snapshot's pages/counters (drops a now-missing selection; an unknown active-page id falls back to the first page; an empty page list gains a fresh "Page 1" so the engine never runs page-less).
ProtectedsceneCompact page list for deltas / summaries (model-facing).
Set (or clear) the selection to a SINGLE item. Unknown IDs clear the selection. Fires SelectionChanged$ when the effective selection actually changes.
Replace the selection with a set of items (the marquee result). Unknown IDs are dropped and duplicates collapse to their first occurrence; order is preserved (the last surviving entry becomes the primary selection). An empty / fully-unknown list clears the selection.
Drop an item below everything else (current min Z − 1). Journals as an 'update'.
Raises the cancelable ItemUpdating$ BEFORE event (Operation: 'reorder') —
returns false when vetoed or the ID is unknown; fires ItemUpdated$ after.
ProtectedsnapshotDeep-copied serializable snapshot of the WHOLE board — every page's items plus the page structure and counters (undo entries / ToJSON). Page items serialize in render order (ascending Z).
Make another page the active page. Tolerant lookup: exact ID first, then case-insensitive name (see FindPage). Switching to the already-active page is a successful no-op (no events, no journal entry).
Raises the cancelable PageSwitching$ BEFORE event — returns false when
vetoed or the page is unknown; fires PageSwitched$ after. Journals a
'replace' op (the visible scene swaps wholesale) but deliberately pushes NO undo
snapshot — switching is navigation, not a content mutation.
Toggle one item's membership in the multi-selection WITHOUT clearing the rest — the shift-click semantics. A newly added item becomes the primary selection (SelectedID); unknown IDs are a no-op.
Serialize the board (state of record — persisted as the session-channel artifact). Emits the VERSION 2 paged shape (see WhiteboardStateJSON); the legacy flat shape is still accepted on load and rehydrates as a single page "Page 1".
Restore the previous snapshot. Emits a 'replace' change.
Patch an item's mutable fields. Returns false when the ID is unknown — or when a handler of the cancelable ItemUpdating$ BEFORE event (or, for patches that touch content fields, the cancelable ContentChanging$ event) vetoed the change. On success ItemUpdated$ — and ContentChanged$ for content patches — fires after the journal/Changed$ emission.
StaticFromRehydrate a board from ToJSON output — BOTH shapes accepted: the current
paged shape (version 2) and the legacy flat shape (version 1, items at the root),
which migrates to one page named "Page 1". Throws on malformed input (use
LoadFromJSON or ParseBoardStateJson for the tolerant variants).
Protected StaticisWhether a patch touches CONTENT fields (drives the ContentChanging/Changed pair).
The whiteboard engine: items + ordered render list, single selection, snapshot-based undo/redo (one entry per user gesture or per agent tool call via RunBatch), change journal + coalesced scene deltas, JSON persistence, and the cancelable BEFORE / AFTER mutation event surface.
Before / after events
Every targeted mutation raises a cancelable BEFORE event and, when it applies, a matching AFTER event:
Handlers run synchronously during the emit; setting
Cancel = trueon the event args aborts the mutation (the caller seesnull/false) with no undo snapshot, journal entry or Changed$ emission. These events layer ALONGSIDE the existing Changed$ / journal / perception machinery — they never replace it. Undo / redo whole-scene replacements are NOT item mutations and only surface through Changed$ as'replace'ops.