3D Transforms
Rotate elements in 3D space with rotateX, rotateY, rotateZ and perspective.
The Motion SDK supports 3D rotation transforms via rotateX, rotateY, and rotateZ properties. Combined with perspective, these create depth effects like card flips, tilts, and spins.
Parameters
| Property | Type | Default | Description |
|---|---|---|---|
rotateX | number | 0 | Rotation around the X axis (horizontal). Positive values tilt the top away from the viewer. In degrees. |
rotateY | number | 0 | Rotation around the Y axis (vertical). Positive values turn the left side away from the viewer. In degrees. |
rotateZ | number | 0 | Rotation around the Z axis — equivalent to the 2D rotate property. In degrees. |
transformOrigin | string | '50% 50%' | Sets the pivot point for all transforms. |
rotateZ and rotate are interchangeable — they produce identical results.
Perspective
3D rotations look flat without perspective. There are two ways to add it:
- CSS on the parent —
perspective: 800px. All children share a single vanishing point, which looks correct when multiple elements rotate together. - Per-element — set
perspectiveinline on the element itself via CSStransform: perspective(800px) rotateY(45deg), or use the SDK’stransformPerspectiveproperty. Each element has its own vanishing point.
For most SDK use cases, setting perspective in CSS on the parent container is the simplest approach:
typescript
import { Motion } from '@motion.page/sdk';
// Parent needs perspective in CSS: .scene { perspective: 800px; }
Motion('flip', '.card', {
from: { rotateY: 180 },
duration: 0.8,
ease: 'power2.out',
}).play(); Axis Directions
- rotateX — positive values tilt the top away (like leaning back in a chair); negative values tilt the top toward the viewer.
- rotateY — positive values turn the left side away (like opening a door to the right); negative values turn the right side away.
- rotateZ — positive values rotate clockwise; negative values rotate counter-clockwise. Identical to the 2D
rotateproperty.
Combining Axes
You can apply multiple rotation axes simultaneously for compound 3D motion:
typescript
Motion('tilt', '.box', {
from: { rotateX: 45, rotateY: -30 },
duration: 1,
ease: 'power2.out',
}).onScroll({ scrub: true }); Common Patterns
Flip in Y (card flip)
typescript
Motion('flip-y', '.card', {
to: { rotateY: 180 },
duration: 0.8,
ease: 'power2.inOut',
}).onClick(); Flip in X (top-down flip)
typescript
Motion('flip-x', '.panel', {
to: { rotateX: 180 },
duration: 0.6,
ease: 'power2.inOut',
}).onClick(); Perspective spin (full 360)
typescript
Motion('spin', '.logo', {
to: { rotateY: 360 },
duration: 1.2,
ease: 'power1.inOut',
repeat: -1,
}).play(); 3D tilt on hover
typescript
Motion('tilt-hover', '.card', {
to: { rotateX: -8, rotateY: 12 },
duration: 0.4,
ease: 'power2.out',
}).onHover({ each: true, onLeave: 'reverse' }); Scroll-driven 3D rotation
typescript
Motion('scroll-rotate', '.hero-image', {
from: { rotateX: 25, rotateY: -15 },
duration: 1,
}).onScroll({ scrub: true }); Tips
- Always set
perspectiveon the parent container in CSS. Without it, 3D rotations render flat. - Add
transform-style: preserve-3dto the rotating element when it has 3D-transformed children (e.g. both faces of a card). - Use
backface-visibility: hiddenin CSS on card faces to hide the reverse side during a flip. transformOrigincontrols the pivot point — the default'50% 50%'works for most 3D rotations, but'left center'creates a door-hinge effect.- Keep
perspectivevalues between 500–1200px for natural-looking depth. Lower values create more dramatic distortion; higher values make rotation more subtle.