Uno de los aspectos más importantes al diseñar un producto digital, junto con la accesibilidad, es la experiencia de usuario. Que es básicamente lo que define cómo una persona interactúa con lo que hemos construido.

Y hay algo que suele marcar la diferencia: que la interfaz reaccione. Sentir que lo que haces tiene una respuesta inmediata hace que todo se perciba más vivo y cuidado. Es verdad que no siempre tiene sentido añadir este tipo de interacciones, pero cuando se usan bien en el contexto y momento adecuados, mejoran muchísimo el resultado final.

Uno de los efectos más simples y llamativos es el cursor tracking. Y aunque pueda parecer complejo a primera vista, es súper sencillo de hacer.

ojos que se mueven cuando pasas el ratón, siguiéndolo con la mirada

¿Qué es exactamente el cursor tracking?

El cursor tracking consiste en detectar la posición del cursor y usarla para actualizar la posición de un elemento en pantalla.

A nivel técnico, se resume en tres pasos:

  1. Escuchar el movimiento del mouse (mousemove)
  2. Obtener sus coordenadas (clientX, clientY)
  3. Actualizar el DOM utilizando esos valores para crear la interacción.

Implementación básica del cursor tracking

Ahora vamos a ver cómo podemos implementar un efecto sencillo de cursor tracking. En este caso, vamos a construir una pequeña estela que sigue al cursor de forma fluida utilizando GSAP, ya que nos permite gestionar las animaciones de forma mucho más fácil y rápida que con CSS puro.

Aquí vemos el ejemplo completo en CodePen:

El HTML: preparando los elementos de la estela

Para este efecto, necesitamos varios elementos que formarán la estela. Cada uno de estos divs será una “partícula” que seguirá la posición del cursor con un ligero retraso respecto a la anterior.

<div class="trail"></div>
<div class="trail"></div>
<div class="trail"></div>
<div class="trail"></div>
<div class="trail"></div>
<div class="trail"></div>

El CSS: posicionamiento y estilo

A continuación, les damos un estilo básico para que funcionen como pequeños puntos. Lo más importante aquí es el position: fixed para que se muevan respecto a la ventana y el pointer-events: none para que los círculos no intercepten los clics destinados a otros botones o enlaces de la web.

body {
  height: 200vh;
  background: #111111;
  overflow: hidden;
}

.trail {
  width: 20px;
  height: 20px;
  background: #d9ed92;
  border-radius: 50%;
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
}

Con esto conseguimos que cada elemento sea un círculo fijo que podremos mover libremente por la pantalla.

El JavaScript: animando con GSAP

Aquí es donde entra GSAP para ayudarnos a hacer la animación de forma más fácil. El truco para que no se muevan todos a la vez como un bloque pegado al ratón está en el delay progresivo.

Primero, seleccionamos todos los divs que hemos creado:

const trails = document.querySelectorAll(".trail");

Luego vamos a centrar las partículas al cargar la página. Si no lo hacemos, el efecto empezaría de golpe desde la esquina superior izquierda de la pantalla (0,0) en cuanto movamos el ratón por primera vez. Con gsap.set las posicionamos directamente en el centro:

// Center the particles on load to avoid the default (0,0) position
const centerX = window.innerWidth / 2;
const centerY = window.innerHeight / 2;

trails.forEach((el) => {
  gsap.set(el, {
    x: centerX,
    y: centerY
  });
});

Es importante decir que esto no es imprescindible. Hay muchas formas de enfocarlo. Por ejemplo, podrías ocultar las partículas con opacidad cero y hacer que aparezcan solo cuando el usuario mueva el ratón. Pero en nuestro ejemplo, como no hay nada más en la pantalla, tiene más sentido que los elementos estén colocados y listos para reaccionar desde el centro.

Por último, añadimos un event listener que detectará el movimiento del ratón. En cada movimiento, lanzaremos una animación de GSAP para cada partícula:

// Cursor tracking with staggered delay to create a smooth trailing effect
window.addEventListener("mousemove", (e) => {
  trails.forEach((el, index) => {
    gsap.to(el, {
      x: e.clientX,
      y: e.clientY,
      duration: 0.2 + index * 0.05, // We use the index so each particle is slightly slower than the previous one
      ease: "power2.out"
    });
  });
});

Al usar el index del array para calcular la duración, conseguimos que la primera partícula sea casi instantánea y las siguientes vayan con un pequeño retraso. El resultado es esa sensación de movimiento orgánico que hace que el efecto sea mucho más visual.

Importante: para que este ejemplo funcione correctamente, necesitamos incluir GSAP en nuestro proyecto. Podemos hacerlo añadiendo el siguiente script:

<script src="https://cdn.jsdelivr.net/npm/gsap@3.15/dist/gsap.min.js"></script>

Cursor tracking avanzado: creando unos ojos que te siguen

Ya hemos visto cómo hacer que algo siga al cursor, pero el cursor tracking no siempre tiene por qué ser un desplazamiento total por la pantalla. Podemos usar esa misma lógica de coordenadas para crear interacciones más sutiles y divertidas, como unos ojos que sigan el movimiento del ratón.

En este caso, en lugar de mover los elementos, vamos a calcular el ángulo y la distancia para que las pupilas se muevan siempre dentro del ojo.

Puedes ver el resultado en Codepen.

El HTML: estructura de los ojos

Para que esto funcione, necesitamos un contenedor para cada ojo y un elemento interno para la pupila.

<div class="eyes-container">
  <div class="eye">
    <div class="pupil"></div>
  </div>
  <div class="eye">
    <div class="pupil"></div>
  </div>
</div>

El CSS: delimitando el movimiento

El truco aquí es que el contenedor .eye tenga un overflow: hidden. Esto nos asegura que, aunque nos pasemos con los cálculos, la pupila nunca se saldrá de la parte blanca del ojo (o si llegase a sobrepasar su contenedor, con esto, no lo veremos).

body {
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100dvh;
  background-color: #f5f5f5;
  overflow: hidden;
}

.eyes-container {
  display: flex;
  gap: 20px;
}

.eye {
  width: 100px;
  height: 100px;
  background-color: white;
  border: 4px solid #1a1a1a;
  border-radius: 50%;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

.pupil {
  width: 40px;
  height: 40px;
  background-color: #1a1a1a;
  border-radius: 50%;
  position: absolute;
}

El JavaScript: un poco de trigonometría y GSAP

Aquí la cosa se pone interesante. Para que los ojos miren hacia donde está el ratón, necesitamos saber el ángulo entre el centro del ojo y el cursor.

Primero, seleccionamos las pupilas que es lo que vamos a mover:

const pupils = document.querySelectorAll(".pupil");

Y ahora calculamos el movimiento. Math.atan2 nos da el ángulo y Math.cos / Math.sin nos dice cuánto desplazar la pupila en los ejes X e Y para que mire en esa dirección:

window.addEventListener("mousemove", (e) => {
  pupils.forEach((pupil) => {


    // Get the parent eye element and its center position
    const eye = pupil.parentElement;
    const rect = eye.getBoundingClientRect();
    const eyeCenterX = rect.left + rect.width / 2;
    const eyeCenterY = rect.top + rect.height / 2;

    // Calculate the angle between the mouse and the eye center
    const angle = Math.atan2(
      e.clientY - eyeCenterY,
      e.clientX - eyeCenterX
    );

    // Define the maximum movement radius for the pupil
    const maxDistance = 25;

    // Measure mouse distance from the eye center and clamp it
    const mouseDistance = Math.hypot(
      e.clientX - eyeCenterX,
      e.clientY - eyeCenterY
    );

    const distance = Math.min(mouseDistance / 10, maxDistance);

    // Calculate pupil offset based on angle and clamped distance
    const moveX = Math.cos(angle) * distance;
    const moveY = Math.sin(angle) * distance;

    // Animate the pupil for a smooth
    gsap.to(pupil, {
      x: moveX,
      y: moveY,
      duration: 0.4,
      ease: "power2.out",
      overwrite: "auto"
    });
  });
});

Importante: al igual que en ejemplo anterior, para que este ejemplo funcione correctamente, necesitamos incluir GSAP en nuestro proyecto. Podemos hacerlo añadiendo el siguiente script:

<script src="https://cdn.jsdelivr.net/npm/gsap@3.15/dist/gsap.min.js"></script>

Como has podido ver, una vez que entiendes cómo capturar las coordenadas del ratón, las posibilidades son casi infinitas (y digo “casi” porque siempre habrá alguna cosa un poco imposible). Pero, con esta base, podemos pasar de una simple estela a una animación más compleja con apenas unos cambios en la lógica del JavaScript.

Y lo mejor de usar GSAP para estos efectos es que nos quita de encima el trabajo pesado de gestionar los frames y los suavizados, permitiéndonos centrar la atención en lo que realmente importa: que la interacción se sienta natural y aporte valor a la experiencia de usuario.

Espero que este post te haya gustado y haya podido ayudarte (aunque sea un poquito) a entender mejor cómo funciona GSAP y puedas hacer tus propias animaciones. ¡A experimentar!

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete