Noureddine RAMDI / liquidGL: real-time WebGL glassmorphism on DOM elements with offscreen snapshot rendering

Created Sat, 23 May 2026 20:41:14 +0000 Modified Sat, 23 May 2026 20:41:27 +0000

naughtyduk/liquidGL

liquidGL uses an offscreen rendering trick to bypass WebGL’s cross-origin security restrictions: it snapshots the DOM via html2canvas, uploads the raster to a WebGL texture, and applies a refracting shader in real-time — effectively giving any fixed-position element a live ’liquid glass’ lens that can also track video and text animations.

What liquidGL is and how it works

liquidGL is a JavaScript library designed to apply a real-time glassmorphism effect inspired by Apple’s “liquid glass” aesthetic to any fixed-position DOM element. The effect simulates a refractive, frosted glass lens that distorts and highlights the background behind the element.

Under the hood, liquidGL works by first snapshotting the page background using the html2canvas library. This offscreen raster capture converts the visible DOM into a pixel texture that can be used as input for WebGL rendering. By doing so, it circumvents the cross-origin pixel reading restrictions that normally prevent WebGL from directly sampling pixels behind a DOM element.

The snapshot is then passed into a custom WebGL shader program that applies refraction, specular highlights, bevel edges, and optional blur to create the liquid glass effect. The shader simulates light bending and reflection on the surface of the target element, producing a convincing glass-like distortion.

liquidGL supports real-time updates for dynamic page content including video elements and animated text. It auto-detects videos and re-renders the glass effect accordingly. Additionally, it allows registering animated elements such as GSAP SplitText animations for smooth integration.

The library is written in JavaScript and depends on html2canvas and WebGL APIs. It is designed for modern browsers with WebGL support and integrates well with smooth-scroll libraries like Lenis and Locomotive Scroll via a syncWith() helper method.

Technical strengths and design tradeoffs

What sets liquidGL apart is its architectural approach to overcoming WebGL’s cross-origin pixel reading limitation. Normally, WebGL cannot read pixels behind other DOM elements due to security restrictions, which is a major barrier to implementing real-time background refraction effects on arbitrary page elements.

liquidGL’s solution is to avoid reading pixels live from the WebGL framebuffer and instead snapshot the page background offscreen using html2canvas. This snapshot is then uploaded as a texture to WebGL for shader processing. This approach is clever but comes with tradeoffs:

  • Performance: html2canvas snapshots can be expensive, especially at high resolutions or with complex pages. liquidGL mitigates this by allowing configurable snapshot quality (resolution parameter) and selective area capture.

  • Latency: There is a frame delay between snapshot capture and WebGL rendering, which can introduce slight lag or stutter in the refraction effect on highly dynamic content.

  • Complexity: Integrating with animated content (videos, text animations) requires additional bookkeeping and re-render triggers, which the library handles with an API for element registration.

  • Visual fidelity: The effect depends on the snapshot quality and shader parameters like bevel depth, refraction strength, and blur radius. Tuning these values can significantly affect appearance and performance.

The code quality appears solid with a modular approach separating snapshotting, shader rendering, and animation syncing. The shader code implements realistic bevel and specular highlights to enhance the glass effect beyond simple refraction.

The library’s API offers extensive customization options:

const glassEffect = liquidGL({
  snapshot: "body", // area used for refraction
  target: ".liquidGL", // element selector
  resolution: 2.0, // snapshot quality
  refraction: 0.01, // base refraction strength
  bevelDepth: 0.08, // edge bevel intensity
  bevelWidth: 0.15, // bevel width proportion
  frost: 0, // blur radius
  shadow: true, // drop shadow
  // ...more options
});

The ability to sync with smooth-scroll libraries is a nice integration point for modern single-page applications.

Quick start

The README provides a straightforward quickstart to get liquidGL running:

Prerequisites

Add both html2canvas and liquidGL scripts before initializing:

<!-- html2canvas – DOM snapshotter (required) -->
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"
  defer
></script>

<!-- liquidGL.js – the library itself -->
<script src="/scripts/liquidGL.js" defer></script>

Note: liquidGL will throw an error if either dependency is missing.

HTML structure

Set up your target element with a child content element:

<body>
  <!-- Target (glassified) -->
  <div class="liquidGL">
    <!-- Content -->
    <div class="content">
      <img src="/example.svg" alt="Alt Text" />
      <p>This example text content will appear on top of the glass.</p>
    </div>
  </div>
</body>

Make sure the target element has a high z-index so it sits above the page background but below any modal or overlay content you want excluded from the effect.

Initialization

Initialize liquidGL after DOM content loads:

<script>
  document.addEventListener("DOMContentLoaded", () => {
    const glassEffect = liquidGL({
      snapshot: "body", // The area used for refraction, <body> recommended
      target: ".liquidGL", // CSS selector for the element(s) to glass-ify
      resolution: 2.0, // The quality of the snapshot
      refraction: 0.01, // Base refraction strength (0–1)
      bevelDepth: 0.08, // Intensity of the edge bevel (0–1)
      bevelWidth: 0.15, // Width of the bevel as a proportion of the element (0–1)
      frost: 0, // Subtle blur radius in px. 0 = crystal clear
      shadow: true, // Adds a soft drop-shadow
      // Additional options...
    });
  });
</script>

This minimal setup provides a working liquid glass effect that can be further customized.

Verdict

liquidGL is a solid, production-ready library for achieving a real-time WebGL glassmorphism effect on fixed DOM elements. Its core technical strength lies in the offscreen snapshot approach that bypasses WebGL’s cross-origin pixel restrictions, a problem that has limited similar effects in the past.

The tradeoff is clear: you pay in snapshot performance and some latency, but gain a flexible, shader-driven refraction effect that works with videos and animated text. The API is well thought out, with many knobs to tune the aesthetic and integration helpers for scroll syncing.

If your project requires a fancy, dynamic glass effect on top of web content, and you can tolerate the performance implications of html2canvas snapshots, liquidGL is worth considering. It’s particularly relevant for interactive landing pages, portfolios, or UI components where the visual polish matters.

However, for highly dynamic or complex pages where snapshotting overhead is prohibitive, or for non-fixed elements, liquidGL might not be the right fit.

Overall, the code is surprisingly clean and the library is a neat example of how to work around browser security to deliver advanced visual effects with WebGL.


→ GitHub Repo: naughtyduk/liquidGL ⭐ 540 · JavaScript