# BehaviorGraph Container-Based Architecture **Core Principle:** All nodes, links, blocks exist within **containers**. Containers manage, run, and render their contents. **Key Insight:** The app can have **multiple root containers**, each loaded from a separate file. Each root container represents a separate graph/document/workspace. ``` App ├── RootContainer1 (loaded from file1.json) │ ├── Node A │ ├── Node B │ └── BehaviorGraph Container (Group 1) │ ├── Node C │ └── BehaviorGraph Container (Nested Group) │ └── Node D │ ├── RootContainer2 (loaded from file2.json) │ ├── Node E │ └── Node F │ └── RootContainer3 (loaded from file3.json) └── BehaviorGraph Container (Group 2) └── Node G ``` ## Architecture Overview ### Container Hierarchy - **App Level** - Has **multiple root containers** (one per loaded file/graph) - Each root container is a separate workspace/graph - **Root Container** (one per file/graph) - Contains top-level nodes for that graph - Contains top-level groups for that graph - Loaded from a single file - **Group Containers** (BehaviorGraph instances) - Contain inner nodes - Can contain nested groups - Have their own pin interface (for external connections) ### Key Benefits 1. **No Duplication**: Each node exists in exactly ONE container 2. **Clear Ownership**: Container owns its nodes/links 3. **Clean Separation**: Containers handle management, execution, rendering 4. **Natural Nesting**: Groups are just containers within containers 5. **Unified Interface**: Root and groups use same container interface 6. **State Management**: Containers have flags (hidden, active/disabled, running, error) ### App Structure Changes ### 2. Group Creation **After:** - Create BehaviorGraph container within **current active root container** - Move selected nodes from active root container → group container - Move links (internal links stay, external links need group pins) - Group container owns these nodes now - Groups belong to the root container they were created in ### 3. Rendering - Render **active root container** (or all root containers if multi-view) - Root container renders its nodes - Root container renders its child containers (groups) - Each container renders its own contents - Different root containers can be in different tabs/views ### 4. Runtime Execution **After:** - **Active root container** runs (or all if running all graphs) - Container iterates its nodes - If node is a container (BehaviorGraph), call container->Run() - Nested containers run recursively - Each root container executes independently (or can be cross-container?) ### 5. Serialization **Before:** - Save all nodes - Save groups with `m_ParentGroup` references - Link up later **After:** - **Each root container saves to its own file** - Save container hierarchy (root container + all nested groups) - Each container saves its nodes/links - Natural tree structure per file - Multiple files = multiple root containers ### Introduces: - ✅ Clean ownership model - ✅ Natural nesting (containers in containers) - ✅ Unified interface (root = container, groups = containers) - ✅ Easier serialization (tree structure) - ✅ Cleaner rendering (containers render themselves) - ✅ State management (hidden, active/disabled, running, error flags) ### New Approach (Container) ``` App::m_RootContainers = [root1, root2] RootContainer1::m_Nodes = [node1, node2] RootContainer1::m_Children = [BehaviorGraphContainer1] BehaviorGraphContainer1::m_Nodes = [node3, node4] // MOVED from root1 RootContainer2::m_Nodes = [node5, node6] // Nodes exist in exactly ONE container // No duplication, no parent tracking needed // Each root container is independent (separate file/graph) ``` # Architecture Decision: Container-Based vs Node-Based ### Core Principle **Everything lives in a container.** Containers own their contents (nodes, links, nested containers). ``` Root Container (implicit, always exists) ├── Node A ├── Node B ├── BehaviorGraph Container (Group 1) │ ├── Node C │ ├── Node D │ └── BehaviorGraph Container (Nested Group) │ └── Node E └── Node F ``` ### Key Concepts 1. **Single Ownership**: Each node/link exists in exactly ONE container 2. **Hierarchical**: Containers can contain other containers (natural nesting) 3. **Unified Interface**: Root and groups use the same container API 4. **Clean Separation**: Container handles management, execution, rendering ### Implementation Structure ```cpp class Container { // Ownership std::vector m_Nodes; // Nodes in this container std::vector m_Links; // Links in this container std::vector m_Children; // Nested containers (groups) // Interface (for groups only - root has no interface) std::vector m_InputFlowPins; std::vector m_OutputFlowPins; std::vector m_InputParamPins; std::vector m_OutputParamPins; // Virtual connections (group pin → inner node pin) std::map m_GroupToInnerPins; // Management void AddNode(Node* node); void RemoveNode(Node* node); void AddLink(Link* link); void RemoveLink(Link* link); // Execution void Run(App* app); // Execute container contents // Rendering void Render(App* app, Pin* newLinkPin); // Query Container* FindContainer(NodeId nodeId); }; class BehaviorGraph : public Container, public ParameterizedBlock { // BehaviorGraph IS a container // Also acts as a block (for runtime execution) // Has group-specific UI (collapsed/expanded modes) }; class App { Container* m_RootContainer; // Default container for top-level items // Convenience methods Container* GetRootContainer() { return m_RootContainer; } Container* FindContainerForNode(NodeId nodeId); // Backward compatibility (optional - can maintain flattened view) std::vector GetAllNodes(); // Recursive flattening std::vector GetAllLinks(); // Recursive flattening }; ``` ## Migration Path ### Phase 2: Make BehaviorGraph a Container 1. BehaviorGraph inherits from Container 2. BehaviorGraph also inherits from ParameterizedBlock (block interface) 3. Group creation moves nodes from root → BehaviorGraph container ### Phase 3: Update All Systems 1. **Rendering**: Container-based (root renders self + children) 2. **Execution**: Container-based (root runs, nested containers run recursively) 3. **Serialization**: Container tree structure 4. **Queries**: Container-aware lookup methods ## Benefits Comparison ### Container-Based (New): - ✅ Single ownership (node owned by exactly one container) - ✅ No `m_ParentGroup` needed (container owns it) - ✅ Unified patterns (all containers same interface) - ✅ Natural serialization (save container tree) - ✅ Clear ownership (container owns contents) ## Decision: Container-Based Architecture **Alternative:** Can implement groups first with node-based approach, then refactor later (but creates technical debt). ## Next Steps 1. **Update Implementation Plan** - Reflect container architecture 2. **Design Container API** - Define exact interface 3. **Implement Root Container** - Move existing code 4. **Implement BehaviorGraph Container** - Group functionality 5. **Update All Systems** - Rendering, execution, serialization See `docs/groups-container-architecture.md` for detailed container design.