Appearance
flexbox
The flexbox component arranges children of a 3D primitive in a one-dimensional row or column, similar to CSS Flexbox. It works on any primitive with a defined width and height (a-plane, a-box, a-entity with a geometry) and positions its children inside the container's bounding box.
The Flexbox family consists of three components that work together:
flexbox– the container that lays out its children along a main axis.flex-grow– marks a child as flexible so it expands into the remaining space.flex-col– gives a child a width expressed as a fraction of a 12-column grid, with values per breakpoint based on the container's size.
Basic usage
A flexbox container distributes its children along the main axis (direction) and aligns them along the cross axis (items). The example below shows three boxes in a row, evenly spaced and vertically centred inside the container.
Direction
direction: row lays children horizontally (main axis = X). direction: column lays them vertically (main axis = Y). justify always controls the main axis and items always controls the cross axis, so swapping direction swaps which property reads as "horizontal".
Main-axis alignment (justify)
justify controls how items are positioned and spaced along the main axis. The five accepted values mirror their CSS counterparts (note the shorter between / around spelling). between places items flush to the container edges with even gaps in between; around surrounds each item with an equal amount of free space (edge gaps end up half the size of the gaps between items).
The five rows below share the same three child boxes — only justify changes.
Cross-axis alignment (items)
items controls where children sit along the cross axis. The composite below puts three sub-containers side by side, each holding the same three items of varying height so the difference between start, center, and end reads at a glance.
Spacing (gap)
gap is a vec2 value. The first number adds spacing between items along the main axis; the second adds spacing between wrapped lines along the cross axis. Both are expressed in metres. A single-row layout only uses the first component; the second only matters when wrap: true.
The example shows both at once — a single-row container on the left (only gap.x) and a wrapping container on the right (both gap.x and gap.y).
Wrapping
With wrap: true, items that don't fit on the current main-axis line continue on the next one. Combine with gap to control spacing both within and between lines.
The four mini containers below show the most common variants together:
- top-left — equal items wrap onto multiple rows (
direction: row); - top-right — items of varying widths still wrap greedily, row by row;
- bottom-left —
direction: column; wrap: true;flows items top-to-bottom and into a second column; - bottom-right —
justify: betweenapplies per line, so each wrapped row distributes its items to the container edges.
Growing
Add the flex-grow attribute to a child to let it expand and consume the remaining main-axis space. Use this to build, for example, a toolbar with a fixed icon on each side and a stretchable centre region. In the example below, green items have flex-grow applied. When multiple children carry flex-grow, the leftover space is divided equally among them (bottom row).
Combining flex-grow with flex-col
When flex-grow sits on a child that also has flex-col, the grow item claims all unused columns on its line of the 12-column grid. Below, the two outer items take 3 columns each (sm: 3) and the middle item — also declared as sm: 3 but with flex-grow — expands to fill the remaining 6.
Responsive grid
flex-col gives a child a width expressed as a fraction of a 12-column grid. You can declare a different column count per breakpoint, and the component picks the largest matching one based on the container's 3D width (see Breakpoints below).
Note: column widths are computed from the container's width without subtracting any gap, so a row where the column counts add up to exactly 12 will overflow and wrap as soon as you add a non-zero gap.x. Use gap: 0 (or smaller column counts) when you want the items to fit on one row.
Basic 12-column layouts
Three common splits, stacked top-to-bottom: thirds (sm: 4, 4 + 4 + 4 = 12), halves (sm: 6, 6 + 6 = 12), and an over-12 case (sm: 5, 5 + 5 + 5 = 15) where the third item wraps because the next column count would overflow.
Responsive across breakpoints
Each of the three containers below holds the same children with flex-col="sm: 12; md: 6; lg: 4". As container width crosses the breakpoints, the same markup reflows from a stack into a half-grid into a one-row layout.
The 3 m container falls below the md threshold (4 m), so each child uses its sm value of 12 columns and they stack. The 6 m container matches md, so each child takes 6 columns (two per row, third wraps). The 8 m container matches lg, so each child takes 4 columns and all three fit on one row.
Custom breakpoints
The named breakpoints (sm, md, lg, xl, 2xl, 3xl) use fixed default thresholds, but you can override those thresholds on the container with customBreakpoints. It accepts 1–6 numbers (metres) that are assigned to the named breakpoints in order: the first to sm, the second to md, and so on. Children keep using the named breakpoints in flex-col.
Below the container sets customBreakpoints: 0 1 1.7, so sm = 0 m, md = 1 m and lg = 1.7 m. At the 2 m container width the lg threshold applies, so each child takes its lg value of 4 columns and all three fit on one row.
If the same container were 1.2 m wide, the md threshold (1 m) would apply (6 columns each, two per row); below 1 m the sm threshold (0 m) would stack them at 12 columns each.
flexbox props
| Property | Type | Default | Description |
|---|---|---|---|
| direction | enum(row, column) | row | Main layout axis. row is horizontal, column is vertical. |
| justify | enum(start, end, center, between, around) | start | Distribution along the main axis. |
| items | enum(start, end, center) | start | Alignment along the cross axis. |
| wrap | boolean | false | If true, items that don't fit on the main axis continue on the next line. |
| gap | vec2 | 0 0 | Spacing between items in metres. First value = main-axis gap, second = cross-axis (line) gap. |
| customBreakpoints | array (1–6 numbers) | [] | Overrides the metre thresholds of the named breakpoints (sm md lg xl 2xl 3xl) in order, e.g. customBreakpoints: 0 1 1.7. |
flex-grow props
| Property | Type | Default | Description |
|---|---|---|---|
| – | boolean | true | When present (or set to true), the item expands into the free main-axis space. |
flex-col props
Each property declares the column count (out of 12) to use at the corresponding breakpoint.
| Property | Type | Default | Description |
|---|---|---|---|
| sm | number | – | Columns when the container is at least the sm width. |
| md | number | – | Columns when the container is at least the md width. |
| lg | number | – | Columns when the container is at least the lg width. |
| xl | number | – | Columns when the container is at least the xl width. |
| 2xl | number | – | Columns when the container is at least the 2xl width. |
| 3xl | number | – | Columns when the container is at least the 3xl width. |
Only breakpoints you set are considered; the component picks the largest one whose threshold is less than or equal to the parent container's 3D width.
Breakpoints
Breakpoints are based on the parent container's width in metres, not on the browser viewport. The default thresholds are:
| Breakpoint | Container width |
|---|---|
sm | ≥ 0 m |
md | ≥ 4 m |
lg | ≥ 7 m |
xl | ≥ 10 m |
2xl | ≥ 12 m |
3xl | ≥ 15 m |
You can override these thresholds per container with the customBreakpoints property on the flexbox component. It takes 1–6 numbers assigned to sm, md, lg, xl, 2xl, 3xl in order. For example, flexbox="… ; customBreakpoints: 3 6" makes sm apply above 3 m and md above 6 m, so flex-col="sm: 12; md: 6" yields 12 columns above 3 m and 6 columns above 6 m. See Custom breakpoints above.
Notes
- The flexbox container must be a primitive with explicit width and height (e.g.
a-plane,a-box, or ana-entitywith a geometry). Children with no bounding box are placed using a 0.1 m fallback size. gapadds spacing without changing item sizes. The second value only matters whenwrap: true.flex-colwidths are calculated from the raw container width (gaps are not subtracted), so setgap: 0when the column counts on a row already add up to exactly 12.flex-growworks in both row and column directions and recomputes when the container resizes.- With
wrap: true,justifyapplies per line — useful when laying out grid cells withflex-col. - For predictable responsive layouts, combine
flex-colwithwrap: trueso wrapped lines flow naturally as the container width crosses breakpoints.
