606 lines
21 KiB
Markdown
606 lines
21 KiB
Markdown
# BehaviorGraph (Groups) Implementation Plan - Container Architecture
|
|
|
|
## Overview
|
|
|
|
This document outlines the implementation plan for adding **BehaviorGraph** groups using a **container-based architecture**. Groups are implemented as nested containers within root containers.
|
|
|
|
**Core Principle:** All nodes, links, blocks exist within **containers**. Containers manage, run, and render their contents. The app supports **multiple root containers** (one per loaded file), and each root can contain groups (nested containers).
|
|
|
|
## Architecture
|
|
|
|
### Container Hierarchy
|
|
|
|
```
|
|
App
|
|
├── RootContainer1 (loaded from file1.json)
|
|
│ ├── Node A (top-level)
|
|
│ ├── Node B (top-level)
|
|
│ └── BehaviorGraph Container (Group 1)
|
|
│ ├── Node C (moved here, owned by Group 1)
|
|
│ ├── Node D (moved here, owned by Group 1)
|
|
│ └── BehaviorGraph Container (Nested Group)
|
|
│ └── Node E (owned by nested group)
|
|
│
|
|
├── RootContainer2 (loaded from file2.json)
|
|
│ └── Node F
|
|
│
|
|
└── RootContainer3 (loaded from file3.json)
|
|
└── BehaviorGraph Container (Group 2)
|
|
└── Node G
|
|
```
|
|
|
|
### Key Concepts
|
|
|
|
1. **Container Base Class**: Base class for all containers (root and groups)
|
|
2. **Root Container**: One per file/graph, contains top-level nodes and groups
|
|
3. **BehaviorGraph Container**: Groups that inherit from Container + ParameterizedBlock
|
|
4. **Single Ownership**: Each node/link exists in exactly ONE container
|
|
5. **No Duplication**: Nodes moved between containers, not copied
|
|
|
|
## Data Structures
|
|
|
|
|
|
### BehaviorGraph Container
|
|
|
|
**File:** `examples/blueprints-example/containers/behavior_graph.h`
|
|
|
|
```cpp
|
|
class BehaviorGraph : public Container, public ParameterizedBlock
|
|
{
|
|
public:
|
|
BehaviorGraph(int id, const char* name);
|
|
|
|
// Container interface
|
|
void AddNode(Node* node) override;
|
|
void RemoveNode(Node* node) override;
|
|
bool CanAddLink(Link* link) const override; // Validate group boundaries
|
|
|
|
// Block interface (from ParameterizedBlock)
|
|
void Build(Node& node, App* app) override;
|
|
void Render(Node& node, App* app, Pin* newLinkPin) override;
|
|
int Run(Node& node, App* app) override; // Propagate to inner blocks
|
|
|
|
// Container execution (called from Run(Node&, App*))
|
|
void Run(App* app) override; // Only if active, sets Running flag during execution
|
|
|
|
// Group-specific
|
|
enum class GroupDisplayMode { Expanded, Collapsed };
|
|
GroupDisplayMode GetDisplayMode() const { return m_DisplayMode; }
|
|
void SetDisplayMode(GroupDisplayMode mode) { m_DisplayMode = mode; }
|
|
|
|
// Pin management
|
|
void AddInputFlowPin(App* app);
|
|
void AddOutputFlowPin(App* app);
|
|
void AddInputParamPin(App* app, PinType type);
|
|
void AddOutputParamPin(App* app, PinType type);
|
|
void RemovePin(ed::PinId pinId, App* app);
|
|
|
|
// Pin mapping (virtual connections)
|
|
void MapGroupPinToInnerPin(ed::PinId groupPin, ed::PinId innerPin);
|
|
void UnmapGroupPin(ed::PinId groupPin);
|
|
|
|
private:
|
|
GroupDisplayMode m_DisplayMode = GroupDisplayMode::Expanded;
|
|
ImVec2 m_GroupSize; // For ed::Group() size
|
|
};
|
|
```
|
|
|
|
|
|
### GroupPin Structure
|
|
|
|
```cpp
|
|
struct GroupPin
|
|
{
|
|
ed::PinId ID;
|
|
std::string Name;
|
|
PinType Type;
|
|
PinKind Kind; // Input or Output
|
|
bool IsFlow; // true = flow pin, false = parameter pin
|
|
};
|
|
```
|
|
|
|
## Implementation Phases
|
|
|
|
|
|
### Phase 2: BehaviorGraph Container (Groups)
|
|
|
|
#### Task 2.1: Create BehaviorGraph Container
|
|
**Files:** `containers/behavior_graph.h`, `containers/behavior_graph.cpp`
|
|
|
|
- Define `BehaviorGraph` class inheriting from `Container` and `ParameterizedBlock`
|
|
- Add `GroupDisplayMode` enum
|
|
- Implement basic `Build()`, `Render()`, `Run()` stubs
|
|
- Add pin management methods (AddInputFlowPin, etc.)
|
|
- Store pins in node's Inputs/Outputs vectors (for ParameterizedBlock compatibility)
|
|
|
|
**Dependencies:** Task 1.1, `block.h`
|
|
|
|
#### Task 2.2: Implement Variable Pin System
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Implement `AddInputFlowPin()`, `AddOutputFlowPin()`
|
|
- Implement `AddInputParamPin()`, `AddOutputParamPin()`
|
|
- Store pins in container's pin vectors AND node's Inputs/Outputs vectors
|
|
- Pin editing similar to `parameter_node.h` (edit name, type, value)
|
|
- Update `Build()` to register pins with node editor
|
|
|
|
**Dependencies:** Task 2.1
|
|
|
|
#### Task 2.3: Implement Pin Removal
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Implement `RemovePin()` method
|
|
- Handle link cleanup when pin removed
|
|
- Remove from both container vectors and node vectors
|
|
- Update virtual connection mappings
|
|
|
|
**Dependencies:** Task 2.2
|
|
|
|
#### Task 2.4: Context Menu for Pin Management
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Extend `OnMenu()` (from ParameterizedBlock) to show:
|
|
- "Add Input Flow Pin"
|
|
- "Add Output Flow Pin"
|
|
- "Add Input Parameter Pin" (with type selection)
|
|
- "Add Output Parameter Pin" (with type selection)
|
|
- "Remove Pin" submenu (list all pins)
|
|
- Handle pin creation/removal from menu
|
|
|
|
**Dependencies:** Task 2.2, 2.3
|
|
|
|
### Phase 3: Display Modes
|
|
|
|
#### Task 3.1: Implement Expanded Mode Rendering
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Render group container with title bar
|
|
- Use `ed::Group(m_GroupSize)` to define group bounds
|
|
- Render flow pins on left/right edges (using `FlowPinRenderer`)
|
|
- Render parameter pins on top/bottom edges (using `ParameterPinRenderer`)
|
|
- Render inner nodes (from `m_Nodes`) inside group bounds
|
|
- Allow user interaction inside group
|
|
|
|
**Reference:** `ref/sample.cpp` lines 1397-1421
|
|
|
|
**Dependencies:** Task 2.1
|
|
|
|
#### Task 3.2: Implement Collapsed Mode Rendering
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Render as compact node (similar to block nodes)
|
|
- Show group name/title
|
|
- Render pins only (no inner nodes visible)
|
|
- Use `FlowPinRenderer` and `ParameterPinRenderer` for compact display
|
|
- Inner nodes not visible but remain in container (positions preserved)
|
|
|
|
**Dependencies:** Task 3.1
|
|
|
|
#### Task 3.3: Mode Toggle
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Add mode toggle to context menu
|
|
- Add keyboard shortcut (optional: 'T' key)
|
|
- Store mode in container state
|
|
- Persist in serialization
|
|
|
|
**Dependencies:** Task 3.1, 3.2
|
|
|
|
#### Task 3.4: Implement Container Flags
|
|
**Files:** `containers/container.cpp`, `containers/behavior_graph.cpp`
|
|
|
|
- Implement flag management (hidden, active/disabled, running, error)
|
|
- **Hidden**: Container not rendered (but still exists)
|
|
- **Active/Disabled**: Disabled containers don't execute (skip Run())
|
|
- **Running**: Set during execution, cleared after (visual feedback)
|
|
- **Error**: Set when container encounters error (visual feedback)
|
|
- Update Render() to check IsHidden()
|
|
- Update Run() to check IsActive() / IsDisabled()
|
|
- Visual indicators for running/error states (e.g., red border for error, pulsing for running)
|
|
|
|
**Dependencies:** Task 1.1
|
|
|
|
### Phase 4: Group Creation
|
|
|
|
#### Task 4.1: Implement 'g' Key Shortcut for Grouping
|
|
**Files:** `app-render.cpp`, `app-logic.cpp`
|
|
|
|
- In `HandleKeyboardShortcuts()`, detect 'g' key press
|
|
- Get selected nodes from active root container
|
|
- Calculate bounding box of selected nodes
|
|
- Create new `BehaviorGraph` container
|
|
- **Move selected nodes** from active root container → group container:
|
|
- Remove nodes from root container's `m_Nodes`
|
|
- Add nodes to group container's `m_Nodes`
|
|
- **Break external links** (links from/to selected nodes to/from external nodes)
|
|
- Move internal links (between selected nodes) to group container
|
|
- Add group container to root container's `m_Children`
|
|
- Set group size to encompass selected nodes (nodes keep absolute positions)
|
|
|
|
**Dependencies:** Task 2.1, 1.3
|
|
|
|
#### Task 4.2: Link Breaking Logic
|
|
**Files:** `app-logic.cpp`
|
|
|
|
- When creating group, scan all links
|
|
- For links connecting selected nodes to external nodes:
|
|
- Remove link from root container
|
|
- Store for potential group pin creation later
|
|
- For links between selected nodes:
|
|
- Move link to group container
|
|
- Clean up link references
|
|
|
|
**Dependencies:** Task 4.1
|
|
|
|
### Phase 5: Pin Connections & Runtime Execution
|
|
|
|
#### Task 5.0: Implement Container Flags (if not done in Phase 3)
|
|
**Files:** `containers/container.cpp`
|
|
|
|
- Implement flag getters/setters
|
|
- Update Render() to respect IsHidden()
|
|
- Update Run() to respect IsActive() / IsDisabled()
|
|
- Visual feedback for Running and Error states
|
|
|
|
**Dependencies:** Task 1.1
|
|
|
|
#### Task 5.1: Implement Virtual Pin Connections
|
|
**Files:** `containers/behavior_graph.cpp`, `app-logic.cpp`
|
|
|
|
- **Group pins act as proxies** - users connect external nodes to group pins
|
|
- **Virtual connections** stored in maps (NOT actual Link objects):
|
|
- `m_GroupToInnerPins`: Maps group input pin → inner node input pin
|
|
- `m_InnerToGroupPins`: Maps inner node output pin → group output pin
|
|
- **Link validation:** Prevent inner nodes from connecting directly to external nodes
|
|
- Override/extend `CanCreateLink()` in App to reject: inner pin ↔ external pin
|
|
- Only allow: group pin ↔ external pin, group pin ↔ inner pin (via mapping), inner pin ↔ inner pin
|
|
- **Pin mapping UI:** When user connects group pin to inner pin (or vice versa), store in mapping
|
|
|
|
**Dependencies:** Task 2.2, 4.1
|
|
|
|
#### Task 5.2: Implement Run() Method for Flow Execution
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Implement `Run(Node&, App*)` method (required for ParameterizedBlock):
|
|
|
|
**Step 1: Parameter propagation FIRST**
|
|
- Copy parameter values from group input pins to connected inner pins
|
|
- Use existing `GetInputParamValue*` helpers on group pins
|
|
- Use existing `SetOutputParamValue*` helpers (but apply to inner node pins)
|
|
- Use `m_GroupToInnerPins` mapping to find target inner pins
|
|
|
|
**Step 2: Flow activation**
|
|
- When group flow input is activated (via `IsInputActive()`):
|
|
- Find inner node connected via `m_GroupToInnerPins` mapping
|
|
- Activate the corresponding inner node's flow input (by index)
|
|
- Multiple activated inputs propagate independently
|
|
|
|
**Step 3: Output collection**
|
|
- After inner blocks execute (may be in next iteration), check inner node output states
|
|
- Iterate through `m_Nodes` (inner nodes)
|
|
- For each inner node output that's active, find mapped group output pin (via `m_InnerToGroupPins`)
|
|
- Activate corresponding group output pin
|
|
|
|
- Call `Run(App*)` from `Run(Node&, App*)` to execute inner blocks
|
|
|
|
**Execution Flow:**
|
|
1. Iteration N: Group input activated → `Run()` copies params, activates inner inputs → returns
|
|
2. Iteration N+1: Runtime detects inner nodes have activated inputs → executes inner blocks
|
|
3. Iteration N+2: Group `Run()` called again → collects inner outputs → activates group outputs
|
|
|
|
**Dependencies:** Task 5.1
|
|
|
|
#### Task 5.3: Update Runtime to Support Containers
|
|
**Files:** `app-runtime.cpp`, `containers/root_container.cpp`
|
|
|
|
- Update `ExecuteRuntimeStep()` to call `m_ActiveRootContainer->Run(app)` (only if active)
|
|
- Update `RootContainer::Run()` to:
|
|
- Check `IsActive()` / `IsDisabled()` - skip if disabled
|
|
- Set `SetRunning(true)` at start, `SetRunning(false)` at end
|
|
- Iterate through its nodes, find blocks with activated inputs
|
|
- Execute blocks
|
|
- For BehaviorGraph containers (in `m_Children`), call their `Run()` recursively (only if active)
|
|
- Container execution propagates through hierarchy naturally
|
|
- Respect disabled flag - disabled containers don't execute
|
|
|
|
**Dependencies:** Task 5.2
|
|
|
|
### Phase 6: Serialization
|
|
|
|
#### Task 6.1: Save Container Data
|
|
**Files:** `app-logic.cpp`, `containers/container.cpp`, `containers/behavior_graph.cpp`
|
|
|
|
- Extend `SaveGraph()` to save active root container:
|
|
- Container saves its nodes
|
|
- Container saves its links
|
|
- Container saves its child containers (recursively)
|
|
- BehaviorGraph saves pins, virtual mappings, display mode
|
|
- Each root container saves to its own file
|
|
|
|
**Dependencies:** Task 4.1, 5.1
|
|
|
|
#### Task 6.2: Load Container Data
|
|
**Files:** `app-logic.cpp`, `containers/container.cpp`, `containers/behavior_graph.cpp`
|
|
|
|
- **Loading order:** Nodes first, then links, then containers
|
|
- Extend `LoadGraph()` to:
|
|
1. Load nodes first (into temporary storage)
|
|
2. Load links (reference nodes by ID)
|
|
3. Load containers (root container first, then nested):
|
|
- Create container
|
|
- Assign nodes to container (by ID lookup)
|
|
- Assign links to container
|
|
- Restore pins, mappings, display mode
|
|
4. Establish virtual connections
|
|
|
|
**Dependencies:** Task 6.1
|
|
|
|
### Phase 7: Edge Cases & Polish
|
|
|
|
#### Task 7.1: Handle Edge Cases
|
|
**Files:** `containers/behavior_graph.cpp`, `app-logic.cpp`
|
|
|
|
- **Group nesting is allowed** - groups can contain other groups
|
|
- **Node deletion when inside group:**
|
|
- When node is deleted, remove from its container's `m_Nodes`
|
|
- Clean up any virtual pin mappings involving this node
|
|
- **Group deletion:**
|
|
- Remove group container from parent's `m_Children`
|
|
- Move inner nodes back to parent container (or delete)
|
|
- Break all links connected to group pins
|
|
- Clean up virtual pin mappings
|
|
- **Link deletion:**
|
|
- When link involving group pin is deleted, remove from virtual mappings
|
|
- When link between inner nodes is deleted, no special handling needed
|
|
- **Root container deletion:**
|
|
- Remove from `m_RootContainers`
|
|
- Delete all nodes/links/containers it owns
|
|
|
|
**Dependencies:** All previous tasks
|
|
|
|
#### Task 7.2: Visual Polish
|
|
**Files:** `containers/behavior_graph.cpp`
|
|
|
|
- Improve styling for collapsed vs expanded modes
|
|
- Add hover effects
|
|
- Add selection highlighting
|
|
- Improve pin layout/spacing
|
|
- Handle link rendering across group boundaries
|
|
|
|
**Dependencies:** Task 3.1, 3.2
|
|
|
|
## File Structure
|
|
|
|
```
|
|
examples/blueprints-example/
|
|
├── containers/
|
|
│ ├── container.h (NEW - base Container class)
|
|
│ ├── container.cpp (NEW)
|
|
│ ├── root_container.h (NEW)
|
|
│ ├── root_container.cpp (NEW)
|
|
│ ├── behavior_graph.h (NEW - BehaviorGraph container)
|
|
│ └── behavior_graph.cpp (NEW)
|
|
├── blocks/
|
|
│ └── (existing files...)
|
|
└── (existing files - updated)
|
|
```
|
|
|
|
## Key Implementation Details
|
|
|
|
### Node Movement (Not Duplication)
|
|
|
|
When creating a group:
|
|
```cpp
|
|
// Before: Nodes in root
|
|
rootContainer->m_Nodes = [node1, node2, node3]
|
|
|
|
// After grouping node1, node2:
|
|
rootContainer->m_Nodes = [node3]
|
|
rootContainer->m_Children = [behaviorGraph1]
|
|
behaviorGraph1->m_Nodes = [node1, node2] // MOVED, not duplicated
|
|
```
|
|
|
|
### Link Validation
|
|
|
|
```cpp
|
|
bool App::CanCreateLink(Pin* a, Pin* b)
|
|
{
|
|
// ... existing validation ...
|
|
|
|
// Check if pins are in different root containers (reject)
|
|
Container* containerA = FindContainerForNode(a->Node->ID);
|
|
Container* containerB = FindContainerForNode(b->Node->ID);
|
|
if (GetRootContainer(containerA) != GetRootContainer(containerB))
|
|
return false; // Cross-root connections not allowed
|
|
|
|
// Check group boundary violations
|
|
if (IsInnerPin(a) && IsExternalPin(b))
|
|
return false; // Inner pins can't connect to external pins
|
|
if (IsExternalPin(a) && IsInnerPin(b))
|
|
return false;
|
|
|
|
// ... rest of validation ...
|
|
}
|
|
```
|
|
|
|
### Container Rendering
|
|
|
|
```cpp
|
|
void RootContainer::Render(App* app, Pin* newLinkPin)
|
|
{
|
|
// Only render if not hidden
|
|
if (IsHidden())
|
|
return;
|
|
|
|
// Render this container's nodes
|
|
for (auto* node : m_Nodes)
|
|
{
|
|
RenderNode(node, app, newLinkPin);
|
|
}
|
|
|
|
// Render links between nodes in this container
|
|
for (auto* link : m_Links)
|
|
{
|
|
RenderLink(link, app);
|
|
}
|
|
|
|
// Render child containers (groups) - only if not hidden
|
|
for (auto* child : m_Children)
|
|
{
|
|
if (child->IsHidden())
|
|
continue;
|
|
|
|
if (auto* group = dynamic_cast<BehaviorGraph*>(child))
|
|
{
|
|
if (group->GetDisplayMode() == GroupDisplayMode::Expanded)
|
|
{
|
|
// Render expanded group with ed::Group()
|
|
group->Render(app, newLinkPin);
|
|
}
|
|
else
|
|
{
|
|
// Render as collapsed node
|
|
RenderCollapsedGroup(group, app, newLinkPin);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Container Execution
|
|
|
|
```cpp
|
|
void RootContainer::Run(App* app)
|
|
{
|
|
// Only execute if active (not disabled)
|
|
if (IsDisabled())
|
|
return;
|
|
|
|
// Set running flag
|
|
SetRunning(true);
|
|
|
|
// Execute blocks in this container
|
|
for (auto* node : m_Nodes)
|
|
{
|
|
if (node->IsBlockBased() && node->BlockInstance)
|
|
{
|
|
// Check if input activated, execute, etc. (existing logic)
|
|
}
|
|
}
|
|
|
|
// Execute child containers (groups) - only if active
|
|
for (auto* child : m_Children)
|
|
{
|
|
if (child->IsDisabled())
|
|
continue;
|
|
|
|
if (auto* group = dynamic_cast<BehaviorGraph*>(child))
|
|
{
|
|
// Group's Run() is called by runtime system when group input is activated
|
|
// But we can also call it here if needed for recursive execution
|
|
}
|
|
}
|
|
|
|
// Clear running flag
|
|
SetRunning(false);
|
|
}
|
|
```
|
|
|
|
## Final TODO List
|
|
|
|
|
|
### Phase 2: BehaviorGraph Container
|
|
4. **Create BehaviorGraph container** (`containers/behavior_graph.h/cpp`)
|
|
- Inherit from Container and ParameterizedBlock
|
|
- Add GroupDisplayMode
|
|
- Implement Build(), Render(), Run() stubs
|
|
|
|
5. **Implement variable pin management** (`behavior_graph.cpp`)
|
|
- AddInputFlowPin, AddOutputFlowPin
|
|
- AddInputParamPin, AddOutputParamPin
|
|
- RemovePin
|
|
- Pin editing (name, type, value)
|
|
|
|
6. **Implement context menu for pins** (`behavior_graph.cpp`)
|
|
- Add/remove pins via menu
|
|
- Similar to parameter_node.h patterns
|
|
|
|
### Phase 3: Display Modes
|
|
7. **Implement expanded mode rendering** (`behavior_graph.cpp`)
|
|
- Render with ed::Group()
|
|
- Render pins and inner nodes
|
|
|
|
8. **Implement collapsed mode rendering** (`behavior_graph.cpp`)
|
|
- Compact node view with pins only
|
|
|
|
9. **Implement mode toggle** (`behavior_graph.cpp`)
|
|
- Context menu and keyboard shortcut
|
|
|
|
10. **Implement container flags** (`container.cpp`)
|
|
- Hidden: Container not rendered
|
|
- Active/Disabled: Disabled containers don't execute
|
|
- Running: Visual feedback during execution
|
|
- Error: Visual feedback for errors
|
|
- Update Render() and Run() to respect flags
|
|
|
|
### Phase 4: Group Creation
|
|
10. **Implement 'g' key shortcut** (`app-render.cpp`)
|
|
- Detect 'g' key press
|
|
- Move selected nodes from root → group container
|
|
- Break external links
|
|
- Move internal links
|
|
|
|
### Phase 5: Pin Connections & Runtime
|
|
11. **Implement virtual pin connections** (`behavior_graph.cpp`)
|
|
- Store mappings (group pin → inner pin)
|
|
- Link validation (prevent inner ↔ external)
|
|
- Pin mapping UI
|
|
|
|
12. **Implement Run() method** (`behavior_graph.cpp`)
|
|
- Parameter propagation
|
|
- Flow activation
|
|
- Output collection
|
|
|
|
13. **Update runtime system** (`app-runtime.cpp`, `root_container.cpp`)
|
|
- Container-based execution
|
|
- Recursive container running
|
|
|
|
### Phase 6: Serialization
|
|
14. **Implement container serialization** (`container.cpp`, `behavior_graph.cpp`)
|
|
- Save container hierarchy
|
|
- Load in correct order (nodes → links → containers)
|
|
|
|
### Phase 7: Polish
|
|
16. **Handle edge cases** (`behavior_graph.cpp`, `app-logic.cpp`)
|
|
- Node deletion
|
|
- Group deletion
|
|
- Link deletion
|
|
- Root container deletion
|
|
|
|
17. **Visual polish** (`behavior_graph.cpp`)
|
|
- Visual indicators for flags (running, error, disabled, hidden)
|
|
- Styling, hover effects, selection
|
|
|
|
## Notes
|
|
|
|
- **Container-based architecture** eliminates duplication - nodes owned by exactly one container
|
|
- **Multiple root containers** - app supports multiple files, each is a root container
|
|
- **BehaviorGraph is a container** - inherits Container + ParameterizedBlock
|
|
- **No m_ParentGroup field** - container owns node, find via `FindContainerForNode()`
|
|
- **Group pins act as proxies** - virtual connections stored in maps
|
|
- **Link validation prevents** inner pins connecting directly to external pins
|
|
- **Group nesting allowed** - containers within containers
|
|
- **Serialization per file** - each root container saves to its own file
|
|
- Reference `app-runtime.cpp` for execution patterns
|
|
- Reference `parameter_node.h` for pin editing patterns
|
|
- Reference `ref/sample.cpp` for group rendering
|
|
- Reference `block.cpp` for pin rendering patterns
|
|
|
|
## Migration Strategy
|
|
|
|
1. **Start with container foundation** - Move existing code to use root container
|
|
2. **Then add BehaviorGraph** - Groups as nested containers
|
|
3. **Incremental migration** - Can maintain flattened view temporarily for compatibility
|
|
|
|
This architecture provides clean separation, no duplication, and natural multi-file support!
|