@marcosdemik/liquidglass 2.0.2 → 2.0.3

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 CHANGED
@@ -62,7 +62,8 @@ var index_exports = {};
62
62
  __export(index_exports, {
63
63
  LiquidGlassButton: () => LiquidGlassButton,
64
64
  cn: () => cn,
65
- generateGlassMaps: () => generateGlassMaps
65
+ generateGlassMaps: () => generateGlassMaps,
66
+ revokeGlassMaps: () => revokeGlassMaps
66
67
  });
67
68
  module.exports = __toCommonJS(index_exports);
68
69
 
@@ -150,7 +151,11 @@ function getGL() {
150
151
  _cachedProgram = { gl, program, canvas };
151
152
  return _cachedProgram;
152
153
  }
153
- function render(width, height, radius, borderSoftness, specularWidth, mode) {
154
+ var _mapCache = /* @__PURE__ */ new Map();
155
+ function cacheKey(w, h, r, bs, sw) {
156
+ return `${w}|${h}|${r}|${bs}|${sw}`;
157
+ }
158
+ function renderToBlob(width, height, radius, borderSoftness, specularWidth, mode) {
154
159
  const { gl, program, canvas } = getGL();
155
160
  canvas.width = width;
156
161
  canvas.height = height;
@@ -164,9 +169,13 @@ function render(width, height, radius, borderSoftness, specularWidth, mode) {
164
169
  gl.uniform1f(gl.getUniformLocation(program, "uSpecularWidth"), specularWidth);
165
170
  gl.uniform1i(gl.getUniformLocation(program, "uMode"), mode);
166
171
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
167
- return canvas.toDataURL("image/png");
172
+ return new Promise((resolve) => {
173
+ canvas.toBlob((blob) => {
174
+ resolve(URL.createObjectURL(blob));
175
+ }, "image/png");
176
+ });
168
177
  }
169
- function generateGlassMaps(opts) {
178
+ async function generateGlassMaps(opts) {
170
179
  const {
171
180
  width,
172
181
  height,
@@ -182,10 +191,20 @@ function generateGlassMaps(opts) {
182
191
  const r = Math.min(radius * scale, rw / 2, rh / 2);
183
192
  const borderSoftness = edgeSize * intensity * scale;
184
193
  const specPx = specularWidth * Math.min(rw, rh);
185
- return {
186
- displacement: render(rw, rh, r, borderSoftness, specPx, 0),
187
- specular: render(rw, rh, r, borderSoftness, specPx, 1)
188
- };
194
+ const key = cacheKey(rw, rh, r, borderSoftness, specPx);
195
+ const cached = _mapCache.get(key);
196
+ if (cached) return cached;
197
+ const [displacement, specular] = await Promise.all([
198
+ renderToBlob(rw, rh, r, borderSoftness, specPx, 0),
199
+ renderToBlob(rw, rh, r, borderSoftness, specPx, 1)
200
+ ]);
201
+ const result = { displacement, specular };
202
+ _mapCache.set(key, result);
203
+ return result;
204
+ }
205
+ function revokeGlassMaps(maps) {
206
+ URL.revokeObjectURL(maps.displacement);
207
+ URL.revokeObjectURL(maps.specular);
189
208
  }
190
209
 
191
210
  // src/liquid-glass-button.tsx
@@ -243,22 +262,18 @@ var LiquidGlassButton = (0, import_react.forwardRef)(
243
262
  const [maps, setMaps] = (0, import_react.useState)(null);
244
263
  (0, import_react.useEffect)(() => {
245
264
  let cancelled = false;
246
- const m = generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality });
247
- let loaded = 0;
248
- const onLoad = () => {
249
- loaded++;
250
- if (loaded === 2 && !cancelled) setMaps(m);
251
- };
252
- const img1 = new Image();
253
- img1.onload = onLoad;
254
- img1.src = m.displacement;
255
- const img2 = new Image();
256
- img2.onload = onLoad;
257
- img2.src = m.specular;
265
+ generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality }).then((m) => {
266
+ if (!cancelled) setMaps(m);
267
+ });
258
268
  return () => {
259
269
  cancelled = true;
260
270
  };
261
271
  }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);
272
+ (0, import_react.useEffect)(() => {
273
+ return () => {
274
+ if (maps) revokeGlassMaps(maps);
275
+ };
276
+ }, [maps]);
262
277
  (0, import_react.useEffect)(() => {
263
278
  const button = buttonRef.current;
264
279
  const displacer = displacerRef.current;
@@ -447,6 +462,7 @@ var LiquidGlassButton = (0, import_react.forwardRef)(
447
462
  0 && (module.exports = {
448
463
  LiquidGlassButton,
449
464
  cn,
450
- generateGlassMaps
465
+ generateGlassMaps,
466
+ revokeGlassMaps
451
467
  });
452
468
  //# sourceMappingURL=index.cjs.map
@@ -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 } 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 } 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<ReturnType<typeof generateGlassMaps> | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n const m = generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality });\n\n // Pre-decode both PNGs\n let loaded = 0;\n const onLoad = () => {\n loaded++;\n if (loaded === 2 && !cancelled) setMaps(m);\n };\n\n const img1 = new Image();\n img1.onload = onLoad;\n img1.src = m.displacement;\n\n const img2 = new Image();\n img2.onload = onLoad;\n img2.src = m.specular;\n\n return () => { cancelled = true; };\n }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);\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\nfunction render(\n width: number,\n height: number,\n radius: number,\n borderSoftness: number,\n specularWidth: number,\n mode: number,\n): 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 return canvas.toDataURL(\"image/png\");\n}\n\nexport function generateGlassMaps(opts: MapOptions): {\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 return {\n displacement: render(rw, rh, r, borderSoftness, specPx, 0),\n specular: render(rw, rh, r, borderSoftness, specPx, 1),\n };\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, 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"]}
package/dist/index.d.cts CHANGED
@@ -48,11 +48,15 @@ interface MapOptions {
48
48
  /** Supersampling multiplier for the displacement map (default: 2). Higher = smoother gradients. */
49
49
  quality?: number;
50
50
  }
51
- declare function generateGlassMaps(opts: MapOptions): {
51
+ declare function generateGlassMaps(opts: MapOptions): Promise<{
52
52
  displacement: string;
53
53
  specular: string;
54
- };
54
+ }>;
55
+ declare function revokeGlassMaps(maps: {
56
+ displacement: string;
57
+ specular: string;
58
+ }): void;
55
59
 
56
60
  declare function cn(...classes: (string | undefined | null | false)[]): string;
57
61
 
58
- export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps };
62
+ export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps, revokeGlassMaps };
package/dist/index.d.ts CHANGED
@@ -48,11 +48,15 @@ interface MapOptions {
48
48
  /** Supersampling multiplier for the displacement map (default: 2). Higher = smoother gradients. */
49
49
  quality?: number;
50
50
  }
51
- declare function generateGlassMaps(opts: MapOptions): {
51
+ declare function generateGlassMaps(opts: MapOptions): Promise<{
52
52
  displacement: string;
53
53
  specular: string;
54
- };
54
+ }>;
55
+ declare function revokeGlassMaps(maps: {
56
+ displacement: string;
57
+ specular: string;
58
+ }): void;
55
59
 
56
60
  declare function cn(...classes: (string | undefined | null | false)[]): string;
57
61
 
58
- export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps };
62
+ export { LiquidGlassButton, type LiquidGlassButtonProps, type MapOptions, cn, generateGlassMaps, revokeGlassMaps };
package/dist/index.js CHANGED
@@ -115,7 +115,11 @@ function getGL() {
115
115
  _cachedProgram = { gl, program, canvas };
116
116
  return _cachedProgram;
117
117
  }
118
- function render(width, height, radius, borderSoftness, specularWidth, mode) {
118
+ var _mapCache = /* @__PURE__ */ new Map();
119
+ function cacheKey(w, h, r, bs, sw) {
120
+ return `${w}|${h}|${r}|${bs}|${sw}`;
121
+ }
122
+ function renderToBlob(width, height, radius, borderSoftness, specularWidth, mode) {
119
123
  const { gl, program, canvas } = getGL();
120
124
  canvas.width = width;
121
125
  canvas.height = height;
@@ -129,9 +133,13 @@ function render(width, height, radius, borderSoftness, specularWidth, mode) {
129
133
  gl.uniform1f(gl.getUniformLocation(program, "uSpecularWidth"), specularWidth);
130
134
  gl.uniform1i(gl.getUniformLocation(program, "uMode"), mode);
131
135
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
132
- return canvas.toDataURL("image/png");
136
+ return new Promise((resolve) => {
137
+ canvas.toBlob((blob) => {
138
+ resolve(URL.createObjectURL(blob));
139
+ }, "image/png");
140
+ });
133
141
  }
134
- function generateGlassMaps(opts) {
142
+ async function generateGlassMaps(opts) {
135
143
  const {
136
144
  width,
137
145
  height,
@@ -147,10 +155,20 @@ function generateGlassMaps(opts) {
147
155
  const r = Math.min(radius * scale, rw / 2, rh / 2);
148
156
  const borderSoftness = edgeSize * intensity * scale;
149
157
  const specPx = specularWidth * Math.min(rw, rh);
150
- return {
151
- displacement: render(rw, rh, r, borderSoftness, specPx, 0),
152
- specular: render(rw, rh, r, borderSoftness, specPx, 1)
153
- };
158
+ const key = cacheKey(rw, rh, r, borderSoftness, specPx);
159
+ const cached = _mapCache.get(key);
160
+ if (cached) return cached;
161
+ const [displacement, specular] = await Promise.all([
162
+ renderToBlob(rw, rh, r, borderSoftness, specPx, 0),
163
+ renderToBlob(rw, rh, r, borderSoftness, specPx, 1)
164
+ ]);
165
+ const result = { displacement, specular };
166
+ _mapCache.set(key, result);
167
+ return result;
168
+ }
169
+ function revokeGlassMaps(maps) {
170
+ URL.revokeObjectURL(maps.displacement);
171
+ URL.revokeObjectURL(maps.specular);
154
172
  }
155
173
 
156
174
  // src/liquid-glass-button.tsx
@@ -208,22 +226,18 @@ var LiquidGlassButton = forwardRef(
208
226
  const [maps, setMaps] = useState(null);
209
227
  useEffect(() => {
210
228
  let cancelled = false;
211
- const m = generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality });
212
- let loaded = 0;
213
- const onLoad = () => {
214
- loaded++;
215
- if (loaded === 2 && !cancelled) setMaps(m);
216
- };
217
- const img1 = new Image();
218
- img1.onload = onLoad;
219
- img1.src = m.displacement;
220
- const img2 = new Image();
221
- img2.onload = onLoad;
222
- img2.src = m.specular;
229
+ generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality }).then((m) => {
230
+ if (!cancelled) setMaps(m);
231
+ });
223
232
  return () => {
224
233
  cancelled = true;
225
234
  };
226
235
  }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);
236
+ useEffect(() => {
237
+ return () => {
238
+ if (maps) revokeGlassMaps(maps);
239
+ };
240
+ }, [maps]);
227
241
  useEffect(() => {
228
242
  const button = buttonRef.current;
229
243
  const displacer = displacerRef.current;
@@ -411,6 +425,7 @@ var LiquidGlassButton = forwardRef(
411
425
  export {
412
426
  LiquidGlassButton,
413
427
  cn,
414
- generateGlassMaps
428
+ generateGlassMaps,
429
+ revokeGlassMaps
415
430
  };
416
431
  //# 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 } 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<ReturnType<typeof generateGlassMaps> | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n const m = generateGlassMaps({ width, height, radius, edgeSize, intensity, specularWidth, quality });\n\n // Pre-decode both PNGs\n let loaded = 0;\n const onLoad = () => {\n loaded++;\n if (loaded === 2 && !cancelled) setMaps(m);\n };\n\n const img1 = new Image();\n img1.onload = onLoad;\n img1.src = m.displacement;\n\n const img2 = new Image();\n img2.onload = onLoad;\n img2.src = m.specular;\n\n return () => { cancelled = true; };\n }, [width, height, radius, edgeSize, intensity, specularWidth, quality]);\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\nfunction render(\n width: number,\n height: number,\n radius: number,\n borderSoftness: number,\n specularWidth: number,\n mode: number,\n): 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 return canvas.toDataURL(\"image/png\");\n}\n\nexport function generateGlassMaps(opts: MapOptions): {\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 return {\n displacement: render(rw, rh, r, borderSoftness, specPx, 0),\n specular: render(rw, rh, r, borderSoftness, specPx, 1),\n };\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, 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcosdemik/liquidglass",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
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",