Core Concepts

Design Elements

Everything on the canvas is a design element. Learn about element types, their properties, and how to create and manipulate them.

Base Element Interface
Common properties shared by all elements
interface BaseElement {
  // Identity
  id: string                    // Unique identifier (auto-generated)
  type: ElementType             // Element type discriminator
  name?: string                 // Optional display name
  
  // Position
  x: number                     // X coordinate
  y: number                     // Y coordinate
  
  // Transform
  rotation?: number             // Rotation in degrees (default: 0)
  opacity?: number              // Opacity 0-1 (default: 1)
  
  // Visual
  fill?: string                 // Fill color (CSS color or gradient)
  stroke?: string               // Stroke color
  strokeWidth?: number          // Stroke width in pixels
  
  // State
  locked?: boolean              // Prevent selection/editing
  visible?: boolean             // Show/hide element
  
  // Metadata
  metadata?: Record<string, unknown>  // Custom data
  created_at?: string           // ISO timestamp
  updated_at?: string           // ISO timestamp
}

type ElementType = 
  | "rectangle" 
  | "ellipse" 
  | "line" 
  | "text" 
  | "image" 
  | "path" 
  | "group"

Element Types

rectangle
Basic rectangle shape with rounded corners support
xywidthheightfillstrokestrokeWidthcornerRadiusrotationopacity
ellipse
Circles and ellipses defined by radii
xyrxryfillstrokestrokeWidthrotationopacity
line
Straight line between two points
x1y1x2y2strokestrokeWidthstrokeDasharrayopacity
text
Text content with font styling
xycontentfontSizefontFamilyfontWeightfilltextAlignrotationopacity
image
Raster or vector images from URL or upload
xywidthheightsrcpreserveAspectRatiorotationopacity
path
Custom SVG paths for complex shapes
dfillstrokestrokeWidthfillRulerotationopacity
group
Container for grouping multiple elements
xychildrenrotationopacity
Type Definitions
Complete TypeScript interfaces for each element type
interface RectangleElement extends BaseElement {
  type: "rectangle"
  width: number
  height: number
  cornerRadius?: number | {
    topLeft: number
    topRight: number
    bottomRight: number
    bottomLeft: number
  }
}

// Example
const rect: RectangleElement = {
  id: "rect_001",
  type: "rectangle",
  x: 100,
  y: 100,
  width: 200,
  height: 150,
  fill: "#3b82f6",
  stroke: "#1d4ed8",
  strokeWidth: 2,
  cornerRadius: 8,
  rotation: 0,
  opacity: 1
}
Element Manipulation
Create, update, and delete elements programmatically
// Creating elements

// Via canvas API
const rect = canvas.addElement({
  type: "rectangle",
  x: 100,
  y: 100,
  width: 200,
  height: 150,
  fill: "#3b82f6"
})

// Via store action
import { useDesignStore } from "@/lib/design/store"

const addElement = useDesignStore(state => state.addElement)

addElement({
  type: "text",
  x: 200,
  y: 200,
  content: "New Text",
  fontSize: 24,
  fill: "#000000"
})

// Via API
const response = await fetch('/api/v1/designs/design_123/elements', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    type: "ellipse",
    x: 300,
    y: 300,
    rx: 50,
    ry: 50,
    fill: "#10b981"
  })
})
Element Grouping
Organize elements into hierarchical groups
// Grouping elements

// Create group from selection
const group = canvas.groupSelected()
// Returns: { id: "group_001", type: "group", children: [...] }

// Create group programmatically
const group = canvas.createGroup([elementId1, elementId2, elementId3])

// Ungroup
canvas.ungroup(groupId)
// Returns children to top level

// Group interface
interface GroupElement extends BaseElement {
  type: "group"
  children: DesignElement[]
}

// Nested groups are supported
const nestedGroup = canvas.createGroup([groupId1, elementId4])

// Access children
const children = canvas.getGroupChildren(groupId)

// Move element into group
canvas.moveToGroup(elementId, groupId)

// Move element out of group
canvas.moveToParent(elementId)  // Moves to canvas root
Z-Order (Layering)
Control element stacking order
// Z-order operations

// Bring to front (topmost)
canvas.bringToFront(elementId)

// Send to back (bottommost)
canvas.sendToBack(elementId)

// Move forward one level
canvas.bringForward(elementId)

// Move backward one level
canvas.sendBackward(elementId)

// Set specific z-index
canvas.setZIndex(elementId, 5)

// Get z-index
const zIndex = canvas.getZIndex(elementId)

// Swap z-order of two elements
canvas.swapZOrder(elementId1, elementId2)

// Reorder multiple elements
canvas.reorderElements([
  { id: "el_1", zIndex: 0 },
  { id: "el_2", zIndex: 1 },
  { id: "el_3", zIndex: 2 }
])
Element Events
Listen for element-specific events
// Element event handling

// Listen for element creation
canvas.on('elementCreated', (element) => {
  console.log('New element:', element.id, element.type)
})

// Listen for element updates
canvas.on('elementUpdated', (element, changes) => {
  console.log('Updated:', element.id, changes)
})

// Listen for element deletion
canvas.on('elementDeleted', (elementId) => {
  console.log('Deleted:', elementId)
})

// Listen for selection changes
canvas.on('selectionChanged', (selectedElements) => {
  console.log('Selected:', selectedElements.length)
})

// Listen for drag events
canvas.on('elementDragStart', (element, position) => {
  console.log('Drag start:', element.id)
})

canvas.on('elementDragEnd', (element, position) => {
  console.log('Drag end:', element.id, position)
})

// Remove listener
const unsubscribe = canvas.on('elementCreated', handler)
unsubscribe()  // Clean up

Related Documentation