AnimationsIntermediateApril 8, 2026

Blurry Cursor

A custom cursor that uses GSAP and linear interpolation (lerp) for a smooth trailing follow effect. When the cursor enters the heading, it expands to 400px and blurs, creating a color-inverted spotlight via mix-blend-mode: difference.

View Full Demo →

Hover

Motion Forward

Design studio

index.jsx
"use client";
import { useEffect, useRef, useState } from "react";
import gsap from "gsap";
import styles from "./styles.module.css";

const lerp = (x, y, a) => x * (1 - a) + y * a;

export default function BlurryCursor() {
  const demoRef   = useRef(null);
  const circleRef = useRef(null);
  const mouse     = useRef({ x: -200, y: -200 });
  const delayed   = useRef({ x: -200, y: -200 });
  const rafId     = useRef(null);
  const [isActive, setIsActive] = useState(false);

  useEffect(() => {
    const el = demoRef.current;
    if (!el) return;

    // Animate in RAF — lerp delayed position toward real mouse position
    const animate = () => {
      delayed.current = {
        x: lerp(delayed.current.x, mouse.current.x, 0.075),
        y: lerp(delayed.current.y, mouse.current.y, 0.075),
      };
      gsap.set(circleRef.current, {
        x: delayed.current.x,
        y: delayed.current.y,
        xPercent: -50,
        yPercent: -50,
      });
      rafId.current = requestAnimationFrame(animate);
    };

    const onMove = (e) => {
      const rect = el.getBoundingClientRect();
      mouse.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };
    };

    const onLeave = () => {
      mouse.current = { x: -200, y: -200 };
      setIsActive(false);
    };

    el.addEventListener("mousemove", onMove);
    el.addEventListener("mouseleave", onLeave);
    rafId.current = requestAnimationFrame(animate);

    return () => {
      el.removeEventListener("mousemove", onMove);
      el.removeEventListener("mouseleave", onLeave);
      cancelAnimationFrame(rafId.current);
    };
  }, []);

  return (
    <div ref={demoRef} className={styles.demo}>
      {/* Text to hover — triggers cursor expansion */}
      <p className={styles.label}>Hover</p>
      <h1
        className={styles.heading}
        onMouseOver={() => setIsActive(true)}
        onMouseLeave={() => setIsActive(false)}
      >
        Motion Forward
      </h1>
      <p className={styles.sub}>Design studio</p>

      {/* Custom cursor — position: absolute within demo container */}
      <div
        ref={circleRef}
        className={`${styles.cursor} ${isActive ? styles.cursorActive : ""}`}
      />
    </div>
  );
}
styles.module.css
.demo {
  position: relative;
  height: 100dvh;
  background: #0d0d0d;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  cursor: none;
  overflow: hidden;
  user-select: none;
}

.label {
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.35);
  margin: 0;
  position: relative;
  z-index: 1;
}

.heading {
  font-size: clamp(3rem, 10vw, 8rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  color: #f5f5f5;
  margin: 0;
  text-align: center;
  padding: 0 0.25em;
  position: relative;
  z-index: 1;
}

.sub {
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.35);
  margin: 0;
  position: relative;
  z-index: 1;
}

/* ── Cursor circle ── */

.cursor {
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 50%;
  pointer-events: none;
  mix-blend-mode: difference;
  background-color: #bce4f2;
  width: 30px;
  height: 30px;
  transition:
    width 0.3s ease-out,
    height 0.3s ease-out,
    filter 0.3s ease-out;
  z-index: 10;
  /* GSAP controls x/y via transform; top/left stay at 0 */
}

.cursorActive {
  width: 400px;
  height: 400px;
  filter: blur(30px);
}
  • gsap

Apr 27, 2026

ANIMATIONS

Cursor Hover Label

A custom cursor label that follows the mouse and fades in when hovering trigger elements. Uses GSAP quickTo for smooth tracking. Trigger elements use data-cursor-label attributes to set label text. Inspired by portfolio/agency sites like Studio PIC.

Apr 27, 2026

ANIMATIONS

Section Transition 01

GSAP ScrollTrigger-based section transition system. Sibling sections opt into parallax, pin, or reveal modes via data attributes. Supports y offset, overlay opacity, and overlay color per section. Mobile strategy simplifies motion on smaller screens.

Apr 27, 2026

ANIMATIONS

Text Reveal 01

GSAP SplitText-based text reveal system. Text elements opt in with data-reveal-01 and split into lines, words, or characters. Supports load-time reveals, scroll-triggered reveals, scrubbed scroll reveals, and manual split-only mode for custom timelines. Per-element overrides for duration, stagger, delay, ease, and replay behavior.