Group (Auto Layout)
.group() adds an auto-layout container that measures its children and stacks them along a row or column — no hand-placed coordinates. Because the group recomputes positions from each child's natural size, the same spec keeps working when headline copy gets longer or a badge is added, which makes groups especially reliable for LLM-generated layouts.
Signature
canvas.group(
children,
direction="column",
gap=0,
padding=0,
position=None,
align=None,
item_align="start",
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
children |
list |
required | Child layers in stacking order. Dicts or layer models of type text, image, shape, svg, or nested group. |
direction |
str |
"column" |
Main axis: "column" stacks top-to-bottom, "row" left-to-right. |
gap |
int |
0 |
Pixels between adjacent children along the main axis. Non-negative. |
padding |
int \| tuple |
0 |
Inner padding: a single int, (vertical, horizontal), or (top, right, bottom, left). |
position |
tuple \| None |
None |
Anchor point of the group box, in pixels or percentage strings. |
align |
str \| Align \| tuple \| None |
None |
Which point of the group box the position refers to, like image layers. See Align. |
item_align |
str |
"start" |
Cross-axis placement of each child: "start", "center", or "end". |
Children must not set position
The group assigns positions. A child that sets its own position raises ValidationError, and a child's align is ignored — use item_align on the group instead.
Examples
Stacked headline block
canvas = Canvas(1280, 720).background(color="#16213E").group(
children=[
{"type": "shape", "shape": "pill", "width": 120, "height": 36, "color": "#E94560"},
{"type": "text", "content": "AUTO LAYOUT", "size": 96, "color": "#FFFFFF", "weight": 900},
{"type": "text", "content": "No coordinates were harmed", "size": 40, "color": "#A2A8D3"},
],
direction="column",
gap=24,
position=("8%", "50%"),
align=("left", "middle"),
)
Horizontal badge row
def chip(label):
return {
"type": "text",
"content": label,
"size": 24,
"color": "#22D3EE",
"weight": 700,
"effects": [
{"type": "background", "color": "#1D2547", "padding": [8, 14], "border_radius": 18},
],
}
canvas.group(
children=[chip("GROUPS"), chip("TOKENS"), chip("LINT")],
direction="row",
gap=14,
position=("50%", "88%"),
align=("center", "middle"),
)
Nested groups
Groups can nest, so a column can contain a row (and vice versa):
canvas.group(
children=[
{"type": "text", "content": "RELEASE 0.5", "size": 96, "color": "#FFFFFF", "weight": 900},
{
"type": "group",
"direction": "row",
"gap": 14,
"children": [chip("GROUPS"), chip("TOKENS"), chip("LINT")],
},
],
direction="column",
gap=28,
position=("7%", "50%"),
align=("left", "middle"),
)
Cross-axis alignment
canvas.group(
children=[
{"type": "text", "content": "CENTERED", "size": 80, "color": "#FFFFFF", "weight": 900},
{"type": "text", "content": "Both children share a center line", "size": 36, "color": "#A2A8D3"},
],
direction="column",
gap=18,
item_align="center", # cross-axis: center each child horizontally
position=("50%", "50%"),
align=("center", "middle"),
)
How sizing works
- Each child is measured at its natural size (text bounds, image dimensions, shape
width/height). - Children are placed one after another along the main axis, separated by
gap. - The group box is the union of the children plus
padding. - The whole box is anchored to
positionaccording toalign.
JSON form
Groups serialize like any other layer. See the JSON Schema page for the full schema:
{
"type": "group",
"direction": "column",
"gap": 24,
"position": ["8%", "50%"],
"align": ["left", "middle"],
"item_align": "start",
"children": [
{ "type": "text", "content": "AUTO LAYOUT", "size": 96, "color": "#FFFFFF", "weight": 900 }
]
}
Validation rules
childrenmust be a non-empty list.- Children must not set
position(the group assigns positions). - Valid child types:
text,image,shape,svg,group. gapcannot be negative;paddingvalues cannot be negative, and a padding tuple must have 2 or 4 elements.