### Global Navigation Setup
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-1.html
Sets up a responsive navigation menu with toggle, click-outside, and escape key functionalities. This code handles the user interaction for opening and closing the navigation.
```javascript
const navToggle = document.querySelector(".nav-toggle");
const navContainer = document.querySelector(".nav-container");
if (navToggle && navContainer) {
navToggle.addEventListener("click", () => {
const isExpanded = navContainer.classList.contains("expanded");
navContainer.classList.toggle("expanded");
navToggle.setAttribute("aria-expanded", !isExpanded);
});
// Close navigation when clicking outside
document.addEventListener("click", (e) => {
if (!navContainer.contains(e.target)) {
navContainer.classList.remove("expanded");
navToggle.setAttribute("aria-expanded", "false");
}
});
// Close navigation when pressing Escape
document.addEventListener("keydown", (e) => {
if (
e.key === "Escape" &&
navContainer.classList.contains("expanded")
) {
navContainer.classList.remove("expanded");
navToggle.setAttribute("aria-expanded", "false");
}
});
}
```
--------------------------------
### Initialize liquidGL and Setup Navigation
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-4.html
Sets up global navigation toggles and initializes the liquidGL effect on specified elements. It also includes event listeners for closing the navigation via clicks outside or the Escape key.
```javascript
document.addEventListener("DOMContentLoaded", () => { /* Global Navigation Setup */ const navToggle = document.querySelector(".nav-toggle"); const navContainer = document.querySelector(".nav-container"); if (navToggle && navContainer) { navToggle.addEventListener("click", () => { const isExpanded = navContainer.classList.contains("expanded"); navContainer.classList.toggle("expanded"); navToggle.setAttribute("aria-expanded", !isExpanded); }); // Close navigation when clicking outside document.addEventListener("click", (e) => { if (!navContainer.contains(e.target)) { navContainer.classList.remove("expanded"); navToggle.setAttribute("aria-expanded", "false"); } }); // Close navigation when pressing Escape document.addEventListener("keydown", (e) => { if ( e.key === "Escape" && navContainer.classList.contains("expanded") ) { navContainer.classList.remove("expanded"); navToggle.setAttribute("aria-expanded", "false"); } }); } // Initialize the liquidGL effect window.glassEffect = liquidGL({ target: ".marquee-card", refraction: 0, bevelDepth: 0.052, bevelWidth: 0.18, frost: 2, shadow: true, specular: true, tilt: false, tiltFactor: 5, reveal: "fade", }); // Build GUI once effect is ready (multi build may return array) const lensList = Array.isArray(window.glassEffect) ? window.glassEffect : [window.glassEffect]; const firstLens = lensList[0]; if (firstLens) { const gui = new lil.GUI(); const glassFolder = gui.addFolder("liquidGL Effect"); const updateAll = (key, value) => { lensList.forEach((ln) => { if (!ln) return; ln.options[key] = value; if (key === "shadow") ln.setShadow(value); if (key === "tilt") ln.setTilt(value); }); }; glassFolder .add(firstLens.options, "refraction", 0, 0.1, 0.001) .onChange((v) => updateAll("refraction", v)); glassFolder .add(firstLens.options, "bevelDepth", 0, 0.2, 0.001) .onChange((v) => updateAll("bevelDepth", v)); glassFolder .add(firstLens.options, "bevelWidth", 0, 0.5, 0.001) .onChange((v) => updateAll("bevelWidth", v)); glassFolder .add(firstLens.options, "frost", 0, 10, 0.1) .onChange((v) => updateAll("frost", v)); glassFolder .add(firstLens.options, "magnify", 1, 5, 0.1) .onChange((v) => updateAll("magnify", v)); glassFolder .add(firstLens.options, "shadow") .onChange((v) => updateAll("shadow", v)); glassFolder .add(firstLens.options, "specular") .onChange((v) => updateAll("specular", v)); glassFolder .add(firstLens.options, "tilt") .onChange((v) => updateAll("tilt", v)); glassFolder .add(firstLens.options, "tiltFactor", 0, 25, 0.1) .onChange((v) => updateAll("tiltFactor", v)); glassFolder .add(firstLens.options, "reveal", ["none", "fade"]) .onChange((v) => updateAll("reveal", v)); glassFolder.close(); } });
```
--------------------------------
### Initialize LiquidGL with Options
Source: https://github.com/naughtyduk/liquidgl/blob/main/README.md
Initialize the library by providing a CSS selector for the target element and configuring various visual and functional parameters. The 'init' callback is ideal for post-snapshot setup.
```javascript
document.addEventListener("DOMContentLoaded", () => {
const glassEffect = liquidGL({
snapshot: "body", // The area used for refraction,
recommended and default
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 under the pane
specular: true, // Animated light highlights (slightly more GPU)
reveal: "fade", // Reveal animation
tilt: false, // Whether tilt on hover is enabled
tiltFactor: 5, // If tilt is enabled, how much tilt
magnify: 1, // Magnification of lens content
on: {
init(instance) {
// The `init` callback fires once liquidGL has taken its snapshot
// and rendered the first frame. It's the ideal place to hide or
// prepare elements for reveal animations (e.g. with GSAP, ScrollTrigger)
// because it ensures the content is visible to the snapshot before
// you hide it from the user.
console.log("liquidGL ready!", instance);
},
},
});
});
```
--------------------------------
### Initialize LiquidGL with GSAP Animations
Source: https://github.com/naughtyduk/liquidgl/blob/main/index.html
This snippet shows the recommended setup for LiquidGL, including GSAP SplitText registration, preloader animation, and LiquidGL initialization with dynamic element registration. It handles responsive refraction and includes an on.init callback for further animations.
```javascript
/* OPTIONAL - Register GSAP SplitText */
gs.registerPlugin(SplitText);
/* OPTIONAL - glassEffect variable declared globally so it can be accessed by the custom controls */
let glassEffect;
/* RECOMMENDED - DOMContentLoaded Event */
document.addEventListener("DOMContentLoaded", () => {
/* Global Navigation Setup */
const navToggle = document.querySelector('.nav-toggle');
const navContainer = document.querySelector('.nav-container');
if (navToggle && navContainer) {
navToggle.addEventListener('click', () => {
const isExpanded = navContainer.classList.contains('expanded');
navContainer.classList.toggle('expanded');
navToggle.setAttribute('aria-expanded', !isExpanded);
});
// Close navigation when clicking outside
document.addEventListener('click', (e) => {
if (!navContainer.contains(e.target)) {
navContainer.classList.remove('expanded');
navToggle.setAttribute('aria-expanded', 'false');
}
});
// Close navigation when pressing Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && navContainer.classList.contains('expanded')) {
navContainer.classList.remove('expanded');
navToggle.setAttribute('aria-expanded', 'false');
}
});
}
/* OPTIONAL - Preloader */
const preloader = document.querySelector(".preloader");
const preloaderProgress = document.querySelector(".preloader-progress");
let progress = { value: 0 };
const loadingTl = gsap.timeline();
loadingTl.to(progress, {
value: 100,
duration: 1.5,
ease: "power1.inOut",
onUpdate: () => {
gsap.set(preloaderProgress, { width: `${progress.value}%` });
},
});
/* RECOMMENDED - Wait for fonts to be loaded */
const fontsReady = document.fonts && document.fonts.ready ? document.fonts.ready : Promise.resolve();
fontsReady.then(() => {
/* 1. OPTIONAL - PREPARE ANIMATIONS BEFORE INITIALISING LIQUIDGL */
gsap.set(".split", { visibility: "visible" });
const allSplitLines = [];
gsap.utils.toArray(".split").forEach((splitEl) => {
const split = SplitText.create(splitEl, {
type: "lines",
linesClass: "line",
mask: "lines",
});
gsap.from(split.lines, {
scrollTrigger: {
trigger: splitEl,
start: "top 50%",
toggleActions: "play none none reverse",
},
duration: 1.2,
yPercent: 180,
stagger: 0.1,
ease: "expo.out",
});
allSplitLines.push(...split.lines);
});
/* 2. REQUIRED - INITIALISE LIQUIDGL */
/* Responsive refraction value */
const getRefractionValue = () => {
return window.innerWidth <= 767 ? 0.011 : 0.026;
};
glassEffect = liquidGL({
target: ".liquidGL",
snapshot: "body",
resolution: 2,
refraction: getRefractionValue(),
bevelDepth: 0.119,
bevelWidth: 0.057,
frost: 0,
specular: true,
shadow: true,
reveal: "fade",
tilt: false,
tiltFactor: 10,
magnify: 1,
on: {
init: function (intro) {
/* OPTIONAL - GSAP ANIMATION OF TARGET ELEMENT */
/* You can animate the target element to create a more dynamic effect, or use the on.init callback to run any code after liquidGL is initialised. */
/* Preloader Animation */
loadingTl.then(() => {
gsap.to(preloader, {
yPercent: -100,
duration: 1,
ease: "expo.inOut",
onComplete: () => {
preloader.style.display = "none";
},
});
/* Target Animation */
gsap.to(intro.el, {
scaleX: 1,
duration: 1.2,
ease: "expo.out",
delay: 0.5,
});
});
},
},
});
/* Handle responsive refraction on window resize */
window.addEventListener('resize', () => {
const newRefraction = getRefractionValue();
if (glassEffect && glassEffect.options) {
glassEffect.options.refraction = newRefraction;
}
});
/* 3. REQUIRED FOR DYNAMIC ELEMENTS - REGISTER DYNAMIC ELEMENTS */
/* You need to register any elements that intersect the target which you want to be refracted. For example animated content, text, etc. You do not need to register videos, they are automatically registered. */
liquidGL.registerDynamic(allSplitL
```
--------------------------------
### Initialize and Register LiquidGL Elements
Source: https://github.com/naughtyduk/liquidgl/blob/main/index.html
Initializes LiquidGL and registers a dynamic element for effects. This is a common setup step for applying LiquidGL to specific HTML elements.
```javascript
lines); liquidGL.registerDynamic(".banner-text-container"); console.log("liquidGL ready!", glassEffect);
```
--------------------------------
### Setup lil-gui Controls for LiquidGL
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-5.html
Configures lil-gui to control LiquidGL effect properties. It synchronizes changes across all LiquidGL instances if multiple are present. Ensure lil-gui is loaded.
```javascript
const lensArr = Array.isArray(glassEffect) ? glassEffect : [glassEffect];
const first = lensArr[0];
if (first) {
const gui = new lil.GUI();
const folder = gui.addFolder("liquidGL Effect");
const sync = (k, v) => {
lensArr.forEach((ln) => {
if (!ln) return;
ln.options[k] = v;
if (k === "shadow") ln.setShadow(v);
if (k === "tilt") ln.setTilt(v);
});
};
folder
.add(first.options, "refraction", 0, 0.1, 0.001)
.onChange((v) => sync("refraction", v));
folder
.add(first.options, "bevelDepth", 0, 0.2, 0.001)
.onChange((v) => sync("bevelDepth", v));
folder
.add(first.options, "bevelWidth", 0, 0.5, 0.001)
.onChange((v) => sync("bevelWidth", v));
folder
.add(first.options, "frost", 0, 10, 0.1)
.onChange((v) => sync("frost", v));
folder
.add(first.options, "magnify", 1, 5, 0.1)
.onChange((v) => sync("magnify", v));
folder
.add(first.options, "shadow")
.onChange((v) => sync("shadow", v));
folder
.add(first.options, "specular")
.onChange((v) => sync("specular", v));
folder.add(first.options, "tilt").onChange((v) => sync("tilt", v));
folder
.add(first.options, "tiltFactor", 0, 25, 0.1)
.onChange((v) => sync("tiltFactor", v));
folder
.add(first.options, "reveal", ["none", "fade"])
.onChange((v) => sync("reveal", v));
folder.close();
}
```
--------------------------------
### Initialize liquidGL Glass Effect
Source: https://context7.com/naughtyduk/liquidgl/llms.txt
Use this snippet to initialize the liquidGL effect on specified target elements. Ensure dependencies are loaded first and the target element has a sufficient z-index. The `on.init` callback is a good place to start animations after the effect is ready.
```html
Hello from inside the glass
```
--------------------------------
### Custom Video Player Controls with GSAP
Source: https://github.com/naughtyduk/liquidgl/blob/main/index.html
Implements a custom video player with interactive controls, including play/pause, progress bar, and fullscreen functionality, using GSAP for animations. This example shows how to manage video playback and UI interactions.
```javascript
document.addEventListener("DOMContentLoaded", () => {
const videoTrigger = document.querySelector(".video-hover-area");
const playIcon = document.querySelector(".play-icon");
const fullscreenPlayer = document.querySelector(".fullscreen-player");
const fullscreenVideo = fullscreenPlayer.querySelector("video");
const closeBtn = document.querySelector(".close-btn");
const customControls = document.querySelector(".custom-controls");
const playPauseBtn = document.querySelector(".play-pause-btn");
const progressBarContainer = document.querySelector(
".progress-bar-container"
);
const progressBarFill = document.querySelector(".progress-bar-fill");
if (!videoTrigger) return;
videoTrigger.style.cursor = "pointer";
gsap.set(playIcon, {
scale: 0,
autoAlpha: 0,
xPercent: -50,
yPercent: -50,
});
gsap.set(fullscreenPlayer, {
xPercent: -100,
visibility: "hidden",
});
let inactivityTimer;
const hideControls = () => {
if (!fullscreenVideo.paused) {
fullscreenPlayer.classList.add("inactive");
}
};
const resetInactivityTimer = () => {
fullscreenPlayer.classList.remove("inactive");
clearTimeout(inactivityTimer);
inactivityTimer = setTimeout(hideControls, 3000);
};
fullscreenPlayer.addEventListener("mousemove", resetInactivityTimer);
fullscreenPlayer.addEventListener("touchstart", resetInactivityTimer);
const togglePlayPause = () => {
if (fullscreenVideo.paused) {
fullscreenVideo.play();
playPauseBtn.classList.add("playing");
playPauseBtn.setAttribute("aria-label", "Pause video");
resetInactivityTimer();
} else {
fullscreenVideo.pause();
playPauseBtn.classList.remove("playing");
playPauseBtn.setAttribute("aria-label", "Play video");
clearTimeout(inactivityTimer);
}
};
playPauseBtn.addEventListener("click", togglePlayPause);
fullscreenVideo.addEventListener("click", (e) => {
e.stopPropagation();
if (e.target === fullscreenVideo) {
togglePlayPause();
}
});
fullscreenVideo.addEventListener("timeupdate", () => {
const progress = (fullscreenVideo.currentTime / fullscreenVideo.duration) * 100;
gsap.to(progressBarFill, {
width: `${progress}%`,
duration: 0.1,
ease: "linear",
});
});
progressBarContainer.addEventListener("click", (e) => {
const rect = progressBarContainer.getBoundingClientRect();
const clickX = e.clientX - rect.left;
const width = rect.width;
const newTime = (clickX / width) * fullscreenVideo.duration;
fullscreenVideo.currentTime = newTime;
});
fullscreenVideo.addEventListener("ended", () => {
playPauseBtn.classList.remove("playing");
playPauseBtn.setAttribute("aria-label", "Play video");
fullscreenPlayer.classList.remove("inactive");
clearTimeout(inactivityTimer);
});
videoTrigger.addEventListener("mouseenter", (e) => {
gsap.set(playIcon, { x: e.clientX, y: e.clientY });
gsap.to(playIcon, { autoAlpha: 1, scale: 1, duration: 0.3 });
});
videoTrigger.addEventListener("mouseleave", () => {
gsap.to(playIcon, { autoAlpha: 0, scale: 0, duration: 0.3 });
});
videoTrigger.addEventListener("mousemove", (e) => {
gsap.to(playIcon, {
x: e.clientX,
y: e.clientY,
duration: 0.4,
ease: "power3.out",
});
});
videoTrigger.addEventListener("click", () => {
gsap.to(fullscreenPlayer, {
xPercent: 0,
visibility: "visible",
duration: 0.8,
ease: "expo.inOut",
onComplete: () => {
fullscreenVideo.play();
playPauseBtn.classLi
},
});
});
});
```
--------------------------------
### Configure LiquidGL Effect Properties via GUI
Source: https://github.com/naughtyduk/liquidgl/blob/main/index.html
Demonstrates how to dynamically control LiquidGL effect properties (refraction, bevel, frost, magnify, shadow, specular, tilt, reveal) using a GUI. This is useful for interactive demos and fine-tuning effects.
```javascript
const lensArr = Array.isArray(glassEffect) ? glassEffect : [glassEffect];
const first = lensArr[0];
if (first) {
const gui = new lil.GUI();
const folder = gui.addFolder("liquidGL Effect");
const sync = (key, value) => {
lensArr.forEach((ln) => {
if (!ln) return;
ln.options[key] = value;
if (key === "shadow") ln.setShadow(value);
if (key === "tilt") ln.setTilt(value);
});
};
folder
.add(first.options, "refraction", 0, 0.1, 0.001)
.onChange((v) => sync("refraction", v));
folder
.add(first.options, "bevelDepth", 0, 0.2, 0.001)
.onChange((v) => sync("bevelDepth", v));
folder
.add(first.options, "bevelWidth", 0, 0.5, 0.001)
.onChange((v) => sync("bevelWidth", v));
folder
.add(first.options, "frost", 0, 10, 0.1)
.onChange((v) => sync("frost", v));
folder
.add(first.options, "magnify", 1, 5, 0.1)
.onChange((v) => sync("magnify", v));
folder
.add(first.options, "shadow")
.onChange((v) => sync("shadow", v));
folder
.add(first.options, "specular")
.onChange((v) => sync("specular", v));
folder
.add(first.options, "tilt")
.onChange((v) => sync("tilt", v));
folder
.add(first.options, "tiltFactor", 0, 25, 0.1)
.onChange((v) => sync("tiltFactor", v));
folder
.add(first.options, "reveal", ["none", "fade"])
.onChange((v) => sync("reveal", v));
folder.close();
}
```
--------------------------------
### liquidGL(options)
Source: https://context7.com/naughtyduk/liquidgl/llms.txt
Initializes the liquid glass effect on specified target elements. It returns a liquidGLLens instance for a single target or an array of instances for multiple targets. The WebGL renderer is created on the first call and reused.
```APIDOC
## liquidGL(options) — Initialize the glass effect
Creates one or more glass lens instances on the elements matched by `target`. Returns a single `liquidGLLens` instance when exactly one element is matched, or an array of instances when multiple elements match. The shared WebGL renderer is created on the first call and reused by all subsequent calls.
### Parameters
#### Options Object
- **target** (string) - Required - CSS selector for the lens element(s).
- **snapshot** (string) - Optional - Area to snapshot for rendering. Use a more specific selector like ".main-content" for performance gains.
- **resolution** (number) - Optional - Snapshot quality, ranging from 0.1 to 3.0. Higher values result in sharper images but consume more memory.
- **refraction** (number) - Optional - Distortion strength across the pane, ranging from 0 to 1.
- **bevelDepth** (number) - Optional - Extra refraction on the rim to simulate depth, ranging from 0 to 1.
- **bevelWidth** (number) - Optional - Width of the bevel zone as a fraction of the shortest side, ranging from 0 to 1.
- **frost** (number) - Optional - Frosted blur radius in pixels. A value of 0 results in a crystal clear effect.
- **shadow** (boolean) - Optional - If true, a soft drop-shadow is applied beneath the pane.
- **specular** (boolean) - Optional - If true, enables animated specular highlights, which may slightly increase GPU usage.
- **reveal** (string) - Optional - Animation effect for revealing the lens. Accepts "fade" or "none".
- **tilt** (boolean) - Optional - If true, enables a 3-D tilt effect on cursor hover.
- **tiltFactor** (number) - Optional - Depth of the 3-D tilt in degrees, ranging from 0 to 25.
- **magnify** (number) - Optional - Lens magnification factor, ranging from 0.001 to 3.0.
- **on** (object) - Optional - An object containing event callbacks.
- **init** (function) - Callback function that fires once after the first snapshot is rendered. Safe to start animations like GSAP reveals here. Receives the `instance` as an argument.
### Request Example
```javascript
document.addEventListener("DOMContentLoaded", () => {
const glassEffect = liquidGL({
target: ".glass-pane",
snapshot: "body",
resolution: 2.0,
refraction: 0.026,
bevelDepth: 0.119,
bevelWidth: 0.057,
frost: 0,
shadow: true,
specular: true,
reveal: "fade",
tilt: false,
tiltFactor: 10,
magnify: 1,
on: {
init(instance) {
console.log("liquidGL ready", instance);
gsap.to(instance.el, { scaleX: 1, duration: 1.2, ease: "expo.out" });
}
}
});
});
```
### Response
- **liquidGLLens** (object) - Returns a single instance for one target, or an array of instances for multiple targets.
```
--------------------------------
### Lenis and GSAP ScrollTrigger Integration
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-2.html
Integrates Lenis smooth scrolling with GSAP ScrollTrigger. This setup allows for custom wheel event handling to ensure Lenis captures scroll events correctly, especially when not originating directly from the scrollable element.
```javascript
window.addEventListener("load", function () {
const lenis = new Lenis({
wrapper: document.querySelector("#left-col"),
});
const leftCol = document.querySelector("#left-col");
document.addEventListener(
"wheel",
(e) => {
if (!leftCol) return;
if (!e.target.closest("#left-col")) {
const simulated = new WheelEvent("wheel", {
deltaX: e.deltaX,
deltaY: e.deltaY,
deltaMode: e.deltaMode,
clientX: e.clientX,
clientY: e.clientY,
bubbles: true,
cancelable: true,
});
leftCol.dispatchEvent(simulated);
e.preventDefault();
}
},
{ passive: false }
);
liquidGL.syncWith({ lenis: lenis });
});
```
--------------------------------
### LiquidGL Presets
Source: https://github.com/naughtyduk/liquidgl/blob/main/README.md
Predefined configurations for common LiquidGL effects.
```APIDOC
## Presets
Below are some ready-made configurations you can copy-paste. Feel free to tweak values to suit your design.
| Name | Settings | Purpose |
| ----------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------- |
| **Default** | `{ refraction: 0, bevelDepth: 0.052, bevelWidth: 0.211, frost: 2, shadow: true, specular: true }` | Balanced default used in the demo. |
| **Alien** | `{ refraction: 0.073, bevelDepth: 0.2, bevelWidth: 0.156, frost: 2, shadow: true, specular: false }` | Strong refraction & deep bevel for a sci-fi look. |
| **Pulse** | `{ refraction: 0.03, bevelDepth: 0, bevelWidth: 0.273, frost: 0, shadow: false, specular: false }` | Flat pane with wide bevel—great for pulsing UI effects. |
| **Frost** | `{ refraction: 0, bevelDepth: 0.035, bevelWidth: 0.119, frost: 0.9, shadow: true, specular: true }` | Softly diffused, privacy-glass style. |
| **Edge** | `{ refraction: 0.047, bevelDepth: 0.136, bevelWidth: 0.076, frost: 2, shadow: true, specular: false }` | Thin bevel and bright rim highlights. |
```
--------------------------------
### Initialize Liquid Glass Effect and GUI Controls
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-3.html
Initializes the Liquid Glass effect on a target element and sets up a GUI using lil-gui to control various effect parameters like refraction, bevel, frost, and shadow. This is useful for creating interactive visual effects.
```javascript
let glassEffect;
let gui, glassFolder;
document.addEventListener("DOMContentLoaded", () => {
// ... other code ...
initializeliquidGL(); // Call immediately on DOM ready
// ... other code ...
});
function initializeliquidGL() {
// Initialize the Liquid Glass effect on our menu
glassEffect = liquidGL({
target: ".morph",
refraction: 0,
bevelDepth: 0.052,
bevelWidth: 0.211,
frost: 7,
shadow: false,
specular: true,
tilt: false,
tiltFactor: 5,
reveal: "fade",
});
const lensList = Array.isArray(glassEffect) ? glassEffect : [glassEffect];
const firstLens = lensList[0];
if (firstLens) {
gui = new lil.GUI();
glassFolder = gui.addFolder("liquidGL Effect");
const updateAll = (key, value) => {
lensList.forEach((ln) => {
if (!ln) return;
ln.options[key] = value;
if (key === "shadow") ln.setShadow(value);
if (key === "tilt") ln.setTilt(value);
});
};
glassFolder
.add(firstLens.options, "refraction", 0, 0.1, 0.001)
.onChange((v) => updateAll("refraction", v));
glassFolder
.add(firstLens.options, "bevelDepth", 0, 0.2, 0.001)
.onChange((v) => updateAll("bevelDepth", v));
glassFolder
.add(firstLens.options, "bevelWidth", 0, 0.5, 0.001)
.onChange((v) => updateAll("bevelWidth", v));
glassFolder
.add(firstLens.options, "frost", 0, 10, 0.1)
.onChange((v) => updateAll("frost", v));
glassFolder
.add(firstLens.options, "magnify", 1, 5, 0.1)
.onChange((v) => updateAll("magnify", v));
glassFolder.add(firstLens.options, "shadow").onChange((v) => updateAll("shadow", v));
glassFolder.add(firstLens.options, "specular").onChange((v) => updateAll("specular", v));
glassFolder.add(firstLens.options, "tilt").onChange((v) => updateAll("tilt", v));
glassFolder
.add(firstLens.options, "tiltFactor", 0, 25, 0.1)
.onChange((v) => updateAll("tiltFactor", v));
glassFolder
.add(firstLens.options, "reveal", ["none", "fade"])
.onChange((v) => updateAll("reveal", v));
glassFolder.close();
}
}
```
--------------------------------
### Initialize LiquidGL Glass Effect
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-2.html
Initializes the LiquidGL glass effect with various customizable options. This function should be called after the DOM is ready. It also sets up a GUI for real-time parameter adjustments.
```javascript
let glassEffect;
document.addEventListener("DOMContentLoaded", () => {
initializeliquidGL();
});
function initializeliquidGL() {
let gui, glassFolder;
glassEffect = liquidGL({
snapshot: ".main-content",
target: ".credit-card-glass",
refraction: 0,
bevelDepth: 0.1,
bevelWidth: 0.17,
frost: 2,
shadow: true,
specular: true,
reveal: "fade",
tilt: true,
tiltFactor: 25,
});
if (glassEffect) {
const lensList = Array.isArray(glassEffect) ? glassEffect : [glassEffect];
const firstLens = lensList[0];
if (firstLens) {
gui = new lil.GUI();
glassFolder = gui.addFolder("liquidGL Effect");
const updateAll = (key, value) => {
lensList.forEach((ln) => {
if (!ln) return;
ln.options[key] = value;
if (key === "shadow") ln.setShadow(value);
if (key === "tilt") ln.setTilt(value);
});
};
glassFolder
.add(firstLens.options, "refraction", 0, 0.1, 0.001)
.onChange((v) => updateAll("refraction", v));
glassFolder
.add(firstLens.options, "bevelDepth", 0, 0.2, 0.001)
.onChange((v) => updateAll("bevelDepth", v));
glassFolder
.add(firstLens.options, "bevelWidth", 0, 0.5, 0.001)
.onChange((v) => updateAll("bevelWidth", v));
glassFolder
.add(firstLens.options, "frost", 0, 10, 0.1)
.onChange((v) => updateAll("frost", v));
glassFolder
.add(firstLens.options, "magnify", 1, 5, 0.1)
.onChange((v) => updateAll("magnify", v));
glassFolder.add(firstLens.options, "shadow").onChange((v) => updateAll("shadow", v));
glassFolder.add(firstLens.options, "specular").onChange((v) => updateAll("specular", v));
glassFolder.add(firstLens.options, "tilt").onChange((v) => updateAll("tilt", v));
glassFolder
.add(firstLens.options, "tiltFactor", 0, 25, 0.1)
.onChange((v) => updateAll("tiltFactor", v));
glassFolder
.add(firstLens.options, "reveal", ["none", "fade"])
.onChange((v) => updateAll("reveal", v));
glassFolder.close();
}
}
}
```
--------------------------------
### Initialize LiquidGL Effect
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-5.html
Initializes the LiquidGL effect on a target element with specified parameters. Ensure the target and snapshot elements exist.
```javascript
glassEffect = liquidGL({
target: ".shape",
snapshot: ".main-content",
refraction: 0.026,
bevelDepth: 0.119,
bevelWidth: 0.057,
frost: 0,
specular: true,
shadow: true,
reveal: "fade",
});
```
--------------------------------
### LiquidGL Parameters
Source: https://github.com/naughtyduk/liquidgl/blob/main/README.md
Configuration options available for the LiquidGL library to customize the glass effect.
```APIDOC
## Parameters
| Option | Type | Default | Description |
| ------------ | -------- | ------------- | ------------------------------------------------------------------------------------------------ |
| `target` | string | `'.liquidGL'` | **Required.** CSS selector for the element(s) to glassify. |
| `snapshot` | string | `'body'` | CSS selector for the element to snapshot. |
| `resolution` | number | `2.0` | Resolution of the background snapshot (clamped 0.1–3.0). Higher is sharper but uses more memory. |
| `refraction` | number | `0.01` | Base refraction offset applied across the pane (0–1). |
| `bevelDepth` | number | `0.08` | Additional refraction on the edge to simulate depth (0–1). |
| `bevelWidth` | number | `0.15` | Width of the bevel zone as a fraction of the shortest side (0–1). |
| `frost` | number | `0` | Blur radius in pixels for a frosted look. `0` is clear. |
| `shadow` | boolean | `true` | Toggles a subtle drop-shadow under the pane. |
| `specular` | boolean | `true` | Enables animated specular highlights that move with time. |
| `reveal` | string | `'fade'` | Reveal animation.
- `'none'`: Renders immediately.
- `'fade'`: Smoothly fades in. |
| `tilt` | boolean | `false` | Enables 3D tilt interaction on cursor movement. |
| `tiltFactor` | number | `5` | Depth of the tilt in degrees (0–25 recommended). |
| `magnify` | number | `1` | Magnification factor of the lens (clamped 0.001–3.0). `1` is no magnification. |
| `on.init` | function | `—` | Callback that runs once the first render completes. Receives the lens instance. |
> The `target` parameter is required; all others are optional.
```
--------------------------------
### Apply Preset Configurations for Visual Styles
Source: https://context7.com/naughtyduk/liquidgl/llms.txt
LiquidGL offers five named presets that can be directly applied to the `liquidGL()` options for ready-made visual styles. Each preset adjusts parameters like refraction, bevel depth, and frost.
```javascript
document.addEventListener("DOMContentLoaded", () => {
// --- Preset: Default ---
// Balanced glass with subtle refraction and light frost
liquidGL({
target: ".glass-default",
refraction: 0, bevelDepth: 0.052, bevelWidth: 0.211,
frost: 2, shadow: true, specular: true,
});
// --- Preset: Alien ---
// Strong distortion and deep bevel for a sci-fi feel
liquidGL({
target: ".glass-alien",
refraction: 0.073, bevelDepth: 0.2, bevelWidth: 0.156,
frost: 2, shadow: true, specular: false,
});
// --- Preset: Pulse ---
// Flat pane with a wide bevel — good for pulsing / pill UI
liquidGL({
target: ".glass-pulse",
refraction: 0.03, bevelDepth: 0, bevelWidth: 0.273,
frost: 0, shadow: false, specular: false,
});
// --- Preset: Frost ---
// Privacy-glass style with soft diffusion
liquidGL({
target: ".glass-frost",
refraction: 0, bevelDepth: 0.035, bevelWidth: 0.119,
frost: 0.9, shadow: true, specular: true,
});
// --- Preset: Edge ---
// Thin bevel with bright rim highlights
liquidGL({
target: ".glass-edge",
refraction: 0.047, bevelDepth: 0.136, bevelWidth: 0.076,
frost: 2, shadow: true, specular: false,
});
});
```
--------------------------------
### HTML Structure for LiquidGL Glass Effect
Source: https://github.com/naughtyduk/liquidgl/blob/main/README.md
Set up the target element with the 'liquidGL' class and a child element for content. Ensure the target has a high z-index to overlay page content correctly.
```html
This example text content will appear on top of the glass.
```
--------------------------------
### Initialize liquidGL Glass Effect
Source: https://github.com/naughtyduk/liquidgl/blob/main/demos/demo-1.html
Initializes the liquidGL glass effect on a target element and sets up a GUI for controlling its properties. Use this when you need to apply a glass-like visual effect to UI elements.
```javascript
let glassEffect;
document.addEventListener("DOMContentLoaded", () => {
// Initialize the Liquid Glass effect on our menu
glassEffect = liquidGL({
target: ".menu-wrap",
refraction: 0,
bevelDepth: 0.052,
bevelWidth: 0.211,
frost: 2,
shadow: true,
specular: true,
tilt: false,
tiltFactor: 5,
reveal: "fade",
});
// Build GUI after liquidGL initialised (multi-awareness)
const lensList = Array.isArray(glassEffect) ? glassEffect : [glassEffect];
const firstLens = lensList[0];
if (firstLens) {
gui = new lil.GUI();
glassFolder = gui.addFolder("liquidGL Effect");
const updateAll = (key, value) => {
lensList.forEach((ln) => {
if (!ln) return;
ln.options[key] = value;
if (key === "shadow") ln.setShadow(value);
if (key === "tilt") ln.setTilt(value);
});
};
glassFolder
.add(firstLens.options, "refraction", 0, 0.1, 0.001)
.onChange((v) => updateAll("refraction", v));
glassFolder
.add(firstLens.options, "bevelDepth", 0, 0.2, 0.001)
.onChange((v) => updateAll("bevelDepth", v));
glassFolder
.add(firstLens.options, "bevelWidth", 0, 0.5, 0.001)
.onChange((v) => updateAll("bevelWidth", v));
glassFolder
.add(firstLens.options, "frost", 0, 10, 0.1)
.onChange((v) => updateAll("frost", v));
glassFolder
.add(firstLens.options, "magnify", 1, 5, 0.1)
.onChange((v) => updateAll("magnify", v));
glassFolder
.add(firstLens.options, "shadow")
.onChange((v) => updateAll("shadow", v));
glassFolder
.add(firstLens.options, "specular")
.onChange((v) => updateAll("specular", v));
glassFolder
.add(firstLens.options, "tilt")
.onChange((v) => updateAll("tilt", v));
glassFolder
.add(firstLens.options, "tiltFactor", 0, 25, 0.1)
.onChange((v) => updateAll("tiltFactor", v));
glassFolder
.add(firstLens.options, "reveal", ["none", "fade"])
.onChange((v) => updateAll("reveal", v));
glassFolder.close();
}
});
```
--------------------------------
### Scoped Snapshot with `snapshot` Option
Source: https://context7.com/naughtyduk/liquidgl/llms.txt
Use the `snapshot` option to target a specific background container for performance improvements on complex pages. This reduces GPU memory usage and speeds up initial capture. Ensure videos within the snapshot container are automatically detected and patched.
```html
```