@maniteja-rao-gurenka/react-liquid-glass
v0.1.2
Published
Physically inspired liquid glass refraction/reflection for the web.
Maintainers
Readme
liquid-glass
Physically based liquid glass effects for the web. Includes a WebGL refraction shader and an SVG GlassSurface filter.
Install
npm install @maniteja-rao-gurenka/react-liquid-glassUsage
import { createGlassEffect } from "@maniteja-rao-gurenka/react-liquid-glass";
const card = document.querySelector(".glass") as HTMLElement;
const bg = document.querySelector("#bg") as HTMLImageElement;
const glass = createGlassEffect(card, {
source: bg,
refraction: 80,
depth: 20,
dispersion: 50,
frost: 12,
splay: 10,
lightIntensity: 80,
lightAngle: -45
});
// Later
// glass.setOptions({ depth: 40 });
// glass.destroy();React Usage
import { useEffect, useRef } from "react";
import { createGlassEffect } from "@maniteja-rao-gurenka/react-liquid-glass";
export function GlassCard() {
const cardRef = useRef<HTMLDivElement | null>(null);
const bgRef = useRef<HTMLCanvasElement | null>(null);
useEffect(() => {
if (!cardRef.current || !bgRef.current) return;
const glass = createGlassEffect(cardRef.current, {
source: bgRef.current,
refraction: 80,
depth: 20,
dispersion: 50,
frost: 12,
splay: 10,
lightIntensity: 80,
lightAngle: -45
});
return () => glass.destroy();
}, []);
return (
<div style={{ position: "relative", minHeight: 240 }}>
<canvas ref={bgRef} style={{ position: "absolute", inset: 0 }} />
<div ref={cardRef} style={{ width: 240, height: 160, borderRadius: 20 }} />
</div>
);
}Glass Surface (SVG)
GlassSurface provides an SVG displacement filter. It works well for cards, pills, and text blocks.
import { createGlassSurface } from "@maniteja-rao-gurenka/react-liquid-glass";
const card = document.querySelector(".glass-card") as HTMLElement;
const glass = createGlassSurface(card, {
borderRadius: 20,
distortionScale: -180,
displace: 0,
blur: 11,
brightness: 50,
opacity: 0.93,
saturation: 1
});SVG targets are auto-wrapped in a div so the filter can be applied:
const icon = document.querySelector("svg") as SVGElement;
createGlassSurface(icon, { borderRadius: 16 });Notes
- For a true refraction effect, you must supply a live source texture. The module does not capture DOM behind your element.
- You can pass an image, canvas, video, or a function that returns a TexImageSource.
- The canvas is inserted as the first child of your target element. Content renders above it.
- GlassSurface wraps existing children in a
.glass-surface__contentcontainer. - For text-only effects, wrap your text in a container and apply the effect to the container if you want layout control.
- For consistent results, keep uniform corner radii and avoid fully opaque fills.
Glass Effect Control Mapping
This package supports Figma-style Glass controls (Light Angle, Light Intensity, Refraction, Depth, Dispersion, Frost, and Splay), so you can reuse familiar values from Figma when configuring the effect.
The glass effect exposes the following controls: Light Angle, Light Intensity, Refraction, Depth, Dispersion, Frost, and Splay. Light Angle sets the light direction, Light Intensity sets the brightness of the projected light, Refraction controls the optical distortion along the curved edge, Depth controls how far the curved edge extends inward, Dispersion controls chromatic splitting along the edge, Frost controls background blur, and Splay controls how widely the projected light spreads.
This library accepts design-tool-style values:
refraction,dispersion,lightIntensity,splay:0–1or0–100(values>= 1are treated as percent)depth:0–1or1–100frost/blur: blur radius inpx(values< 1are treated as0–1)
API
export type LiquidGlassOptions = {
source?: TexImageSource | (() => TexImageSource | null);
sourceUrl?: string;
refraction?: number; // Refraction (0-1 or 0-100)
depth?: number; // Depth (0-1 or 1-100, where 1 is the minimum)
reflection?: number; // Environmental reflection strength
dispersion?: number; // Dispersion (0-1 or 0-100)
frost?: number; // Frost blur radius (px)
blur?: number; // Alias for frost (px)
noiseScale?: number; // Noise frequency
flowSpeed?: number; // Animation speed
flowStrength?: number; // Normal intensity
tint?: [number, number, number, number]; // RGBA, tint alpha controls mix
backgroundColor?: [number, number, number, number];
radius?: number; // Override border radius (px)
edge?: number; // Edge highlight strength
splay?: number; // Light splay (0-1 or 0-100)
lightIntensity?: number; // Light intensity (0-1 or 0-100)
bulge?: number; // Lens bulge amount
lightAngle?: number; // Light angle (degrees)
lightPosition?: [number, number]; // Optional light position (UV override)
mode?: "lens" | "organic"; // Lens = clear glass, Organic = liquid noise
useDevicePixelRatio?: boolean;
preserveDrawingBuffer?: boolean;
autoStart?: boolean;
mixBlendMode?: string;
};
export declare class LiquidGlass {
constructor(target: HTMLElement, options?: LiquidGlassOptions);
setOptions(options: Partial<LiquidGlassOptions>): void;
setSource(source: TexImageSource | (() => TexImageSource | null) | null): void;
setSourceUrl(url: string): void;
start(): void;
stop(): void;
destroy(): void;
}
export declare function createLiquidGlass(
target: HTMLElement,
options?: LiquidGlassOptions
): LiquidGlass;
export type GlassEffectOptions = LiquidGlassOptions;
export declare class GlassEffect extends LiquidGlass {}
export declare function createGlassEffect(
target: HTMLElement,
options?: GlassEffectOptions
): GlassEffect;
export type GlassSurfaceOptions = {
width?: number | string;
height?: number | string;
borderRadius?: number;
borderWidth?: number;
brightness?: number;
opacity?: number;
blur?: number;
displace?: number;
backgroundOpacity?: number;
saturation?: number;
distortionScale?: number;
redOffset?: number;
greenOffset?: number;
blueOffset?: number;
xChannel?: "R" | "G" | "B" | "A";
yChannel?: "R" | "G" | "B" | "A";
mixBlendMode?: string;
className?: string;
style?: Partial<CSSStyleDeclaration>;
useDefaultStyles?: boolean;
preserveLayout?: boolean;
};
export declare class GlassSurface {
constructor(target: HTMLElement, options?: GlassSurfaceOptions);
setOptions(options: Partial<GlassSurfaceOptions>): void;
destroy(): void;
}
export declare function createGlassSurface(
target: HTMLElement | SVGElement,
options?: GlassSurfaceOptions
): GlassSurface;