LAYOUT SCHEMA

Comprehensive guidelines for AI-assisted development within the Editor platform

AI Layout Schema Reference

Session 55: THE SINGLE SOURCE OF TRUTH for AI-trainable layout configuration.

Overview

All container-like widgets (Section, Container, Card, etc.) use the same layout schema. This ensures:

  1. Consistent JSON - AI agents can rely on predictable structure
  2. DRY - Properties defined once in BaseLayoutConfig
  3. Platform-agnostic - Works for Angular (web) and Flutter (mobile)
  4. AI-trainable - Clear property names with metadata

Type Hierarchy

BaseLayoutConfig (core-models/base-layout.types.ts)
├── SectionWidgetConfig (extends BaseLayoutConfig)
├── ContainerWidgetConfig (extends BaseLayoutConfig)
└── [Future widgets extend BaseLayoutConfig]

Quick Reference

Layout Types

Value Description Use Case
flex CSS Flexbox Most layouts, flexible children
grid CSS Grid Structured columns, card grids
free Absolute positioning Drag-and-drop canvas

Layout Presets

Preset Description
vertical-stack Column layout, top-aligned
horizontal-row Row layout, center-aligned
centered-content Center both axes
two-column 2-column grid
three-column 3-column grid
four-column 4-column grid
sidebar-left 30%/70% split
sidebar-right 70%/30% split
hero-section Centered with extra gap
navigation-bar Row with space-between

JSON Schema

Minimal Example

{
  "layoutType": "flex",
  "flexDirection": "column",
  "gap": 16,
  "padding": 20
}

Grid Layout

{
  "layoutType": "grid",
  "gridColumns": 3,
  "gridColumnWidths": [1, 2, 1],
  "gap": 24,
  "padding": 32,
  "responsiveEnabled": true,
  "mobile": {
    "columns": 1,
    "layout": "stack"
  },
  "tablet": {
    "columns": 2
  }
}

AI Content Placement

{
  "layoutType": "grid",
  "gridColumns": 3,
  "gridColumnWidths": [1, 1, 1],
  "contentPlacement": {
    "targetColumn": 2,
    "emptyColumns": [0, 1]
  }
}

Full Schema Definition

BaseLayoutConfig

// Note: Uses ContainerLayoutType to avoid conflict with LayoutType in layout-config.types.ts
type ContainerLayoutType = 'flex' | 'grid' | 'free';

interface BaseLayoutConfig {
  // === LAYOUT TYPE ===
  layoutType?: ContainerLayoutType;  // default: 'flex'
  layoutPreset?: string;  // Quick configuration preset

  // === FLEX PROPERTIES ===
  flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
  flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';

  // === ALIGNMENT ===
  justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
  alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
  alignContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'stretch';

  // === GRID PROPERTIES ===
  gridColumns?: number;  // Number of columns (1-12)
  gridColumnWidths?: number[];  // Custom widths as fractions [1, 2, 1]
  gridRows?: number;  // Number of rows (0 = auto)
  gridRowHeights?: number[];  // Custom heights as fractions
  gridAutoFlow?: 'row' | 'column' | 'dense';
  justifyItems?: 'start' | 'end' | 'center' | 'stretch';

  // === SPACING ===
  gap?: number;  // Space between children (pixels)
  padding?: number;  // Inner padding (pixels)
  paddingTop?: number;
  paddingRight?: number;
  paddingBottom?: number;
  paddingLeft?: number;
  margin?: number;  // Outer margin (pixels)
  marginTop?: number;
  marginRight?: number;
  marginBottom?: number;
  marginLeft?: number;

  // === APPEARANCE ===
  backgroundColor?: string;
  backgroundImage?: string;
  borderRadius?: number;
  borderWidth?: number;
  borderColor?: string;
  borderStyle?: 'none' | 'solid' | 'dashed' | 'dotted';
  boxShadow?: string;
  opacity?: number;  // 0-1

  // === BEHAVIOR ===
  overflow?: 'visible' | 'hidden' | 'scroll' | 'auto';
  allowDrop?: boolean;  // Accept dropped widgets

  // === RESPONSIVE ===
  responsiveEnabled?: boolean;
  mobile?: {
    columns?: number;
    columnWidths?: number[];
    gap?: number;
    padding?: number;
    flexDirection?: string;
    layout?: 'default' | 'stack' | 'reverse';
  };
  tablet?: {
    columns?: number;
    columnWidths?: number[];
    gap?: number;
    padding?: number;
    flexDirection?: string;
  };

  // === AI CONTENT PLACEMENT ===
  contentPlacement?: {
    targetColumn?: number;  // 0-based column index for primary content
    emptyColumns?: number[];  // Column indices to leave empty
    targetRow?: number;
    emptyRows?: number[];
  };
}

ItemLayoutConfig (for individual widgets)

interface ItemLayoutConfig {
  // Self-alignment (override parent)
  alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch';
  justifySelf?: 'auto' | 'start' | 'end' | 'center' | 'stretch';
  textAlign?: 'left' | 'center' | 'right' | 'justify';

  // Flex item properties
  flexGrow?: number;  // How much item grows
  flexShrink?: number;  // How much item shrinks
  flexBasis?: string;  // Base size
  order?: number;  // Visual order

  // Sizing
  width?: string | number;
  height?: string | number;
  minWidth?: string | number;
  maxWidth?: string | number;

  // Grid placement
  gridColumn?: number | string;  // e.g., 1, "1 / 3", "span 2"
  gridRow?: number | string;
}

AI Training Examples

Example 1: Create a Hero Section

Prompt: "Create a hero section with centered content"

Expected JSON:

{
  "type": "section",
  "config": {
    "sectionName": "Hero",
    "layoutType": "flex",
    "layoutPreset": "centered-content",
    "flexDirection": "column",
    "justifyContent": "center",
    "alignItems": "center",
    "gap": 24,
    "padding": 64
  }
}

Example 2: Three Column Grid

Prompt: "Make 3 columns, put content in the last column"

Expected JSON:

{
  "type": "section",
  "config": {
    "layoutType": "grid",
    "gridColumns": 3,
    "gridColumnWidths": [1, 1, 1],
    "gap": 24,
    "responsiveEnabled": true,
    "mobile": { "columns": 1, "layout": "stack" },
    "tablet": { "columns": 2 },
    "contentPlacement": {
      "targetColumn": 2,
      "emptyColumns": [0, 1]
    }
  }
}

Example 3: Sidebar Layout

Prompt: "Create a sidebar on the left taking 30% width"

Expected JSON:

{
  "type": "section",
  "config": {
    "layoutType": "grid",
    "layoutPreset": "sidebar-left",
    "gridColumns": 2,
    "gridColumnWidths": [0.3, 0.7],
    "gap": 24,
    "responsiveEnabled": true,
    "mobile": { "columns": 1, "layout": "stack" }
  }
}

Example 4: Responsive Card Grid

Prompt: "Create a card grid that shows 4 columns on desktop, 2 on tablet, 1 on mobile"

Expected JSON:

{
  "type": "container",
  "config": {
    "layoutType": "grid",
    "gridColumns": 4,
    "gridColumnWidths": [1, 1, 1, 1],
    "gap": 16,
    "padding": 24,
    "responsiveEnabled": true,
    "mobile": { "columns": 1 },
    "tablet": { "columns": 2 }
  }
}

Property Importance for AI

Property Importance Notes
layoutType Essential Always specify
gap Essential Always specify for visual consistency
padding Essential Almost always needed
flexDirection Common When layoutType is 'flex'
gridColumns Common When layoutType is 'grid'
justifyContent Common For alignment
alignItems Common For alignment
responsiveEnabled High For mobile-friendly layouts
mobile.columns High Usually 1 for mobile
layoutPreset High Use presets for standard layouts
gridColumnWidths Advanced For custom column sizing
contentPlacement AI-only For specifying content position

Child Ordering and Reordering

Session 54.3: Unified order-based reordering for all layout types.

How Child Order Works

Children within any container are ordered by the order property in their config:

{
  "id": "heading-1",
  "type": "heading",
  "parentId": "section-1",
  "config": {
    "order": 0,
    "text": "First Item"
  }
}
Property Type Description
order number Sort order (lower = first). Default: array index

AI Instructions for Reordering

When an AI needs to reorder children:

  1. Swap order values between the two widgets
  2. Emit both widgets with updated configs
  3. Let the system sort - children are automatically sorted by order when retrieved

Example - Moving "Text" before "Heading":

Before:

[
  { "id": "heading-1", "config": { "order": 0 } },
  { "id": "text-1", "config": { "order": 1 } }
]

After:

[
  { "id": "heading-1", "config": { "order": 1 } },
  { "id": "text-1", "config": { "order": 0 } }
]

Reorder Commands AI Should Understand

Command Action
"move heading up/left" Swap order with previous sibling
"move heading down/right" Swap order with next sibling
"swap heading and text" Swap order values between two items
"reverse order" Invert all order values
"put heading first" Set heading order=0, increment others

Container Height Calculation

Session 54.3: Smart adaptive heights using pixels (platform-agnostic).

Height Calculation Logic

Layout Type Formula
flex (column) sum(childHeights) + padding*2 + gap*(n-1)
flex (row) max(childHeights) + padding*2
grid sum(rowMaxHeights) + padding*2 + gap*(rows-1)
free max(childBottoms) + padding*2

JSON Schema for Heights

{
  "type": "section",
  "config": {
    "layoutType": "flex",
    "flexDirection": "column",
    "padding": 24,
    "gap": 16
  },
  "positions": {
    "desktop": {
      "height": 450,
      "heightUnit": "px",
      "minHeight": 100
    }
  }
}

AI Instructions for Heights

Height Calculation Example:

Given a section with:

Calculated height: 100 + 150 + (24*2) + 16 = 314px

Property Template System (Opt-In Model)

Session 54.3: Refactored to explicit template subscription for better AI training.

Architecture Overview

Each widget declares which property templates it needs via propertyTemplateIds. This ensures:

  1. Only relevant properties - No typography on images, no colors where not needed
  2. Smaller AI context - Focused, accurate property suggestions
  3. Better performance - Fewer properties to render/process
  4. Explicit dependencies - Clear what each widget supports

Template Categories

Category Description Templates
universal Most widgets need these template_spacing, template_border_shadow, template_sizing_dimensions, template_colors
layout Container layouts template_container, template_section
content Text/typography template_text, template_typography
media Images/video/effects template_image, template_effects
form Form inputs template_input, template_form_field
widget Widget-specific template_button, template_card, etc.

Widget Template Matrix

Widget Templates
section template_section, template_container, template_colors, template_spacing, template_border_shadow
container template_container, template_colors, template_spacing, template_border_shadow
heading template_text, template_typography, template_colors, template_spacing
text template_text, template_typography, template_colors, template_spacing
button template_button, template_colors, template_spacing, template_border_shadow
image template_image, template_sizing_dimensions, template_border_shadow, template_effects, template_spacing
card template_card, template_colors, template_spacing, template_border_shadow
input template_input, template_form_field, template_colors, template_spacing, template_border_shadow

AI Instructions for Properties

When generating widget configurations:

  1. Check the widget's propertyTemplateIds - Only use properties from those templates
  2. Don't add irrelevant properties - No typography on images, no layout on text
  3. Use template category hints - universal templates apply to most widgets

Example - Correct Image Config:

{
  "type": "image",
  "config": {
    "src": "https://example.com/image.jpg",
    "alt": "Description",
    "objectFit": "cover",
    "borderRadius": 8,
    "opacity": 1,
    "padding": 16
  }
}

Example - WRONG Image Config (has typography):

{
  "type": "image",
  "config": {
    "src": "https://example.com/image.jpg",
    "fontSize": 16,
    "fontWeight": "bold"
  }
}

Files Reference

Changelog