Scale

Scale elements uniformly or independently on X/Y axes.

Scale controls how large or small an element appears during an animation. Use scale for uniform scaling, or scaleX / scaleY for independent axis control. All three are unitless — 1 means normal size.

Basic Scale

Pass scale inside from or to. A value of 1 is the element’s natural size.

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

Motion("grow", ".box", {
  from: { scale: 0 },
  duration: 0.5,
  ease: "back.out(1.7)",
}).onPageLoad();

Because scale: 1 is a natural CSS default, omitting to is correct here — the SDK resolves the missing endpoint from the element’s current computed style and animates to full size automatically.

Common Values

ValueResult
0Invisible (zero size)
0.5Half size
1Normal size (natural default)
1.5150% size
2Double size

Independent Axes — scaleX and scaleY

Use scaleX and scaleY when you want non-uniform scaling — stretching or squashing on one axis only.

typescript
// Squash horizontally
Motion("squash", ".box", {
  to: { scaleX: 0.6, scaleY: 1.2 },
  duration: 0.3,
  ease: "power2.inOut",
}).onHover({ each: true, onLeave: "reverse" });

Common Patterns

Zoom In on Scroll

Reveal an element by scaling it in as it enters the viewport.

typescript
Motion("zoom-in", ".card", {
  from: { scale: 0.8, opacity: 0 },
  duration: 0.6,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

Pop In with Opacity

Combine scale and opacity for a soft, polished entrance effect.

typescript
Motion("pop-in", ".modal", {
  from: { scale: 0.9, opacity: 0 },
  duration: 0.4,
  ease: "back.out(1.4)",
}).onPageLoad();

The two properties animate in parallel — the element fades in while simultaneously growing to its natural size.

Pulse (Infinite Repeat with Yoyo)

Gently pulse an element to draw attention.

typescript
Motion("pulse", ".badge", {
  to: { scale: 1.15 },
  duration: 0.6,
  ease: "power1.inOut",
  repeat: { times: -1, yoyo: true },
}).onPageLoad();

yoyo: true reverses the animation on each cycle, producing a continuous breathe effect without any visible jump.

Rubber Band (scaleX + scaleY)

Animate scaleX and scaleY in opposite directions for a rubbery, organic feel.

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

Motion("rubber-band", ".button", [
  {
    target: ".button",
    to: { scaleX: 1.3, scaleY: 0.7 },
    duration: 0.15,
    ease: "power2.out",
  },
  {
    target: ".button",
    to: { scaleX: 0.85, scaleY: 1.15 },
    duration: 0.1,
    ease: "power2.inOut",
  },
  {
    target: ".button",
    to: { scaleX: 1.05, scaleY: 0.95 },
    duration: 0.1,
    ease: "power2.inOut",
  },
  {
    target: ".button",
    duration: 0.15,
    ease: "power2.out",
  },
]).onClick({ each: true });

Transform Origin

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

typescript
// Scale up from the bottom-left corner
Motion("corner-scale", ".card", {
  from: { scale: 0, transformOrigin: "0% 100%" },
  duration: 0.5,
  ease: "power3.out",
}).onPageLoad();

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