Waypoint Stage
Place each passage of content by coordinate on an oversized canvas, and let scroll drive a camera that pans, zooms, and rotates along a waypoint path for a Prezi-style spatial narrative.
This is a WebberUI Pro component
Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.
npx shadcn@latest add "https://webberui.com/r/waypoint-stage.json?t=<install token>"Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<WaypointStage />
Installation
npx shadcn@latest add "https://webberui.com/r/waypoint-stage.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/waypoint-stage.
Usage
Wrap a number of Waypoints in a WaypointStage; each waypoint declares its coordinates on the canvas with x / y, and its zoom / rotate decide the composition the camera arrives at. Scrolling drives the camera to fly to them in order.
import { Waypoint, WaypointStage } from "@/components/ui/waypoint-stage";
<WaypointStage>
<Waypoint x={0} y={0} label="Opening">
<h2 className="text-4xl font-bold">Welcome</h2>
</Waypoint>
<Waypoint x={800} y={-320} zoom={1.4} rotate={-8} label="Key point">
<p className="max-w-sm">Fly here to zoom in on a tilted composition.</p>
</Waypoint>
<Waypoint x={-360} y={420} zoom={1.2} rotate={6} label="Closing">
<p>Then turn to somewhere else.</p>
</Waypoint>
</WaypointStage>By default the window is the scroll container and the stage is pinned at h-screen. If it sits inside a nested overflow-y-auto container, pass that container's ref to container and override the stage height with stageClassName to the container's visible height (such as h-[300px]).
Props
WaypointStage
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Put Waypoint children here |
pace | number | 1 | Scroll length of each leg (in units of the pinned stage height) |
dwell | number | 0.25 | Proportion of the leg spent lingering after arriving at each waypoint (0–0.49) |
zoomOut | number | 0.72 | How far the camera pulls back between two waypoints (1 means no pull-back) |
smooth | boolean | true | Whether to smooth the camera work with a spring |
showPath | boolean | true | Whether to draw the dashed path connecting the waypoints |
showNav | boolean | true | Whether to show the clickable navigation dots that jump between waypoints |
grid | boolean | true | Whether to lay down the faint dot-grid texture |
container | RefObject<HTMLElement | null> | — | Ref of the nested scroll container; defaults to the window as scroll container |
stageClassName | string | "h-screen" | Height of the pinned stage container |
className | string | — | The outer scroll track container |
Waypoint
| Prop | Type | Default | Description |
|---|---|---|---|
x | number | — | X coordinate of the waypoint's center on the canvas (px) |
y | number | — | Y coordinate of the waypoint's center on the canvas (px) |
zoom | number | 1 | Zoom when the camera arrives; >1 zooms in, <1 zooms out |
rotate | number | 0 | Rotation angle of this waypoint on the canvas (degrees); it is straightened on arrival |
label | string | — | Name used by the navigation dots and assistive technology |
children | ReactNode | — | Waypoint content |
How it works
- The camera is implemented in pure CSS
transform(translate+scale+rotate, with the origin anchored to the viewport center) — no WebGL needed. Content is centered on its own coordinates, so the camera arrives with it straightened and centered. - The transition uses a "pull back first, then push in" keyframe;
zoomOutcontrols how far it pulls back midway, anddwellcontrols how long it lingers after arriving. - The track height is computed automatically from the number of waypoints and
pace: more waypoints and a largerpacemean a longer scroll distance and more leisurely camera work. - For nested scrolling, always pass both
containerand a matchingstageClassName, souseScrollcorrectly treats that container as its scroll source.
Accessibility
- When the user has "reduce motion" enabled at the system level, the camera work is disabled entirely and the waypoints are instead laid out in order as static vertical passages, avoiding the discomfort that sweeping zoom and rotation can cause.
- The navigation dots are focusable buttons carrying
aria-labelandaria-current, operable with the keyboard and jumping smoothly to their waypoint. - The stage also carries an
sr-onlyordered list for assistive technology to announce, decoupled from the animated visuals. - The
ResizeObserverand the springs are all cleaned up on unmount by Motion and the effects.
Strata Headers
Section headers pin to the top and stack up in order once you scroll past them, accumulating into a live table of contents built out of your reading progress.
Data Duel Split
A page-scale A/B duel split screen — scrolling reveals the metrics round by round while the divider in the middle slides like a tug-of-war rope and the running score at the bottom jumps in sync.