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

@dpawlikowski/liquid-glass

v0.3.0

Published

Pure CSS and SVG liquid glass refraction effect inspired by iOS and visionOS.

Readme

liquid-glass

npm License: MIT Bundle size

Liquid glass refraction effect built entirely from CSS and SVG — no WebGL, no canvas, no runtime dependencies.

  • Refraction via feTurbulence + feDisplacementMap on a duplicated scene layer
  • Chromatic edge aberration via mix-blend-mode: screen pseudo-elements
  • Animated turbulence that auto-pauses for prefers-reduced-motion
  • backdrop-filter: blur() saturate() frosted glass surface
  • Three presets (subtle, vivid, vision) with full CSS variable override
  • React component with TypeScript declarations included

Live demo →


Install

npm install @dpawlikowski/liquid-glass

Quick start

HTML + vanilla JS

<link rel="stylesheet" href="node_modules/@dpawlikowski/liquid-glass/src/core/liquid-glass.css">

<div class="liquid-glass liquid-glass--vivid">
  <span class="liquid-glass__refraction" aria-hidden="true"></span>
  <div class="liquid-glass__content">
    Hello
  </div>
</div>

<script type="module">
  import { injectLiquidGlassFilter } from "@dpawlikowski/liquid-glass";
  injectLiquidGlassFilter();
</script>

Set --lg-scene-background to match your page background for strongest refraction:

.liquid-glass {
  --lg-scene-background: url("./bg.svg");
}

React

import "@dpawlikowski/liquid-glass/css";
import { LiquidGlass } from "@dpawlikowski/liquid-glass/react";

export function Card() {
  return (
    <LiquidGlass intensity="vision" style={{ "--lg-radius": "36px" }}>
      Settings
    </LiquidGlass>
  );
}

Presets

| Class | Description | |---|---| | liquid-glass--subtle | Minimal blur, low opacity — good for chrome and overlays | | liquid-glass--vivid | Strong saturation, sharp refraction — the default | | liquid-glass--vision | visionOS-style: large radius, deep shadow, wide blur |


CSS variables

| Variable | Default | Description | |---|---|---| | --lg-blur | 8px | backdrop-filter blur radius | | --lg-saturate | 180% | backdrop-filter saturation | | --lg-opacity | 0.58 | White tint fill opacity | | --lg-radius | 24px | Border radius | | --lg-border-opacity | 0.45 | Top/side border alpha | | --lg-tint | 255 255 255 | Tint RGB (space-separated, used in rgb()) | | --lg-shadow | 0 22px 70px … | Box shadow | | --lg-scene-background | transparent | Background on .liquid-glass__refraction |

Override any variable on the element or a parent:

.my-panel {
  --lg-blur: 16px;
  --lg-opacity: 0.3;
  --lg-radius: 32px;
}

JavaScript API

import {
  injectLiquidGlassFilter,
  updateLiquidGlassFilter,
  setLiquidGlassMotion,
  filterDefaults,
  SCALE_MIN,
  SCALE_MAX,
} from "@dpawlikowski/liquid-glass";

// Inject once — idempotent, safe to call multiple times.
injectLiquidGlassFilter({ scale: filterDefaults.scale });

// Live-update without re-injection.
updateLiquidGlassFilter("liquid-glass-filter", { scale: 14 });

// Pause / resume the turbulence animation.
setLiquidGlassMotion("liquid-glass-filter", false);

// Scale is clamped to [SCALE_MIN, SCALE_MAX] = [0, 25].
console.log(SCALE_MIN, SCALE_MAX); // 0 25

injectLiquidGlassFilter(options?)

| Option | Default | Description | |---|---|---| | id | "liquid-glass-filter" | SVG filter element id | | baseFrequency | 0.008 | feTurbulence base frequency | | numOctaves | 2 | Turbulence octaves | | scale | 18 | feDisplacementMap scale (clamped to [0, 25]) | | seed | 7 | Noise seed | | animate | true | Animate turbulence frequency | | duration | "7s" | Animation cycle duration |

All defaults are available as filterDefaults so you never need to hardcode them:

import { filterDefaults } from "@dpawlikowski/liquid-glass";

// Reference defaults instead of duplicating magic numbers.
injectLiquidGlassFilter({ scale: filterDefaults.scale * 0.75 });

updateLiquidGlassFilter(id, options)

Live-updates scale or baseFrequency on an already-injected filter. Returns the <filter> element, or null if the id is not found.

setLiquidGlassMotion(id, enabled, options?)

Enables or disables the <animate> turbulence animation. Pass { baseFrequency, duration } in options to change animation parameters at the same time.


React component

import "@dpawlikowski/liquid-glass/css";
import { LiquidGlass } from "@dpawlikowski/liquid-glass/react";

<LiquidGlass
  intensity="vivid"       // preset suffix
  refractive={true}       // include refraction layer
  filterId="my-filter"    // custom SVG filter id
  as="section"            // root element type
  style={{ "--lg-radius": "28px" }}
>
  Glass content
</LiquidGlass>

Props

| Prop | Default | Description | |---|---|---| | intensity | "vivid" | Preset: "subtle", "vivid", "vision", or a custom suffix | | refractive | true | Include .liquid-glass__refraction layer | | as | "div" | Root element tag | | filterId | "liquid-glass-filter" | SVG filter id — the filter is injected automatically | | style | — | Forwarded; merge CSS variable overrides here |

All other props (className, onClick, aria-*, etc.) are forwarded to the root element.


Browser support

| Browser | Status | |---|---| | Chrome / Edge 105+ | Full | | Safari 16+ | Full (keep scale ≤ 18 to avoid artifacts) | | Firefox 103+ | Full | | No backdrop-filter | Graceful fallback: opaque white tint |


Performance

SVG turbulence and displacement map have a real GPU cost. Follow these rules to keep the effect smooth:

  • Keep scale between 12 and 18. Values above 25 are clamped and cause Safari artifacts.
  • Animate one or two hero surfaces — not every card on the page.
  • Use refractive={false} (or omit .liquid-glass__refraction) when exact backdrop mirroring is not needed.
  • Test on a mid-range Android device, not just a desktop browser.
  • Use setLiquidGlassMotion(id, false) to pause animation on low-power or battery-saver conditions.

Development

npm install
npm test            # unit tests (node:test + happy-dom)
npm run check       # smoke check — validates files, API surface, and CSS selectors
npm run dev         # interactive demo server
npm run build:demo  # production demo build → dist-demo/
npm pack            # preview the published tarball (runs test + check via prepack)

Publish

The package is published as @dpawlikowski/liquid-glass (the unscoped liquid-glass name is taken on npm).

npm login
npm publish --access public

License

MIT © Dominik Pawlikowski