Skip to content
Docs
Open Promoeyes
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