# glass.md

This file is a practical guide for creating the Liquid Glass effect used by `rdev/liquid-glass-react`.

## What the effect actually is

This library does **not** just add blur and call it glass. It combines:

1. **A displacement map** to bend the background like liquid
2. **Backdrop blur and saturation** to create the frosted glass body
3. **Chromatic aberration** on the edges for the Apple-like refracted look
4. **Mouse-driven elasticity** so the shape reacts like soft material

The repo exposes a React component called `LiquidGlass` and supports React 18+ as a peer dependency. The README also notes that Safari and Firefox only partially support the effect, and displacement is not fully visible there.

---

## Requirements

Before using the effect, make sure you have:

- React 18 or newer
- React DOM 18 or newer
- A browser with good support for `backdrop-filter` and SVG filters
- A layout where the glass element can sit above visible background content

Install the package:

```bash
npm install liquid-glass-react
```

If you are building your own version from scratch, you will also need:

- TypeScript
- A rendering target that supports SVG filter primitives
- Mouse tracking logic if you want the elastic motion
- Good layered backgrounds, because glass over a flat background looks fake fast

---

## Basic usage

The simplest usage is to wrap any content in `LiquidGlass`.

```tsx
import LiquidGlass from "liquid-glass-react"

function App() {
  return (
    <LiquidGlass>
      <div className="p-6">
        <h2>Your content here</h2>
        <p>This will have the liquid glass effect</p>
      </div>
    </LiquidGlass>
  )
}
```

### What matters here

- The children are still normal React nodes
- The glass effect is applied around the children, not inside them
- The component handles positioning, transform, and filter work for you

---

## Button-style glass

This repo shows a tighter configuration for pill buttons.

```tsx
<LiquidGlass
  displacementScale={64}
  blurAmount={0.1}
  saturation={130}
  aberrationIntensity={2}
  elasticity={0.35}
  cornerRadius={100}
  padding="8px 16px"
  onClick={() => console.log("Button clicked!")}
>
  <span className="text-white font-medium">Click Me</span>
</LiquidGlass>
```

Use this style when:

- The component is small
- You want a tactile hover and click feel
- You want stronger refraction on the edges

---

## Mouse container mode

If you want the glass to react to mouse movement across a larger region, pass `mouseContainer`.

```tsx
import { useRef } from "react"
import LiquidGlass from "liquid-glass-react"

function App() {
  const containerRef = useRef<HTMLDivElement>(null)

  return (
    <div ref={containerRef} className="w-full h-screen bg-image">
      <LiquidGlass
        mouseContainer={containerRef}
        elasticity={0.3}
        style={{ position: "fixed", top: "50%", left: "50%" }}
      >
        <div className="p-6">
          <h2>Glass responds to mouse anywhere in the container</h2>
        </div>
      </LiquidGlass>
    </div>
  )
}
```

This is the right pattern when:

- The glass is floating over a large visual scene
- You want one parent area to drive the effect
- You do not want the mouse tracking limited to the element itself

---

## If you are building the effect yourself

This is the important part. Do not fake it with only:

```css
backdrop-filter: blur(20px);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
```

That is regular frosted glass. It is not liquid glass.

A real liquid glass effect needs the following pipeline:

1. Render a displacement map
2. Feed that map into an SVG filter
3. Use `feDisplacementMap` to bend the content
4. Add `backdrop-filter` blur and saturation
5. Split channels slightly to create color fringing
6. Animate transform based on pointer position

---

## Core implementation pattern

### 1. Keep the glass container relative

The wrapper should be positioned in a predictable way so you can layer filters and content inside it.

```tsx
<div className="relative">
  <LiquidGlass>
    <div>Content</div>
  </LiquidGlass>
</div>
```

### 2. Use a backdrop layer and a sharp content layer

The effect works best when the background is warped, but the foreground text stays crisp.

```tsx
<div className="glass">
  <span className="glass__warp" />
  <div className="glass__content">Sharp content here</div>
</div>
```

### 3. Use SVG filter primitives for refraction

The repo uses a filter chain around `feImage`, `feDisplacementMap`, `feBlend`, and `feComposite`.

A simplified version looks like this:

```tsx
<svg style={{ position: "absolute", width: 0, height: 0 }} aria-hidden="true">
  <defs>
    <filter id="liquid-glass">
      <feImage href={displacementMapUrl} result="map" />
      <feDisplacementMap
        in="SourceGraphic"
        in2="map"
        scale={70}
        xChannelSelector="R"
        yChannelSelector="B"
      />
    </filter>
  </defs>
</svg>
```

That is the part that makes the edges bend instead of just blurring.

### 4. Add backdrop blur and saturation

This is the frosting layer.

```tsx
style={{
  backdropFilter: "blur(20px) saturate(140%)",
}}
```

### 5. Add elastic motion

The repo tracks pointer position and uses it to compute a transform.

```tsx
const transform = `translate(calc(-50% + ${x}px), calc(-50% + ${y}px)) scale(${scale})`
```

The point is simple:

- The element should stretch slightly toward the pointer
- The motion should fade out when the pointer is far away
- The stronger the elasticity, the more alive the material feels

---

## Prop guide

These are the props exposed by the library and what they are for:

| Prop | Purpose | Good starting value |
| --- | --- | --- |
| `displacementScale` | Strength of the background warp | `70` for large surfaces, `40-64` for buttons |
| `blurAmount` | Frosted blur amount | `0.0625` default, higher for heavier blur |
| `saturation` | Color boost inside the glass | `140` to `180` |
| `aberrationIntensity` | Chromatic edge split | `1.5` to `2.5` |
| `elasticity` | How soft the movement feels | `0.15` default, `0.3+` for buttons |
| `cornerRadius` | Border radius in pixels | `999` for pills, `24-40` for cards |
| `padding` | Internal spacing | `24px 32px` or smaller for buttons |
| `overLight` | Tune for bright backdrops | `true` on white or pale backgrounds |
| `mode` | Displacement mode | `standard` first, then `shader` if needed |
| `mouseContainer` | Parent area for pointer tracking | `useRef` container for scene-driven layouts |

---

## Best practices

### Use a real background

Glass looks bad on a flat canvas. Put it over:

- a gradient
- an image
- a dense UI
- layered shapes with contrast

### Keep text readable

Do not bury text inside a noisy effect. Use:

```tsx
<div className="relative z-10 text-white">
  Content
</div>
```

### Use stronger blur on bright surfaces

The repo exposes `overLight` for exactly this reason. Bright backgrounds need more blur and stronger shadowing to keep contrast usable.

### Do not overdo chromatic aberration

If the color split is too strong, the element starts looking broken instead of premium.

### Respect browser limitations

The README warns that Safari and Firefox only partially support the effect, especially the displacement part. That means:

- test the fallback
- do not rely on identical rendering everywhere
- avoid hard dependencies on the full effect for critical UI

---

## Minimal DIY version

If you only want the look and do not care about the exact interaction model, this is the minimum viable version:

```tsx
export function SimpleGlass({ children }: { children: React.ReactNode }) {
  return (
    <div
      style={{
        position: "relative",
        borderRadius: 32,
        overflow: "hidden",
        background: "rgba(255,255,255,0.08)",
        backdropFilter: "blur(24px) saturate(150%)",
        border: "1px solid rgba(255,255,255,0.18)",
        boxShadow: "0 12px 40px rgba(0,0,0,0.25)",
        padding: "24px 32px",
      }}
    >
      <div style={{ position: "relative", zIndex: 1, color: "white" }}>
        {children}
      </div>
    </div>
  )
}
```

That is not full liquid glass, but it is a clean starting point.

---

## Better DIY version with displacement

If you want closer behavior, you need a displacement map.

```tsx
const displacementMapUrl = "data:image/jpeg;base64,..."

export function GlassWithFilter({ children }: { children: React.ReactNode }) {
  return (
    <>
      <svg style={{ position: "absolute", width: 0, height: 0 }} aria-hidden="true">
        <defs>
          <filter id="glass-filter">
            <feImage href={displacementMapUrl} result="map" />
            <feDisplacementMap
              in="SourceGraphic"
              in2="map"
              scale={70}
              xChannelSelector="R"
              yChannelSelector="B"
            />
          </filter>
        </defs>
      </svg>

      <div
        style={{
          filter: "url(#glass-filter)",
          backdropFilter: "blur(20px) saturate(140%)",
          borderRadius: 32,
          overflow: "hidden",
        }}
      >
        {children}
      </div>
    </>
  )
}
```

That gets you much closer to a real liquid-like bend.

---

## Implementation checklist

Before calling the effect done, confirm these are all true:

- The background behind the element is visually rich
- Blur and saturation are applied
- The glass has a rounded shape
- There is a warp or displacement layer
- The foreground text remains readable
- Hover and click feel natural
- The layout still works on smaller screens
- Safari and Firefox fallbacks are acceptable

---

## What not to do

Do not:

- apply the effect to huge walls of text
- ignore browser support
- use giant displacement values everywhere
- make the content unreadable
- use the effect where a normal card would be better

This is a visual accent, not a default UI style.

---

## Recommended starting presets

### Card

```tsx
<LiquidGlass
  displacementScale={48}
  blurAmount={0.08}
  saturation={150}
  aberrationIntensity={1.8}
  elasticity={0.18}
  cornerRadius={32}
  padding="24px 28px"
>
  <div>Your card content</div>
</LiquidGlass>
```

### Button

```tsx
<LiquidGlass
  displacementScale={64}
  blurAmount={0.1}
  saturation={130}
  aberrationIntensity={2}
  elasticity={0.35}
  cornerRadius={999}
  padding="10px 18px"
>
  <span>Action</span>
</LiquidGlass>
```

### Floating panel

```tsx
<LiquidGlass
  displacementScale={56}
  blurAmount={0.06}
  saturation={140}
  aberrationIntensity={1.5}
  elasticity={0.22}
  cornerRadius={40}
  padding="28px 32px"
  overLight={false}
>
  <div>Panel content</div>
</LiquidGlass>
```

---

## Bottom line

If you want the Apple-like liquid glass feel, the trick is not just blur. It is the combination of:

- displacement
- edge refraction
- slight chromatic aberration
- elastic pointer response
- a strong visual background

That is what makes the effect look expensive instead of amateur.