Scroll Stage
FreeA pinned stage that hands its children a 0–1 scroll progress motion value, so any transform can be scrubbed by the thumb instead of played on a timer.

Installation
npx shadcn add https://useplanes.com/r/scroll-stage.json
<ScrollStage height="300vh">
<Hero />
</ScrollStage>
function Hero() {
const rotateX = useStageTransform([0, 0.5], [18, 0]);
const scale = useStageTransform([0, 0.5], [0.86, 1]);
return <motion.img src="/app.png" style={{ rotateX, scale }} />;
}Examples
Stepped states
useStageStep splits progress into n equal segments and only re-renders when the segment changes, so the per-frame path stays on motion values.
function Reel() {
const step = useStageStep(3);
return <Panel active={step} />;
}Reduced motion
Progress still tracks scroll (it is position, not decoration). Read ctx.reduced to flatten your own transforms — e.g. map to opacity only.
const { progress, reduced } = useScrollStage();
const y = useTransform(progress, [0, 1], reduced ? [0, 0] : [80, -80]);Use cases
Hero media scroll-out
A screenshot that stands up from a tilted perspective to flat as the visitor scrolls in.
Feature reels
Step through features while a pinned panel swaps state — useStageStep(n) gives the active index.
Product reveals
Scrub an image sequence or 3D-ish transform with scroll, Apple product-page style.
Storytelling sections
Pin a chart or map and let scroll drive what it shows.