Lesson Plan
The LessonPlan modality organizes slides into sections, where each slide embeds a whiteboard. It is the only current parent modality — it implements HasChildren and uses Slot for hot/cold child session management. Like all modalities, a single struct implements Reducer, Component, and Modality.
Type Summary
Section titled “Type Summary”| Associated Type | Concrete Type |
|---|---|
Synced | LessonPlanSynced |
Ephemeral | LessonPlanEphemeral |
Position | SlidePosition |
ChildComponent | Slot<Session<Whiteboard, SessionIntent<WhiteboardIntent>>, Vec<WhiteboardElement>> |
Component::Metadata | LessonPlanMetadata |
Component::Output | Vec<CompiledSlide> |
Snapshot | LessonPlanSnapshot |
Session type: Session<LessonPlan, ParentSessionIntent<LessonPlanIntent, SessionIntent<WhiteboardIntent>>>
Struct
Section titled “Struct”pub struct LessonPlan { state: State<LessonPlanSynced, LessonPlanEphemeral>, children: HashMap<String, Slot< Session<Whiteboard, SessionIntent<WhiteboardIntent>>, Vec<WhiteboardElement>, >>,}The children map is keyed by placement ID. Each value is a Slot that is either Cold (cached output) or Hot (full child session).
Position
Section titled “Position”SlidePosition describes a slide’s place in the lesson structure:
pub struct SlidePosition { pub section_id: String, pub enabled: bool, pub duration: Duration,}Implements Clone, PartialEq, Hash, Describe. Describe output: "slide in section X, enabled, 5min".
Synced State
Section titled “Synced State”pub struct LessonPlanSynced { pub placements: Vec<ComponentPlacement<SlidePosition>>, // resource metadata (HasResourceMeta)}Every placement uses component_key: "whiteboard" and component_id: Some("specific-whiteboard-uuid"). Each slide always references a specific whiteboard instance loaded from storage.
Compilation
Section titled “Compilation”layout() iterates placements, looks up children by component_id, and calls slot.compile(). Cold slots return cached Vec<WhiteboardElement>; Hot slots delegate to the child Session::compile() which returns its already-compiled output.
LessonPlan overrides layout() to filter disabled slides:
fn layout<F>(&self, compile_child: F, values: &HashMap<String, PropertyValue>) -> Result<Vec<(ComponentPlacement<SlidePosition>, Vec<WhiteboardElement>)>, CompileError>where F: Fn(&ComponentPlacement<SlidePosition>, &WhiteboardMetadata, &HashMap<String, PropertyValue>) -> Result<Vec<WhiteboardElement>, CompileError>,{ self.placements().iter() .filter(|p| p.position.enabled) .map(|p| { let meta = self.child_metadata(p); let resolved = resolve_bindings(&p.bindings, values); compile_child(p, &meta, &resolved).map(|out| (p.clone(), out)) }) .collect()}child_metadata() returns WhiteboardMetadata for the slide’s whiteboard. assemble() builds Vec<CompiledSlide> from the (placement, child output) pairs.
Parent Dispatch
Section titled “Parent Dispatch”The ParentSessionIntent enum routes commands to the lesson plan or its children:
pub enum ParentSessionIntent<I, CI> { Base(SessionIntent<I>), // delegate to leaf behavior Child { id: Option<String>, intent: CI }, // route to child session WarmChild { id: String }, // promote Cold -> Hot}Child { id: None, intent } routes to selected_child_id(). The concrete type for LessonPlan:
ParentSessionIntent<LessonPlanIntent, SessionIntent<WhiteboardIntent>>Feedback
Section titled “Feedback”pub enum ParentSessionFeedback { Base(SessionFeedback), ChildWarmed { id: String, bytes: Vec<u8> },}Related
Section titled “Related”- Children — HasChildren impl, hot/cold lifecycle, child AI
Whiteboard— the child modality embedded in each slideReducer— state management via the Genvoy patternCommand— the universal envelopeFRB API Layer— thin open/dispatch/close surface