mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 22:59:14 +00:00
Major refactor to solve snap-back issues and create single source of truth for node positions: - Add Yjs-based CRDT layout store for conflict-free position management - Implement layout mutations service with clean API - Create Vue composables for layout access and node dragging - Add one-way sync from layout store to LiteGraph - Disable LiteGraph dragging when Vue nodes mode is enabled - Add z-index management with bring-to-front on node interaction - Add comprehensive TypeScript types for layout system - Include unit tests for layout store operations - Update documentation to reflect CRDT architecture This provides a solid foundation for both single-user performance and future real-time collaboration features. Co-Authored-By: Claude <noreply@anthropic.com>
4.6 KiB
4.6 KiB
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
customReffor 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 mutationsuseNodeLayout(nodeId)- Per-node reactive data and drag handlersuseLayoutSync()- One-way sync from Layout to LiteGraph
Usage Examples
Basic Node Access
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
<script setup>
const {
position,
nodeStyle,
startDrag,
handleDrag,
endDrag
} = useNodeLayout(props.nodeId)
</script>
<template>
<div
:style="nodeStyle"
@pointerdown="startDrag"
@pointermove="handleDrag"
@pointerup="endDrag"
>
<!-- Node content -->
</div>
</template>
Performance Optimizations
1. Spatial Query Caching
- Cache for
queryNodesInBoundsresults - 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 painton 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 layoutgetAllNodes()- Get all nodes as reactive MapgetNodesInBounds(bounds)- Reactive spatial queryqueryNodeAtPoint(point)- Non-reactive point queryqueryNodesInBounds(bounds)- Non-reactive bounds queryinitializeFromLiteGraph(nodes)- Initialize from existing graph
LayoutMutations Methods
moveNode(nodeId, position)- Update node positionresizeNode(nodeId, size)- Update node sizesetNodeZIndex(nodeId, zIndex)- Update rendering ordercreateNode(nodeId, layout)- Add new nodedeleteNode(nodeId)- Remove nodesetSource(source)- Set mutation sourcesetActor(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:
localStorage.setItem('layout-debug', 'true')
location.reload()