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:
- Consistent JSON - AI agents can rely on predictable structure
- DRY - Properties defined once in
BaseLayoutConfig - Platform-agnostic - Works for Angular (web) and Flutter (mobile)
- 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:
- Swap order values between the two widgets
- Emit both widgets with updated configs
- Let the system sort - children are automatically sorted by
orderwhen 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
- Always use pixel values for platform-agnostic support
- Calculate based on content - sum children + padding + gaps
- Set minHeight for empty containers (default: 100px)
- Avoid
autoorfit-content- use explicit pixel values
Height Calculation Example:
Given a section with:
- 2 children (100px and 150px tall)
- padding: 24px
- gap: 16px
- flexDirection: column
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:
- Only relevant properties - No typography on images, no colors where not needed
- Smaller AI context - Focused, accurate property suggestions
- Better performance - Fewer properties to render/process
- 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:
- Check the widget's
propertyTemplateIds- Only use properties from those templates - Don't add irrelevant properties - No typography on images, no layout on text
- Use template category hints -
universaltemplates 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
- Type Definition:
libs/libs-foundational/core-models/src/lib/types/base-layout.types.ts - Property Types:
libs/libs-foundational/core-properties/src/lib/unified/unified-property.types.ts - Section Widget:
libs/libs-widgets/widgets/src/lib/section/section.widget.ts - Container Widget:
libs/libs-widgets/widgets/src/lib/container/container.widget.ts - Canvas Rendering:
libs/libs-structural/page-builder/src/lib/components/canvas-widget/canvas-widget.component.ts - Property Templates:
libs/libs-foundational/core-properties/src/lib/unified/unified-property.service.ts - Properties Panel:
libs/libs-structural/page-builder/src/lib/components/properties-panel/properties-panel.component.ts - Backend Templates:
apis/backend-api/src/app/core-properties/templates/layout.templates.ts - Reorder Service:
libs/libs-structural/page-builder/src/lib/services/child-reorder.service.ts - Height Service:
libs/libs-structural/page-builder/src/lib/services/container-height.service.ts
Changelog
- Session 54.3: Refactored property system to opt-in template subscription model
- Session 54.3: Added
templateCategoryto templates for AI organization - Session 54.3: Updated all widget definitions with explicit
propertyTemplateIds - Session 54.3: Added unified order-based reordering system
- Session 54.3: Added smart container height calculation service
- Session 55: Created unified BaseLayoutConfig interface
- All container widgets now extend the same base
- Added contentPlacement for AI-driven layouts
- Added responsive configuration schema
- Added alignment properties for individual items