### 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
Alt Text

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
```