npm package: @maniteja-rao-gurenka/react-liquid-glass
Description: Physically inspired liquid glass refraction/reflection for the web.
Latest version: 0.1.2

﻿# liquid-glass

Physically based liquid glass effects for the web. Includes a WebGL refraction shader and an SVG GlassSurface filter.

## Install

```bash
npm install @maniteja-rao-gurenka/react-liquid-glass
```

## Usage

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

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

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

```ts
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__content` container.
- 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–1` or `0–100` (values `>= 1` are treated as percent)
- `depth`: `0–1` or `1–100`
- `frost` / `blur`: blur radius in `px` (values `< 1` are treated as `0–1`)

## API

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