lightsparkdev/grid-api · Archived

liquid-glass

Build and reuse the "liquid glass" refraction UI in components/grid-wallet-demo (the LiquidGlass / Glass / GlassOver components). Use this skill when the user asks for a glass / liquid-glass / frosted / refraction / squircle UI element — e.g. "make a glass button", "glass tab bar", "glass card", "glass panel", "glass nav", "make this glass", "glass border that expands on hover", "frosted surface", or to tune the glass effect (refraction, chroma, specular, blur, corner smoothing, shadow).

First seen Jun 18, 2026

Installation

$ npx skills add lightsparkdev/grid-api --skill liquid-glass

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from lightsparkdev/grid-api.

npx skills add lightsparkdev/grid-api

Browse all from lightsparkdev/grid-api

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 26
License LICENSE
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Allowed toolsRead, Glob, Grep

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,319 B
  • docs SUMMARY.md 514 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 15 installs

SKILL.md

Liquid Glass

Reusable refraction glass for components/grid-wallet-demo. Full docs: components/grid-wallet-demo/src/components/liquid-glass/README.md — read it before implementing anything non-trivial.

The rule that prevents 90% of the pain

The glass refracts its own CHILDREN, not the page behind it. There is no "frost whatever is behind me" mode (backdrop-filter can't refract portably). To bend a background you put a copy of it inside the glass. So:

  • Glass over a known backdrop (color / gradient / image / pattern) → use

GlassOver, which makes the copy for you.

  • Glass over live UI behind a small surface (over a static screen) →

achievable: feed the glass a positioned copy of that UI. See "Refract live UI behind a small surface" in the gotchas / README.

  • Glass over arbitrary scrolling/animating DOM → not achievable. Tell the user.

Exception: a big frosted surface (sheet/modal) should NOT refract — the per-frame SVG filter tanks Safari. Use FrostPanel (GPU backdrop-filter + a specular edge). Refraction is for the small, tactile elements.

Skipping this gives a flat panel that doesn't lens (the classic failure).

Pick the right entry point

Need Use
Glass button / tab bar / card / chip over a known bg GlassOver (easiest)
Refract content you already render, or custom backdrop wiring Glass (= LiquidGlass)
A big frosted sheet/modal (no refraction — fast on Safari) FrostPanel (BottomSheet uses it)
A small surface that refracts the (static) screen behind it GlassOver's backdropNode
A lens over the LIVE aurora that must work on Safari WebGL: AuroraLensButton (circle) / AuroraLensPanel (rect squircle)
The phone preview's WebGL stage glass-gl/StageGL — bespoke, don't reuse

SVG vs shader (which renderer): default to the SVG path (Glass / GlassOver) for anything made of live DOM — buttons, tab bars, cards, text, layouts (keeps content selectable/clickable). The shader / WebGL path is only needed when you're refracting content that is not live DOM — a <canvas> drawing (e.g. a generated QR) or a <video> (Safari won't SVG-filter those). There is no auto-switching and no general "glass over a canvas/video" yet: the only WebGL renderer (StageGL) is bespoke to the phone and re-derives the math in GLSL. If a canvas/video glass actually comes up, generalize StageGL (or build a map-fed WebGL glass) on demand — don't assume a drop-in exists.

Minimal usage

import { GlassOver } from '@/components/liquid-glass';

const BG = 'linear-gradient(135deg, #5b9dff, #b07cff)';

<div style={{ background: BG }}>
  <GlassOver backdrop={BG} radius={16} depth={10} scale={18} cornerSmoothing={0.6}>
    <span style={{ display: 'block', padding: '12px 22px', color: '#fff', fontWeight: 600 }}>
      Settings
    </span>
  </GlassOver>
</div>

backdrop = the same CSS background the surface sits on (gets refracted). children = content on top (not refracted). Any GlassConfig field is a prop. Start from a preset (DEFAULTGLASS, PHONESHELL_GLASS) and override. Frosted surfaces (FrostPanel) use the slimmer FrostConfig, not GlassConfig.

Must-know gotchas (details in the README)

  • Hover/resize: animate transform: scale(), never width/height/radius — the

displacement map re-bakes on shape change (jank).

  • Refraction needs texture: over a flat color you only see specular/edge rim.
  • Tiny elements: lower depth/scale or they over-distort.
  • specularRotation is directional (45° puts a bright highlight on the

top-left/bottom-right corners) — rotate or lower edgeStrength to move it.

  • corner-shape: squircle is Chromium-only (graceful circular fallback).
  • Outer drop shadow → round the wrapper. A glass surface clips itself with

overflow: hidden, so an outer box-shadow has to live on a wrapper around the glass (inside, the clip eats it). box-shadow traces that wrapper's own border-radius/corner-shape, not the glass child's — so an unrounded wrapper gives a square halo around round glass. Give the shadow wrapper the same border-radius + corner-shape as the glass (see GlassSymbolButton / GlassWindowButtonGroup .root). Same rule for any border/background painted on a wrapper. Debug heuristic: a square around glass = a rounding-unaware layer.

  • Tiled backgrounds: pass GlassOver's backdropOffset={{x,y}} to align.
  • Circles & pills auto-lens radially (Aave's production circle/pill model,

detected from the geometry — no flag). splay doesn't apply to them; the dome applies to circles only. Don't fight it with per-axis expectations.

  • Live/changing content inside a lens is a Safari minefield — stale

filter-output caching, composited descendants escaping the lens unfiltered (translateZ(0)/will-change/motion's filter: blur(0px) leftovers), canvas/video killing the filter, and a LAYOUT-bounds source-size ceiling. Read "Safari field notes" in the README before attempting; the full experiment is parked on pat/scroll-refraction-experiment.

  • WebKit renders SVG displacement over a copied subtree as EMPTY output at

notification size (confirmed June 2026 — see the README's "Confirmed dead end" postmortem). Don't retry it: use the WebGL lenses for Safari refraction and gate the SVG path to Chromium. Squircle-rect corner rules for Safari (map smoothing with cornerRadii, overlay border-radius intersection, one-element frost, no drop-shadow wrappers) are in the same section.

  • Verifying a bend over a soft backdrop: displacement is invisible without

texture — draw a sharp debug grid through the bent coordinates to check.

  • Big sheets/modals don't refract — they frost. A large displacement lens

re-runs its whole SVG filter every frame while the surface animates, which tanks Safari (CPU feDisplacementMap). Use FrostPanel (GPU backdrop-filter + a static specular edge); keep refractive Glass/GlassOver for the small buttons on top. Example: apps/shared/BottomSheet (FrostPanel) → aurora/PasskeySheet.

  • **Refract live UI behind a small surface:** pass a copy of the behind-UI as

GlassOver's backdropNode, anchored to align, and counter-animate it against any slide so it stays put while the glass slides over it. Behind-UI must be static while open. (Not for big sheets — see above.)

When tuning

There's a live tuning panel: run the demo (npm run dev, port 4000), open the App panel, switch it to swag mode. Sliders map 1:1 to GlassConfig.