# Layout System Architecture ## Overview The Layout System provides a single source of truth for node positions, sizes, and spatial data in the ComfyUI frontend. It uses CRDT (Conflict-free Replicated Data Types) via Yjs to eliminate snap-back issues and ownership conflicts between LiteGraph and Vue components. ## Architecture ``` ┌─────────────────────┐ ┌────────────────────┐ │ Layout Store │────▶│ LiteGraph Canvas │ │ (CRDT/Yjs) │ │ (One-way sync) │ └────────┬────────────┘ └────────────────────┘ │ │ Mutations API │ ┌────────▼────────────┐ │ Vue Components │ │ (Read + Mutate) │ └─────────────────────┘ ``` ## Key Components ### 1. Layout Store (`/src/stores/layoutStore.ts`) - **Yjs-based CRDT implementation** for conflict-free operations - **Single source of truth** for all layout data - **Reactive state** with Vue `customRef` for shared write access - **Spatial queries** - find nodes at point or in bounds - **Operation history** - tracks all changes with actor/source ### 2. Layout Mutations (`/src/services/layoutMutations.ts`) - **Clean API** for modifying layout state - **Source tracking** - identifies where changes originated (canvas/vue/external) - **Direct operations** - no queuing, CRDT handles consistency ### 3. Vue Integration (`/src/composables/graph/useLayout.ts`) - **`useLayout()`** - Access store and mutations - **`useNodeLayout(nodeId)`** - Per-node reactive data and drag handlers - **`useLayoutSync()`** - One-way sync from Layout to LiteGraph ## Usage Examples ### Basic Node Access ```typescript const { store, mutations } = useLayout() // Get reactive node layout const nodeRef = store.getNodeLayoutRef('node-123') const position = computed(() => nodeRef.value?.position ?? { x: 0, y: 0 }) ``` ### Vue Component Integration ```vue ``` ## Performance Optimizations ### 1. **Spatial Query Caching** - Cache for `queryNodesInBounds` results - Cleared on any mutation for consistency ### 2. **Direct Transform Updates** - CSS `transform: translate()` for GPU acceleration - No layout recalculation during dragging - Smooth 60fps performance ### 3. **CSS Containment** - `contain: layout style paint` on nodes - Isolates rendering for better performance ### 4. **One-Way Data Flow** - Layout → LiteGraph only - Prevents circular updates and conflicts - Source tracking avoids sync loops ## CRDT Benefits Using Yjs even for single-user mode provides: - **Zero race conditions** between Vue and Canvas updates - **Built-in operation tracking** for debugging - **Future-proof** - ready for real-time collaboration - **Minimal overhead** - Yjs is optimized for local operations ## Node Stacking/Z-Index Based on LiteGraph's implementation: - Nodes are rendered in array order (later = on top) - Clicking a node brings it to front via `bringToFront()` - Z-index in layout store tracks rendering order - TODO: Implement interaction-based stacking ## API Reference ### LayoutStore Methods - `getNodeLayoutRef(nodeId)` - Get reactive node layout - `getAllNodes()` - Get all nodes as reactive Map - `getNodesInBounds(bounds)` - Reactive spatial query - `queryNodeAtPoint(point)` - Non-reactive point query - `queryNodesInBounds(bounds)` - Non-reactive bounds query - `initializeFromLiteGraph(nodes)` - Initialize from existing graph ### LayoutMutations Methods - `moveNode(nodeId, position)` - Update node position - `resizeNode(nodeId, size)` - Update node size - `setNodeZIndex(nodeId, zIndex)` - Update rendering order - `createNode(nodeId, layout)` - Add new node - `deleteNode(nodeId)` - Remove node - `setSource(source)` - Set mutation source - `setActor(actor)` - Set actor for CRDT ## Future Enhancements - [ ] Interaction-based z-index updates - [ ] QuadTree integration for O(log n) spatial queries - [ ] Undo/redo via operation history - [ ] Real-time collaboration via Yjs network adapters - [ ] Performance metrics collection ## Debug Mode Enable debug logging in development or via console: ```javascript localStorage.setItem('layout-debug', 'true') location.reload() ```