Clip Path
Reveal and mask elements with animated CSS clip-path.
Clip path masks portions of an element using CSS clip-path, letting you reveal or hide content by animating the shape of the visible region. Use it for circle reveals, diagonal wipes, polygon morphs, and any geometry-driven entrance or exit effect.
Basic Usage
Pass 'clip-path' (or clipPath) inside from and/or to. Both endpoints must use the same shape function for smooth interpolation.
import { Motion } from "@motion.page/sdk";
Motion("reveal", "#hero", {
from: { "clip-path": "circle(0% at 50% 50%)" },
to: { "clip-path": "circle(75% at 50% 50%)" },
duration: 1,
ease: "power2.out",
}).onPageLoad(); Supported Shapes
| Shape | Example |
|---|---|
circle | 'circle(50% at 50% 50%)' |
ellipse | 'ellipse(60% 30% at 50% 50%)' |
inset | 'inset(10px 20px round 8px)' |
polygon | 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)' |
rect | 'rect(10px 90px 90px 10px)' |
xywh | 'xywh(10% 10% 80% 80%)' |
Property Name
Both forms are equivalent — use whichever fits your style:
// kebab-case (quoted)
from: { "clip-path": "circle(0% at 50% 50%)" }
// camelCase
from: { clipPath: "circle(0% at 50% 50%)" } The SDK also automatically writes -webkit-clip-path alongside clip-path for Safari compatibility — you don’t need to set it manually.
Interpolation Rules
For smooth animation between two states:
- Same shape on both ends —
circle → circle,polygon → polygon. Mixing shapes (e.g.circle → inset) causes a hard swap at progress ≥ 0.5. - Polygon vertex counts must match —
polygon(0% 0%, 100% 0%, 100% 100%)(3 vertices) cannot smoothly tween to a 4-vertex polygon. - Units are preserved — mix of
%andpxvalues within a shape is fine, but the same unit should be used for each corresponding coordinate betweenfromandto.
From-Only / To-Only
Like all SDK properties, you can supply just one endpoint and the SDK reads the other from the element’s computed CSS:
// from-only — element has clip-path set in CSS, animate into it
Motion("reveal", ".card", {
from: { clipPath: "inset(100% 0% 0% 0%)" },
duration: 0.7,
ease: "power3.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });
// to-only — animate away from the element's natural clip-path
Motion("hide", ".card", {
to: { clipPath: "inset(0% 0% 100% 0%)" },
duration: 0.5,
ease: "power2.in",
}).onClick({ each: true }); Shape Examples
Circle Reveal
Expand a circle from the center — the classic reveal effect.
Motion("circle-reveal", "#hero", {
from: { "clip-path": "circle(0% at 50% 50%)" },
to: { "clip-path": "circle(75% at 50% 50%)" },
duration: 1,
ease: "power2.out",
}).onPageLoad(); Ellipse
Expand an ellipse from a custom focal point.
Motion("ellipse-in", ".banner", {
from: { clipPath: "ellipse(0% 0% at 50% 50%)" },
to: { clipPath: "ellipse(80% 60% at 50% 50%)" },
duration: 0.9,
ease: "power3.out",
}).onPageLoad(); Inset
inset clips all four edges simultaneously. Shrink from all sides to reveal content.
Motion("inset-reveal", ".image", {
from: { "clip-path": "inset(50% round 8px)" },
to: { "clip-path": "inset(0% round 8px)" },
duration: 0.8,
ease: "expo.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" }); Polygon Diagonal Wipe (Hover)
Morph a polygon on hover for a sharp diagonal wipe effect.
Motion("wipe", ".card", {
from: { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" },
to: { clipPath: "polygon(100% 0%, 100% 0%, 100% 100%, 100% 100%)" },
duration: 0.4,
ease: "power2.inOut",
}).onHover({ each: true, onLeave: "reverse" }); rect
rect specifies the clipping rectangle using top, right, bottom, and left edge values.
Motion("rect-reveal", ".panel", {
from: { "clip-path": "rect(50% 50% 50% 50%)" },
to: { "clip-path": "rect(0% 100% 100% 0%)" },
duration: 0.7,
ease: "power2.out",
}).onPageLoad(); xywh
xywh defines the clip region by x offset, y offset, width, and height — useful when you know the dimensions of the visible area you want.
Motion("xywh-reveal", ".feature", {
from: { clipPath: "xywh(50% 50% 0% 0%)" },
to: { clipPath: "xywh(0% 0% 100% 100%)" },
duration: 0.8,
ease: "power3.out",
}).onPageLoad(); Common Patterns
Circle Reveal on Page Load
The most common use case — reveal a hero section or image with an expanding circle.
import { Motion } from "@motion.page/sdk";
Motion("hero-reveal", "#hero", {
from: { "clip-path": "circle(0% at 50% 50%)" },
to: { "clip-path": "circle(150% at 50% 50%)" },
duration: 1.2,
ease: "power2.out",
}).onPageLoad(); Using 150% guarantees the circle covers the full element regardless of its aspect ratio.
Diagonal Wipe on Hover
Reveal a card overlay with a triangle wipe driven by hover.
Motion("card-wipe", ".card .overlay", {
from: { clipPath: "polygon(0% 0%, 0% 0%, 0% 100%, 0% 100%)" },
to: { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" },
duration: 0.5,
ease: "power2.out",
}).onHover({ each: true, onLeave: "reverse" }); Polygon Morph (Shape Shifting)
Smoothly morph between two polygon shapes — vertex count must be identical.
Motion("morph", ".blob", {
from: { clipPath: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)" },
to: { clipPath: "polygon(25% 0%, 75% 25%, 100% 75%, 25% 100%)" },
duration: 2,
ease: "power1.inOut",
repeat: { times: -1, yoyo: true },
}).onPageLoad(); Both shapes here use 4 vertices — the morph is smooth because the vertex counts match.