Motion Path
`<pura-motion-path>` makes its slotted content ride an SVG path, the gsap MotionPath move done natively: `offset-path: path(...)` places the content on the curve and `offset-distance` ramps `0%` to `100%` to travel it, with `offset-rotate: auto` keeping it faced along the direction of travel (disable with `no-rotate`). The default `trigger="scrub"` ties the travel 1:1 to a scroll-driven timeline (`animation-timeline: view()` or `scroll()`), so the content moves along the curve as you scroll, with no per-frame JS. `trigger="view"` travels once when scrolled into view (eased by the spring primitive); `trigger="load"` travels once on connect. Path coordinates are px in the host's box (offset-path has no viewBox), so size the host to fit the path. `show-path` draws a faint dotted guide of the same path behind the mover. SSR and reduced motion are safe: before JS the content sits at the path start fully visible, the scrub block is gated behind `prefers-reduced-motion: no-preference`, and reduced motion lands the content at the path end. Each instance registers in `window.__puraMotionPaths` by `data-pura-id` with `{ path, replay }`.
Preview
<!-- default: the dot travels the curve as you scroll -->
<pura-motion-path path="M 10 80 C 80 10, 220 10, 290 80"
style="width: 300px; height: 100px;">
<span style="display:block;width:16px;height:16px;border-radius:50%;background:currentColor"></span>
</pura-motion-path>
<!-- an arrow that faces its travel, once on view -->
<pura-motion-path trigger="view" show-path
path="M 20 100 Q 160 -40 300 100"
style="width: 320px; height: 120px;">
<span>➤</span>
</pura-motion-path>
<!-- keep the content upright -->
<pura-motion-path no-rotate path="M 0 0 L 240 0"
style="width: 240px; height: 40px;">
<span>upright</span>
</pura-motion-path> Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
trigger | "scrub" | "view" | "load" | scrub | scrub ties the travel 1:1 to a scroll-driven timeline; view travels once when scrolled into view; load travels once on connect. |
timeline | "view" | "scroll" | view | Scrub only. view maps the element's own view progress; scroll maps the nearest scroll container. |
path | string | wave | SVG path d-string to travel. Coordinates are px in the host's box (offset-path has no viewBox). |
no-rotate | boolean | false | Keep the content upright instead of rotating to face the direction of travel. |
show-path | boolean | false | Draw a faint dotted guide of the path behind the moving content. |
line-color | string | currentColor | Guide stroke color (with show-path). |
range | string | cover 0% cover 50% | animation-range for the scrub timeline. Default completes the travel as the element reaches viewport center, then holds. |
preset | "default" | "gentle" | "wobbly" | "stiff" | "slow" | "snappy" | default | Spring easing for view/load triggers. Or set stiffness/damping/mass directly. |
Installation
pura is copy-paste and dependency-free. Load the whole library, or just this component.
<link rel="stylesheet" href="/pura/tokens.css">
<script type="module" src="/pura/lib/motion-path.js"></script> import "./pura/lib/motion-path.js";