Liquid Glass

Realistic WebGL glass effects for any HTML element

View on GitHub @ybouane
0:00

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt.

Regular Glass
Frosted Glass
Dark Glass
-- FPS

What is Liquid Glass?

Liquid Glass is a lightweight JavaScript/TypeScript library that applies realistic glass refraction, blur, chromatic aberration, and lighting effects to any HTML element using WebGL shaders. It captures the DOM content behind each glass element, processes it through a multi-pass rendering pipeline, and composites the result in real time.

The library handles layered compositing (glass-on-glass), dynamic content updates, draggable floating panels, responsive resizing, and works with any background — images, videos, canvases, or plain HTML.

Getting Started

Install via npm:

npm install liquid-glass

Basic usage:

import { LiquidGlass } from 'liquid-glass';

const instance = await LiquidGlass.init({
    root: document.querySelector('#my-root'),
    glassElements: document.querySelectorAll('.glass'),
});

// Later:
instance.destroy();

The root element must be a positioned container (position: relative) and each glass element must be a direct child of the root. Each glass element gets a child <canvas> injected automatically for the shader output.

Interactive Playground

Adjust the sliders to see how each parameter affects the glass effect in real time. Drag the glass panel to move it around.

Glass

Configuration Options

Each glass element can be configured individually via data-config (JSON) or globally via the defaults option:

OptionTypeDefaultDescription
blurAmountnumber0Background blur strength — softens / frosts the captured background (0–1)
refractionnumber0.69How much the glass bends light
chromAberrationnumber0.05Color fringing at edges
edgeHighlightnumber0.05Inner glow / rim lighting
specularnumber0Specular highlight (Blinn-Phong)
fresnelnumber1Fresnel reflection at grazing angles
cornerRadiusnumber65Corner radius in CSS px
zRadiusnumber40Bevel depth (curvature)
brightnessnumber0Brightness adjustment (-0.5 to 0.5)
saturationnumber0Saturation (-1 to 1)
shadowOpacitynumber0.3Drop shadow opacity
floatingbooleanfalseEnable drag-to-move
buttonbooleanfalseButton mode (hover/press shader feedback)
bevelModenumber00 = biconvex pill, 1 = dome (flat bottom)

Frosted Panel

element.dataset.config = JSON.stringify({
    blurAmount: 0.25,
    cornerRadius: 30,
});
Frosted Glass

Dark Glass

element.dataset.config = JSON.stringify({
    brightness: -0.3,
    blurAmount: 0.25,
    cornerRadius: 50,
});
Dark Glass

Button Mode

Set button: true to make a glass element react to hover and press: hovering brightens it, pressing flattens the bevel and deepens the shadow. Try the button below:

element.dataset.config = JSON.stringify({
    button: true,
    cornerRadius: 24,
});
Click Me

Dome Bevel (Magnifier)

Set bevelMode: 1 with equal cornerRadius and zRadius for a half-sphere lens effect. Try dragging the dome below:

element.dataset.config = JSON.stringify({
    bevelMode: 1,
    cornerRadius: 50,
    zRadius: 50,
    floating: true,
    blurAmount: 0,
    refraction: 1.2,
});
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Limitations & Gotchas

The library leans on real-time DOM rasterisation and a multi-pass WebGL pipeline. That comes with a handful of constraints worth knowing before you wire it into a production page.

Structural

Performance

Text alignment

API

instance.markChanged()

Call markChanged(element) after you update something the library can't observe on its own — a <canvas> you just painted, an <img> you just swapped, a CSS property you just toggled. Only glasses overlapping that element will re-render. Call with no argument to invalidate everything.

instance.markChanged(myCanvasElement); // targeted
instance.markChanged();                // everything