@marcosdemik/liquidglass 2.0.3 → 2.0.4
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/dist/index.cjs +31 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +30 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -63,6 +63,7 @@ __export(index_exports, {
|
|
|
63
63
|
LiquidGlassButton: () => LiquidGlassButton,
|
|
64
64
|
cn: () => cn,
|
|
65
65
|
generateGlassMaps: () => generateGlassMaps,
|
|
66
|
+
getCachedGlassMaps: () => getCachedGlassMaps,
|
|
66
67
|
revokeGlassMaps: () => revokeGlassMaps
|
|
67
68
|
});
|
|
68
69
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -202,6 +203,25 @@ async function generateGlassMaps(opts) {
|
|
|
202
203
|
_mapCache.set(key, result);
|
|
203
204
|
return result;
|
|
204
205
|
}
|
|
206
|
+
function getCachedGlassMaps(opts) {
|
|
207
|
+
var _a;
|
|
208
|
+
const {
|
|
209
|
+
width,
|
|
210
|
+
height,
|
|
211
|
+
radius = 60,
|
|
212
|
+
edgeSize = 30,
|
|
213
|
+
intensity = 0.7,
|
|
214
|
+
specularWidth = 0.02,
|
|
215
|
+
quality = 2
|
|
216
|
+
} = opts;
|
|
217
|
+
const scale = Math.max(1, Math.round(quality));
|
|
218
|
+
const rw = width * scale;
|
|
219
|
+
const rh = height * scale;
|
|
220
|
+
const r = Math.min(radius * scale, rw / 2, rh / 2);
|
|
221
|
+
const borderSoftness = edgeSize * intensity * scale;
|
|
222
|
+
const specPx = specularWidth * Math.min(rw, rh);
|
|
223
|
+
return (_a = _mapCache.get(cacheKey(rw, rh, r, borderSoftness, specPx))) != null ? _a : null;
|
|
224
|
+
}
|
|
205
225
|
function revokeGlassMaps(maps) {
|
|
206
226
|
URL.revokeObjectURL(maps.displacement);
|
|
207
227
|
URL.revokeObjectURL(maps.specular);
|
|
@@ -259,10 +279,18 @@ var LiquidGlassButton = (0, import_react.forwardRef)(
|
|
|
259
279
|
const displacerRef = (0, import_react.useRef)(null);
|
|
260
280
|
const blurRef = (0, import_react.useRef)(null);
|
|
261
281
|
const filterId = "lg" + (0, import_react.useId)().replace(/:/g, "");
|
|
262
|
-
const
|
|
282
|
+
const mapOpts = { width, height, radius, edgeSize, intensity, specularWidth, quality };
|
|
283
|
+
const [maps, setMaps] = (0, import_react.useState)(
|
|
284
|
+
() => getCachedGlassMaps(mapOpts)
|
|
285
|
+
);
|
|
263
286
|
(0, import_react.useEffect)(() => {
|
|
287
|
+
const cached = getCachedGlassMaps(mapOpts);
|
|
288
|
+
if (cached) {
|
|
289
|
+
setMaps(cached);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
264
292
|
let cancelled = false;
|
|
265
|
-
generateGlassMaps(
|
|
293
|
+
generateGlassMaps(mapOpts).then((m) => {
|
|
266
294
|
if (!cancelled) setMaps(m);
|
|
267
295
|
});
|
|
268
296
|
return () => {
|
|
@@ -463,6 +491,7 @@ var LiquidGlassButton = (0, import_react.forwardRef)(
|
|
|
463
491
|
LiquidGlassButton,
|
|
464
492
|
cn,
|
|
465
493
|
generateGlassMaps,
|
|
494
|
+
getCachedGlassMaps,
|
|
466
495
|
revokeGlassMaps
|
|
467
496
|
});
|
|
468
497
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/liquid-glass-button.tsx","../src/utils.ts","../src/generate-displacement-map.ts"],"sourcesContent":["export { LiquidGlassButton } from \"./liquid-glass-button\";\nexport type { LiquidGlassButtonProps } from \"./liquid-glass-button\";\nexport { generateGlassMaps, revokeGlassMaps } from \"./generate-displacement-map\";\nexport type { MapOptions } from \"./generate-displacement-map\";\nexport { cn } from \"./utils\";\n","import React, { useRef, useEffect, useState, useId, forwardRef } from \"react\";\nimport gsap from \"gsap\";\nimport { cn } from \"./utils\";\nimport { generateGlassMaps, revokeGlassMaps } from \"./generate-displacement-map\";\n\nexport interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Button width in px */\n width?: number;\n /** Button height in px */\n height?: number;\n /** Border radius in px */\n radius?: number;\n /** Edge thickness of the glass refraction zone */\n edgeSize?: number;\n /** Edge refraction intensity (0-1) */\n intensity?: number;\n /** Specular rim thickness relative to size (0-1) */\n specularWidth?: number;\n /** feDisplacementMap scale - how much the background refracts */\n displacement?: number;\n /** Gaussian blur applied to the background */\n blur?: number;\n /** Saturation applied to the displaced result */\n saturation?: number;\n /** Brightness boost on the backdrop-filter (1 = normal) */\n brightness?: number;\n /** Background tint color of the glass */\n glassColor?: string;\n /** Scale multiplier on hover */\n hoverScale?: number;\n /** Displacement scale on hover */\n hoverDisplacement?: number;\n /** Blur amount on hover */\n hoverBlur?: number;\n /** Duration of hover animation in seconds */\n hoverDuration?: number;\n /** Disable all GSAP animations */\n disableAnimation?: boolean;\n /** Supersampling quality for the displacement map (default 2, higher = smoother) */\n quality?: number;\n}\n\nexport const LiquidGlassButton = forwardRef<HTMLButtonElement, LiquidGlassButtonProps>(\n function LiquidGlassButton({\n children, className, style,\n width = 300,\n height = 56,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n displacement = 55,\n blur = 1,\n saturation = 150,\n brightness = 1.1,\n glassColor = \"transparent\",\n hoverScale = 1.08,\n hoverDisplacement = 125,\n hoverBlur = 4,\n hoverDuration = 0.25,\n disableAnimation = false,\n quality = 2,\n ...props\n }, ref) {\n const internalRef = useRef<HTMLButtonElement>(null);\n const buttonRef = (ref as React.RefObject<HTMLButtonElement>) ?? internalRef;\n\n const displacerRef = useRef<SVGFEDisplacementMapElement>(null);\n const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n\n const filterId = \"lg\" + useId().replace(/:/g, \"\");\n\n const [maps, setMaps] = useState<{ displacement: string; specular: string } | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality })\n .then((m) => {\n if (!cancelled) setMaps(m);\n });\n\n return () => {\n cancelled = true;\n };\n }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);\n\n useEffect(() => {\n return () => {\n if (maps) revokeGlassMaps(maps);\n };\n }, [maps]);\n\n useEffect(() => {\n const button = buttonRef.current;\n const displacer = displacerRef.current;\n const blurEl = blurRef.current;\n if (!button || !displacer || !blurEl || disableAnimation) return;\n\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const fx = {\n displacement: displacement,\n blur: blur,\n };\n\n const sync = () => {\n displacer.setAttribute(\"scale\", fx.displacement.toString());\n blurEl.setAttribute(\"stdDeviation\", fx.blur.toString());\n };\n\n sync();\n\n const onEnter = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: hoverDisplacement,\n blur: hoverBlur,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: hoverScale,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n });\n };\n\n const onLeave = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: displacement,\n blur: blur,\n duration: hoverDuration,\n ease: \"power2.out\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: 1,\n duration: hoverDuration,\n ease: \"power2.out\",\n });\n };\n\n const onClick = () => {\n gsap.killTweensOf(button);\n const cur = gsap.getProperty(button, \"scale\") as number;\n gsap.timeline()\n .to(button, { scale: cur * 0.92, duration: 0.08, ease: \"power2.in\" })\n .to(button, { scale: hoverScale, duration: 0.25, ease: \"back.out(2)\" });\n };\n\n button.addEventListener(\"pointerenter\", onEnter);\n button.addEventListener(\"pointerleave\", onLeave);\n button.addEventListener(\"click\", onClick);\n\n return () => {\n button.removeEventListener(\"pointerenter\", onEnter);\n button.removeEventListener(\"pointerleave\", onLeave);\n button.removeEventListener(\"click\", onClick);\n gsap.killTweensOf([button, fx]);\n };\n }, [buttonRef, maps, displacement, blur, hoverScale, hoverDisplacement, hoverBlur, hoverDuration, disableAnimation]);\n\n if (!maps) return null;\n\n return (\n <>\n <button\n ref={buttonRef}\n className={cn(\"relative overflow-hidden shadow-lg cursor-pointer\", className)}\n style={{ width, height, borderRadius: radius, border: \"none\", background: glassColor, ...style }}\n {...props}\n >\n <div\n className=\"absolute inset-0\"\n style={{\n backdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n WebkitBackdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n borderRadius: \"inherit\",\n willChange: \"backdrop-filter\",\n transform: \"translateZ(0)\",\n }}\n />\n <div\n className=\"absolute inset-0 inline-flex items-center justify-center font-bold text-white\"\n style={{ background: \"hsl(0 100% 100% / 15%)\", borderRadius: \"inherit\" }}\n >\n {children}\n </div>\n </button>\n\n <svg\n colorInterpolationFilters=\"sRGB\"\n style={{ position: \"absolute\", width: 0, height: 0, overflow: \"hidden\" }}\n aria-hidden=\"true\"\n >\n <defs>\n <filter id={filterId}>\n <feGaussianBlur\n ref={blurRef}\n in=\"SourceGraphic\"\n stdDeviation={blur}\n result=\"blurred_source\"\n />\n <feImage\n href={maps.displacement}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"displacement_map\"\n />\n <feDisplacementMap\n ref={displacerRef}\n in=\"blurred_source\"\n in2=\"displacement_map\"\n scale={displacement}\n xChannelSelector=\"R\"\n yChannelSelector=\"G\"\n result=\"displaced\"\n />\n <feColorMatrix\n in=\"displaced\"\n type=\"saturate\"\n result=\"displaced_saturated\"\n values={saturation.toString()}\n />\n <feImage\n href={maps.specular}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"specular_layer\"\n />\n <feGaussianBlur\n in=\"specular_layer\"\n stdDeviation=\"1\"\n result=\"blurred_specular_layer\"\n />\n <feComposite\n in=\"displaced_saturated\"\n in2=\"blurred_specular_layer\"\n operator=\"in\"\n result=\"final_specular_layer\"\n />\n <feBlend\n in=\"final_specular_layer\"\n in2=\"displaced\"\n mode=\"normal\"\n />\n </filter>\n </defs>\n </svg>\n </>\n );\n }\n);\n","export function cn(...classes: (string | undefined | null | false)[]) {\n return classes.filter(Boolean).join(\" \");\n}\n","export interface MapOptions {\n width: number;\n height: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n specularWidth?: number;\n /** Supersampling multiplier for the displacement map (default: 2). Higher = smoother gradients. */\n quality?: number;\n}\n\nconst VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;\n\nconst FRAG = `\nprecision highp float;\nuniform vec2 uRes;\nuniform float uRadius;\nuniform float uBorderSoftness;\nuniform float uSpecularWidth;\nuniform int uMode; // 0 = displacement, 1 = specular\n\nfloat sdRoundedBox(vec2 p, vec2 b, float r){\n r = min(r, min(b.x, b.y));\n vec2 q = abs(p) - b + r;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;\n}\n\nvec3 calcNormal(vec2 p, vec2 b, float r){\n float e = max(0.5, min(b.x, b.y) * 0.01);\n vec2 h = vec2(e, 0.0);\n return normalize(vec3(\n sdRoundedBox(p+h.xy, b, r) - sdRoundedBox(p-h.xy, b, r),\n sdRoundedBox(p+h.yx, b, r) - sdRoundedBox(p-h.yx, b, r),\n -e * 2.0\n ));\n}\n\nvoid main(){\n vec2 p = gl_FragCoord.xy - uRes * 0.5;\n vec2 halfSize = uRes * 0.5 - 1.0;\n float d = sdRoundedBox(p, halfSize, uRadius);\n\n if(d > 0.0){ gl_FragColor = vec4(0.0); return; }\n\n if(uMode == 0){\n vec3 n = calcNormal(p, halfSize, uRadius);\n vec3 nc = n * 0.5 + 0.5;\n float border = smoothstep(-uBorderSoftness, 0.0, d);\n vec3 flat_ = vec3(0.5, 0.5, 1.0);\n gl_FragColor = vec4(mix(flat_, nc, border), 1.0);\n } else {\n float rim = smoothstep(-uSpecularWidth - 2.0, -uSpecularWidth, d)\n * (1.0 - smoothstep(-2.0, 0.0, d));\n float glow = smoothstep(-uBorderSoftness, 0.0, d) * 0.1;\n float s = clamp(rim + glow, 0.0, 1.0);\n gl_FragColor = vec4(vec3(s), s);\n }\n}\n`;\n\nfunction compile(gl: WebGLRenderingContext, type: number, src: string) {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n return s;\n}\n\nlet _cachedProgram: { gl: WebGLRenderingContext; program: WebGLProgram; canvas: HTMLCanvasElement } | null = null;\n\nfunction getGL() {\n if (_cachedProgram) return _cachedProgram;\n\n const canvas = document.createElement(\"canvas\");\n const gl = canvas.getContext(\"webgl\", { preserveDrawingBuffer: true, premultipliedAlpha: false })!;\n\n const vs = compile(gl, gl.VERTEX_SHADER, VERT);\n const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = gl.createProgram()!;\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n gl.useProgram(program);\n\n const buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);\n const pos = gl.getAttribLocation(program, \"position\");\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n _cachedProgram = { gl, program, canvas };\n return _cachedProgram;\n}\n\n// ── Cache ──────────────────────────────────────────────────────\n\nconst _mapCache = new Map<string, { displacement: string; specular: string }>();\n\nfunction cacheKey(\n w: number, h: number, r: number, bs: number, sw: number,\n): string {\n return `${w}|${h}|${r}|${bs}|${sw}`;\n}\n\n// ── Render ─────────────────────────────────────────────────────\n\nfunction renderToBlob(\n width: number,\n height: number,\n radius: number,\n borderSoftness: number,\n specularWidth: number,\n mode: number,\n): Promise<string> {\n const { gl, program, canvas } = getGL();\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(program);\n\n gl.uniform2f(gl.getUniformLocation(program, \"uRes\"), width, height);\n gl.uniform1f(gl.getUniformLocation(program, \"uRadius\"), radius);\n gl.uniform1f(gl.getUniformLocation(program, \"uBorderSoftness\"), borderSoftness);\n gl.uniform1f(gl.getUniformLocation(program, \"uSpecularWidth\"), specularWidth);\n gl.uniform1i(gl.getUniformLocation(program, \"uMode\"), mode);\n\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\n return new Promise((resolve) => {\n canvas.toBlob((blob) => {\n resolve(URL.createObjectURL(blob!));\n }, \"image/png\");\n });\n}\n\n// ── Public API ─────────────────────────────────────────────────\n\nexport async function generateGlassMaps(opts: MapOptions): Promise<{\n displacement: string;\n specular: string;\n}> {\n const {\n width,\n height,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n quality = 2,\n } = opts;\n\n const scale = Math.max(1, Math.round(quality));\n const rw = width * scale;\n const rh = height * scale;\n\n const r = Math.min(radius * scale, rw / 2, rh / 2);\n const borderSoftness = edgeSize * intensity * scale;\n const specPx = specularWidth * Math.min(rw, rh);\n\n const key = cacheKey(rw, rh, r, borderSoftness, specPx);\n const cached = _mapCache.get(key);\n if (cached) return cached;\n\n const [displacement, specular] = await Promise.all([\n renderToBlob(rw, rh, r, borderSoftness, specPx, 0),\n renderToBlob(rw, rh, r, borderSoftness, specPx, 1),\n ]);\n\n const result = { displacement, specular };\n _mapCache.set(key, result);\n return result;\n}\n\nexport function revokeGlassMaps(maps: { displacement: string; specular: string }) {\n URL.revokeObjectURL(maps.displacement);\n URL.revokeObjectURL(maps.specular);\n}\n"],"mappings":"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","names":["LiquidGlassButton","gsap"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/liquid-glass-button.tsx","../src/utils.ts","../src/generate-displacement-map.ts"],"sourcesContent":["export { LiquidGlassButton } from \"./liquid-glass-button\";\nexport type { LiquidGlassButtonProps } from \"./liquid-glass-button\";\nexport { generateGlassMaps, getCachedGlassMaps, revokeGlassMaps } from \"./generate-displacement-map\";\nexport type { MapOptions } from \"./generate-displacement-map\";\nexport { cn } from \"./utils\";\n","import React, { useRef, useEffect, useState, useId, forwardRef } from \"react\";\nimport gsap from \"gsap\";\nimport { cn } from \"./utils\";\nimport { generateGlassMaps, getCachedGlassMaps, revokeGlassMaps } from \"./generate-displacement-map\";\n\nexport interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Button width in px */\n width?: number;\n /** Button height in px */\n height?: number;\n /** Border radius in px */\n radius?: number;\n /** Edge thickness of the glass refraction zone */\n edgeSize?: number;\n /** Edge refraction intensity (0-1) */\n intensity?: number;\n /** Specular rim thickness relative to size (0-1) */\n specularWidth?: number;\n /** feDisplacementMap scale - how much the background refracts */\n displacement?: number;\n /** Gaussian blur applied to the background */\n blur?: number;\n /** Saturation applied to the displaced result */\n saturation?: number;\n /** Brightness boost on the backdrop-filter (1 = normal) */\n brightness?: number;\n /** Background tint color of the glass */\n glassColor?: string;\n /** Scale multiplier on hover */\n hoverScale?: number;\n /** Displacement scale on hover */\n hoverDisplacement?: number;\n /** Blur amount on hover */\n hoverBlur?: number;\n /** Duration of hover animation in seconds */\n hoverDuration?: number;\n /** Disable all GSAP animations */\n disableAnimation?: boolean;\n /** Supersampling quality for the displacement map (default 2, higher = smoother) */\n quality?: number;\n}\n\nexport const LiquidGlassButton = forwardRef<HTMLButtonElement, LiquidGlassButtonProps>(\n function LiquidGlassButton({\n children, className, style,\n width = 300,\n height = 56,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n displacement = 55,\n blur = 1,\n saturation = 150,\n brightness = 1.1,\n glassColor = \"transparent\",\n hoverScale = 1.08,\n hoverDisplacement = 125,\n hoverBlur = 4,\n hoverDuration = 0.25,\n disableAnimation = false,\n quality = 2,\n ...props\n }, ref) {\n const internalRef = useRef<HTMLButtonElement>(null);\n const buttonRef = (ref as React.RefObject<HTMLButtonElement>) ?? internalRef;\n\n const displacerRef = useRef<SVGFEDisplacementMapElement>(null);\n const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n\n const filterId = \"lg\" + useId().replace(/:/g, \"\");\n\n const mapOpts = { width, height, radius, edgeSize, intensity, specularWidth, quality };\n const [maps, setMaps] = useState<{ displacement: string; specular: string } | null>(\n () => getCachedGlassMaps(mapOpts),\n );\n\n useEffect(() => {\n // If already have maps from cache, skip\n const cached = getCachedGlassMaps(mapOpts);\n if (cached) {\n setMaps(cached);\n return;\n }\n\n let cancelled = false;\n generateGlassMaps(mapOpts).then((m) => {\n if (!cancelled) setMaps(m);\n });\n\n return () => { cancelled = true; };\n }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);\n\n useEffect(() => {\n return () => {\n if (maps) revokeGlassMaps(maps);\n };\n }, [maps]);\n\n useEffect(() => {\n const button = buttonRef.current;\n const displacer = displacerRef.current;\n const blurEl = blurRef.current;\n if (!button || !displacer || !blurEl || disableAnimation) return;\n\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const fx = {\n displacement: displacement,\n blur: blur,\n };\n\n const sync = () => {\n displacer.setAttribute(\"scale\", fx.displacement.toString());\n blurEl.setAttribute(\"stdDeviation\", fx.blur.toString());\n };\n\n sync();\n\n const onEnter = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: hoverDisplacement,\n blur: hoverBlur,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: hoverScale,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n });\n };\n\n const onLeave = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: displacement,\n blur: blur,\n duration: hoverDuration,\n ease: \"power2.out\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: 1,\n duration: hoverDuration,\n ease: \"power2.out\",\n });\n };\n\n const onClick = () => {\n gsap.killTweensOf(button);\n const cur = gsap.getProperty(button, \"scale\") as number;\n gsap.timeline()\n .to(button, { scale: cur * 0.92, duration: 0.08, ease: \"power2.in\" })\n .to(button, { scale: hoverScale, duration: 0.25, ease: \"back.out(2)\" });\n };\n\n button.addEventListener(\"pointerenter\", onEnter);\n button.addEventListener(\"pointerleave\", onLeave);\n button.addEventListener(\"click\", onClick);\n\n return () => {\n button.removeEventListener(\"pointerenter\", onEnter);\n button.removeEventListener(\"pointerleave\", onLeave);\n button.removeEventListener(\"click\", onClick);\n gsap.killTweensOf([button, fx]);\n };\n }, [buttonRef, maps, displacement, blur, hoverScale, hoverDisplacement, hoverBlur, hoverDuration, disableAnimation]);\n\n if (!maps) return null;\n\n return (\n <>\n <button\n ref={buttonRef}\n className={cn(\"relative overflow-hidden shadow-lg cursor-pointer\", className)}\n style={{ width, height, borderRadius: radius, border: \"none\", background: glassColor, ...style }}\n {...props}\n >\n <div\n className=\"absolute inset-0\"\n style={{\n backdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n WebkitBackdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n borderRadius: \"inherit\",\n willChange: \"backdrop-filter\",\n transform: \"translateZ(0)\",\n }}\n />\n <div\n className=\"absolute inset-0 inline-flex items-center justify-center font-bold text-white\"\n style={{ background: \"hsl(0 100% 100% / 15%)\", borderRadius: \"inherit\" }}\n >\n {children}\n </div>\n </button>\n\n <svg\n colorInterpolationFilters=\"sRGB\"\n style={{ position: \"absolute\", width: 0, height: 0, overflow: \"hidden\" }}\n aria-hidden=\"true\"\n >\n <defs>\n <filter id={filterId}>\n <feGaussianBlur\n ref={blurRef}\n in=\"SourceGraphic\"\n stdDeviation={blur}\n result=\"blurred_source\"\n />\n <feImage\n href={maps.displacement}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"displacement_map\"\n />\n <feDisplacementMap\n ref={displacerRef}\n in=\"blurred_source\"\n in2=\"displacement_map\"\n scale={displacement}\n xChannelSelector=\"R\"\n yChannelSelector=\"G\"\n result=\"displaced\"\n />\n <feColorMatrix\n in=\"displaced\"\n type=\"saturate\"\n result=\"displaced_saturated\"\n values={saturation.toString()}\n />\n <feImage\n href={maps.specular}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"specular_layer\"\n />\n <feGaussianBlur\n in=\"specular_layer\"\n stdDeviation=\"1\"\n result=\"blurred_specular_layer\"\n />\n <feComposite\n in=\"displaced_saturated\"\n in2=\"blurred_specular_layer\"\n operator=\"in\"\n result=\"final_specular_layer\"\n />\n <feBlend\n in=\"final_specular_layer\"\n in2=\"displaced\"\n mode=\"normal\"\n />\n </filter>\n </defs>\n </svg>\n </>\n );\n }\n);\n","export function cn(...classes: (string | undefined | null | false)[]) {\n return classes.filter(Boolean).join(\" \");\n}\n","export interface MapOptions {\n width: number;\n height: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n specularWidth?: number;\n /** Supersampling multiplier for the displacement map (default: 2). Higher = smoother gradients. */\n quality?: number;\n}\n\nconst VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;\n\nconst FRAG = `\nprecision highp float;\nuniform vec2 uRes;\nuniform float uRadius;\nuniform float uBorderSoftness;\nuniform float uSpecularWidth;\nuniform int uMode; // 0 = displacement, 1 = specular\n\nfloat sdRoundedBox(vec2 p, vec2 b, float r){\n r = min(r, min(b.x, b.y));\n vec2 q = abs(p) - b + r;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;\n}\n\nvec3 calcNormal(vec2 p, vec2 b, float r){\n float e = max(0.5, min(b.x, b.y) * 0.01);\n vec2 h = vec2(e, 0.0);\n return normalize(vec3(\n sdRoundedBox(p+h.xy, b, r) - sdRoundedBox(p-h.xy, b, r),\n sdRoundedBox(p+h.yx, b, r) - sdRoundedBox(p-h.yx, b, r),\n -e * 2.0\n ));\n}\n\nvoid main(){\n vec2 p = gl_FragCoord.xy - uRes * 0.5;\n vec2 halfSize = uRes * 0.5 - 1.0;\n float d = sdRoundedBox(p, halfSize, uRadius);\n\n if(d > 0.0){ gl_FragColor = vec4(0.0); return; }\n\n if(uMode == 0){\n vec3 n = calcNormal(p, halfSize, uRadius);\n vec3 nc = n * 0.5 + 0.5;\n float border = smoothstep(-uBorderSoftness, 0.0, d);\n vec3 flat_ = vec3(0.5, 0.5, 1.0);\n gl_FragColor = vec4(mix(flat_, nc, border), 1.0);\n } else {\n float rim = smoothstep(-uSpecularWidth - 2.0, -uSpecularWidth, d)\n * (1.0 - smoothstep(-2.0, 0.0, d));\n float glow = smoothstep(-uBorderSoftness, 0.0, d) * 0.1;\n float s = clamp(rim + glow, 0.0, 1.0);\n gl_FragColor = vec4(vec3(s), s);\n }\n}\n`;\n\nfunction compile(gl: WebGLRenderingContext, type: number, src: string) {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n return s;\n}\n\nlet _cachedProgram: { gl: WebGLRenderingContext; program: WebGLProgram; canvas: HTMLCanvasElement } | null = null;\n\nfunction getGL() {\n if (_cachedProgram) return _cachedProgram;\n\n const canvas = document.createElement(\"canvas\");\n const gl = canvas.getContext(\"webgl\", { preserveDrawingBuffer: true, premultipliedAlpha: false })!;\n\n const vs = compile(gl, gl.VERTEX_SHADER, VERT);\n const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = gl.createProgram()!;\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n gl.useProgram(program);\n\n const buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);\n const pos = gl.getAttribLocation(program, \"position\");\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n _cachedProgram = { gl, program, canvas };\n return _cachedProgram;\n}\n\n// ── Cache ──────────────────────────────────────────────────────\n\nconst _mapCache = new Map<string, { displacement: string; specular: string }>();\n\nfunction cacheKey(\n w: number, h: number, r: number, bs: number, sw: number,\n): string {\n return `${w}|${h}|${r}|${bs}|${sw}`;\n}\n\n// ── Render ─────────────────────────────────────────────────────\n\nfunction renderToBlob(\n width: number,\n height: number,\n radius: number,\n borderSoftness: number,\n specularWidth: number,\n mode: number,\n): Promise<string> {\n const { gl, program, canvas } = getGL();\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(program);\n\n gl.uniform2f(gl.getUniformLocation(program, \"uRes\"), width, height);\n gl.uniform1f(gl.getUniformLocation(program, \"uRadius\"), radius);\n gl.uniform1f(gl.getUniformLocation(program, \"uBorderSoftness\"), borderSoftness);\n gl.uniform1f(gl.getUniformLocation(program, \"uSpecularWidth\"), specularWidth);\n gl.uniform1i(gl.getUniformLocation(program, \"uMode\"), mode);\n\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\n return new Promise((resolve) => {\n canvas.toBlob((blob) => {\n resolve(URL.createObjectURL(blob!));\n }, \"image/png\");\n });\n}\n\n// ── Public API ─────────────────────────────────────────────────\n\nexport async function generateGlassMaps(opts: MapOptions): Promise<{\n displacement: string;\n specular: string;\n}> {\n const {\n width,\n height,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n quality = 2,\n } = opts;\n\n const scale = Math.max(1, Math.round(quality));\n const rw = width * scale;\n const rh = height * scale;\n\n const r = Math.min(radius * scale, rw / 2, rh / 2);\n const borderSoftness = edgeSize * intensity * scale;\n const specPx = specularWidth * Math.min(rw, rh);\n\n const key = cacheKey(rw, rh, r, borderSoftness, specPx);\n const cached = _mapCache.get(key);\n if (cached) return cached;\n\n const [displacement, specular] = await Promise.all([\n renderToBlob(rw, rh, r, borderSoftness, specPx, 0),\n renderToBlob(rw, rh, r, borderSoftness, specPx, 1),\n ]);\n\n const result = { displacement, specular };\n _mapCache.set(key, result);\n return result;\n}\n\nexport function getCachedGlassMaps(opts: MapOptions): { displacement: string; specular: string } | null {\n const {\n width,\n height,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n quality = 2,\n } = opts;\n\n const scale = Math.max(1, Math.round(quality));\n const rw = width * scale;\n const rh = height * scale;\n\n const r = Math.min(radius * scale, rw / 2, rh / 2);\n const borderSoftness = edgeSize * intensity * scale;\n const specPx = specularWidth * Math.min(rw, rh);\n\n return _mapCache.get(cacheKey(rw, rh, r, borderSoftness, specPx)) ?? null;\n}\n\nexport function revokeGlassMaps(maps: { displacement: string; specular: string }) {\n URL.revokeObjectURL(maps.displacement);\n URL.revokeObjectURL(maps.specular);\n}\n"],"mappings":"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","names":["LiquidGlassButton","gsap"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -52,6 +52,10 @@ declare function generateGlassMaps(opts: MapOptions): Promise<{
|
|
|
52
52
|
displacement: string;
|
|
53
53
|
specular: string;
|
|
54
54
|
}>;
|
|
55
|
+
declare function getCachedGlassMaps(opts: MapOptions): {
|
|
56
|
+
displacement: string;
|
|
57
|
+
specular: string;
|
|
58
|
+
} | null;
|
|
55
59
|
declare function revokeGlassMaps(maps: {
|
|
56
60
|
displacement: string;
|
|
57
61
|
specular: string;
|
|
@@ -59,4 +63,4 @@ declare function revokeGlassMaps(maps: {
|
|
|
59
63
|
|
|
60
64
|
declare function cn(...classes: (string | undefined | null | false)[]): string;
|
|
61
65
|
|
|
62
|
-
export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps, revokeGlassMaps };
|
|
66
|
+
export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps, getCachedGlassMaps, revokeGlassMaps };
|
package/dist/index.d.ts
CHANGED
|
@@ -52,6 +52,10 @@ declare function generateGlassMaps(opts: MapOptions): Promise<{
|
|
|
52
52
|
displacement: string;
|
|
53
53
|
specular: string;
|
|
54
54
|
}>;
|
|
55
|
+
declare function getCachedGlassMaps(opts: MapOptions): {
|
|
56
|
+
displacement: string;
|
|
57
|
+
specular: string;
|
|
58
|
+
} | null;
|
|
55
59
|
declare function revokeGlassMaps(maps: {
|
|
56
60
|
displacement: string;
|
|
57
61
|
specular: string;
|
|
@@ -59,4 +63,4 @@ declare function revokeGlassMaps(maps: {
|
|
|
59
63
|
|
|
60
64
|
declare function cn(...classes: (string | undefined | null | false)[]): string;
|
|
61
65
|
|
|
62
|
-
export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps, revokeGlassMaps };
|
|
66
|
+
export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps, getCachedGlassMaps, revokeGlassMaps };
|
package/dist/index.js
CHANGED
|
@@ -166,6 +166,25 @@ async function generateGlassMaps(opts) {
|
|
|
166
166
|
_mapCache.set(key, result);
|
|
167
167
|
return result;
|
|
168
168
|
}
|
|
169
|
+
function getCachedGlassMaps(opts) {
|
|
170
|
+
var _a;
|
|
171
|
+
const {
|
|
172
|
+
width,
|
|
173
|
+
height,
|
|
174
|
+
radius = 60,
|
|
175
|
+
edgeSize = 30,
|
|
176
|
+
intensity = 0.7,
|
|
177
|
+
specularWidth = 0.02,
|
|
178
|
+
quality = 2
|
|
179
|
+
} = opts;
|
|
180
|
+
const scale = Math.max(1, Math.round(quality));
|
|
181
|
+
const rw = width * scale;
|
|
182
|
+
const rh = height * scale;
|
|
183
|
+
const r = Math.min(radius * scale, rw / 2, rh / 2);
|
|
184
|
+
const borderSoftness = edgeSize * intensity * scale;
|
|
185
|
+
const specPx = specularWidth * Math.min(rw, rh);
|
|
186
|
+
return (_a = _mapCache.get(cacheKey(rw, rh, r, borderSoftness, specPx))) != null ? _a : null;
|
|
187
|
+
}
|
|
169
188
|
function revokeGlassMaps(maps) {
|
|
170
189
|
URL.revokeObjectURL(maps.displacement);
|
|
171
190
|
URL.revokeObjectURL(maps.specular);
|
|
@@ -223,10 +242,18 @@ var LiquidGlassButton = forwardRef(
|
|
|
223
242
|
const displacerRef = useRef(null);
|
|
224
243
|
const blurRef = useRef(null);
|
|
225
244
|
const filterId = "lg" + useId().replace(/:/g, "");
|
|
226
|
-
const
|
|
245
|
+
const mapOpts = { width, height, radius, edgeSize, intensity, specularWidth, quality };
|
|
246
|
+
const [maps, setMaps] = useState(
|
|
247
|
+
() => getCachedGlassMaps(mapOpts)
|
|
248
|
+
);
|
|
227
249
|
useEffect(() => {
|
|
250
|
+
const cached = getCachedGlassMaps(mapOpts);
|
|
251
|
+
if (cached) {
|
|
252
|
+
setMaps(cached);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
228
255
|
let cancelled = false;
|
|
229
|
-
generateGlassMaps(
|
|
256
|
+
generateGlassMaps(mapOpts).then((m) => {
|
|
230
257
|
if (!cancelled) setMaps(m);
|
|
231
258
|
});
|
|
232
259
|
return () => {
|
|
@@ -426,6 +453,7 @@ export {
|
|
|
426
453
|
LiquidGlassButton,
|
|
427
454
|
cn,
|
|
428
455
|
generateGlassMaps,
|
|
456
|
+
getCachedGlassMaps,
|
|
429
457
|
revokeGlassMaps
|
|
430
458
|
};
|
|
431
459
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/liquid-glass-button.tsx","../src/utils.ts","../src/generate-displacement-map.ts"],"sourcesContent":["import React, { useRef, useEffect, useState, useId, forwardRef } from \"react\";\nimport gsap from \"gsap\";\nimport { cn } from \"./utils\";\nimport { generateGlassMaps, revokeGlassMaps } from \"./generate-displacement-map\";\n\nexport interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Button width in px */\n width?: number;\n /** Button height in px */\n height?: number;\n /** Border radius in px */\n radius?: number;\n /** Edge thickness of the glass refraction zone */\n edgeSize?: number;\n /** Edge refraction intensity (0-1) */\n intensity?: number;\n /** Specular rim thickness relative to size (0-1) */\n specularWidth?: number;\n /** feDisplacementMap scale - how much the background refracts */\n displacement?: number;\n /** Gaussian blur applied to the background */\n blur?: number;\n /** Saturation applied to the displaced result */\n saturation?: number;\n /** Brightness boost on the backdrop-filter (1 = normal) */\n brightness?: number;\n /** Background tint color of the glass */\n glassColor?: string;\n /** Scale multiplier on hover */\n hoverScale?: number;\n /** Displacement scale on hover */\n hoverDisplacement?: number;\n /** Blur amount on hover */\n hoverBlur?: number;\n /** Duration of hover animation in seconds */\n hoverDuration?: number;\n /** Disable all GSAP animations */\n disableAnimation?: boolean;\n /** Supersampling quality for the displacement map (default 2, higher = smoother) */\n quality?: number;\n}\n\nexport const LiquidGlassButton = forwardRef<HTMLButtonElement, LiquidGlassButtonProps>(\n function LiquidGlassButton({\n children, className, style,\n width = 300,\n height = 56,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n displacement = 55,\n blur = 1,\n saturation = 150,\n brightness = 1.1,\n glassColor = \"transparent\",\n hoverScale = 1.08,\n hoverDisplacement = 125,\n hoverBlur = 4,\n hoverDuration = 0.25,\n disableAnimation = false,\n quality = 2,\n ...props\n }, ref) {\n const internalRef = useRef<HTMLButtonElement>(null);\n const buttonRef = (ref as React.RefObject<HTMLButtonElement>) ?? internalRef;\n\n const displacerRef = useRef<SVGFEDisplacementMapElement>(null);\n const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n\n const filterId = \"lg\" + useId().replace(/:/g, \"\");\n\n const [maps, setMaps] = useState<{ displacement: string; specular: string } | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n\n generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality })\n .then((m) => {\n if (!cancelled) setMaps(m);\n });\n\n return () => {\n cancelled = true;\n };\n }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);\n\n useEffect(() => {\n return () => {\n if (maps) revokeGlassMaps(maps);\n };\n }, [maps]);\n\n useEffect(() => {\n const button = buttonRef.current;\n const displacer = displacerRef.current;\n const blurEl = blurRef.current;\n if (!button || !displacer || !blurEl || disableAnimation) return;\n\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const fx = {\n displacement: displacement,\n blur: blur,\n };\n\n const sync = () => {\n displacer.setAttribute(\"scale\", fx.displacement.toString());\n blurEl.setAttribute(\"stdDeviation\", fx.blur.toString());\n };\n\n sync();\n\n const onEnter = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: hoverDisplacement,\n blur: hoverBlur,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: hoverScale,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n });\n };\n\n const onLeave = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: displacement,\n blur: blur,\n duration: hoverDuration,\n ease: \"power2.out\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: 1,\n duration: hoverDuration,\n ease: \"power2.out\",\n });\n };\n\n const onClick = () => {\n gsap.killTweensOf(button);\n const cur = gsap.getProperty(button, \"scale\") as number;\n gsap.timeline()\n .to(button, { scale: cur * 0.92, duration: 0.08, ease: \"power2.in\" })\n .to(button, { scale: hoverScale, duration: 0.25, ease: \"back.out(2)\" });\n };\n\n button.addEventListener(\"pointerenter\", onEnter);\n button.addEventListener(\"pointerleave\", onLeave);\n button.addEventListener(\"click\", onClick);\n\n return () => {\n button.removeEventListener(\"pointerenter\", onEnter);\n button.removeEventListener(\"pointerleave\", onLeave);\n button.removeEventListener(\"click\", onClick);\n gsap.killTweensOf([button, fx]);\n };\n }, [buttonRef, maps, displacement, blur, hoverScale, hoverDisplacement, hoverBlur, hoverDuration, disableAnimation]);\n\n if (!maps) return null;\n\n return (\n <>\n <button\n ref={buttonRef}\n className={cn(\"relative overflow-hidden shadow-lg cursor-pointer\", className)}\n style={{ width, height, borderRadius: radius, border: \"none\", background: glassColor, ...style }}\n {...props}\n >\n <div\n className=\"absolute inset-0\"\n style={{\n backdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n WebkitBackdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n borderRadius: \"inherit\",\n willChange: \"backdrop-filter\",\n transform: \"translateZ(0)\",\n }}\n />\n <div\n className=\"absolute inset-0 inline-flex items-center justify-center font-bold text-white\"\n style={{ background: \"hsl(0 100% 100% / 15%)\", borderRadius: \"inherit\" }}\n >\n {children}\n </div>\n </button>\n\n <svg\n colorInterpolationFilters=\"sRGB\"\n style={{ position: \"absolute\", width: 0, height: 0, overflow: \"hidden\" }}\n aria-hidden=\"true\"\n >\n <defs>\n <filter id={filterId}>\n <feGaussianBlur\n ref={blurRef}\n in=\"SourceGraphic\"\n stdDeviation={blur}\n result=\"blurred_source\"\n />\n <feImage\n href={maps.displacement}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"displacement_map\"\n />\n <feDisplacementMap\n ref={displacerRef}\n in=\"blurred_source\"\n in2=\"displacement_map\"\n scale={displacement}\n xChannelSelector=\"R\"\n yChannelSelector=\"G\"\n result=\"displaced\"\n />\n <feColorMatrix\n in=\"displaced\"\n type=\"saturate\"\n result=\"displaced_saturated\"\n values={saturation.toString()}\n />\n <feImage\n href={maps.specular}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"specular_layer\"\n />\n <feGaussianBlur\n in=\"specular_layer\"\n stdDeviation=\"1\"\n result=\"blurred_specular_layer\"\n />\n <feComposite\n in=\"displaced_saturated\"\n in2=\"blurred_specular_layer\"\n operator=\"in\"\n result=\"final_specular_layer\"\n />\n <feBlend\n in=\"final_specular_layer\"\n in2=\"displaced\"\n mode=\"normal\"\n />\n </filter>\n </defs>\n </svg>\n </>\n );\n }\n);\n","export function cn(...classes: (string | undefined | null | false)[]) {\n return classes.filter(Boolean).join(\" \");\n}\n","export interface MapOptions {\n width: number;\n height: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n specularWidth?: number;\n /** Supersampling multiplier for the displacement map (default: 2). Higher = smoother gradients. */\n quality?: number;\n}\n\nconst VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;\n\nconst FRAG = `\nprecision highp float;\nuniform vec2 uRes;\nuniform float uRadius;\nuniform float uBorderSoftness;\nuniform float uSpecularWidth;\nuniform int uMode; // 0 = displacement, 1 = specular\n\nfloat sdRoundedBox(vec2 p, vec2 b, float r){\n r = min(r, min(b.x, b.y));\n vec2 q = abs(p) - b + r;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;\n}\n\nvec3 calcNormal(vec2 p, vec2 b, float r){\n float e = max(0.5, min(b.x, b.y) * 0.01);\n vec2 h = vec2(e, 0.0);\n return normalize(vec3(\n sdRoundedBox(p+h.xy, b, r) - sdRoundedBox(p-h.xy, b, r),\n sdRoundedBox(p+h.yx, b, r) - sdRoundedBox(p-h.yx, b, r),\n -e * 2.0\n ));\n}\n\nvoid main(){\n vec2 p = gl_FragCoord.xy - uRes * 0.5;\n vec2 halfSize = uRes * 0.5 - 1.0;\n float d = sdRoundedBox(p, halfSize, uRadius);\n\n if(d > 0.0){ gl_FragColor = vec4(0.0); return; }\n\n if(uMode == 0){\n vec3 n = calcNormal(p, halfSize, uRadius);\n vec3 nc = n * 0.5 + 0.5;\n float border = smoothstep(-uBorderSoftness, 0.0, d);\n vec3 flat_ = vec3(0.5, 0.5, 1.0);\n gl_FragColor = vec4(mix(flat_, nc, border), 1.0);\n } else {\n float rim = smoothstep(-uSpecularWidth - 2.0, -uSpecularWidth, d)\n * (1.0 - smoothstep(-2.0, 0.0, d));\n float glow = smoothstep(-uBorderSoftness, 0.0, d) * 0.1;\n float s = clamp(rim + glow, 0.0, 1.0);\n gl_FragColor = vec4(vec3(s), s);\n }\n}\n`;\n\nfunction compile(gl: WebGLRenderingContext, type: number, src: string) {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n return s;\n}\n\nlet _cachedProgram: { gl: WebGLRenderingContext; program: WebGLProgram; canvas: HTMLCanvasElement } | null = null;\n\nfunction getGL() {\n if (_cachedProgram) return _cachedProgram;\n\n const canvas = document.createElement(\"canvas\");\n const gl = canvas.getContext(\"webgl\", { preserveDrawingBuffer: true, premultipliedAlpha: false })!;\n\n const vs = compile(gl, gl.VERTEX_SHADER, VERT);\n const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = gl.createProgram()!;\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n gl.useProgram(program);\n\n const buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);\n const pos = gl.getAttribLocation(program, \"position\");\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n _cachedProgram = { gl, program, canvas };\n return _cachedProgram;\n}\n\n// ── Cache ──────────────────────────────────────────────────────\n\nconst _mapCache = new Map<string, { displacement: string; specular: string }>();\n\nfunction cacheKey(\n w: number, h: number, r: number, bs: number, sw: number,\n): string {\n return `${w}|${h}|${r}|${bs}|${sw}`;\n}\n\n// ── Render ─────────────────────────────────────────────────────\n\nfunction renderToBlob(\n width: number,\n height: number,\n radius: number,\n borderSoftness: number,\n specularWidth: number,\n mode: number,\n): Promise<string> {\n const { gl, program, canvas } = getGL();\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(program);\n\n gl.uniform2f(gl.getUniformLocation(program, \"uRes\"), width, height);\n gl.uniform1f(gl.getUniformLocation(program, \"uRadius\"), radius);\n gl.uniform1f(gl.getUniformLocation(program, \"uBorderSoftness\"), borderSoftness);\n gl.uniform1f(gl.getUniformLocation(program, \"uSpecularWidth\"), specularWidth);\n gl.uniform1i(gl.getUniformLocation(program, \"uMode\"), mode);\n\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\n return new Promise((resolve) => {\n canvas.toBlob((blob) => {\n resolve(URL.createObjectURL(blob!));\n }, \"image/png\");\n });\n}\n\n// ── Public API ─────────────────────────────────────────────────\n\nexport async function generateGlassMaps(opts: MapOptions): Promise<{\n displacement: string;\n specular: string;\n}> {\n const {\n width,\n height,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n quality = 2,\n } = opts;\n\n const scale = Math.max(1, Math.round(quality));\n const rw = width * scale;\n const rh = height * scale;\n\n const r = Math.min(radius * scale, rw / 2, rh / 2);\n const borderSoftness = edgeSize * intensity * scale;\n const specPx = specularWidth * Math.min(rw, rh);\n\n const key = cacheKey(rw, rh, r, borderSoftness, specPx);\n const cached = _mapCache.get(key);\n if (cached) return cached;\n\n const [displacement, specular] = await Promise.all([\n renderToBlob(rw, rh, r, borderSoftness, specPx, 0),\n renderToBlob(rw, rh, r, borderSoftness, specPx, 1),\n ]);\n\n const result = { displacement, specular };\n _mapCache.set(key, result);\n return result;\n}\n\nexport function revokeGlassMaps(maps: { displacement: string; specular: string }) {\n URL.revokeObjectURL(maps.displacement);\n URL.revokeObjectURL(maps.specular);\n}\n"],"mappings":"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","names":["LiquidGlassButton"]}
|
|
1
|
+
{"version":3,"sources":["../src/liquid-glass-button.tsx","../src/utils.ts","../src/generate-displacement-map.ts"],"sourcesContent":["import React, { useRef, useEffect, useState, useId, forwardRef } from \"react\";\nimport gsap from \"gsap\";\nimport { cn } from \"./utils\";\nimport { generateGlassMaps, getCachedGlassMaps, revokeGlassMaps } from \"./generate-displacement-map\";\n\nexport interface LiquidGlassButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Button width in px */\n width?: number;\n /** Button height in px */\n height?: number;\n /** Border radius in px */\n radius?: number;\n /** Edge thickness of the glass refraction zone */\n edgeSize?: number;\n /** Edge refraction intensity (0-1) */\n intensity?: number;\n /** Specular rim thickness relative to size (0-1) */\n specularWidth?: number;\n /** feDisplacementMap scale - how much the background refracts */\n displacement?: number;\n /** Gaussian blur applied to the background */\n blur?: number;\n /** Saturation applied to the displaced result */\n saturation?: number;\n /** Brightness boost on the backdrop-filter (1 = normal) */\n brightness?: number;\n /** Background tint color of the glass */\n glassColor?: string;\n /** Scale multiplier on hover */\n hoverScale?: number;\n /** Displacement scale on hover */\n hoverDisplacement?: number;\n /** Blur amount on hover */\n hoverBlur?: number;\n /** Duration of hover animation in seconds */\n hoverDuration?: number;\n /** Disable all GSAP animations */\n disableAnimation?: boolean;\n /** Supersampling quality for the displacement map (default 2, higher = smoother) */\n quality?: number;\n}\n\nexport const LiquidGlassButton = forwardRef<HTMLButtonElement, LiquidGlassButtonProps>(\n function LiquidGlassButton({\n children, className, style,\n width = 300,\n height = 56,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n displacement = 55,\n blur = 1,\n saturation = 150,\n brightness = 1.1,\n glassColor = \"transparent\",\n hoverScale = 1.08,\n hoverDisplacement = 125,\n hoverBlur = 4,\n hoverDuration = 0.25,\n disableAnimation = false,\n quality = 2,\n ...props\n }, ref) {\n const internalRef = useRef<HTMLButtonElement>(null);\n const buttonRef = (ref as React.RefObject<HTMLButtonElement>) ?? internalRef;\n\n const displacerRef = useRef<SVGFEDisplacementMapElement>(null);\n const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n\n const filterId = \"lg\" + useId().replace(/:/g, \"\");\n\n const mapOpts = { width, height, radius, edgeSize, intensity, specularWidth, quality };\n const [maps, setMaps] = useState<{ displacement: string; specular: string } | null>(\n () => getCachedGlassMaps(mapOpts),\n );\n\n useEffect(() => {\n // If already have maps from cache, skip\n const cached = getCachedGlassMaps(mapOpts);\n if (cached) {\n setMaps(cached);\n return;\n }\n\n let cancelled = false;\n generateGlassMaps(mapOpts).then((m) => {\n if (!cancelled) setMaps(m);\n });\n\n return () => { cancelled = true; };\n }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);\n\n useEffect(() => {\n return () => {\n if (maps) revokeGlassMaps(maps);\n };\n }, [maps]);\n\n useEffect(() => {\n const button = buttonRef.current;\n const displacer = displacerRef.current;\n const blurEl = blurRef.current;\n if (!button || !displacer || !blurEl || disableAnimation) return;\n\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const fx = {\n displacement: displacement,\n blur: blur,\n };\n\n const sync = () => {\n displacer.setAttribute(\"scale\", fx.displacement.toString());\n blurEl.setAttribute(\"stdDeviation\", fx.blur.toString());\n };\n\n sync();\n\n const onEnter = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: hoverDisplacement,\n blur: hoverBlur,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: hoverScale,\n duration: hoverDuration,\n ease: \"back.out(1.4)\",\n });\n };\n\n const onLeave = () => {\n gsap.killTweensOf([fx, button]);\n gsap.to(fx, {\n displacement: displacement,\n blur: blur,\n duration: hoverDuration,\n ease: \"power2.out\",\n onUpdate: sync,\n });\n gsap.to(button, {\n scale: 1,\n duration: hoverDuration,\n ease: \"power2.out\",\n });\n };\n\n const onClick = () => {\n gsap.killTweensOf(button);\n const cur = gsap.getProperty(button, \"scale\") as number;\n gsap.timeline()\n .to(button, { scale: cur * 0.92, duration: 0.08, ease: \"power2.in\" })\n .to(button, { scale: hoverScale, duration: 0.25, ease: \"back.out(2)\" });\n };\n\n button.addEventListener(\"pointerenter\", onEnter);\n button.addEventListener(\"pointerleave\", onLeave);\n button.addEventListener(\"click\", onClick);\n\n return () => {\n button.removeEventListener(\"pointerenter\", onEnter);\n button.removeEventListener(\"pointerleave\", onLeave);\n button.removeEventListener(\"click\", onClick);\n gsap.killTweensOf([button, fx]);\n };\n }, [buttonRef, maps, displacement, blur, hoverScale, hoverDisplacement, hoverBlur, hoverDuration, disableAnimation]);\n\n if (!maps) return null;\n\n return (\n <>\n <button\n ref={buttonRef}\n className={cn(\"relative overflow-hidden shadow-lg cursor-pointer\", className)}\n style={{ width, height, borderRadius: radius, border: \"none\", background: glassColor, ...style }}\n {...props}\n >\n <div\n className=\"absolute inset-0\"\n style={{\n backdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n WebkitBackdropFilter: `url(#${filterId}) brightness(${brightness * 100}%)`,\n borderRadius: \"inherit\",\n willChange: \"backdrop-filter\",\n transform: \"translateZ(0)\",\n }}\n />\n <div\n className=\"absolute inset-0 inline-flex items-center justify-center font-bold text-white\"\n style={{ background: \"hsl(0 100% 100% / 15%)\", borderRadius: \"inherit\" }}\n >\n {children}\n </div>\n </button>\n\n <svg\n colorInterpolationFilters=\"sRGB\"\n style={{ position: \"absolute\", width: 0, height: 0, overflow: \"hidden\" }}\n aria-hidden=\"true\"\n >\n <defs>\n <filter id={filterId}>\n <feGaussianBlur\n ref={blurRef}\n in=\"SourceGraphic\"\n stdDeviation={blur}\n result=\"blurred_source\"\n />\n <feImage\n href={maps.displacement}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"displacement_map\"\n />\n <feDisplacementMap\n ref={displacerRef}\n in=\"blurred_source\"\n in2=\"displacement_map\"\n scale={displacement}\n xChannelSelector=\"R\"\n yChannelSelector=\"G\"\n result=\"displaced\"\n />\n <feColorMatrix\n in=\"displaced\"\n type=\"saturate\"\n result=\"displaced_saturated\"\n values={saturation.toString()}\n />\n <feImage\n href={maps.specular}\n x=\"0\"\n y=\"0\"\n width={width}\n height={height}\n result=\"specular_layer\"\n />\n <feGaussianBlur\n in=\"specular_layer\"\n stdDeviation=\"1\"\n result=\"blurred_specular_layer\"\n />\n <feComposite\n in=\"displaced_saturated\"\n in2=\"blurred_specular_layer\"\n operator=\"in\"\n result=\"final_specular_layer\"\n />\n <feBlend\n in=\"final_specular_layer\"\n in2=\"displaced\"\n mode=\"normal\"\n />\n </filter>\n </defs>\n </svg>\n </>\n );\n }\n);\n","export function cn(...classes: (string | undefined | null | false)[]) {\n return classes.filter(Boolean).join(\" \");\n}\n","export interface MapOptions {\n width: number;\n height: number;\n radius?: number;\n edgeSize?: number;\n intensity?: number;\n specularWidth?: number;\n /** Supersampling multiplier for the displacement map (default: 2). Higher = smoother gradients. */\n quality?: number;\n}\n\nconst VERT = `attribute vec4 position; void main(){ gl_Position = position; }`;\n\nconst FRAG = `\nprecision highp float;\nuniform vec2 uRes;\nuniform float uRadius;\nuniform float uBorderSoftness;\nuniform float uSpecularWidth;\nuniform int uMode; // 0 = displacement, 1 = specular\n\nfloat sdRoundedBox(vec2 p, vec2 b, float r){\n r = min(r, min(b.x, b.y));\n vec2 q = abs(p) - b + r;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;\n}\n\nvec3 calcNormal(vec2 p, vec2 b, float r){\n float e = max(0.5, min(b.x, b.y) * 0.01);\n vec2 h = vec2(e, 0.0);\n return normalize(vec3(\n sdRoundedBox(p+h.xy, b, r) - sdRoundedBox(p-h.xy, b, r),\n sdRoundedBox(p+h.yx, b, r) - sdRoundedBox(p-h.yx, b, r),\n -e * 2.0\n ));\n}\n\nvoid main(){\n vec2 p = gl_FragCoord.xy - uRes * 0.5;\n vec2 halfSize = uRes * 0.5 - 1.0;\n float d = sdRoundedBox(p, halfSize, uRadius);\n\n if(d > 0.0){ gl_FragColor = vec4(0.0); return; }\n\n if(uMode == 0){\n vec3 n = calcNormal(p, halfSize, uRadius);\n vec3 nc = n * 0.5 + 0.5;\n float border = smoothstep(-uBorderSoftness, 0.0, d);\n vec3 flat_ = vec3(0.5, 0.5, 1.0);\n gl_FragColor = vec4(mix(flat_, nc, border), 1.0);\n } else {\n float rim = smoothstep(-uSpecularWidth - 2.0, -uSpecularWidth, d)\n * (1.0 - smoothstep(-2.0, 0.0, d));\n float glow = smoothstep(-uBorderSoftness, 0.0, d) * 0.1;\n float s = clamp(rim + glow, 0.0, 1.0);\n gl_FragColor = vec4(vec3(s), s);\n }\n}\n`;\n\nfunction compile(gl: WebGLRenderingContext, type: number, src: string) {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n return s;\n}\n\nlet _cachedProgram: { gl: WebGLRenderingContext; program: WebGLProgram; canvas: HTMLCanvasElement } | null = null;\n\nfunction getGL() {\n if (_cachedProgram) return _cachedProgram;\n\n const canvas = document.createElement(\"canvas\");\n const gl = canvas.getContext(\"webgl\", { preserveDrawingBuffer: true, premultipliedAlpha: false })!;\n\n const vs = compile(gl, gl.VERTEX_SHADER, VERT);\n const fs = compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = gl.createProgram()!;\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n gl.useProgram(program);\n\n const buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);\n const pos = gl.getAttribLocation(program, \"position\");\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n _cachedProgram = { gl, program, canvas };\n return _cachedProgram;\n}\n\n// ── Cache ──────────────────────────────────────────────────────\n\nconst _mapCache = new Map<string, { displacement: string; specular: string }>();\n\nfunction cacheKey(\n w: number, h: number, r: number, bs: number, sw: number,\n): string {\n return `${w}|${h}|${r}|${bs}|${sw}`;\n}\n\n// ── Render ─────────────────────────────────────────────────────\n\nfunction renderToBlob(\n width: number,\n height: number,\n radius: number,\n borderSoftness: number,\n specularWidth: number,\n mode: number,\n): Promise<string> {\n const { gl, program, canvas } = getGL();\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(program);\n\n gl.uniform2f(gl.getUniformLocation(program, \"uRes\"), width, height);\n gl.uniform1f(gl.getUniformLocation(program, \"uRadius\"), radius);\n gl.uniform1f(gl.getUniformLocation(program, \"uBorderSoftness\"), borderSoftness);\n gl.uniform1f(gl.getUniformLocation(program, \"uSpecularWidth\"), specularWidth);\n gl.uniform1i(gl.getUniformLocation(program, \"uMode\"), mode);\n\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\n return new Promise((resolve) => {\n canvas.toBlob((blob) => {\n resolve(URL.createObjectURL(blob!));\n }, \"image/png\");\n });\n}\n\n// ── Public API ─────────────────────────────────────────────────\n\nexport async function generateGlassMaps(opts: MapOptions): Promise<{\n displacement: string;\n specular: string;\n}> {\n const {\n width,\n height,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n quality = 2,\n } = opts;\n\n const scale = Math.max(1, Math.round(quality));\n const rw = width * scale;\n const rh = height * scale;\n\n const r = Math.min(radius * scale, rw / 2, rh / 2);\n const borderSoftness = edgeSize * intensity * scale;\n const specPx = specularWidth * Math.min(rw, rh);\n\n const key = cacheKey(rw, rh, r, borderSoftness, specPx);\n const cached = _mapCache.get(key);\n if (cached) return cached;\n\n const [displacement, specular] = await Promise.all([\n renderToBlob(rw, rh, r, borderSoftness, specPx, 0),\n renderToBlob(rw, rh, r, borderSoftness, specPx, 1),\n ]);\n\n const result = { displacement, specular };\n _mapCache.set(key, result);\n return result;\n}\n\nexport function getCachedGlassMaps(opts: MapOptions): { displacement: string; specular: string } | null {\n const {\n width,\n height,\n radius = 60,\n edgeSize = 30,\n intensity = 0.7,\n specularWidth = 0.02,\n quality = 2,\n } = opts;\n\n const scale = Math.max(1, Math.round(quality));\n const rw = width * scale;\n const rh = height * scale;\n\n const r = Math.min(radius * scale, rw / 2, rh / 2);\n const borderSoftness = edgeSize * intensity * scale;\n const specPx = specularWidth * Math.min(rw, rh);\n\n return _mapCache.get(cacheKey(rw, rh, r, borderSoftness, specPx)) ?? null;\n}\n\nexport function revokeGlassMaps(maps: { displacement: string; specular: string }) {\n URL.revokeObjectURL(maps.displacement);\n URL.revokeObjectURL(maps.specular);\n}\n"],"mappings":"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","names":["LiquidGlassButton"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marcosdemik/liquidglass",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "Liquid Glass UI effect for React - glassmorphism refraction with SVG filters, WebGL and GSAP animations",
|
|
5
5
|
"author": "Marcos Demik <marcosdemik>",
|
|
6
6
|
"license": "MIT",
|