Rotation

Rotate elements in 2D with degree values.

Rotation spins elements around a pivot point. Use rotate for standard 2D rotation, or rotateX / rotateY for 3D perspective tilts. All values are in degrees — no unit suffix needed.

Basic Rotation

Pass rotate inside from or to. Positive values spin clockwise, negative values spin counter-clockwise.

typescript
import { Motion } from "@motion.page/sdk";

// Spin in from 90° clockwise
Motion("spin-in", ".icon", {
  from: { rotate: 90, opacity: 0 },
  duration: 0.5,
  ease: "power3.out",
}).onPageLoad();

Because rotate: 0 is a natural CSS default, omitting to is correct here — the SDK resolves the missing endpoint automatically and animates the element back to its un-rotated state.

Direction

ValueDirection
Positive (rotate: 45)Clockwise
Negative (rotate: -45)Counter-clockwise
typescript
// Counter-clockwise entrance
Motion("spin-ccw", ".arrow", {
  from: { rotate: -90, opacity: 0 },
  duration: 0.4,
  ease: "expo.out",
}).onPageLoad();

Full Rotations

Use multiples of 360 to spin the element one or more complete turns.

typescript
// One full clockwise spin
Motion("spin-once", ".logo", {
  from: { rotate: 0 },
  to: { rotate: 360 },
  duration: 1,
  ease: "power2.inOut",
}).onClick({ each: true });

A value of 360 is one full turn, 720 is two full turns, -360 is one full counter-clockwise turn, and so on.

Transform Origin

Rotation always pivots around the transform origin — by default the element’s center (50% 50%). Change this with transformOrigin to spin from a corner, edge, or any custom point.

ValuePivot point
'center'Center of the element (default)
'top left'Top-left corner (0% 0%)
'bottom right'Bottom-right corner (100% 100%)
'0% 100%'Bottom-left corner
'50% 0%'Top center
typescript
// Spin from the bottom-left corner (like a clock hand)
Motion("clock-hand", ".needle", {
  from: { rotate: -30, transformOrigin: "0% 100%" },
  to: { rotate: 30 },
  duration: 0.8,
  ease: "power2.inOut",
}).onPageLoad();

See the Transform Origin page for all supported values and examples.

Combining with Other Transforms

Rotation pairs naturally with scale and opacity to create richer entrance effects.

typescript
// Scale + rotate for a spiral entrance
Motion("spiral-in", ".card", {
  from: { scale: 0, rotate: 180, opacity: 0 },
  duration: 0.6,
  ease: "back.out(1.4)",
}).onPageLoad();
typescript
// Fade + rotate for a spin-in reveal
Motion("spin-fade", ".badge", {
  from: { rotate: -45, opacity: 0 },
  duration: 0.4,
  ease: "power3.out",
  stagger: 0.1,
}).onScroll({ scrub: false, toggleActions: "play none none none" });

Common Patterns

Spinner

An infinitely rotating element using repeat: -1 and a linear ease for constant speed.

typescript
Motion("spinner", ".loader", {
  from: { rotate: 0 },
  to: { rotate: 360 },
  duration: 1,
  ease: "none",
  repeat: -1,
}).onPageLoad();

Wiggle

Alternate between small positive and negative angles with yoyo: true for an attention-grabbing shake.

typescript
Motion("wiggle", ".notification", {
  to: { rotate: 12 },
  duration: 0.12,
  ease: "power1.inOut",
  repeat: { times: 5, yoyo: true },
}).onPageLoad();

yoyo: true reverses the animation on each cycle, rocking the element back and forth without any hard reset.

Spiral In

Combine scale: 0 with rotate: 180 so the element grows and unwinds into its natural state simultaneously.

typescript
Motion("spiral-in", ".icon", {
  from: { scale: 0, rotate: 180, opacity: 0 },
  duration: 0.7,
  ease: "expo.out",
}).onPageLoad();

Because rotate: 0, scale: 1, and opacity: 1 are all natural CSS defaults, omitting to is correct — the SDK fills in the endpoints automatically.

Hover Spin

Rotate an icon a quarter-turn on hover and reverse on leave.

typescript
Motion("hover-spin", ".arrow-icon", {
  to: { rotate: 90 },
  duration: 0.3,
  ease: "power2.out",
}).onHover({ each: true, onLeave: "reverse" });

Scroll-Driven Rotation

Drive rotation with scroll progress for a parallax feel.

typescript
Motion("scroll-rotate", ".decorative-ring", {
  from: { rotate: 0 },
  to: { rotate: 360 },
  duration: 1,
}).onScroll({ scrub: true });

Notes

  • Values are in degrees. rotate: 90 means 90 degrees — no unit suffix.
  • rotate: 0 is the natural CSS default. Do not include to: { rotate: 0 } when animating from a rotated state back to normal — the SDK resolves it automatically.
  • For 3D perspective tilts, use rotateX (tilt toward/away) and rotateY (tilt left/right). These require a perspective set on the parent element in CSS.
  • Combining repeat: -1 with ease: "none" (or ease: "linear") produces the smoothest continuous spinner — eased repeats will stutter at the loop boundary.
  • Large rotation values on text or images can cause subpixel rendering artifacts. Prefer will-change: transform on elements that animate frequently.