glasskit-js 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LiquidGlass.mjs +1 -1
- package/README.md +44 -96
- package/liquid-glass.d.ts +2 -0
- package/liquid-glass.js +14 -6
- package/package.json +1 -1
package/LiquidGlass.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import LG from "./liquid-glass.js";
|
|
|
19
19
|
const GLASS_KEYS = [
|
|
20
20
|
"mode", "frost", "refraction", "depth", "dispersion", "splay",
|
|
21
21
|
"lightAngle", "lightIntensity", "curvature", "convexity",
|
|
22
|
-
"tint", "tintOpacity", "sheen", "sheenColor", "saturate", "brightness", "radius", "background",
|
|
22
|
+
"tint", "tintOpacity", "sheen", "sheenColor", "saturate", "brightness", "shadow", "radius", "background",
|
|
23
23
|
];
|
|
24
24
|
|
|
25
25
|
export default function LiquidGlass({ as: Tag = "div", children, ...props }) {
|
package/README.md
CHANGED
|
@@ -1,54 +1,28 @@
|
|
|
1
1
|
# Glasskit
|
|
2
2
|
|
|
3
|
-
**Drop-in Apple / Figma "Liquid Glass" for the web
|
|
3
|
+
**Drop-in Apple / Figma "Liquid Glass" for the web.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/glasskit-js)
|
|
6
|
+
[](https://bundlephobia.com/package/glasskit-js)
|
|
7
|
+
[](https://www.npmjs.com/package/glasskit-js?activeTab=dependencies)
|
|
8
|
+
[](./liquid-glass.d.ts)
|
|
9
|
+
[](./LICENSE)
|
|
4
10
|
|
|
5
11
|
The only liquid-glass tool that lets you **switch the rendering engine** (pure CSS · SVG
|
|
6
|
-
displacement · cross-browser clone · WebGL), apply it to **any element/shape**,
|
|
7
|
-
|
|
12
|
+
displacement · cross-browser clone · WebGL), apply it to **any element/shape**, and use it
|
|
13
|
+
from **vanilla JS, a web component, or React** — with zero dependencies.
|
|
8
14
|
|
|
9
|
-
>
|
|
15
|
+
> 🎛️ **[Try the generator →](https://amanblog.github.io/glasskit/)** — tune it visually and copy the code in any framework.
|
|
10
16
|
|
|
17
|
+
```bash
|
|
18
|
+
npm i glasskit-js
|
|
11
19
|
```
|
|
12
|
-
liquid-glass.js ← the engine (zero deps, UMD + <glass-kit> web component)
|
|
13
|
-
liquid-glass.d.ts ← TypeScript types
|
|
14
|
-
LiquidGlass.mjs ← React/Next.js wrapper (default export, no JSX — works in any bundler)
|
|
15
|
-
package.json ← npm package "glasskit-js"
|
|
16
|
-
demo.html ← minimal standalone playground
|
|
17
|
-
site/ ← the generator website (static, deploy as-is)
|
|
18
|
-
index.html · app.js · benchmark.html · liquid-glass.js
|
|
19
|
-
bench/ ← automated cross-browser benchmark runner (Playwright)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## The engine
|
|
25
|
-
|
|
26
|
-
### Modes — the switch nobody else gives you
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|------|:---:|---|---|---|
|
|
30
|
-
| `css` | ✗ (blur) | **all** | live backdrop | default product UI, mobile, Safari/FF |
|
|
31
|
-
| `svg` | ✓ | **Chromium** | live backdrop | the "wow" surface on Chrome/Edge |
|
|
32
|
-
| `svg-clone` | ✓ | **all** | a cloned DOM element | cross-browser refraction over DOM |
|
|
33
|
-
| `webgl` | ✓ | **all** | an img/canvas/video | hero over a fixed background/video |
|
|
34
|
-
| `auto` | — | — | — | Chromium→`svg`, else `svg-clone` if `background` set, else `css` |
|
|
35
|
-
|
|
36
|
-
`svg-clone` is the cross-browser trick: Safari/Firefox don't allow an SVG filter in
|
|
37
|
-
`backdrop-filter`, so it **clones the background element and filters the clone** instead.
|
|
38
|
-
It refracts DOM, not `<canvas>` pixels — use `webgl` for canvas/video backgrounds.
|
|
39
|
-
|
|
40
|
-
### Params ↔ Figma's Glass panel
|
|
21
|
+
> npm: **`glasskit-js`** · global: **`Glasskit`** · web component: **`<glass-kit>`**
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|---|---|---|---|---|
|
|
44
|
-
| Frost | `frost` | | curvature (sphere→squircle) | `curvature` |
|
|
45
|
-
| Refraction | `refraction` | | convex↔concave | `convexity` |
|
|
46
|
-
| Depth | `depth` | | tint | `tint`, `tintOpacity` |
|
|
47
|
-
| Dispersion | `dispersion` | | corner radius | `radius` |
|
|
48
|
-
| Splay | `splay` | | | |
|
|
49
|
-
| Light (angle / %) | `lightAngle` / `lightIntensity` | | | |
|
|
23
|
+
---
|
|
50
24
|
|
|
51
|
-
|
|
25
|
+
## Usage
|
|
52
26
|
|
|
53
27
|
```html
|
|
54
28
|
<!-- vanilla / CDN -->
|
|
@@ -74,71 +48,45 @@ import Glass from 'glasskit-js/react';
|
|
|
74
48
|
style={{ borderRadius: 999, padding: '14px 28px' }}>Get tickets</Glass>
|
|
75
49
|
```
|
|
76
50
|
|
|
77
|
-
### Shapes
|
|
78
|
-
Any **rounded rectangle (incl. pills & circles)** works with zero extra code — a
|
|
79
|
-
`ResizeObserver` regenerates the refraction map on resize. Arbitrary outlines (blobs,
|
|
80
|
-
SVG paths) keep the blur/tint/highlight via `clip-path`, but refraction edges assume a
|
|
81
|
-
rounded box; supply a custom displacement map for true custom outlines.
|
|
82
|
-
|
|
83
51
|
---
|
|
84
52
|
|
|
85
|
-
##
|
|
86
|
-
|
|
87
|
-
Static — no build step. Tune visually → switch engine → copy code for React, Vue,
|
|
88
|
-
vanilla, web component, CSS, or Tailwind. Plus a preset gallery and a benchmark page.
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
npx serve site # or: python3 -m http.server --directory site
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**Deploy to Cloudflare Pages:** create a Pages project, set the **build command empty**
|
|
95
|
-
and the **output/root directory to `site`**. Pure static files. (Vercel: framework
|
|
96
|
-
"Other", output dir `site`.) Then set your domain in the `og:`/`canonical` tags and add an
|
|
97
|
-
`og.png` (a generator script lives at `bench/og.mjs`).
|
|
53
|
+
## Modes — the switch nobody else gives you
|
|
98
54
|
|
|
99
|
-
|
|
55
|
+
| Mode | Real refraction | Browsers | Refracts | Best for |
|
|
56
|
+
|------|:---:|---|---|---|
|
|
57
|
+
| `css` | ✗ (blur) | **all** | live backdrop | default product UI, mobile, Safari/FF |
|
|
58
|
+
| `svg` | ✓ | **Chromium** | live backdrop | the "wow" surface on Chrome/Edge |
|
|
59
|
+
| `svg-clone` | ✓ | **all** | a cloned DOM element | cross-browser refraction over DOM |
|
|
60
|
+
| `webgl` | ✓ | **all** | an img/canvas/video | hero over a fixed background/video |
|
|
61
|
+
| `auto` | — | — | — | Chromium→`svg`, else `svg-clone` if `background` set, else `css` |
|
|
100
62
|
|
|
101
|
-
|
|
63
|
+
`svg-clone` is the cross-browser trick: Safari/Firefox don't allow an SVG filter in
|
|
64
|
+
`backdrop-filter`, so it **clones the background element and filters the clone** instead.
|
|
65
|
+
It refracts DOM, not `<canvas>` pixels — use `webgl` for canvas/video backgrounds.
|
|
102
66
|
|
|
103
|
-
|
|
104
|
-
animates them over a live backdrop, and records **avg/min FPS, avg & p95 frame time,
|
|
105
|
-
jank %, and JS heap**. Results are saved per browser in `localStorage`, so running it in
|
|
106
|
-
Chrome → Safari → Firefox builds a cross-browser comparison. Export JSON anytime.
|
|
67
|
+
## Params ↔ Figma's Glass panel
|
|
107
68
|
|
|
108
|
-
|
|
69
|
+
| Figma slider | Option | | Optical extras | Option |
|
|
70
|
+
|---|---|---|---|---|
|
|
71
|
+
| Frost | `frost` | | curvature (sphere→squircle) | `curvature` |
|
|
72
|
+
| Refraction | `refraction` | | convex↔concave | `convexity` |
|
|
73
|
+
| Depth | `depth` | | tint | `tint`, `tintOpacity` |
|
|
74
|
+
| Dispersion | `dispersion` | | corner radius | `radius` |
|
|
75
|
+
| Splay | `splay` | | | |
|
|
76
|
+
| Light (angle / %) | `lightAngle` / `lightIntensity` | | | |
|
|
109
77
|
|
|
110
|
-
|
|
111
|
-
npm i # installs playwright-core
|
|
112
|
-
npm run bench # uses your installed Chrome
|
|
113
|
-
node bench/run-playwright.mjs --dur 2.5 --counts 1,5,15,30,60 --modes css,svg,svg-clone,webgl
|
|
114
|
-
npx playwright install webkit firefox # to also bench Safari & Firefox engines
|
|
115
|
-
```
|
|
116
|
-
Writes `bench/results.json` and `bench/results.csv`.
|
|
78
|
+
## Shapes
|
|
117
79
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
80
|
+
Any **rounded rectangle (incl. pills & circles)** works with zero extra code — a
|
|
81
|
+
`ResizeObserver` regenerates the refraction map on resize. Arbitrary outlines (blobs,
|
|
82
|
+
SVG paths) keep the blur/tint/highlight via `clip-path`, but refraction edges assume a
|
|
83
|
+
rounded box; supply a custom displacement map for true custom outlines.
|
|
121
84
|
|
|
122
85
|
---
|
|
123
86
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Two GitHub Actions handle shipping:
|
|
127
|
-
|
|
128
|
-
- **`.github/workflows/pages.yml`** — deploys `site/` to GitHub Pages on every push to `main` that touches `site/`.
|
|
129
|
-
- **`.github/workflows/release.yml`** — publishes to npm when a `v*` tag is pushed, via **npm Trusted Publishing (OIDC)** — no `NPM_TOKEN`, provenance generated automatically.
|
|
130
|
-
|
|
131
|
-
**One-time bootstrap** (npm requires the package to exist before a trusted publisher can be configured):
|
|
132
|
-
|
|
133
|
-
1. `npm publish --access public` once from a logged-in machine to create `glasskit-js`.
|
|
134
|
-
2. npmjs.com → the package → **Settings → Trusted Publisher** → GitHub Actions, repo `amanblog/glasskit`, workflow `release.yml`.
|
|
135
|
-
|
|
136
|
-
After that, cutting a release is tokenless:
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
npm version patch # bumps package.json + creates the vX.Y.Z tag & commit
|
|
140
|
-
git push --follow-tags # CI verifies tag == version, then publishes with provenance
|
|
141
|
-
```
|
|
87
|
+
Built something with it, or want to hack on the engine, generator, or benchmark?
|
|
88
|
+
See **[CONTRIBUTING.md](./CONTRIBUTING.md)**.
|
|
142
89
|
|
|
143
90
|
## License
|
|
144
|
-
|
|
91
|
+
|
|
92
|
+
MIT — see [LICENSE](./LICENSE).
|
package/liquid-glass.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export interface LiquidGlassOptions {
|
|
|
43
43
|
saturate?: number;
|
|
44
44
|
/** Backdrop brightness (css mode). @default 1.04 */
|
|
45
45
|
brightness?: number;
|
|
46
|
+
/** Outer drop shadow as any CSS box-shadow value; "none" or "" removes it. The inner light border/bezel are controlled by `lightIntensity`. @default "0 8px 30px rgba(0,0,0,0.18)" */
|
|
47
|
+
shadow?: string;
|
|
46
48
|
/** Override corner radius (px). null = read element's border-radius. @default null */
|
|
47
49
|
radius?: number | null;
|
|
48
50
|
/** Element or selector to refract. Required for `svg-clone` and `webgl`. */
|
package/liquid-glass.js
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
sheenColor: '255,255,255', // "r,g,b" — recolor the gloss
|
|
43
43
|
saturate: 1.4,
|
|
44
44
|
brightness: 1.04,
|
|
45
|
+
shadow: '0 8px 30px rgba(0,0,0,0.18)', // outer drop shadow; 'none'/'' removes it, or pass any CSS box-shadow
|
|
45
46
|
radius: null, // null = read element border-radius
|
|
46
47
|
background: null // Element|selector — required for 'svg-clone' & 'webgl'
|
|
47
48
|
};
|
|
@@ -58,6 +59,11 @@
|
|
|
58
59
|
function clamp8(v) { return v < 0 ? 0 : v > 255 ? 255 : Math.round(v); }
|
|
59
60
|
// only ever emit a clean "r,g,b" triplet into inline CSS — blocks url()/expression smuggling
|
|
60
61
|
function safeRGB(v) { return (typeof v === 'string' && /^\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*$/.test(v)) ? v.replace(/\s+/g, '') : '255,255,255'; }
|
|
62
|
+
// allow only box-shadow-shaped CSS (lengths/colors); reject url()/expression/extra declarations
|
|
63
|
+
function safeShadow(v) {
|
|
64
|
+
if (typeof v !== 'string' || !v || v === 'none') return '';
|
|
65
|
+
return /url\(|expression|javascript:|[;{}<>]/i.test(v) ? '' : v;
|
|
66
|
+
}
|
|
61
67
|
function num(v, d) { var n = parseFloat(v); return isFinite(n) ? n : d; }
|
|
62
68
|
function resolveEl(x) { return typeof x === 'string' ? document.querySelector(x) : x; }
|
|
63
69
|
function readRadius(el) { return parseFloat(getComputedStyle(el).borderRadius) || 0; }
|
|
@@ -251,11 +257,13 @@
|
|
|
251
257
|
overlay.style.background = sh <= 0 ? 'none' :
|
|
252
258
|
'linear-gradient(' + (num(o.lightAngle, -45) + 90) + 'deg,rgba(' + sc + ',' + (0.6 * sh).toFixed(3) +
|
|
253
259
|
') 0%,rgba(' + sc + ',0) 30%,rgba(' + sc + ',0) 70%,rgba(' + sc + ',' + (0.14 * sh).toFixed(3) + ') 100%)';
|
|
254
|
-
|
|
260
|
+
// inset light border + bezel (scale with lightIntensity) and a separately controllable outer drop shadow
|
|
261
|
+
var insets =
|
|
255
262
|
'inset 0 0 0 1px rgba(255,255,255,' + (0.30 * li) + '),' +
|
|
256
263
|
'inset ' + (Math.cos(a) * 2).toFixed(1) + 'px ' + (Math.sin(a) * 2).toFixed(1) + 'px 2px rgba(255,255,255,' + (0.5 * li) + '),' +
|
|
257
|
-
'inset ' + (-Math.cos(a) * 2).toFixed(1) + 'px ' + (-Math.sin(a) * 2).toFixed(1) + 'px 6px rgba(0,0,0,.15)
|
|
258
|
-
|
|
264
|
+
'inset ' + (-Math.cos(a) * 2).toFixed(1) + 'px ' + (-Math.sin(a) * 2).toFixed(1) + 'px 6px rgba(0,0,0,.15)';
|
|
265
|
+
var drop = safeShadow(o.shadow);
|
|
266
|
+
overlay.style.boxShadow = drop ? insets + ',' + drop : insets;
|
|
259
267
|
}
|
|
260
268
|
|
|
261
269
|
/* ------------------------------ WebGL ------------------------------ */
|
|
@@ -389,7 +397,7 @@
|
|
|
389
397
|
/* ===================== <glass-kit> web component ===================== */
|
|
390
398
|
var ATTRS = ['mode', 'frost', 'refraction', 'depth', 'dispersion', 'splay', 'light-angle',
|
|
391
399
|
'light-intensity', 'curvature', 'convexity', 'tint', 'tint-opacity', 'sheen', 'sheen-color',
|
|
392
|
-
'radius', 'background'];
|
|
400
|
+
'shadow', 'radius', 'background'];
|
|
393
401
|
function camel(s) { return s.replace(/-([a-z])/g, function (_, c) { return c.toUpperCase(); }); }
|
|
394
402
|
function defineElement() {
|
|
395
403
|
if (typeof customElements === 'undefined' || customElements.get('glass-kit')) return;
|
|
@@ -399,7 +407,7 @@
|
|
|
399
407
|
ATTRS.forEach(function (a) {
|
|
400
408
|
if (!node.hasAttribute(a)) return;
|
|
401
409
|
var v = node.getAttribute(a), key = camel(a);
|
|
402
|
-
opts[key] = (a === 'mode' || a === 'tint' || a === 'sheen-color' || a === 'background') ? v : parseFloat(v);
|
|
410
|
+
opts[key] = (a === 'mode' || a === 'tint' || a === 'sheen-color' || a === 'shadow' || a === 'background') ? v : parseFloat(v);
|
|
403
411
|
});
|
|
404
412
|
return opts;
|
|
405
413
|
}
|
|
@@ -416,5 +424,5 @@
|
|
|
416
424
|
}
|
|
417
425
|
if (typeof window !== 'undefined') { if (document.readyState !== 'loading') defineElement(); else document.addEventListener('DOMContentLoaded', defineElement); }
|
|
418
426
|
|
|
419
|
-
return { apply: apply, defineElement: defineElement, isChromium: isChromium, pickMode: pickMode, DEFAULTS: DEFAULTS, version: '1.0.
|
|
427
|
+
return { apply: apply, defineElement: defineElement, isChromium: isChromium, pickMode: pickMode, DEFAULTS: DEFAULTS, version: '1.0.2' };
|
|
420
428
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glasskit-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Drop-in Apple/Figma 'Liquid Glass' for any element — switch between pure CSS, SVG displacement (live backdrop), cross-browser clone-mode, or WebGL. Real refraction, chromatic aberration, specular highlight. Zero dependencies. Class + <liquid-glass> web component.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"liquid-glass",
|