Retour au catalogue

Hero Cursor Mask

Hero à double couche avec effet masque curseur : une version dark et une version light superposées. La version light est révélée via un clipPath circle animé qui suit la souris (useSpring). Inspiré de la technique Olivier Larose. Effet wow garanti au premier survol.

herocomplex Both Responsive a11y
boldeleganteditorialagencyportfoliosaascentered
Theme

Cómo crear una sección hero revelada al cursor en React

Un hero revelado al cursor en React apila dos capas y recorta la superior con un clip-path circular que sigue al puntero mediante un spring de Framer Motion, revelando la capa de debajo. Se construye con useMotionValue para la posición y useSpring para el radio.

  • Stack: React + Framer Motion + Tailwind v4, ~290 líneas, cero dependencias adicionales.
  • API clave: useMotionValue, useSpring, useMotionTemplate, clip-path.
  • Accesible: ambas capas llevan el mismo texto legible; la máscara es decorativa.
  • Necesita un fallback estático en dispositivos táctiles (sin puntero).

Hero Cursor Mask es un hero React a pantalla completa donde mover el cursor revela una segunda capa, más clara, a través de una ventana circular animada con spring. Convierte un titular estático en una superficie táctil que invita a explorar, el tipo de detalle que hace que una landing parezca hecha a mano en lugar de salida de una plantilla.

Anatomía

Dos capas de contenido idénticas se apilan en posición absoluta: una capa base oscura (fondo + cuadrícula de puntos + viñeta radial) y una capa clara encima. La capa clara queda oculta en todas partes salvo dentro de un clip-path circular que sigue al puntero. Un punto de acento de 12px actúa como cursor personalizado, fusionado con mix-blend-difference para que siga siendo visible sobre ambas capas.

Cómo funciona

El efecto se apoya en useMotionValue + useSpring de Framer Motion. Las coordenadas del puntero alimentan dos motion values (mouseX/mouseY); el radio del círculo es su propio spring (stiffness 200, damping 28) que se expande de 0 a 180px al entrar y se cierra al salir. useMotionTemplate los ensambla en una cadena clip-path en vivo `circle(${size}px at ${x}px ${y}px)`, de modo que la revelación sigue al cursor con una inercia natural en lugar de saltar de golpe.

Cómo crearlo en React

  1. Apila dos capas a pantalla completa

    Renderiza el mismo contenido dos veces dentro de un contenedor relative con overflow:hidden. La capa inferior usa tu tema oscuro, la superior el claro. Pon cursor:none en el contenedor, dibujarás el tuyo propio.

  2. Rastrea el puntero con motion values

    En mousemove, convierte clientX/Y a coordenadas relativas al contenedor con getBoundingClientRect y escríbelas en los motion values mouseX/mouseY. Mantén un spring separado para el radio para que se abra y se cierre con suavidad.

    const mouseX = useMotionValue(0);
    const size = useSpring(rawSize, { stiffness: 200, damping: 28 });
    const clipPath = useMotionTemplate`circle(${size}px at ${mouseX}px ${mouseY}px)`;
  3. Recorta la capa superior

    Aplica el clipPath animado (y -webkit-clip-path) a la capa clara. Añade una pequeña motion.div posicionada en mouseX/mouseY con mixBlendMode:'difference' como cursor personalizado.

Cuándo usarlo

Úsalo en un hero de landing de marca/producto donde quieras una interacción memorable por encima de la línea de flotación, agencias, herramientas de diseño, productos de IA. Evítalo en páginas densas o críticas para la conversión donde un CTA claro importa más que el efecto, y ofrece un fallback estático en dispositivos táctiles (no hay cursor que seguir).

Usado por

  • Linear, Superficies reactivas al cursor y revelaciones spotlight en todo su sitio de marketing.
  • Vercel, Degradados guiados por el puntero y destacados enmascarados en las secciones hero.
  • Family, Interacciones lúdicas guiadas por el cursor como sello de la marca.

FAQ

¿Funciona la máscara de cursor en móvil?

No, no hay puntero en pantallas táctiles, así que muestra una versión estática de la capa clara u oscura como fallback en móvil y omite los listeners de mousemove.

¿Por qué usar un spring en lugar de una transición CSS?

El spring da peso e inercia a la revelación para que siga al cursor de forma natural; una transición CSS lineal resulta mecánica y se retrasa de manera uniforme sin importar la velocidad.

¿Es accesible?

Ambas capas contienen el mismo texto legible, así que los lectores de pantalla y los usuarios sin JS conservan todo el contenido; la máscara es puramente decorativa y la capa oscura se basta por sí sola.

"use client";

import {
  motion,
  useMotionTemplate,
  useMotionValue,
  useSpring,
} from "framer-motion";
import { ArrowRight } from "lucide-react";
import { useCallback, useRef } from "react";

interface HeroCursorMaskProps {
  badge?: string;
  title?: string;
  titleAccent?: string;
  description?: string;
  ctaLabel?: string;
  ctaUrl?: string;
}

const EASE = [0.16, 1, 0.3, 1] as const;
const CIRCLE_EXPANDED = 180;

Code complet réservé à Pro

Code source intégral, export multi-framework et playground.

Passer en Pro, 9,99€/mois

Reseñas

Hero React revelado al cursor (máscara clip-path), Código +