April 8, 2026/Intermediate/Cursor Effects

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.

Hover

Motion Forward

Design studio

"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>
  );
}
  • gsap

Related Components

4W AGO
Split Vignettecursor-effects
1MO AGO
Cursor Repel Textcursor-effects
3MO AGO
Cursor Hover Labelcursor-effects