Whiteboard
The Whiteboard modality is a free-form canvas where components are placed at absolute positions and compiled into rendered elements. It implements all three core traits — Reducer, Component, and Modality — on a single struct.
Type Summary
Section titled “Type Summary”| Associated Type | Concrete Type |
|---|---|
Synced | WhiteboardSynced |
Ephemeral | WhiteboardEphemeral |
Position | WhiteboardPosition |
ChildComponent | dyn WhiteboardComponent |
Component::Metadata | WhiteboardMetadata |
Component::Output | Vec<WhiteboardElement> |
Snapshot | WhiteboardSnapshot |
Session type: Session<Whiteboard, SessionIntent<WhiteboardIntent>>
Struct
Section titled “Struct”pub struct Whiteboard { rt: Runtime<Self>,}Embeds Runtime<Self> which holds State<WhiteboardSynced, WhiteboardEphemeral> inside rt.state. Implements Reducer<State = State<WhiteboardSynced, WhiteboardEphemeral>>, Component<Metadata = WhiteboardMetadata, Output = Vec<WhiteboardElement>>, and Modality.
Position
Section titled “Position”WhiteboardPosition describes where a component sits on the canvas:
pub struct WhiteboardPosition { pub x: f64, pub y: f64, pub w: f64, pub h: f64, pub rotation: f64, pub z_index: i32,}Implements Clone, PartialEq, Hash, Describe. Describe output: "x:100 y:200 w:400 h:300".
Synced State
Section titled “Synced State”WhiteboardSynced stores only placements — there is no separate objects list. Every shape, text box, or card on the canvas is a ComponentPlacement<WhiteboardPosition>.
pub struct WhiteboardSynced { pub placements: Vec<ComponentPlacement<WhiteboardPosition>>, // resource metadata (HasResourceMeta)}Each placement has a component_key (e.g. "text_box", "card", "shape") that maps to a static component in the registry, and an optional component_id for forked/customized instances loaded from storage.
Ephemeral State
Section titled “Ephemeral State”WhiteboardEphemeral holds runtime-only state that is not persisted:
pub struct WhiteboardEphemeral { pub output: Vec<WhiteboardElement>, pub selected_ids: Vec<String>, pub current_tool: ToolType, pub tool_color: Color, pub tool_thickness: f64, pub tool_shape_type: ShapeType, pub tool_font_family: TextFontFamily, pub canvas_zoom: f64, pub canvas_pan_x: f64, pub canvas_pan_y: f64, pub canvas_width: f64, pub canvas_height: f64, // the Embedded Prose RFC: Embedded Prose pub doc: LoroDoc, // LoroDoc handle for creating LoroText containers pub prose_editors: HashMap<String, Prose>, // embedded prose editors keyed by placement ID pub focused_text_id: Option<String>, // currently focused text element for inline editing}The doc, prose_editors, and focused_text_id fields were added by the Embedded Prose RFC (Embedded Prose). Text elements now have live LoroText containers instead of opaque prose_bytes. The Prose embedded Reducer handles text editing without a separate ProseSession.
Elements
Section titled “Elements”Elements are the compiled output — leaf rendered primitives on the canvas. The old WhiteboardObject enum is renamed to WhiteboardElement:
pub enum WhiteboardElement { Path(PathElement), Shape(ShapeElement), Text(TextElement), Image(ImageElement), Native(NativeElement), // ... additional variants}Elements are never directly mutated. You modify placements, property values, and metadata; recompilation flows downward to produce new elements.
Compilation
Section titled “Compilation”The whiteboard’s compile() delegates to layout(), which iterates all placements, resolves bindings, and calls compile_child for each:
// Simplified flowfn compile(&self, metadata: &WhiteboardMetadata, values: &HashMap<String, PropertyValue>) -> Result<Vec<WhiteboardElement>, CompileError>{ let pairs = self.layout(|placement, meta, resolved| { self.compile_child(placement, meta, resolved) }, values)?; Ok(self.assemble(pairs))}child_metadata() extracts a Rect from the placement’s WhiteboardPosition. assemble() flattens the per-component Vec<WhiteboardElement> outputs into a single Vec<WhiteboardElement>.
Related
Section titled “Related”- Intents — all
WhiteboardIntentvariants - Components — the
WhiteboardComponentsubtrait and built-ins Reducer— state management via the Genvoy patternCommand— the universal envelope wrappingWhiteboardIntentLesson Plan— parent modality that embeds whiteboards as child sessionsFRB Patterns— how whiteboard types cross the Dart/Rust boundary