Componente WebGL Hover para Astro: Efectos de Imagen con Rendimiento Optimizado

Componente WebGL Hover para Astro: Efectos de Imagen con Rendimiento Optimizado

astro-webgl-hover es un componente para Astro que permite crear efectos hover con transiciones WebGL entre imágenes. Utiliza Curtains.js y GSAP para lograr animaciones fluidas con efecto displacement, manteniendo el rendimiento optimizado incluso en dispositivos de gama baja.

Este proyecto está basado en una publicación anterior donde exploraba el efecto de distorsión de imágenes con WebGL. Ahora he llevado esa idea más allá, empaquetándola como un componente reutilizable y publicado en npm.

Instalación

Puedes instalar el paquete en tu proyecto ejecutando el siguiente comando:

npm install @ivanalbizu/astro-webgl-hover

¿Cómo crear efectos hover WebGL en Astro?

Con este componente, solo necesitas importar dos elementos y configurar las imágenes. La complejidad de WebGL, shaders y animaciones queda abstraída para que puedas enfocarte en el diseño.

<WebglHoverImages>
  <WebglHoverImage
    texture0="/img-a.jpg"
    texture1="/img-b.jpg"
    map="/displacement.jpg"
    intensity={0.5}
    easeIn="elastic.out(1, 0.3)"
  />
</WebglHoverImages>

Configuración

Props de WebglHoverImages

Configuración global que aplica a todas las imágenes del contenedor:

PropTipoDefaultDescripción
durationInnumber0.8Duración de la animación de entrada (segundos)
durationOutnumber0.8Duración de la animación de salida (segundos)
easeInstring'power2.out'Curva de easing GSAP para entrada
easeOutstring'power2.out'Curva de easing GSAP para salida
displacementAnglenumber0Ángulo del desplazamiento en grados (0-360)
intensitynumber1Intensidad del efecto de distorsión
zoomnumber0Nivel de zoom durante la animación
imageRotationnumber0Rotación de la imagen en grados
noiseSpeednumber0.5Velocidad del ruido animado
noiseScalenumber6.0Escala del patrón de ruido
rgbShiftIntensitynumber0Intensidad de la aberración cromática
debugbooleanfalseActiva el panel de control lil-gui

Props de WebglHoverImage

Configuración individual por imagen (sobrescribe la configuración global):

PropTipoRequeridoDescripción
texture0stringImagen inicial (estado de reposo)
texture1stringImagen final (estado hover)
mapstringMapa de desplazamiento (imagen en blanco/negro)
altstringNoTexto alternativo para accesibilidad
intensitynumberNoSobrescribe intensidad global
zoomnumberNoSobrescribe zoom global
imageRotationnumberNoSobrescribe rotación global
noiseSpeednumberNoSobrescribe velocidad de ruido global
noiseScalenumberNoSobrescribe escala de ruido global
rgbShiftIntensitynumberNoSobrescribe RGB shift global

Aspectos Relevantes del componente

Como maquetador y desarrollador, mi prioridad no fue solo “que se vea bien”, sino “que funcione bien para todos”. Aquí es donde destacan las virtudes técnicas del proyecto:

1. Rendimiento y Accesibilidad (Progressive Enhancement)

Uno de los mayores desafíos de WebGL es el consumo de recursos. He implementado un sistema de detección de rendimiento (en performance.ts) que evalúa el contexto del usuario antes de iniciar WebGL:

  • Detección de Hardware: Analiza la memoria del dispositivo y los núcleos de la CPU para identificar dispositivos de gama baja.
  • Modo Ahorro de Datos: Respeta la configuración del navegador si el usuario ha solicitado ahorrar datos (saveData).
  • Preferencias de Movimiento: Se integra con la media query prefers-reduced-motion.

Si se detecta un entorno limitado, el componente hace un fallback automático a una versión CSS optimizada, garantizando que la web siga siendo funcional y rápida sin bloquear el hilo principal.

export function isLowPerformance(): boolean {
  const nav = navigator as NavigatorWithExtensions;

  // Detect "Data Saver" mode from Browser/OS
  if (nav.connection?.saveData) {
    return true;
  }

  // Hardware Heuristics
  const memory = nav.deviceMemory;  // RAM in GB (Chrome/Edge)
  const cores = navigator.hardwareConcurrency;

  // Less than 4GB RAM or 2 or fewer cores → low-end device
  return (memory !== undefined && memory < 4)
      || (cores !== undefined && cores <= 2);
}

export function shouldUseFallback(): boolean {
  return prefersReducedMotion() || isLowPerformance();
}

2. Experiencia de Desarrollo (DX)

Para facilitar el ajuste fino de las animaciones, incluí un Modo Debug. Al activar debug={true}, se inyecta un panel de control (lil-gui) que permite modificar en tiempo real parámetros como:

  • Intensidad y ángulo del desplazamiento.
  • Escala y velocidad del ruido (noise).
  • Curvas de animación (easing) de GSAP.
  • Efectos de aberración cromática (RGB Shift).

Esto permite a los diseñadores y desarrolladores iterar sobre el aspecto visual directamente en el navegador, sin necesidad de tocar el código constantemente.

3. Abstracción Limpia

El código fuente utiliza TypeScript para garantizar el tipado y la estabilidad. La lógica de WebGL, el redimensionado del canvas y la gestión del ciclo de vida de los componentes están completamente desacoplados de la capa de presentación, siguiendo las mejores prácticas de la arquitectura de componentes en Astro.

Requisitos y Compatibilidad

RequisitoVersión
Astro4.x o superior
Node.js18.x o superior
NavegadoresChrome, Firefox, Safari, Edge (con WebGL)

Dependencias incluidas: Curtains.js, GSAP, lil-gui (solo en modo debug).

El componente detecta automáticamente dispositivos sin soporte WebGL o con bajo rendimiento y aplica un fallback CSS.

Conclusión

Este proyecto refleja mi filosofía de trabajo: la tecnología avanzada debe ser accesible y respetuosa con el usuario. No se trata solo de usar las últimas herramientas, sino de empaquetarlas de forma que aporten valor real sin comprometer la calidad del producto final.

Si quieres probarlo o ver el código fuente: