motion-scene

Scroll-driven animation timeline. Pin a stage while scroll progress drives children through keyframes — purely declarative via data attributes.

Live showcase Declare · Sequence · Compose

How it works

Wrap a scene in a tall container. The inner stage sticks while the user scrolls. Children with data-from/data-to are scrubbed from their start keyframe to their end keyframe as scroll advances through data-startdata-end (0–1 progress values).

Preview

Scroll inside the box to drive the animation.

STEP_01
STEP_02
STEP_03

Import

CSS variable

The scene exposes --progress (0–1) so you can drive your own CSS effects off scroll position.

Custom scroll container

By default the scene tracks document scroll. Pass a CSS selector via container to use an overflow element instead.

Without pinning

Set the pin attribute to false (omit it) if you want scrubbed children but no sticky stage.

Properties

Attribute Property Type Default Description
height height string '200vh' Height of the scroll container — controls how much scroll the scene consumes.
pin pin boolean true When present, the inner stage sticks to the viewport while scrolling. Omit to disable.
container container string '' CSS selector for a custom scroll container. Defaults to document scroll when empty.

Child data attributes

Property Type Default Description
data-from JSON Starting keyframe — e.g. {"opacity":0,"y":"-20px"}. Supports x, y, scale, rotate, and any CSS property.
data-to JSON Ending keyframe — same shape as data-from.
data-start number 0 Scene progress (0–1) at which this child's animation begins.
data-end number 1 Scene progress (0–1) at which this child's animation ends.

Accessibility

Respects prefers-reduced-motion: when enabled, all scroll-driven animations are disabled and children render at their end state immediately.