Scene Graph
Immutable SceneState with pure mutation functions
The scene graph is the central data structure representing all elements on a page. All mutations are immutable — they return new SceneState objects rather than modifying in place.
SceneState
interface SceneState {
elements: Map<string, Element>;
elementOrder: string[]; // z-order sorted IDs
}| Field | Description |
|---|---|
elements | Map of element ID to Element for O(1) lookup |
elementOrder | Array of element IDs in z-order (rendering order) |
Functions
createScene
Creates an empty scene.
function createScene(): SceneState;import { createScene } from '@hfu.digital/boardkit-core';
const scene = createScene();
// { elements: Map(0), elementOrder: [] }addElement
Adds an element to the scene. Returns a new SceneState.
function addElement(scene: SceneState, element: Element): SceneState;import { createScene, addElement } from '@hfu.digital/boardkit-core';
const scene = createScene();
const updated = addElement(scene, myElement);
// original scene is unchangedremoveElement
Removes an element by ID. Returns a new SceneState.
function removeElement(scene: SceneState, id: string): SceneState;updateElement
Patches an element with partial data. Returns a new SceneState. Returns the original scene if the element is not found.
function updateElement(scene: SceneState, id: string, patch: Partial<Element>): SceneState;getElement
Retrieves an element by ID. Returns undefined if not found.
function getElement(scene: SceneState, id: string): Element | undefined;getElementsByPage
Returns all elements belonging to a specific page, in z-order.
function getElementsByPage(scene: SceneState, pageId: string): Element[];loadElements
Creates a SceneState from an array of elements, sorted by zIndex.
function loadElements(elements: Element[]): SceneState;This is useful for initializing the scene from server data:
import { loadElements } from '@hfu.digital/boardkit-core';
const elements = await fetch('/api/boards/123/pages/456/elements').then(r => r.json());
const scene = loadElements(elements);Immutability Pattern
All mutation functions follow the same pattern: they create new Map and Array instances rather than modifying the existing ones. This is critical for React integration, where useSyncExternalStore relies on reference equality to detect changes.
// Each call returns a NEW SceneState
const s1 = createScene();
const s2 = addElement(s1, elementA);
const s3 = addElement(s2, elementB);
const s4 = removeElement(s3, elementA.id);
// s1, s2, s3, s4 are all different objects
console.log(s1 === s2); // false
console.log(s2.elements.size); // 1
console.log(s3.elements.size); // 2
console.log(s4.elements.size); // 1