scrolling
scrolling
Scrolling primitives — every way content MOVES INSIDE A VIEWPORT, one scenario per scene. The subject is the `scroll` / `carousel-scroll` track and the overflow mask that makes it read: a container whose subtree scrolls becomes a clip box (CSS `overflow: hidden`), so content taller/wider than the box is cut at its edges instead of bleeding over the rest of the frame.
Read the rig's notes
THE CURRENT GRAMMAR — the `scroll` property channel on the viewport itself:
card(x=… y=… w=… h=…) <- the VIEWPORT (clips by default)
scroll <- x/y only; moves the CHILDREN
0 0 0
6 easeInOutCubic 0 620
…rows, taller than the box…
positive scroll.y scrolls DOWN (content travels up, lower rows come in);
positive scroll.x scrolls RIGHT. A bare scalar is the vertical amount.
The travel is CLAMPED at both ends: however large a value is authored,
the last row parks on the viewport's midline and the box is never left
empty. NEVER animate `position` to scroll a card — that moves the card,
its border and its shadow across the frame instead of its content.
The scenes below still use the older `<animate><scroll by=…>` track, which
translates a content GROUP inside a clip box rather than the container's
children, and is unclamped:
card(x=… y=… w=… h=… clip=true) <- the VIEWPORT (the mask)
item(component=group w=… layout=column …) <- the CONTENT (taller than it)
animate
scroll(by=620 start=1.2 end=6.6 axis=y easing=easeInOutCubic)
children
…rows…
axis=y · positive `by` scrolls content UP (lower content comes into view)
axis=x · positive `by` scrolls content LEFT (righter content comes in)
from/to · scroll the other way — from=520 to=0 walks content back DOWN
A <card> clips automatically once its subtree scrolls; clip=true is the
explicit opt-in used everywhere here so the mask is visible in the source.
PIXEL-SPACE SECTION (scenes 01–05) — one full-stage <ui3d> per scene, world
mapped 1:1 to the 1920x1080 stage (camera at 960 540 1320).
01. list — the baseline: one column taller than its card, masked
02. rails — axis=x, two strips travelling in opposite directions
03. carousel — the <carousel> component + its carousel-scroll track
04. parallax — three lanes, three rates, one of them running backwards
05. nested — a vertical viewport whose rows are horizontal viewports;
the clip boxes INTERSECT instead of the inner replacing
the outer
DEVICE SECTION (scenes 06–10) — real devices at true physical size, the same
tracks running on real glass. Scene 05 owns the boundary cut (transition=none),
since match-move cannot carry a haze rig across a coordinate-system change.
06. chrome — a sticky nav bar: the page scrolls UNDER a bar drawn after
(and therefore on top of) the viewport
07. iphone — a feed between a pinned status header and a pinned tab bar
08. ipad — split view: the master list scrolls, the detail pane does not
09. macbook — two speeds on one screen: the doc runs fast, its contents
rail crawls
10. imac — three viewports at once: a log up, a thumbnail wall up
slowly, a ticker sideways
Matched haze rides every scene (haze-a/haze-b + dot-a/b/c in px scenes,
wz0..wz2 in device scenes) so transition=match-move carries the backdrop.
Preview: /packages/runtime/index.html?project=promos/primitives/scrolling/scrolling.promo- Topic
- uis
- Scenes
- 10
- Kind
- reference rig
//
Scrolling primitives — every way content MOVES INSIDE A VIEWPORT, one
scenario per scene. The subject is the `scroll` / `carousel-scroll` track
and the overflow mask that makes it read: a container whose subtree scrolls
becomes a clip box (CSS `overflow: hidden`), so content taller/wider than
the box is cut at its edges instead of bleeding over the rest of the frame.
THE CURRENT GRAMMAR — the `scroll` property channel on the viewport itself:
card(x=… y=… w=… h=…) <- the VIEWPORT (clips by default)
scroll <- x/y only; moves the CHILDREN
0 0 0
6 easeInOutCubic 0 620
…rows, taller than the box…
positive scroll.y scrolls DOWN (content travels up, lower rows come in);
positive scroll.x scrolls RIGHT. A bare scalar is the vertical amount.
The travel is CLAMPED at both ends: however large a value is authored,
the last row parks on the viewport's midline and the box is never left
empty. NEVER animate `position` to scroll a card — that moves the card,
its border and its shadow across the frame instead of its content.
The scenes below still use the older `<animate><scroll by=…>` track, which
translates a content GROUP inside a clip box rather than the container's
children, and is unclamped:
card(x=… y=… w=… h=… clip=true) <- the VIEWPORT (the mask)
item(component=group w=… layout=column …) <- the CONTENT (taller than it)
animate
scroll(by=620 start=1.2 end=6.6 axis=y easing=easeInOutCubic)
children
…rows…
axis=y · positive `by` scrolls content UP (lower content comes into view)
axis=x · positive `by` scrolls content LEFT (righter content comes in)
from/to · scroll the other way — from=520 to=0 walks content back DOWN
A <card> clips automatically once its subtree scrolls; clip=true is the
explicit opt-in used everywhere here so the mask is visible in the source.
PIXEL-SPACE SECTION (scenes 01–05) — one full-stage <ui3d> per scene, world
mapped 1:1 to the 1920x1080 stage (camera at 960 540 1320).
01. list — the baseline: one column taller than its card, masked
02. rails — axis=x, two strips travelling in opposite directions
03. carousel — the <carousel> component + its carousel-scroll track
04. parallax — three lanes, three rates, one of them running backwards
05. nested — a vertical viewport whose rows are horizontal viewports;
the clip boxes INTERSECT instead of the inner replacing
the outer
DEVICE SECTION (scenes 06–10) — real devices at true physical size, the same
tracks running on real glass. Scene 05 owns the boundary cut (transition=none),
since match-move cannot carry a haze rig across a coordinate-system change.
06. chrome — a sticky nav bar: the page scrolls UNDER a bar drawn after
(and therefore on top of) the viewport
07. iphone — a feed between a pinned status header and a pinned tab bar
08. ipad — split view: the master list scrolls, the detail pane does not
09. macbook — two speeds on one screen: the doc runs fast, its contents
rail crawls
10. imac — three viewports at once: a log up, a thumbnail wall up
slowly, a ticker sideways
Matched haze rides every scene (haze-a/haze-b + dot-a/b/c in px scenes,
wz0..wz2 in device scenes) so transition=match-move carries the backdrop.
Preview: /packages/runtime/index.html?project=promos/primitives/scrolling/scrolling.promo
promo#scrolling
// =======================================================================
// SCENE 01 · LIST — the baseline vertical scroll
// =======================================================================
scene#s01-list(duration=7 transition=match-mo