Claude-skill-registry dev-debug-canvas-nested-groups
This skill should be used when debugging Vue Flow canvas issues involving nested nodes, parent-child relationships, position coordinate systems, and containment detection. Triggers on nested group problems, section nodes jumping, parent-child synchronization bugs, position persistence issues, and coordinate transformation errors in Vue Flow implementations.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dev-debug-canvas-nested-groups" ~/.claude/skills/majiayu000-claude-skill-registry-dev-debug-canvas-nested-groups && rm -rf "$T"
skills/data/dev-debug-canvas-nested-groups/SKILL.mdVue Flow Nested Nodes Debugging Skill
Overview
Debug Vue Flow nested nodes, parent-child relationships, position coordinate systems, and containment detection issues. This skill provides systematic diagnostic procedures, code patterns, and utilities for troubleshooting complex canvas hierarchy problems.
When to Use This Skill
Use this skill when encountering:
- Nested groups not moving together when parent is dragged
- Section nodes jumping to unexpected positions
- Parent-child relationships not being recognized
- Tasks inside groups not being detected correctly
- Position values appearing incorrect after operations
- Groups resetting or losing their nested structure
- Coordinate mismatches between UI and stored data
Quick Diagnostic
Before deep debugging, run these quick checks:
// 1. Check if parentNode is properly set const node = getNode('task-123') console.log('Parent:', node?.parentNode) // Should be group ID or undefined // 2. Verify coordinate types console.log('Position (relative):', node?.position) console.log('ComputedPosition (absolute):', node?.computedPosition) // 3. Check extent mode console.log('Extent:', node?.extent) // 'parent' for constrained children
Core Concept: Coordinate Systems
CRITICAL: Vue Flow uses TWO coordinate systems that must not be confused:
| Property | Type | When Used |
|---|---|---|
| Relative to parent | Child nodes with set |
| Absolute canvas coords | Root nodes (no parent) |
| Always absolute | Use for canvas operations |
Golden Rule: Store relative positions for children, use
computedPosition for calculations.
Debugging Workflow
Step 1: Identify the Problem Type
Consult the troubleshooting tree in
references/troubleshooting-tree.md:
- Position Issues: Node jumping, incorrect placement, reset positions
- Hierarchy Issues: Parent-child not recognized, nesting lost
- Movement Issues: Children not moving with parent, group drag problems
- Containment Issues: Tasks not detected inside groups
Step 2: Enable Debug Logging
Add targeted logging based on problem type:
// For position debugging watch(() => node.position, (newPos, oldPos) => { console.log(`[POSITION] ${node.id}: ${JSON.stringify(oldPos)} → ${JSON.stringify(newPos)}`) }, { deep: true }) // For hierarchy debugging watch(() => node.parentNode, (newParent, oldParent) => { console.log(`[HIERARCHY] ${node.id}: parent ${oldParent} → ${newParent}`) })
Step 3: Use Diagnostic Utilities
Load the debugging utilities from
scripts/vueFlowDebug.ts:
import { logNodeHierarchy, validateParentChild, dumpCanvasState } from './vueFlowDebug' // Dump full canvas state dumpCanvasState(getNodes.value, getEdges.value) // Validate all parent-child relationships validateParentChild(getNodes.value) // Log hierarchy tree logNodeHierarchy(getNodes.value)
Step 4: Apply Fix Patterns
Consult
references/code-patterns.md for proven solutions:
- Reparenting: Correct way to move node between parents
- Position Conversion: Converting between coordinate systems
- Containment Detection: Proper center-point-in-bounds check
Common Bugs and Solutions
Bug 1: Child Not Moving with Parent
Symptom: Dragging parent leaves children behind
Cause:
parentNode property not set or position stored as absolute
Fix:
// Ensure parentNode is set updateNode(childId, { parentNode: parentId }) // Convert to relative position const parent = getNode(parentId) const relativePos = { x: child.computedPosition.x - parent.computedPosition.x, y: child.computedPosition.y - parent.computedPosition.y } updateNode(childId, { position: relativePos })
Bug 2: Node Jumping When Set as Child
Symptom: Node teleports when assigned parent
Cause: Absolute position interpreted as relative after parent set
Fix: Convert position BEFORE setting parentNode:
const parent = getNode(parentId) const child = getNode(childId) // Step 1: Calculate relative position first const relativePos = { x: child.computedPosition.x - parent.computedPosition.x, y: child.computedPosition.y - parent.computedPosition.y } // Step 2: Update both in same call updateNode(childId, { parentNode: parentId, position: relativePos })
Bug 3: Containment Detection Fails
Symptom: Tasks inside group not recognized
Cause: Comparing relative position against absolute bounds
Fix: Always use
computedPosition for containment:
function isInsideGroup(task: Node, group: Node): boolean { // WRONG: task.position (may be relative) // RIGHT: task.computedPosition (always absolute) const taskCenter = { x: task.computedPosition.x + (task.dimensions?.width ?? 200) / 2, y: task.computedPosition.y + (task.dimensions?.height ?? 100) / 2 } return ( taskCenter.x >= group.computedPosition.x && taskCenter.x <= group.computedPosition.x + (group.dimensions?.width ?? 400) && taskCenter.y >= group.computedPosition.y && taskCenter.y <= group.computedPosition.y + (group.dimensions?.height ?? 300) ) }
Bug 4: Position Persistence Issues
Symptom: Positions reset on page reload
Cause: Storing
computedPosition instead of position for children
Fix: Store the correct coordinate type:
function saveNodePosition(node: Node) { // For children: store relative position // For root nodes: store absolute position // node.position is ALWAYS what should be stored await saveToDatabase({ id: node.id, position: node.position, // NOT computedPosition parentNode: node.parentNode }) }
Bug 5: Stale Parent Reference
Symptom: "Stale parentGroupId" warnings, child outside parent bounds
Cause: Parent moved/deleted but child still references it
Fix: Validate and repair on load:
function validateHierarchy(nodes: Node[]) { const nodeMap = new Map(nodes.map(n => [n.id, n])) for (const node of nodes) { if (node.parentNode && !nodeMap.has(node.parentNode)) { console.warn(`Orphan node ${node.id} - parent ${node.parentNode} missing`) // Convert to root node node.parentNode = undefined // Position is already absolute-equivalent, keep as-is } } }
Resources
references/
- Deep dive into Vue Flow coordinate systemscoordinate-system.md
- Systematic problem diagnosis flowcharttroubleshooting-tree.md
- Proven code patterns for common operationscode-patterns.md
- Playwright E2E test patterns for nested groups and parent movemente2e-test-patterns.md
scripts/
- TypeScript debugging utilities for Vue FlowvueFlowDebug.ts
Verification Checklist
After applying fixes, verify:
- Dragging parent moves all children together
- Positions persist correctly across page reloads
- New tasks dropped in group are detected as children
- Nested groups maintain hierarchy when moved
- No position jumping on any operation
- Console shows no stale parent warnings