3D✨ Premium

Rollercoaster

An orange two-wheeled cart rides a rollercoaster track (climb, big drop, dip, small hump) in 4 s, tilting its nose with the slope thanks to offset-rotate: auto, slowing at the start and the finish, then starts over: the only trajectory in the catalog where the object orients itself — CSS only, zero JavaScript, cart stopped mid-drop when the user reduces motion.

CSSoffset-rotatePath

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →

3 usage examples

The new season's coaster — family theme park website — Rollercoaster example 1

① The new season's coaster — family theme park website

WhenAnnouncement of the park's new ride: the Forest Serpent, a wooden coaster open from 1.10 m; the red track on wooden pillars fills the scene, and the cart in the park's colors dives nose first into the big drop.
WhyThe cart tipping into the drop conveys the feel of the ride without a video, while the height limit and opening date stay readable next to it.
SettingsScene enlarged (transform: scale(1.32)); 3 px red track #b91c1c, brown rail #92400e; wooden pillars added in the same svg, behind the track; green #16a34a body with a yellow stripe.
The mine cart going down — mining museum website — Rollercoaster example 2

② The mine cart going down — mining museum website

WhenPage for the "Down to -150 m" guided tour: the track becomes a gallery in the earth, lit by two lamps, with wooden props, and the miners' gray cart climbs and drops along the slopes.
WhyThe cart tilting with the slope makes the steepness of the gallery readable, with no photo or cross-section.
SettingsBrown radial-gradient background; 2.5 px steel-gray track, dark gray rail; props and lamps added to the scenery; #78716c body with almost square corners (border-radius: 2px), same offset-anchor.
The summer alpine coaster — mountain resort "Summer activities" page — Rollercoaster example 3

③ The summer alpine coaster — mountain resort "Summer activities" page

WhenPage for the alpine coaster: against meadows and peaks, the red sled climbs, plunges into the big drop and rides over the small hump, above the opening hours.
WhyThe sled following the dips and humps while tilting shows the track better than a map, and the slowdown at the finish suggests braking at the bottom of the run.
SettingsScene enlarged (transform: scale(1.32)); 3 px light gray track, slate rail; red #dc2626 body rounded into a sled; mountains in clip-path behind the scene.

How it works

The .fx-0040-root root (background #0a0a0f, at least 300 px tall) centers a 320 × 220 px .mp-roller-scene. An <svg> draws the track, ten quadratic Bézier curves in an amber line at 15%, and a second white line at 5%, the same shifted 4 px down: the double rail. The .mp-roller-car is a 20 × 14 px #f59e0b rectangle with rounded corners; its ::after pseudo-element draws a 5 px gray wheel and the second one with a box-shadow offset by 11 px.

The cart gets the track path as offset-path: path(…) and an offset-distance animation from 0 to 100% in 4 s, ease-in-out, looping. offset-rotate: auto turns it at every moment in the direction of the tangent: measured at four points of the ride, the angle of the car body follows the slope of the path within half a degree (68° versus 68.2° on the climb, 71.5° versus 71.6° on the big drop), identically in Chromium 151, Firefox 153 and WebKit 26.

offset-anchor: 50% 100% picks the point of the cart that sits on the path: the middle of the bottom of the body, not its center. The body therefore rides above the line, and the wheels, which stick out 4 px below the body, fall between the two rail lines; the cart also pivots around that point. The easing applies to the whole ride: slow start, full speed on the big drop, braking on the last hump, then the cart jumps back to the start.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, a block scoped to .fx-0040-root stops the cart in the middle of the big drop (offset-distance: 50%), nose down: the still image still says "rollercoaster". Measured: 0% of pixels change over 0.8 s in Chromium, Firefox and WebKit, versus 0.75% in normal mode.
  • Decorative content: the scene carries no text; the svg and the cart, an empty div, are ignored by screen readers. Write next to it what the track stands for (ride, mine gallery, slope).
  • Contrast: the orange cart measures 9.2:1 on the dark background; the track, at 15%, and the rail, at 5%, are deliberately faint. On a light background, darken and thicken them, as in the examples.
  • Rhythm: a 4 s loop, no flashing; the return to the start is a jump of the cart.

Browser compatibility

CSS only: offset-path: path(), offset-rotate: auto, offset-anchor and animated offset-distance, no JavaScript, no dependency. Measured in Chromium 151, Firefox 153 and WebKit 26 (Safari's engine): same positions, same body angle, same stop under reduced motion. Not checked on a real Safari.

Chrome 116+✓ Full (offset-anchor)
Firefox 72+✓ Full
Safari 16+✓ WebKit 26 measured, Safari not checked
Edge 116+✓ Full
Mobile iOS 16+✓ Not checked on a device
Android Chrome✓ Full

A browser that supports offset-path but not offset-anchor centers the body on the path: the cart still rides and tilts, the wheels pass just below the rail. Without offset-path, the cart stays still at the top left of the scene and the track stays drawn.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0040-root">
  <div class="mp-roller-scene">
    <svg viewBox="0 0 320 220" fill="none">
      <path d="M10,180 Q40,180 60,120 … 300,140" … />   <!-- track -->
      <path d="M10,184 Q40,184 60,124 … 300,144" … />   <!-- rail -->
    </svg>
    <div class="mp-roller-car"></div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Cart color and shape (CSS — .mp-roller-car) 20 × 14 px, #f59e0b, 4 px corners, orange glow Change background, border-radius and box-shadow. If you change the size, keep the wheels (::after, bottom: -4px) under the body.
Point on the rail (CSS — offset-anchor) 50% 100% (middle of the bottom of the body) 50% 50% centers the body on the line; 50% 18px puts the bottom of the wheels on the line. The cart pivots around this point.
Orientation (CSS — offset-rotate) auto (follows the slope) auto 180deg flips the cart (reverse); 0deg keeps it level, like a hanging gondola.
Speed and easing (CSS — 4s ease-in-out) 4 s, slow start and finish linear gives a constant speed; cubic-bezier(.5,0,.8,.6) speeds up on the drop. 6 s for a quiet tour, 2.5 s for a thrill ride.
Track (HTML + CSS) Climb, big drop, dip, small hump over 320 × 220 px The path is written three times: the track line, the rail (same path, 4 px lower) and the offset-path. Change all three together.
Background (CSS — .fx-0040-root) #0a0a0f Change or remove the background; on a light background, darken and thicken the track and the rail.

FAQ

offset-rotate: auto: the browser computes the tangent of the path at the point reached and rotates the element accordingly, at every frame. Nothing to compute, no JavaScript. Measured: the body angle follows the slope within half a degree in Chromium, Firefox and WebKit.
The track is open: it starts on the left and ends on the right, higher up. At the end of the loop, the animation restarts at 0%. For a loop without a jump, draw a closed track (one that returns to its starting point) and switch the animation to linear; for a single run, use 1 and forwards instead of infinite.
It is the only one where the object orients itself along the slope. In Bezier Curve or Bounce Path, a round ball follows its curve with no visible rotation. As soon as the object has a front and a back (cart, sled, car, plane), Rollercoaster is the one you need.