npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

liquidglass.css

v0.0.24

Published

Physics-based liquid glass refraction effect using CSS and SVG filters

Readme

.card {
  --glass-refraction: 80%;
  --glass-thickness: 50%;
  --glass-softness: 15%;
  --glass-gloss: 60%;
  --glass-saturation: 45%;
  --glass-dispersion: 30%;
  --glass-specular-angle: -60deg;
  --glass-specular-width: 2px;
  border-radius: 20px;
}

Features

  • Typed CSS Custom Properties — Registered via @property so values accept their canonical units (<length>, <percentage>, <angle>)
  • Physics-Based — Snell's law refraction, not blur approximation
  • GPU-First Renderer — WebGPU → WebGL2 → WASM-SIMD auto-fallback
  • CSS Paint Worklet Specular — Phong highlight via Canvas2D, no per-pixel loop, repaints on geometry/parameter change automatically
  • Auto Radius Trackingborder-radius is mirrored to --glass-radius via a global MutationObserver + ResizeObserver
  • Tailwind CSS v4 — Native plugin via @plugin "liquidglass.css"
  • CSS-in-JS — First-class support for Emotion, styled-components, StyleX, Vanilla Extract, Panda CSS, UnoCSS
  • Framework Agnostic — Works with React, Vue, Svelte, or vanilla
  • Adaptive Performance — Smart throttling at scale

Quick Start

npm install liquidglass.css

One import. That's it.

import "liquidglass.css";
.glass-panel {
  --glass-refraction: 60%;
  --glass-thickness: 50%;
  --glass-softness: 15%;
  border-radius: 24px;
}

border-radius is observed automatically — you don't have to keep --glass-radius in sync. Bare numbers (e.g. 60 instead of 60%) are also accepted for backward compatibility.

<div class="glass-panel">
  Your content here
</div>

Tailwind CSS v4

Native plugin support — same import, just add @plugin in CSS.

import "liquidglass.css";
@import "tailwindcss";
@plugin "liquidglass.css";
<div class="glass-refraction-[80%] glass-thickness-50 glass-softness-[15%] rounded-2xl">
  Your content here
</div>

All parameters are available as utilities:

| Utility | CSS Property | |---------|--------------| | glass-refraction-{value} | --glass-refraction | | glass-thickness-{value} | --glass-thickness | | glass-softness-{value} | --glass-softness | | glass-gloss-{value} | --glass-gloss | | glass-saturation-{value} | --glass-saturation | | glass-dispersion-{value} | --glass-dispersion | | glass-specular-angle-{value} | --glass-specular-angle | | glass-specular-width-{value} | --glass-specular-width | | glass-specular-shininess-{value} | --glass-specular-shininess | | glass-{value} | --glass-refraction (shorthand) |

Arbitrary values work: glass-refraction-[73%], glass-specular-angle-[-45deg].

StyleX

Type-safe glass styles for Meta's StyleX.

import "liquidglass.css";
import * as stylex from '@stylexjs/stylex';
import { glass } from 'liquidglass.css/stylex';

const styles = stylex.create({
  // Composite styles
  card: {
    ...glass({
      refraction: '80%',
      thickness: '50%',
      softness: '15%',
    }),
    borderRadius: '20px',
  },
  // Presets
  frosted: {
    ...glass.presets.frosted,
    borderRadius: '16px',
  },
  // Individual properties
  custom: {
    ...glass.refraction('60%'),
    ...glass.thickness('40%'),
  }
});

<div {...stylex.props(styles.card)}>Content</div>

API:

  • glass({ ... }) — composite styles
  • glass.refraction(), glass.thickness(), etc. — individual properties
  • glass.presets.subtle, glass.presets.frosted, etc. — preset styles

Emotion

Single import — CSS engine auto-initializes.

import { css } from '@emotion/react';
import { glass } from 'liquidglass.css/emotion';

const cardStyle = css({
  ...glass({ refraction: '80%', thickness: '50%' }),
  borderRadius: '20px',
});

const frostedStyle = css({
  ...glass.presets.frosted,
  borderRadius: '16px',
});

<div css={cardStyle}>Content</div>

styled-components

Single import — CSS engine auto-initializes.

import styled from 'styled-components';
import { glass } from 'liquidglass.css/styled-components';

// Object syntax
const Card = styled.div({
  ...glass({ refraction: '80%', thickness: '50%' }),
  borderRadius: '20px',
});

// Template literal syntax
const FrostedCard = styled.div`
  ${glass.presets.frosted}
  border-radius: 16px;
`;

Vanilla Extract

Build-time CSS — import the runtime separately.

import "liquidglass.css";
// styles.css.ts
import { style } from '@vanilla-extract/css';
import { glass } from 'liquidglass.css/vanilla-extract';

export const card = style({
  ...glass({ refraction: '80%', thickness: '50%' }),
  borderRadius: '20px',
});

export const frosted = style({
  ...glass.presets.frosted,
  borderRadius: '16px',
});

Panda CSS

Build-time CSS — import the runtime separately.

import "liquidglass.css";
// panda.config.ts
import { defineConfig } from '@pandacss/dev';
import { glassPreset } from 'liquidglass.css/panda';

export default defineConfig({
  presets: ['@pandacss/preset-base', glassPreset],
  // ...
});
// app.tsx
import { css } from '../styled-system/css';

<div className={css({
  glassRefraction: '80%',
  glassThickness: '50%',
  borderRadius: '20px',
})}>
  Content
</div>

// Or use preset recipes
<div className={css({ glass: 'frosted', borderRadius: 'xl' })}>
  Content
</div>

UnoCSS

Build-time CSS — import the runtime separately.

import "liquidglass.css";
// uno.config.ts
import { defineConfig } from 'unocss';
import { presetGlass } from 'liquidglass.css/unocss';

export default defineConfig({
  presets: [presetGlass()],
});
<div class="glass-refraction-80 glass-thickness-50 rounded-2xl">
  Content
</div>

<!-- Arbitrary values -->
<div class="glass-refraction-[73%] glass-specular-angle-[-45deg]">
  Content
</div>

<!-- Presets -->
<div class="glass-preset-frosted rounded-xl">
  Content
</div>

Parameters

All parameters are registered as typed CSS Custom Properties. Each prefix is --glass-.

Surface

| Property | Unit | Range | Default | Description | |----------|------|-------|---------|-------------| | refraction | <percentage> | 0–100 | 50 | Lens distortion intensity | | thickness | <percentage> | 0–100 | 50 | Edge steepness / glass depth | | softness | <percentage> | 0–100 | 10 | Background blur amount | | gloss | <percentage> | 0–100 | 50 | Specular highlight intensity | | saturation | <percentage> | 0–100 | 45 | Color saturation boost | | dispersion | <percentage> | 0–100 | 30 | Chromatic edge blur |

Specular (CSS Paint Worklet)

| Property | Unit | Range | Default | Description | |----------|------|-------|---------|-------------| | specular-angle | <angle> | -180–180 | -60deg | Light direction | | specular-width | <length> | 1–50 | 2px | Bezel highlight width | | specular-shininess | <number> | 1–128 | 8 | Phong exponent |

Renderer (advanced)

| Property | Values | Default | Description | |----------|--------|---------|-------------| | displacement-renderer | gpu | gl2 | wasm | gpu | Displacement backend (auto-fallback) | | displacement-resolution | <percentage> | 40 | Map resolution | | displacement-min-resolution | <percentage> | 10 | Min resolution during resize | | displacement-smoothing | <percentage> | 0 | Map smoothing blur | | displacement-refresh-interval | <integer> | 12 | Frame skip during resize | | enable-optimization | 0 | 1 | 1 | Master optimization toggle |

Dynamic Updates

Parameters respond to any CSS change:

/* Hover state */
.glass-panel:hover {
  --glass-refraction: 80%;
}

/* Media queries */
@media (prefers-reduced-motion: reduce) {
  .glass-panel {
    --glass-refraction: 0%;
  }
}

/* Complex selectors */
.container > div:nth-child(2) {
  --glass-refraction: 60%;
}

Or via JavaScript:

element.style.setProperty('--glass-refraction', '90%');
element.style.setProperty('--glass-specular-angle', '45deg');
element.style.setProperty('--glass-specular-width', '3px');

How It Works

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│   1. Renderer (WebGPU / WebGL2 / WASM-SIMD) generates the        │
│      displacement map from border-radius                         │
│                              ↓                                   │
│   2. SVG filter chain (feImage → feDisplacementMap → output)     │
│      refracts the backdrop, with optional slope-blur dispersion  │
│                              ↓                                   │
│   3. CSS Paint Worklet draws the Phong specular bezel directly   │
│      onto the element via Canvas2D — no SVG primitive            │
│                              ↓                                   │
│   4. Adaptive throttling and predictive resize keep it smooth    │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

The displacement map encodes refraction vectors:

  • Red channel → X displacement
  • Green channel → Y displacement
  • Blue channel → Edge mask for dispersion

Specular runs on its own paint worklet, so changing --glass-specular-* does not invalidate the displacement bitmap — and resizing does not rerun the specular path.

Framework Examples

React

import "liquidglass.css";

function GlassCard({ children }) {
  return (
    <div className="glass-card">
      {children}
    </div>
  );
}
.glass-card {
  --glass-refraction: 70%;
  --glass-gloss: 60%;
  border-radius: 20px;
}

Vue

<script setup>
import "liquidglass.css";
</script>

<template>
  <div class="glass-panel">
    <slot />
  </div>
</template>

<style scoped>
.glass-panel {
  --glass-refraction: 70%;
  --glass-gloss: 60%;
  border-radius: 16px;
}
</style>

Vanilla

<script type="module">
  import "https://unpkg.com/liquidglass.css/dist/liquidglass.js";
</script>

<div style="
  --glass-refraction: 80%;
  --glass-softness: 20%;
  border-radius: 24px;
">
  Content
</div>

Browser Support

| Browser | Version | Notes | |---------|---------|-------| | Chrome | 105+ | Full support (CSS Paint API + backdrop-filter SVG) | | Edge | 105+ | Full support | | Safari | — | backdrop-filter SVG not supported | | Firefox | — | backdrop-filter SVG / CSS Paint API not supported |

Note: Unsupported browsers gracefully fall back to backdrop-filter: blur(20px). The specular bezel layer simply doesn't render when CSS Paint API is missing.

Performance

  • GPU-First Renderer — WebGPU when available, WebGL2 next, WASM-SIMD as last resort. Switch explicitly via --glass-displacement-renderer: gl2; etc.
  • CSS Paint API Specular — The browser caches and re-invokes the worklet only when a registered @property value or geometry changes. No JS render loop for highlights.
  • Adaptive Throttling — Rendering intervals scale with element count
  • Viewport Culling — Off-screen elements pause updates
  • Predictive Rendering — Anticipates size changes during resize
  • Morph Transitions — Crossfade prevents jarring updates

Roadmap

  • [x] CSS Houdini paint worklet (specular)
  • [x] WebGPU / WebGL2 / WASM-SIMD displacement renderers
  • [x] Typed @property registration for all parameters
  • [x] Tailwind CSS v4 native plugin
  • [x] CSS-in-JS integrations (Emotion, styled-components, StyleX, Vanilla Extract, Panda CSS, UnoCSS)
  • [ ] Firefox/Safari support via canvas fallback
  • [ ] Animated displacement maps
  • [ ] Custom displacement textures

Contributing

git clone https://github.com/ihasq/liquidglass.css.git
cd liquidglass.css
npm install
npm run dev

Visit liquidglass-css.pages.dev/labs/ to experiment with parameters live, or run cd site && npm run dev locally.

Quality gates:

npm run build       # tsc + vite lib build
npm run test        # type / build / SMT / e2e integrity suite
npx knip            # static dead-code analysis

Acknowledgments

This project would not have been possible without the groundbreaking work of @KubeKhrm and kube.io.

His invention goes far beyond simply applying displacement via SVG filters. He identified the precise mathematical formulas required to simulate physically-accurate glass refraction — deriving how border-radius geometry translates into displacement vectors that create the characteristic lens distortion effect. The core technique of encoding these computed refraction vectors into RGB channels and applying them via feDisplacementMap — the very heart of liquidglass.css — originated from his brilliant research.

We stand on the shoulders of giants. Thank you, Kube.

License

MIT License.