Opacity

Fade elements in and out with opacity animations.

Opacity controls element transparency from fully invisible (0) to fully visible (1). It’s the foundation of fade animations.

Basic Fade-In

The simplest fade-in pattern uses from: { opacity: 0 }. Since opacity: 1 is the element’s natural CSS state, the SDK auto-resolves it as the to value — you only need to declare where the animation starts.

Implicit Values

opacity: 1 is the natural CSS default. The SDK reads it from the element’s computed style, so you don’t need to spell it out.

typescript
// ✅ Do this — SDK fills in to: { opacity: 1 } automatically
Motion("fade-in", ".element", {
  from: { opacity: 0 },
  duration: 0.6,
}).play();

// ❌ Don't do this — redundant, opacity: 1 is already the natural state
Motion("fade-in", ".element", {
  from: { opacity: 0 },
  to: { opacity: 1 },
  duration: 0.6,
}).play();

Partial Opacity

For ghost or dim effects, animate to values like 0.3 or 0.5. When neither endpoint is the natural 1, you need both from and to.

typescript
Motion("ghost", ".overlay", {
  from: { opacity: 0 },
  to: { opacity: 0.5 },
  duration: 0.4,
}).play();

Combining with Other Properties

Opacity pairs naturally with movement and other effects. These combos are the bread and butter of polished UI animations.

typescript
// Fade + slide up — the classic reveal
Motion("reveal", ".card", {
  from: { opacity: 0, y: 40 },
  duration: 0.6,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

// Fade + scale
Motion("pop", ".badge", {
  from: { opacity: 0, scale: 0.8 },
  duration: 0.5,
  ease: "back.out",
}).play();

// Fade + blur
Motion("blur-in", ".hero", {
  from: { opacity: 0, filter: "blur(10px)" },
  duration: 0.8,
  ease: "power2.out",
}).play();

Common Patterns

Fade-in on scroll — the bread and butter of scroll-driven reveals:

typescript
Motion("scroll-reveal", ".section", {
  from: { opacity: 0, y: 30 },
  duration: 0.6,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

Fade-out on page exit:

typescript
Motion("exit", "body", {
  to: { opacity: 0 },
  duration: 0.4,
  ease: "power2.in",
}).onPageExit({ skipHref: ["anchor", "mailto"] });

Staggered fade-in for lists:

typescript
Motion("list", ".item", {
  from: { opacity: 0, y: 20 },
  duration: 0.5,
  stagger: 0.1,
  ease: "power2.out",
}).onScroll({ scrub: false, toggleActions: "play none none none" });

Crossfade — fade out old, fade in new:

typescript
// Fade out the current element
Motion("crossfade-out", ".old", {
  to: { opacity: 0 },
  duration: 0.3,
}).play();

// Fade in the new element
Motion("crossfade-in", ".new", {
  from: { opacity: 0 },
  duration: 0.3,
  delay: 0.3,
}).play();