Advertisement

WebGL Lens Distortion Hover

| by Vladimir | 3 min read | code by Alain
Advanced

Tech & Dependencies

HTML CSS JavaScript
GSAP Curtains.js

Features

  • Lens Distortion
  • RGB Split
  • Custom Shaders

Browser Support

Chrome 60+ Edge 79+ Firefox 55+ Safari 12+

Core

This is a WebGL Lens Distortion Hover. It manipulates a raster image through a custom GLSL fragment shader to create a dynamic, fish-eye bulging effect. Its function is to replace static CSS opacity or scale transitions with a high-fidelity optical illusion, drawing profound tactile focus to portfolio or hero imagery.

Specs

  • Weight: ~120 KB (Dependencies: GSAP, Curtains.js).
  • Performance: GPU-accelerated. The fluid distortion occurs entirely within the shader, bypassing the browser’s layout and paint cycles.
  • Theming / Customization: The image source is easily swappable in the HTML. Distortion intensity and easing curves are hardcoded within the GLSL fragment shader mathematics.
  • Responsiveness: Fluid. Viewport boundaries and canvas resizing are handled by the WebGL wrapper.
  • Web APIs: WebGL API.
  • Graceful Degradation: [!] Poor. The native <img> is set to display: none. If JavaScript or WebGL fails to initialize, the container remains completely empty.

Anatomy

  • HTML: A structural wrapper. It contains a hidden <img> data source, a .plane div to define physical dimensions, and a #canvas container for the WebGL render target. The GLSL vertex and fragment shaders are embedded as inline <script> tags.
  • CSS: Stripped down. It sizes the bounding boxes and layers the absolute canvas over the background.
  • JS: The controller. It initializes the Curtains.js WebGL wrapper, passing the DOM image as a texture. Event listeners on the container trigger GSAP tweens, modulating a single uProgress uniform from 0 to 1.

Logic

The architectural core is the chromatic aberration logic written inside the fragment shader, driven by a single JavaScript variable.

float d = exponentialEasing(length( uv - .5 ), progress) - 1.0 + progress * 0.75; 
vec2 centerInterp = (uv - 0.5) * d;

vec2 r = centerInterp * (progress * 0.6 + 0.4) + uv;
vec2 g = centerInterp * (progress * 0.9 + 0.1) + uv;
vec2 b = centerInterp * (progress * 0.9 + 0.1) + uv;

vec4 color = vec4( texture2D( texture0, r).r , texture2D( texture0, g ).g, texture2D( texture0, b).b , 1.); 

When the mouse enters the element, GSAP tweens uProgress. The shader calculates the pixel’s distance from the center (length(uv - .5)). Instead of sampling the texture once, it calculates three separate offset coordinates (r, g, b) utilizing the exponential easing curve. By shifting the red channel at a slightly different multiplier (0.6) than the green and blue channels (0.9), the shader mathematically splits the spectrum at the edges of the distortion, perfectly mimicking a physical, imperfect glass lens.

Feel

Glassy and optical. The hover effect doesn’t feel like a digital animation; it feels like passing a thick, curved magnifying glass over a photograph. The GSAP easing applied to the uniform gives the liquid bulge a satisfying elasticity, while the RGB split adds a raw, photographic realism to the distortion.

Advertisement