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

Value Result
0 Invisible (zero size)
0.5 Half size
1 Normal size (natural default)
1.5 150% size
2 Double 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.