layout
layout
Layout primitives — every layout container the engine has, one scene each. Each scene holds a static pose: the CONTAINER does the arranging, not keyframes. Three matched haze lobes (hz0..hz2) ride every scene so `transition=match-move` carries the backdrop across each cut.
Read the rig's notes
WORLD-SPACE FLOW CONTAINERS (children measured by their real 3D bounds and
re-arranged EVERY FRAME — packages/engine/lib/flow-layout-3d.ts):
1. row — main axis +X; a tile scaling 0→1 shoves its siblings apart LIVE
2. column — main axis −Y (top→bottom), align=start, nested rows inside
3. isle — main axis −Z: a depth stack, first child nearest the camera
4. stack — isle plus a cumulative shift-x / shift-y cascade (a fanned deck)
5. grid — two axes: columns +X, rows −Y, tracks sized by content;
plane=xz lays the same grid on the floor
9. word-cloud — seeded ink-mask packing; a non-<text> child packs as a slot
UI-SURFACE LAYOUTS (inside <ui3d>, resolved in pixels then mapped to world):
6. grid — the same tag under a ui surface: equal-width cells resolved
from the panel's own width, span=2 for a full-bleed cell
7. row/column/group — the Yoga flex path: layout=, flex=, w="fill", gap,
padding, align, justify. `group` is a bare flex <div>.
8. stack/orbit/carousel — the `items`-based components: a z-stack at one
anchor, an orbit pivot, and a horizontal strip. (ui/container
is the one layout NOT demoed — it double-applies the stage
transform and draws outside its panel.)
Every flow-container child is authored with NO x/y/size — that is the point.
(The `items`-based components in scene 8 are the exception: they are absolute
by design, so their children keep their own coords.)
Preview: /packages/runtime/index.html?project=promos/primitives/layout.promo- Topic
- layouts
- Scenes
- 9
- Kind
- reference rig
//
Layout primitives — every layout container the engine has, one scene each.
Each scene holds a static pose: the CONTAINER does the arranging, not
keyframes. Three matched haze lobes (hz0..hz2) ride every scene so
`transition=match-move` carries the backdrop across each cut.
WORLD-SPACE FLOW CONTAINERS (children measured by their real 3D bounds and
re-arranged EVERY FRAME — packages/engine/lib/flow-layout-3d.ts):
1. row — main axis +X; a tile scaling 0→1 shoves its siblings apart LIVE
2. column — main axis −Y (top→bottom), align=start, nested rows inside
3. isle — main axis −Z: a depth stack, first child nearest the camera
4. stack — isle plus a cumulative shift-x / shift-y cascade (a fanned deck)
5. grid — two axes: columns +X, rows −Y, tracks sized by content;
plane=xz lays the same grid on the floor
9. word-cloud — seeded ink-mask packing; a non-<text> child packs as a slot
UI-SURFACE LAYOUTS (inside <ui3d>, resolved in pixels then mapped to world):
6. grid — the same tag under a ui surface: equal-width cells resolved
from the panel's own width, span=2 for a full-bleed cell
7. row/column/group — the Yoga flex path: layout=, flex=, w="fill", gap,
padding, align, justify. `group` is a bare flex <div>.
8. stack/orbit/carousel — the `items`-based components: a z-stack at one
anchor, an orbit pivot, and a horizontal strip. (ui/container
is the one layout NOT demoed — it double-applies the stage
transform and draws outside its panel.)
Every flow-container child is authored with NO x/y/size — that is the point.
(The `items`-based components in scene 8 are the exception: they are absolute
by design, so their children keep their own coords.)
Preview: /packages/runtime/index.html?project=promos/primitives/layout.promo
promo#layout
// =======================================================================
// SCENE 01 · ROW — main axis +X, cross axis centred
// =======================================================================
scene#s01-row(duration=4 transition=match-move transition-duration=0.8)
camera(type=perspective fov=42 near=8.5 far=17000 position="0 0 765" look_at="0 0 0")
background(top=#0b1020 bottom=#05070f)
lights
light#amb(type=ambient color=#8fb2ff intensity=1.0)
light#key(type=directional color=#ffffff intensity=1.7 position="340 680 510")
light#fill(type=directional color=#7aa2ff intensity=0.6 position="-510 170 340")
haze#hz0(match=hz0 blend=add opacity=0.5 position="-552 272 -1020" color=#5B2EFF size="88400 74800" pulse=0 decay=0)
haze#hz1(match=hz1 blend=add opacity=0.42 position="468 -221 -1020" color=#00C8FF size="107100 78540" pulse=0 decay=0)
haze#hz2(match=hz2 blend=add opacity=0.32 position="42.5 34 -1020" color=#00FFB2 size="82280 67320" pulse=0 decay=0)
text#s01-title(text=row kind=layer size=200 worldHeight=52.7 color=#e8eefc weight=700 align=center position="0 247 0")
text#s01-sub(text="gap · align · justify — children carry no x/y" kind=layer size=110 worldHeight=22.1 color=#8ea3c8 weight=500 align=center position="0 187 0")
// Cross-axis alignment: four tiles of different heights, centred on Y by default.
row#s01-heights(gap=28.9 position="0 63.75 0")
rect#s01-h1(width=89.25 height=59.5 depth=6.8 rx=10.2 fill=#60a5fa)
rect#s01-h2(width=89.25 height=128 depth=6.8 rx=10.2 fill=#818cf8)
rect#s01-h3(width=89.25 height=89.25 depth=6.8 rx=10.2 fill=#f472b6)
rect#s01-h4(width=89.25 height=72.25 depth=6.8 rx=10.2 fill=#34d399)
// Live measurement: the gold tile animates scale 0→1 and its siblings are
// re-laid-out EVERY FRAME, so the row breathes open around it.
row#s01-push(gap=25.5 position="0 -127 0")
rect#s01-p1(width=102 height