Skip to content
Docs
Open Promoeyes
ui-ui3d

ui-ui3d

ui vs ui3d — the SAME surface twice, side by side, in millimetres.

Read the rig's notes
Left:  <ui width=480 height=300>   — the flat path: the items rasterise into
       one texture painted on a single 480×300 mm plane.
Right: <ui3d width=480 height=300> — the mesh path: the same items emit as
       real planes in the world, one mesh per item, pixel-matched so that
       1 stage unit ≡ 1 mm (width == stage_width, no world_* mapping).

Both share one build core, so the item tree is copied VERBATIM between the
two — same boxes, same text sizes, same tracks. The point of the reel is
that they are indistinguishable at rest, and that the same child tracks
(opacity / scale / position dx dy / content draws) play identically on both.
Only dz (+z toward the camera) has no texture equivalent; it is not used here.
One more real difference to keep in mind: a <ui> texture CLIPS at its stage
bounds, a <ui3d> mesh does not — so content is kept inside the 480×300 box.

Placement differs by one convention: a <ui> plane is CENTRED on its position,
while a pixel-matched <ui3d> puts its stage's BOTTOM-LEFT corner at its
position (the stage's y-down pixels are flipped into world y-up, so the top
edge lands at position.y + height). So the left plane sits at "-270 0 0" and
the right stage at "30 -150 0" (= centre 270,0 for a 480×300 box) and the two
land at mirrored spots on screen.

  01. dashboard   a metrics card: header, two stats, a progress bar
  02. thread      a chat card: avatar header + three bubbles cascading in
  03. widgets     stat-ring + line-chart + typewriter-free content draws

Capture: nx run tools:capture:webgl -- --project promos/primitives/uis/ui-ui3d.promo
Preview: /packages/runtime/index.html?project=promos/primitives/uis/ui-ui3d.promo
Topic
uis
Scenes
23
Kind
reference rig
//
    ui vs ui3d — the SAME surface twice, side by side, in millimetres.

    Left:  <ui width=480 height=300>   — the flat path: the items rasterise into
           one texture painted on a single 480×300 mm plane.
    Right: <ui3d width=480 height=300> — the mesh path: the same items emit as
           real planes in the world, one mesh per item, pixel-matched so that
           1 stage unit ≡ 1 mm (width == stage_width, no world_* mapping).

    Both share one build core, so the item tree is copied VERBATIM between the
    two — same boxes, same text sizes, same tracks. The point of the reel is
    that they are indistinguishable at rest, and that the same child tracks
    (opacity / scale / position dx dy / content draws) play identically on both.
    Only dz (+z toward the camera) has no texture equivalent; it is not used here.
    One more real difference to keep in mind: a <ui> texture CLIPS at its stage
    bounds, a <ui3d> mesh does not — so content is kept inside the 480×300 box.

    Placement differs by one convention: a <ui> plane is CENTRED on its position,
    while a pixel-matched <ui3d> puts its stage's BOTTOM-LEFT corner at its
    position (the stage's y-down pixels are flipped into world y-up, so the top
    edge lands at position.y + height). So the left plane sits at "-270 0 0" and
    the right stage at "30 -150 0" (= centre 270,0 for a 480×300 box) and the two
    land at mirrored spots on screen.

      01. dashboard   a metrics card: header, two stats, a progress bar
      02. thread      a chat card: avatar header + three bubbles cascading in
      03. widgets     stat-ring + line-chart + typewriter-free content draws

    Capture: nx run tools:capture:webgl -- --project promos/primitives/uis/ui-ui3d.promo
    Preview: /packages/runtime/index.html?project=promos/primitives/uis/ui-ui3d.promo
promo#ui-ui3d
  // =======================================================================
  // SCENE 01 · DASHBOARD
  // =======================================================================
  scene#s01-dashboard(duration=15 transition=match-move transition-duration=1.2)
    camera(type=perspective fov=30 near=8.5 far=17000 position="0 0 1250" look_at="0 0 0")
      // slow tour: wide → the <ui> plane → the <ui3d> panel → back to both
      properties
        frame(smooth=0.35)
          keyframes
            kf(time=0 position="0 0 1250" look_at="0 0 0" fov=30)
            kf(time=1.2 position="0 0 1250" look_at="0 0 0" fov=30 easing=linear)
            kf(time=4.6 node=s01-ui bounds=union fill=100 side=front easing=easeInOutSine)
            kf(time=6.6 node=s01-ui bounds=union fill=100 side=front easing=linear)
            kf(time=9.6 node=s01-ui3d bounds=union fill=100 side=front easing=easeInOutSine)
            kf(time=11.6 node=s01-ui3d bounds=union fill=100 side=front easing=linear)
            kf(time=14.2 position="0 0 1250" look_at="0 0 0" fov=30 easing=easeInOutSine)
            kf(time=15 position="0 0 1250" look_at="0 0 0" fov=30 easing=linear)
    background(top=#0b1020 bottom=#05070f)
    lights
      light#s01-amb(type=ambient color=#ffffff intensity=1.0)
      light#s01-key(type=directional color=#ffffff intensity=1.6 position="340 680 510")
    haze#s01-hz0(match=hz0 blend=add opacity=0.2 position="-600 300 -900" color=#2563EB size="3200 2400" pulse=0 decay=0)
    haze#s01-hz1(match=hz1 blend=add opacity=0.16 position="600 -100 -900" color=#7C3AED size="3000 2200" pulse=0 decay=0)
    text#s01-title(text="ui vs ui3d · dashboard" kind=layer size=220 worldHeight=40 color=#e8eefc weight=700 align=center position="0 270 0")
    text#s01-l(text="<ui> · one texture, one plane" kind=layer size=120 worldHeight=18 color=#8ea3c8 weight=500 align=center position="-270 200 0")
    text#s01-r(text="<ui3d> · one mesh per item" kind=layer size=120 worldHeight=18 color=#8ea3c8 weight=500 align=center position="270 200 0")
    ui#s01-ui(width=480 height=300 position="-270 0 0")
      card(x=0 y=0 w=480 h=300