Back to library
INTERACTION_040

Kinetic Text.

Oversized type scales and drifts in opposing directions for a poster feel. Each line scaled to 0.94 with alternating horizontal offsets before the trigger; scaling to 1 and drifting the lines in opposite directions once the section enters view, then continues with scroll position.

CATEGORY
Text
COMPLEXITY
Intermediate
TECH
CSS
PLATFORM
Both
PERFORMANCE
Medium
LIVE PLAYGROUND
MAKEITPREMIUM
CSS / CSS
/* Kinetic Text — Oversized type scales and drifts in opposing directions for a poster feel. */
.kinetic-text {
  --dur: 900ms;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --stagger: 60ms;
  will-change: transform, opacity;
}

.kinetic-text > * {
  opacity: 0;
  transform: translateY(14px);
  animation: kinetic-text-in var(--dur) var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* each line scaled to 0.94 with alternating horizontal offsets -> scaling to 1 and drifting the lines in opposite directions */
@keyframes kinetic-text-in {
  to {
    opacity: 1;
    transform: none;
    filter: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kinetic-text > * {
    opacity: 1;
    transform: none;
    animation: none;
  }
}
React / TSX
import { useEffect, useRef } from "react";

/** Kinetic Text — trigger: the section enters view, then continues with scroll position */
export function KineticText({ children }: { children: React.ReactNode }) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      el.dataset["state"] = "in";
      return;
    }
    const io = new IntersectionObserver(
      ([entry]) => {
        if (entry?.isIntersecting) {
          el.dataset["state"] = "in";
          io.unobserve(el);
        }
      },
      { threshold: 0.2 },
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);

  return (
    <div ref={ref} className="kinetic-text" data-state="out">
      {children}
    </div>
  );
}

IF YOU LIKE THIS, STEAL THESE TOO.

MAKE IT
FEEL PREMIUM.
INTERACTION_036CSS

Clip Path Heading Reveal

A heading wipes into view as its clip rectangle opens left to right.

Text / LightView
MAKE ITPREMIUMKINETIC
INTERACTION_038CSS

Rolling Words

One word in a sentence rolls over like a split-flap counter.

Text / LightView
VAULT/#%
INTERACTION_043CSS + JS

Decoding Text

Characters cycle through symbols before locking into the real word.

Text / LightView
VAULT/#%
INTERACTION_044CSS + JS

Scrambled Text Reveal

The whole string shuffles and settles like a mechanical board.

Text / LightView