Skip to content

Latest commit

 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QuickLiquid

npm bundle size types license

Apple-style liquid glass for React and vanilla JavaScript.
Real SVG backdrop refraction, physical rim lighting, chromatic dispersion, spring gestures, and droplet-style merge animations.

Live demo · Physics notes · npm

A droplet of glass falls onto a seam of light; five droplets fuse into a single lens; the lens crosses the frame refracting the QuickLiquid wordmark as it passes

Every surface in that clip is a live LiquidGlassEngine, and the wordmark is page content sitting behind the glass — those letters are being displaced by a real SVG map, not by a video effect.
Source: demo/src/reel/Intro.tsx · source is in demo/src/reel/Intro.tsx


Why QuickLiquid

QuickLiquid is a small UI effects engine for building premium refractive surfaces: nav bars, command palettes, tab indicators, floating controls, cards, sheets, and glassy buttons. It works as a React component or as a framework-free DOM engine.

01 optics

Real refraction
SVG displacement maps bend the backdrop through a convex glass bezel instead of faking the look with a flat translucent layer.

02 motion

Liquid response
Press, bounce, jiggle, drag, mount, exit, and tab transitions use spring-based motion primitives.

03 cache

Built for reuse
Same-size glass elements share one refcounted displacement map, and strength changes update filter attributes without rebuilding maps.

04 color

Chromatic edges
Red, green, and blue channels can refract at slightly different scales for realistic prismatic rims.

05 groups

Droplet merging
Grouped elements can form smooth metaball bridges as they approach each other.

06 fallback

Graceful fallback
Chromium gets full SVG backdrop refraction. Other engines keep the frost, tint, shadow, and lighting layers.

Install

npm install quick-liquid

Requirements:

  • Node 18+ for local builds
  • React 18+ only if you use quick-liquid/react
  • No stylesheet import required

Quick Start

React

import { LiquidGlass } from 'quick-liquid/react';

export function CommandButton() {
  return (
    <LiquidGlass
      config={{
        material: 'regular',
        borderRadius: 24,
        dynamicLighting: true,
        chromaticAberration: 0.22,
      }}
      liquidPress={{ scale: 0.92, squish: 0.03 }}
      animateIn={120}
      className="command-glass"
    >
      <button type="button">Open Command Center</button>
    </LiquidGlass>
  );
}

Vanilla DOM

import { LiquidGlassEngine } from 'quick-liquid';

const card = document.querySelector<HTMLElement>('[data-liquid-card]');

if (card) {
  const glass = new LiquidGlassEngine(card, {
    material: 'clear',
    refractionStrength: 28,
    dynamicLighting: true,
    quality: 'high',
  });

  glass.enableLiquidPress({ scale: 0.94, squish: 0.025 });
}

Material Presets

Start with a material and override only the knobs you need.

Preset Feel Good for
clear Low blur, stronger lensing Hero controls, dock-like UI, colorful backgrounds
thin Light frost, readable refraction Toolbars, small buttons, chips
regular Balanced frost and depth Cards, nav bars, command palettes
thick More blur and tint Sheets, overlays, text-heavy surfaces
ultra Softest, most opaque Large panels and modal backgrounds
adaptive Balanced preset with adaptive tint hook Apps that feed their own environment color
const config = {
  material: 'regular',
  blur: 18,
  refractionStrength: 20,
  tintOpacity: 0.08,
};

Configuration

Option Type Default Description
material 'clear' | 'thin' | 'regular' | 'thick' | 'ultra' | 'adaptive' unset Applies a curated glass preset. Explicit values override preset values.
blur number 3 Backdrop frost blur in CSS pixels.
saturation number 1.5 Backdrop saturation boost through the glass.
tint string '255, 255, 255' RGB tint string.
tintOpacity number 0.04 Material tint opacity.
refractionStrength number 22 Maximum rim displacement in CSS pixels.
bezelWidth number 34 Width of the curved refractive bezel band.
thickness number 24 Virtual glass slab depth.
ior number 1.5 Index of refraction.
chromaticAberration number 0.3 Per-channel dispersion amount from 0 to 1.
lightAngle number -35 Light direction in degrees.
edgeHighlight number 0.9 Rim highlight intensity.
specularStrength number 0.42 Soft bezel sheen intensity.
fresnelPower number 2.2 Rim lobe sharpness.
hoverLighting boolean false Brightens the rim on hover.
cursorTracking boolean false Lets the rim light follow the pointer.
dynamicLighting boolean false Alias that enables cursor-driven lighting.
parallax boolean false Adds subtle pointer parallax.
elevation number 1 Shadow or ambient glow multiplier.
borderRadius number 28 Glass corner radius in CSS pixels.
quality 'high' | 'medium' | 'low' 'high' Displacement map resolution tier.
refractionMode 'auto' | 'svg' | 'css' 'auto' Choose full SVG refraction or CSS-only fallback.
appearance 'light' | 'dark' | 'auto' 'auto' Adapts tint, lighting, and shadow for light or dark backdrops.
backdropLuminance number unset Optional 0..1 luminance hint for custom backdrop sampling.

Animation API

QuickLiquid exports the glass engine plus reusable animation primitives from quick-liquid.

import {
  LiquidButton,
  LiquidDrag,
  LiquidGesture,
  LiquidGroup,
  LiquidTabBar,
  Spring,
} from 'quick-liquid';

Liquid buttons

import { LiquidButton } from 'quick-liquid';

const button = document.querySelector<HTMLElement>('.glass-button');

if (button) {
  new LiquidButton(button).onTap(() => {
    console.log('Tapped');
  });
}

Merging groups

import { LiquidGroup, LiquidGesture } from 'quick-liquid';

const container = document.querySelector<HTMLElement>('.dock');
const items = document.querySelectorAll<HTMLElement>('.dock-item');

if (container) {
  const group = new LiquidGroup(container, {
    mergeDistance: 60,
    blendRadius: 28,
  });

  items.forEach((item) => {
    group.add(item);
    new LiquidGesture(item).onDrag(() => group.updatePositions());
  });
}

Liquid tab indicators

import { LiquidGlassEngine, LiquidTabBar } from 'quick-liquid';

const nav = document.querySelector<HTMLElement>('.tabs');
const tabs = [...document.querySelectorAll<HTMLElement>('.tab')];

if (nav && tabs.length) {
  const tabBar = new LiquidTabBar(nav, tabs, { spring: 'snappy' });

  new LiquidGlassEngine(tabBar.getIndicator(), {
    material: 'clear',
    borderRadius: 999,
  });

  tabs.forEach((tab, index) => {
    tab.addEventListener('click', () => tabBar.select(index));
  });
}

Import Map

Import Exports
quick-liquid LiquidGlassEngine, DEFAULT_CONFIG, MATERIAL_PRESETS, springs, gestures, transitions, morphing, groups, tab bar utilities
quick-liquid/react LiquidGlass, LiquidGlassProps, LiquidGlassRef

Browser Notes

The full refraction path depends on backdrop-filter: url(...), which currently works in Chromium-based browsers. Safari and Firefox receive a CSS fallback with blur, saturation, tint, lighting, and shadow.

For Chromium refraction, avoid these styles on the glass host element because they can prevent the browser from resolving the live backdrop:

  • isolation
  • filter
  • opacity
  • mask
  • explicit stacking changes on the internal lens layer

The public playground demonstrates the supported Chromium refraction path and the CSS fallback remains available through refractionMode: 'css'.

Performance Model

QuickLiquid is designed around a cache-first rendering path:

  • A 1-D lookup table reduces the physical refraction calculation.
  • Only the rounded bezel band is iterated when generating displacement maps.
  • Same-geometry elements share a refcounted map.
  • refractionStrength and chromatic aberration updates only change SVG filter scale attributes when geometry is unchanged.
  • quality: 'medium' or quality: 'low' can be used for dense lists or background UI.

You can read live engine metrics:

const metrics = glass.getPerformanceMetrics();

console.log(metrics.mapGenMs, metrics.mapPixelsComputed);

Local Development

npm install
npm run typecheck
npm run build:lib
npm run dev

Useful workspace scripts:

Command What it does
npm run dev Starts the demo workspace.
npm run dev:landing Starts the landing/docs site.
npm run typecheck Type-checks packages/quick-liquid.
npm run build:lib Builds the library package with tsup.
npm run build Builds the library, demo, and landing site.

Intro reel

The animation at the top of this README is a React component, not a video file. It composes at a fixed 1920x1080, and every value on screen is a pure function of the film clock — which is what lets it be scrubbed by hand and captured frame-perfectly rather than screen-recorded.

Run npm run dev in demo/ and open /reel.html to play it. Space plays and pauses, R replays, the arrow keys step a frame at a time (hold shift for a second), and H hides the transport bar. ?clean=1 opens it with no chrome at all.

Command (from demo/) What it does
The shipped GIF is a lightweight preview; the reel itself remains a live React
composition in the browser.

Documentation

License

MIT. See LICENSE.

About

Liquid Glass - Heavily Optimised

Topics

Resources

Stars

213 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages