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