Skip to content
Docs
Open Promoeyes
flex-vs-abs

flex-vs-abs

flex-vs-abs — A/B harness for the habits-2 "One portable canvas" card. Both sides paint the SAME composition; only the way it is authored differs. Left: absolute pixels — every x/y/w/h baked from the flex result at THAT container size. Right: the flex grammar (layout/gap/padding/fill/flex). Scene 1 is the 510x476 box, scene 2 the 374x544 one; the halves match to within a pixel of sub-pixel texture sampling in both.

Read the rig's notes
THE COST IS IN THE DIFF, NOT THE PICTURE. Going from scene 1 to scene 2 the
absolute card needs a wholly new coordinate set — 9 of its 9 placed boxes
move, the two-column split collapses, every y shifts. That is the number a
still frame cannot show you and the reason the flex grammar exists.

HONEST CAVEAT — the flex half is NOT one tree shared by both scenes either.
Scene 2's flex card is hand-reflowed: scene 1 is column[header, ROW[col,
col], footer], scene 2 is column[header, COLUMN[...], footer]. Feeding
scene 1's markup verbatim into the 374-wide box does NOT reflow it — it
overflows, because the leaves are absolute (`text(x=17 y=23.8)` inside each
pill). Flex resolves the pill; the label inside it is an out-of-flow child
of a non-flow card, so flex-scene.ts never hands it a wrap width and it
paints at natural width, ~25 units past the card edge. Making this reel a
true one-tree-two-boxes test means authoring the LEAVES with flex too
(layout=row + padding instead of x/y), which is a separate change.

Preview: /packages/runtime/index.html?project=promos/new/flex-vs-abs-demo/flex-vs-abs.promo
Topic
uis
Scenes
2
Kind
reference rig
//
    flex-vs-abs — A/B harness for the habits-2 "One portable canvas" card.
    Both sides paint the SAME composition; only the way it is authored differs.
    Left: absolute pixels — every x/y/w/h baked from the flex result at THAT
    container size. Right: the flex grammar (layout/gap/padding/fill/flex).
    Scene 1 is the 510x476 box, scene 2 the 374x544 one; the halves match to
    within a pixel of sub-pixel texture sampling in both.

    THE COST IS IN THE DIFF, NOT THE PICTURE. Going from scene 1 to scene 2 the
    absolute card needs a wholly new coordinate set — 9 of its 9 placed boxes
    move, the two-column split collapses, every y shifts. That is the number a
    still frame cannot show you and the reason the flex grammar exists.

    HONEST CAVEAT — the flex half is NOT one tree shared by both scenes either.
    Scene 2's flex card is hand-reflowed: scene 1 is column[header, ROW[col,
    col], footer], scene 2 is column[header, COLUMN[...], footer]. Feeding
    scene 1's markup verbatim into the 374-wide box does NOT reflow it — it
    overflows, because the leaves are absolute (`text(x=17 y=23.8)` inside each
    pill). Flex resolves the pill; the label inside it is an out-of-flow child
    of a non-flow card, so flex-scene.ts never hands it a wrap width and it
    paints at natural width, ~25 units past the card edge. Making this reel a
    true one-tree-two-boxes test means authoring the LEAVES with flex too
    (layout=row + padding instead of x/y), which is a separate change.

    Preview: /packages/runtime/index.html?project=promos/new/flex-vs-abs-demo/flex-vs-abs.promo
promo#flex-vs-abs
  scene#original-size(duration=3 transition=none)
    camera(type=perspective fov=40 near=8.5 far=8500 position="0 0 731" look_at="0 0 0")
    primitive#board-1(position="0 0 -510")
      geometry(type=plane width=1632 height=918)
      material(ref=basic toneMapped=false)
        map_from(flip_y=false)
          ui(width=1632 height=918)
            card(x=0 y=0 w=1632 h=918 r=0 fill=#07070c shadow=false)
            text(text="Absolute px, container 510×476" x=306 y=170 size=22.1 weight=800 color=#929295 align=center)
            text(text="Flex, container 510×476" x=1326 y=170 size=22.1 weight=800 color=#5865f2 align=center)
            // LEFT: absolute px — the flex result below, baked at 510x476
            card(x=51 y=230 w=510 h=476 r=20.4 fill=#14141c stroke=#4545a0 stroke_width=1.7 shadow=true)
              icon(set=tabler name=git-merge x=29 y=33 size=25.5 color=#5865f2 stroke_width=1.7 origin=top-left)
              text(text="One portable canvas" x=68 y=33 size=20.4 weight=900 color=#f0f0f0 align=left origin=top-left)
              card(x=29 y=147 w=240 h=102 r=13.6 fill=#1a1a28 shadow=false)
                icon(set=tabler name=bolt x=17 y=22.1 size=23.8 color=#5865f2 stroke_width=1.7)
                text(text="My Workflow" x=54.4 y=28.9 size=18.7 weight=800 color=#ffffff align=left)
                text(text="Automation → Agent → App" x=17 y=64.6 size=13.6 weight=600 color=#929295 align=left)
              text(text="Consistency anywhere" x=74 y=260 size=13.6 weight=600 color=#929295 align=left origin=top-left)
              text(text="Logic runs on" x=289 y=127 size=15.3 weight=800 color=#f0f0f0 align=left origin=top-left)
              card(x=289 y=154 w=192 h=39 r=6.8 fill=#1a1a28 shadow=false)
                text(text="Server · Phone · Desktop" x=17 y=23.8 size=13.6 weight=600 color=#5865f2 align=left)
              text(text="Audited once" x=289 y=230 size=15.3 weight=800 color=#f0f0f0 align=left origin=top-left)
              card(x=289 y=258 w=192 h=39 r=6.8 fill=#1a1a28 shadow=false)
                text(text="Trusted everywhere" x=17 y=23.8 size=13.6 weight=600 color=#5865f2 align=left)
              card(x=29 y=362 w=452 h=85 r=13.6 fill=#1a1a28 shadow=false)
                icon(set=tabler name=shield-check x=20.4 y=28.9 size=25.5 color=#5865f2 stroke_width=2.21)
                text(text="Bu