| name | canvas-debugging |
| description | Debug canvas layout issues, grid positioning problems, and component overlap. Use when troubleshooting Konva canvas rendering, grid constraints, snap-to-grid behavior, or visual layout mismatches. Includes Canvas→CSS Grid conversion debugging. |
| allowed-tools | Read, Glob, Grep |
Canvas Debugging Skill
Visual Layout Builder의 Konva 기반 Canvas 시스템 디버깅을 위한 전문 스킬입니다. Grid 위치 계산, 컴포넌트 충돌, 스냅 동작 문제를 해결합니다.
When to Use
- Canvas에서 컴포넌트 위치가 잘못 표시될 때
- Grid 스냅이 예상대로 동작하지 않을 때
- 컴포넌트 겹침(overlap) 문제 발생 시
- Canvas→CSS Grid 변환 오류 디버깅
- Breakpoint 전환 시 레이아웃 문제
- 드래그 앤 드롭 동작 이상
components/canvas/ 관련 이슈
Canvas System Architecture
Core Components
components/canvas/
├── KonvaCanvas.tsx # Main canvas with Konva Stage/Layer
├── ComponentNode.tsx # Individual component rendering
├── ComponentPreview.tsx # Drag preview
├── Canvas.tsx # Canvas + component management
└── index.ts # Public exports
Canvas Coordinate System
Canvas Grid (0-based coordinates)
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│0,0│1,0│2,0│3,0│4,0│5,0│6,0│7,0│8,0│9,0│10 │11 │ Row 0
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│0,1│1,1│2,1│...│...│...│...│...│...│...│...│11,1 Row 1
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│...│...│...│...│...│...│...│...│...│...│...│...│ ...
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
CanvasLayout:
- x: Grid column start (0-based)
- y: Grid row start (0-based)
- width: Number of columns to span
- height: Number of rows to span
CSS Grid Conversion (1-based)
gridColumn: `${x + 1} / ${x + width + 1}`
gridRow: `${y + 1} / ${y + height + 1}`
gridArea: `${y + 1} / ${x + 1} / ${y + height + 1} / ${x + width + 1}`
Common Issues & Solutions
Issue 1: Component Position Mismatch
Symptom: Component appears in wrong position after drag
Debug Steps:
const cellWidth = canvasWidth / gridCols
const cellHeight = canvasHeight / gridRows
console.log('Cell dimensions:', { cellWidth, cellHeight })
const gridX = Math.floor(pixelX / cellWidth)
const gridY = Math.floor(pixelY / cellHeight)
console.log('Grid position:', { gridX, gridY })
console.log('Component layout:', component.responsiveCanvasLayout?.[breakpoint])
Common Causes:
Math.round() vs Math.floor() inconsistency
- Canvas padding/margin not accounted for
- Breakpoint mismatch (editing mobile, viewing desktop)
Issue 2: Component Overlap Detection
Symptom: Components overlap but no warning shown
Debug with schema-validation.ts:
import { validateSchema } from '@/lib/schema-validation'
const result = validateSchema(schema)
const overlapWarnings = result.warnings?.filter(
w => w.code === 'CANVAS_COMPONENTS_OVERLAP'
)
console.log('Overlapping components:', overlapWarnings)
Overlap Detection Logic:
function checkOverlap(a: CanvasLayout, b: CanvasLayout): boolean {
return !(
a.x + a.width <= b.x ||
b.x + b.width <= a.x ||
a.y + a.height <= b.y ||
b.y + b.height <= a.y
)
}
Issue 3: Grid Snap Not Working
Symptom: Components don't snap to grid when dragged
Debug Steps:
export function snapToGrid(
x: number,
y: number,
cellWidth: number,
cellHeight: number
): { x: number; y: number } {
console.log('Input:', { x, y })
console.log('Cell size:', { cellWidth, cellHeight })
const snappedX = Math.round(x / cellWidth) * cellWidth
const snappedY = Math.round(y / cellHeight) * cellHeight
console.log('Snapped:', { snappedX, snappedY })
return { x: snappedX, y: snappedY }
}
Check Grid Constraints:
import { GRID_CONSTRAINTS } from '@/lib/schema-utils'
console.log('Grid constraints:', {
minCols: GRID_CONSTRAINTS.minCols,
maxCols: GRID_CONSTRAINTS.maxCols,
minRows: GRID_CONSTRAINTS.minRows,
maxRows: GRID_CONSTRAINTS.maxRows
})
Issue 4: Canvas Out of Bounds
Symptom: Component placed outside grid bounds
Validation Code: CANVAS_OUT_OF_BOUNDS
function validateBounds(layout: CanvasLayout, gridCols: number, gridRows: number) {
const issues = []
if (layout.x < 0 || layout.y < 0) {
issues.push('CANVAS_NEGATIVE_COORDINATE')
}
if (layout.x + layout.width > gridCols) {
issues.push(`Out of bounds: x(${layout.x}) + width(${layout.width}) > gridCols(${gridCols})`)
}
if (layout.y + layout.height > gridRows) {
issues.push(`Out of bounds: y(${layout.y}) + height(${layout.height}) > gridRows(${gridRows})`)
}
return issues
}
Issue 5: Breakpoint Layout Inheritance
Symptom: Component has layout in mobile but not in desktop
Debug:
const component = schema.components.find(c => c.id === 'c1')
console.log('Canvas layouts by breakpoint:')
for (const bp of schema.breakpoints) {
const layout = component?.responsiveCanvasLayout?.[bp.name]
console.log(` ${bp.name}:`, layout || 'MISSING')
}
const normalized = normalizeSchema(schema)
const normalizedComponent = normalized.components.find(c => c.id === 'c1')
console.log('After normalization:')
for (const bp of normalized.breakpoints) {
const layout = normalizedComponent?.responsiveCanvasLayout?.[bp.name]
console.log(` ${bp.name}:`, layout || 'STILL MISSING')
}
Issue 6: CSS Grid Conversion Errors
Symptom: AI-generated code doesn't match canvas layout
Debug canvas-to-grid.ts:
import { canvasToGridPositions } from '@/lib/canvas-to-grid'
const positions = canvasToGridPositions(
schema.components,
'desktop',
12,
8
)
console.log('Grid positions:')
positions.forEach(p => {
console.log(` ${p.componentId}:`)
console.log(` gridColumn: ${p.gridColumn}`)
console.log(` gridRow: ${p.gridRow}`)
console.log(` gridArea: ${p.gridArea}`)
})
Expected Format:
c1 (Header):
gridColumn: "1 / 13" // Full width (12 cols)
gridRow: "1 / 2" // 1 row height
gridArea: "1 / 1 / 2 / 13"
Visual Layout Descriptor Debugging
import { describeVisualLayout } from '@/lib/visual-layout-descriptor'
const description = describeVisualLayout(
schema.components,
'desktop',
12,
8
)
console.log('Summary:', description.summary)
console.log('\nRow by row:')
description.rowByRow.forEach(row => console.log(' ', row))
console.log('\nSpatial relationships:')
description.spatialRelationships.forEach(rel => console.log(' ', rel))
console.log('\nImplementation hints:')
description.implementationHints.forEach(hint => console.log(' ', hint))
Canvas Validation Codes
| Code | Type | Description |
|---|
CANVAS_LAYOUT_ORDER_MISMATCH | Warning | Canvas order ≠ DOM order |
COMPLEX_GRID_LAYOUT_DETECTED | Warning | Side-by-side components |
CANVAS_COMPONENTS_OVERLAP | Warning | Components overlapping |
CANVAS_OUT_OF_BOUNDS | Warning | Outside grid bounds |
CANVAS_ZERO_SIZE | Warning | width=0 or height=0 |
CANVAS_NEGATIVE_COORDINATE | Error | x<0 or y<0 |
CANVAS_FRACTIONAL_COORDINATE | Warning | Non-integer coordinates |
CANVAS_COMPONENT_NOT_IN_LAYOUT | Warning | Not in layout.components |
MISSING_CANVAS_LAYOUT | Warning | No canvas position |
Debugging Konva Rendering
Stage/Layer Issues
useEffect(() => {
console.log('Stage dimensions:', {
width: stageRef.current?.width(),
height: stageRef.current?.height()
})
console.log('Layer children:', layerRef.current?.children?.length)
}, [])
Component Node Position
const handleDragEnd = (e: Konva.KonvaEventObject<DragEvent>) => {
const node = e.target
console.log('Drag end position:', {
x: node.x(),
y: node.y(),
absolutePosition: node.absolutePosition()
})
const gridX = Math.floor(node.x() / cellWidth)
const gridY = Math.floor(node.y() / cellHeight)
console.log('Grid position:', { gridX, gridY })
}
Grid Constraint Validation
import { calculateMinimumGridSize } from '@/lib/grid-constraints'
const { minCols, minRows } = calculateMinimumGridSize(
schema.components,
'desktop'
)
console.log('Minimum required grid:', { minCols, minRows })
console.log('Current grid:', {
cols: breakpoint.gridCols,
rows: breakpoint.gridRows
})
if (breakpoint.gridCols < minCols || breakpoint.gridRows < minRows) {
console.warn('Grid too small for components!')
}
Quick Debug Checklist
console.log('Current breakpoint:', currentBreakpoint)
console.log('Grid config:', breakpoint)
schema.components.forEach(c => {
const layout = c.responsiveCanvasLayout?.[currentBreakpoint]
console.log(`${c.id} (${c.name}):`, layout || 'NO LAYOUT')
})
const result = validateSchema(schema)
console.log('Validation:', result)
const gridPositions = canvasToGridPositions(
schema.components,
currentBreakpoint,
breakpoint.gridCols,
breakpoint.gridRows
)
console.log('CSS Grid positions:', gridPositions)
Reference Files
components/canvas/KonvaCanvas.tsx - Canvas 렌더링
components/canvas/ComponentNode.tsx - 컴포넌트 노드
lib/canvas-to-grid.ts - Canvas→CSS Grid 변환
lib/canvas-utils.ts - Canvas 유틸리티
lib/grid-constraints.ts - Grid 제약 조건
lib/snap-to-grid.ts - 스냅 로직
lib/schema-validation.ts - Canvas 검증 로직
lib/visual-layout-descriptor.ts - 시각적 레이아웃 설명