The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .gitignore
├── LICENSE
├── README.md
├── assets
    ├── button.png
    ├── card.png
    ├── project-liquid.gif
    └── video.mov
├── bun.lock
├── esbuild.config.js
├── liquid-glass-example
    ├── .gitignore
    ├── README.md
    ├── bun.lock
    ├── bun.lockb
    ├── next.config.ts
    ├── package.json
    ├── postcss.config.mjs
    ├── public
    │   └── favicon.ico
    ├── src
    │   ├── pages
    │   │   ├── _app.tsx
    │   │   ├── _document.tsx
    │   │   ├── api
    │   │   │   └── hello.ts
    │   │   └── index.tsx
    │   └── styles
    │   │   └── globals.css
    └── tsconfig.json
├── package-lock.json
├── package.json
├── src
    ├── index.tsx
    ├── shader-utils.ts
    └── utils.ts
└── tsconfig.json


/.gitignore:
--------------------------------------------------------------------------------
  1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
  2 | 
  3 | # Logs
  4 | 
  5 | logs
  6 | _.log
  7 | npm-debug.log_
  8 | yarn-debug.log*
  9 | yarn-error.log*
 10 | lerna-debug.log*
 11 | .pnpm-debug.log*
 12 | 
 13 | # Caches
 14 | 
 15 | .cache
 16 | 
 17 | # Diagnostic reports (https://nodejs.org/api/report.html)
 18 | 
 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
 20 | 
 21 | # Runtime data
 22 | 
 23 | pids
 24 | _.pid
 25 | _.seed
 26 | *.pid.lock
 27 | 
 28 | # Directory for instrumented libs generated by jscoverage/JSCover
 29 | 
 30 | lib-cov
 31 | 
 32 | # Coverage directory used by tools like istanbul
 33 | 
 34 | coverage
 35 | *.lcov
 36 | 
 37 | # nyc test coverage
 38 | 
 39 | .nyc_output
 40 | 
 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
 42 | 
 43 | .grunt
 44 | 
 45 | # Bower dependency directory (https://bower.io/)
 46 | 
 47 | bower_components
 48 | 
 49 | # node-waf configuration
 50 | 
 51 | .lock-wscript
 52 | 
 53 | # Compiled binary addons (https://nodejs.org/api/addons.html)
 54 | 
 55 | build/Release
 56 | 
 57 | # Dependency directories
 58 | 
 59 | node_modules/
 60 | jspm_packages/
 61 | 
 62 | # Snowpack dependency directory (https://snowpack.dev/)
 63 | 
 64 | web_modules/
 65 | 
 66 | # TypeScript cache
 67 | 
 68 | *.tsbuildinfo
 69 | 
 70 | # Optional npm cache directory
 71 | 
 72 | .npm
 73 | 
 74 | # Optional eslint cache
 75 | 
 76 | .eslintcache
 77 | 
 78 | # Optional stylelint cache
 79 | 
 80 | .stylelintcache
 81 | 
 82 | # Microbundle cache
 83 | 
 84 | .rpt2_cache/
 85 | .rts2_cache_cjs/
 86 | .rts2_cache_es/
 87 | .rts2_cache_umd/
 88 | 
 89 | # Optional REPL history
 90 | 
 91 | .node_repl_history
 92 | 
 93 | # Output of 'npm pack'
 94 | 
 95 | *.tgz
 96 | 
 97 | # Yarn Integrity file
 98 | 
 99 | .yarn-integrity
100 | 
101 | # dotenv environment variable files
102 | 
103 | .env
104 | .env.development.local
105 | .env.test.local
106 | .env.production.local
107 | .env.local
108 | 
109 | # parcel-bundler cache (https://parceljs.org/)
110 | 
111 | .parcel-cache
112 | 
113 | # Next.js build output
114 | 
115 | .next
116 | out
117 | 
118 | # Nuxt.js build / generate output
119 | 
120 | .nuxt
121 | dist
122 | 
123 | # Build output
124 | dist/
125 | 
126 | # Gatsby files
127 | 
128 | # Comment in the public line in if your project uses Gatsby and not Next.js
129 | 
130 | # https://nextjs.org/blog/next-9-1#public-directory-support
131 | 
132 | # public
133 | 
134 | # vuepress build output
135 | 
136 | .vuepress/dist
137 | 
138 | # vuepress v2.x temp and cache directory
139 | 
140 | .temp
141 | 
142 | # Docusaurus cache and generated files
143 | 
144 | .docusaurus
145 | 
146 | # Serverless directories
147 | 
148 | .serverless/
149 | 
150 | # FuseBox cache
151 | 
152 | .fusebox/
153 | 
154 | # DynamoDB Local files
155 | 
156 | .dynamodb/
157 | 
158 | # TernJS port file
159 | 
160 | .tern-port
161 | 
162 | # Stores VSCode versions used for testing VSCode extensions
163 | 
164 | .vscode-test
165 | 
166 | # yarn v2
167 | 
168 | .yarn/cache
169 | .yarn/unplugged
170 | .yarn/build-state.yml
171 | .yarn/install-state.gz
172 | .pnp.*
173 | 
174 | # IntelliJ based IDEs
175 | .idea
176 | 
177 | # Finder (MacOS) folder config
178 | .DS_Store
179 | 
180 | liquid-glass-example/src/components
181 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2025 MAX ROVENSKY
2 | 
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 | 
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 | 
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # Liquid Glass React
  2 | 
  3 | Apple's Liquid Glass effect for React.
  4 | 
  5 | Card Example              |  Button Example
  6 | :-------------------------:|:-------------------------:
  7 | ![](https://github.com/rdev/liquid-glass-react/raw/master/assets/card.png)  |  ![](https://github.com/rdev/liquid-glass-react/raw/master/assets/button.png)
  8 | 
  9 | ## 🎬  Demo
 10 | 
 11 | [Click here](https://liquid-glass.maxrovensky.com) to see it in action!
 12 | 
 13 | ![project liquid gif](./assets/project-liquid.gif)
 14 | 
 15 | ## ✨ Features
 16 | 
 17 | - Proper edgy bending and refraction
 18 | - Multiple refraction modes
 19 | - Configurable frosty level
 20 | - Supports arbitrary child elements
 21 | - Configurable paddings
 22 | - Correct hover and click effects
 23 | - Edges and highlights take on the underlying light like Apple's does
 24 | - Configurable chromatic aberration
 25 | - Configurable elasticity, to mimic Apple's "liquid" feel
 26 | 
 27 | > **⚠️ NOTE:** Safari and Firefox only partially support the effect (displacement will not be visible)
 28 | 
 29 | ## 🚀 Usage
 30 | 
 31 | ### Installation
 32 | 
 33 | ```bash
 34 | npm install liquid-glass-react
 35 | ```
 36 | 
 37 | ### Basic Usage
 38 | 
 39 | ```tsx
 40 | import LiquidGlass from 'liquid-glass-react'
 41 | 
 42 | function App() {
 43 |   return (
 44 |     <LiquidGlass>
 45 |       <div className="p-6">
 46 |         <h2>Your content here</h2>
 47 |         <p>This will have the liquid glass effect</p>
 48 |       </div>
 49 |     </LiquidGlass>
 50 |   )
 51 | }
 52 | ```
 53 | 
 54 | ### Button Example
 55 | 
 56 | ```tsx
 57 | <LiquidGlass
 58 |   displacementScale={64}
 59 |   blurAmount={0.1}
 60 |   saturation={130}
 61 |   aberrationIntensity={2}
 62 |   elasticity={0.35}
 63 |   cornerRadius={100}
 64 |   padding="8px 16px"
 65 |   onClick={() => console.log('Button clicked!')}
 66 | >
 67 |   <span className="text-white font-medium">Click Me</span>
 68 | </LiquidGlass>
 69 | ```
 70 | 
 71 | ### Mouse Container Example
 72 | 
 73 | When you want the glass effect to respond to mouse movement over a larger area (like a parent container), use the `mouseContainer` prop:
 74 | 
 75 | ```tsx
 76 | function App() {
 77 |   const containerRef = useRef<HTMLDivElement>(null)
 78 | 
 79 |   return (
 80 |     <div ref={containerRef} className="w-full h-screen bg-image">
 81 |       <LiquidGlass
 82 |         mouseContainer={containerRef}
 83 |         elasticity={0.3}
 84 |         style={{ position: 'fixed', top: '50%', left: '50%' }}
 85 |       >
 86 |         <div className="p-6">
 87 |           <h2>Glass responds to mouse anywhere in the container</h2>
 88 |         </div>
 89 |       </LiquidGlass>
 90 |     </div>
 91 |   )
 92 | }
 93 | ```
 94 | 
 95 | ## Props
 96 | 
 97 | | Prop | Type | Default | Description |
 98 | |------|------|---------|-------------|
 99 | | `children` | `React.ReactNode` | - | The content to render inside the glass container |
100 | | `displacementScale` | `number` | `70` | Controls the intensity of the displacement effect |
101 | | `blurAmount` | `number` | `0.0625` | Controls the blur/frosting level |
102 | | `saturation` | `number` | `140` | Controls color saturation of the glass effect |
103 | | `aberrationIntensity` | `number` | `2` | Controls chromatic aberration intensity |
104 | | `elasticity` | `number` | `0.15` | Controls the "liquid" elastic feel (0 = rigid, higher = more elastic) |
105 | | `cornerRadius` | `number` | `999` | Border radius in pixels |
106 | | `className` | `string` | `""` | Additional CSS classes |
107 | | `padding` | `string` | - | CSS padding value |
108 | | `style` | `React.CSSProperties` | - | Additional inline styles |
109 | | `overLight` | `boolean` | `false` | Whether the glass is over a light background |
110 | | `onClick` | `() => void` | - | Click handler |
111 | | `mouseContainer` | `React.RefObject<HTMLElement \| null> \| null` | `null` | Container element to track mouse movement on (defaults to the glass component itself) |
112 | | `mode` | `"standard" \| "polar" \| "prominent" \| "shader"` | `"standard"` | Refraction mode for different visual effects. `shader` is the most accurate but not the most stable. |
113 | | `globalMousePos` | `{ x: number; y: number }` | - | Global mouse position coordinates for manual control |
114 | | `mouseOffset` | `{ x: number; y: number }` | - | Mouse position offset for fine-tuning positioning |
115 | 


--------------------------------------------------------------------------------
/assets/button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rdev/liquid-glass-react/ac48eab18d1f7f444ae30002d240cae29c863a21/assets/button.png


--------------------------------------------------------------------------------
/assets/card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rdev/liquid-glass-react/ac48eab18d1f7f444ae30002d240cae29c863a21/assets/card.png


--------------------------------------------------------------------------------
/assets/project-liquid.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rdev/liquid-glass-react/ac48eab18d1f7f444ae30002d240cae29c863a21/assets/project-liquid.gif


--------------------------------------------------------------------------------
/assets/video.mov:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rdev/liquid-glass-react/ac48eab18d1f7f444ae30002d240cae29c863a21/assets/video.mov


--------------------------------------------------------------------------------
/bun.lock:
--------------------------------------------------------------------------------
  1 | {
  2 |   "lockfileVersion": 1,
  3 |   "workspaces": {
  4 |     "": {
  5 |       "name": "liquid-glass-react",
  6 |       "devDependencies": {
  7 |         "@biomejs/biome": "^1.9.4",
  8 |         "@types/react": "^18.2.0",
  9 |         "@types/react-dom": "^18.2.0",
 10 |         "esbuild": "^0.19.0",
 11 |         "react": "^18.2.0",
 12 |         "react-dom": "^18.2.0",
 13 |         "typescript": "^5.0.0",
 14 |       },
 15 |       "peerDependencies": {
 16 |         "react": ">=16.8.0",
 17 |         "react-dom": ">=16.8.0",
 18 |       },
 19 |     },
 20 |   },
 21 |   "packages": {
 22 |     "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
 23 | 
 24 |     "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
 25 | 
 26 |     "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
 27 | 
 28 |     "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
 29 | 
 30 |     "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
 31 | 
 32 |     "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
 33 | 
 34 |     "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
 35 | 
 36 |     "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
 37 | 
 38 |     "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
 39 | 
 40 |     "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
 41 | 
 42 |     "@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
 43 | 
 44 |     "@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
 45 | 
 46 |     "@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
 47 | 
 48 |     "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
 49 | 
 50 |     "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
 51 | 
 52 |     "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
 53 | 
 54 |     "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
 55 | 
 56 |     "@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
 57 | 
 58 |     "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
 59 | 
 60 |     "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
 61 | 
 62 |     "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
 63 | 
 64 |     "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
 65 | 
 66 |     "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
 67 | 
 68 |     "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
 69 | 
 70 |     "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
 71 | 
 72 |     "@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
 73 | 
 74 |     "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
 75 | 
 76 |     "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
 77 | 
 78 |     "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
 79 | 
 80 |     "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
 81 | 
 82 |     "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
 83 | 
 84 |     "@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
 85 | 
 86 |     "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
 87 | 
 88 |     "@types/react": ["@types/react@18.3.23", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w=="],
 89 | 
 90 |     "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
 91 | 
 92 |     "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
 93 | 
 94 |     "esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": "bin/esbuild" }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
 95 | 
 96 |     "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
 97 | 
 98 |     "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": "cli.js" }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
 99 | 
100 |     "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
101 | 
102 |     "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="],
103 | 
104 |     "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
105 | 
106 |     "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
107 |   }
108 | }
109 | 


--------------------------------------------------------------------------------
/esbuild.config.js:
--------------------------------------------------------------------------------
 1 | const esbuild = require('esbuild');
 2 | const path = require('path');
 3 | 
 4 | const createBuildConfig = (format) => ({
 5 |   entryPoints: ['src/index.ts'],
 6 |   bundle: true,
 7 |   format,
 8 |   outfile: format === 'esm' ? 'dist/index.esm.js' : 'dist/index.js',
 9 |   external: ['react', 'react-dom'],
10 |   target: ['es2020'],
11 |   jsx: 'automatic',
12 |   jsxImportSource: 'react',
13 |   minify: process.env.NODE_ENV === 'production',
14 |   sourcemap: true,
15 |   platform: 'browser',
16 |   splitting: false,
17 |   loader: {
18 |     '.tsx': 'tsx',
19 |     '.ts': 'ts',
20 |     '.js': 'js',
21 |     '.jsx': 'jsx'
22 |   },
23 |   define: {
24 |     'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
25 |   }
26 | });
27 | 
28 | const buildAll = async () => {
29 |   try {
30 |     console.log('🚀 Building ESM bundle...');
31 |     await esbuild.build(createBuildConfig('esm'));
32 |     console.log('✅ ESM bundle built successfully');
33 | 
34 |     console.log('🚀 Building CJS bundle...');
35 |     await esbuild.build(createBuildConfig('cjs'));
36 |     console.log('✅ CJS bundle built successfully');
37 | 
38 |     console.log('🎉 All bundles built successfully!');
39 |   } catch (error) {
40 |     console.error('❌ Build failed:', error);
41 |     process.exit(1);
42 |   }
43 | };
44 | 
45 | const watch = async () => {
46 |   try {
47 |     console.log('👀 Starting watch mode for ESM bundle...');
48 |     const ctx = await esbuild.context(createBuildConfig('esm'));
49 |     await ctx.watch();
50 |     console.log('✅ Watch mode active - listening for changes...');
51 |   } catch (error) {
52 |     console.error('❌ Watch mode failed:', error);
53 |     process.exit(1);
54 |   }
55 | };
56 | 
57 | // Check command line arguments
58 | const args = process.argv.slice(2);
59 | if (args.includes('--watch')) {
60 |   watch();
61 | } else {
62 |   buildAll();
63 | }
64 | 
65 | module.exports = { createBuildConfig, buildAll, watch };


--------------------------------------------------------------------------------
/liquid-glass-example/.gitignore:
--------------------------------------------------------------------------------
 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 2 | 
 3 | # dependencies
 4 | /node_modules
 5 | /.pnp
 6 | .pnp.*
 7 | .yarn/*
 8 | !.yarn/patches
 9 | !.yarn/plugins
10 | !.yarn/releases
11 | !.yarn/versions
12 | 
13 | # testing
14 | /coverage
15 | 
16 | # next.js
17 | /.next/
18 | /out/
19 | 
20 | # production
21 | /build
22 | 
23 | # misc
24 | .DS_Store
25 | *.pem
26 | 
27 | # debug
28 | npm-debug.log*
29 | yarn-debug.log*
30 | yarn-error.log*
31 | .pnpm-debug.log*
32 | 
33 | # env files (can opt-in for committing if needed)
34 | .env*
35 | 
36 | # vercel
37 | .vercel
38 | 
39 | # typescript
40 | *.tsbuildinfo
41 | next-env.d.ts
42 | 


--------------------------------------------------------------------------------
/liquid-glass-example/README.md:
--------------------------------------------------------------------------------
 1 | This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/pages/api-reference/create-next-app).
 2 | 
 3 | ## Getting Started
 4 | 
 5 | First, run the development server:
 6 | 
 7 | ```bash
 8 | npm run dev
 9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | # or
14 | bun dev
15 | ```
16 | 
17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18 | 
19 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
20 | 
21 | [API routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
22 | 
23 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes) instead of React pages.
24 | 
25 | This project uses [`next/font`](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
26 | 
27 | ## Learn More
28 | 
29 | To learn more about Next.js, take a look at the following resources:
30 | 
31 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
32 | - [Learn Next.js](https://nextjs.org/learn-pages-router) - an interactive Next.js tutorial.
33 | 
34 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
35 | 
36 | ## Deploy on Vercel
37 | 
38 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
39 | 
40 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/pages/building-your-application/deploying) for more details.
41 | 


--------------------------------------------------------------------------------
/liquid-glass-example/bun.lock:
--------------------------------------------------------------------------------
  1 | {
  2 |   "lockfileVersion": 1,
  3 |   "workspaces": {
  4 |     "": {
  5 |       "name": "liquid-glass-example",
  6 |       "dependencies": {
  7 |         "liquid-glass-react": "latest",
  8 |         "lucide-react": "^0.514.0",
  9 |         "next": "15.3.3",
 10 |         "react": "^19.0.0",
 11 |         "react-dom": "^19.0.0",
 12 |       },
 13 |       "devDependencies": {
 14 |         "@tailwindcss/postcss": "^4",
 15 |         "@types/node": "^20",
 16 |         "@types/react": "^19",
 17 |         "@types/react-dom": "^19",
 18 |         "tailwindcss": "^4",
 19 |         "typescript": "^5",
 20 |       },
 21 |     },
 22 |   },
 23 |   "packages": {
 24 |     "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
 25 | 
 26 |     "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
 27 | 
 28 |     "@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
 29 | 
 30 |     "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="],
 31 | 
 32 |     "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="],
 33 | 
 34 |     "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.1.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA=="],
 35 | 
 36 |     "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.1.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ=="],
 37 | 
 38 |     "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.1.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA=="],
 39 | 
 40 |     "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew=="],
 41 | 
 42 |     "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.1.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ=="],
 43 | 
 44 |     "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.1.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA=="],
 45 | 
 46 |     "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q=="],
 47 | 
 48 |     "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w=="],
 49 | 
 50 |     "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A=="],
 51 | 
 52 |     "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ=="],
 53 | 
 54 |     "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q=="],
 55 | 
 56 |     "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw=="],
 57 | 
 58 |     "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ=="],
 59 | 
 60 |     "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA=="],
 61 | 
 62 |     "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA=="],
 63 | 
 64 |     "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.2", "", { "dependencies": { "@emnapi/runtime": "^1.4.3" }, "cpu": "none" }, "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ=="],
 65 | 
 66 |     "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ=="],
 67 | 
 68 |     "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw=="],
 69 | 
 70 |     "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="],
 71 | 
 72 |     "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
 73 | 
 74 |     "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
 75 | 
 76 |     "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
 77 | 
 78 |     "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="],
 79 | 
 80 |     "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
 81 | 
 82 |     "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
 83 | 
 84 |     "@next/env": ["@next/env@15.3.3", "", {}, "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw=="],
 85 | 
 86 |     "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg=="],
 87 | 
 88 |     "@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw=="],
 89 | 
 90 |     "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw=="],
 91 | 
 92 |     "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA=="],
 93 | 
 94 |     "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw=="],
 95 | 
 96 |     "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw=="],
 97 | 
 98 |     "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ=="],
 99 | 
100 |     "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw=="],
101 | 
102 |     "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
103 | 
104 |     "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
105 | 
106 |     "@tailwindcss/node": ["@tailwindcss/node@4.1.8", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.8" } }, "sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q=="],
107 | 
108 |     "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.8", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.8", "@tailwindcss/oxide-darwin-arm64": "4.1.8", "@tailwindcss/oxide-darwin-x64": "4.1.8", "@tailwindcss/oxide-freebsd-x64": "4.1.8", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.8", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.8", "@tailwindcss/oxide-linux-arm64-musl": "4.1.8", "@tailwindcss/oxide-linux-x64-gnu": "4.1.8", "@tailwindcss/oxide-linux-x64-musl": "4.1.8", "@tailwindcss/oxide-wasm32-wasi": "4.1.8", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.8", "@tailwindcss/oxide-win32-x64-msvc": "4.1.8" } }, "sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A=="],
109 | 
110 |     "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg=="],
111 | 
112 |     "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A=="],
113 | 
114 |     "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw=="],
115 | 
116 |     "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg=="],
117 | 
118 |     "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8", "", { "os": "linux", "cpu": "arm" }, "sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ=="],
119 | 
120 |     "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q=="],
121 | 
122 |     "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ=="],
123 | 
124 |     "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g=="],
125 | 
126 |     "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg=="],
127 | 
128 |     "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.8", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.10", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg=="],
129 | 
130 |     "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA=="],
131 | 
132 |     "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.8", "", { "os": "win32", "cpu": "x64" }, "sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ=="],
133 | 
134 |     "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.8", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.8", "@tailwindcss/oxide": "4.1.8", "postcss": "^8.4.41", "tailwindcss": "4.1.8" } }, "sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw=="],
135 | 
136 |     "@types/node": ["@types/node@20.19.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q=="],
137 | 
138 |     "@types/react": ["@types/react@19.1.7", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-BnsPLV43ddr05N71gaGzyZ5hzkCmGwhMvYc8zmvI8Ci1bRkkDSzDDVfAXfN2tk748OwI7ediiPX6PfT9p0QGVg=="],
139 | 
140 |     "@types/react-dom": ["@types/react-dom@19.1.6", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw=="],
141 | 
142 |     "busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
143 | 
144 |     "caniuse-lite": ["caniuse-lite@1.0.30001721", "", {}, "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ=="],
145 | 
146 |     "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
147 | 
148 |     "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
149 | 
150 |     "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
151 | 
152 |     "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
153 | 
154 |     "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
155 | 
156 |     "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
157 | 
158 |     "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
159 | 
160 |     "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
161 | 
162 |     "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
163 | 
164 |     "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
165 | 
166 |     "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
167 | 
168 |     "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
169 | 
170 |     "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
171 | 
172 |     "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
173 | 
174 |     "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
175 | 
176 |     "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
177 | 
178 |     "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
179 | 
180 |     "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
181 | 
182 |     "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
183 | 
184 |     "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
185 | 
186 |     "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
187 | 
188 |     "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
189 | 
190 |     "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
191 | 
192 |     "liquid-glass-react": ["liquid-glass-react@1.0.0", "", { "peerDependencies": { "react": ">=19", "react-dom": ">=19" } }, "sha512-2IKXBoYJAkKZIINSIdRxHbita9BCPooSKlNzEZrs9uSw0retWovYeTl3fqKtXYvOQo0Myza4NL4DoRC28uJGtQ=="],
193 | 
194 |     "lucide-react": ["lucide-react@0.514.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-HXD0OAMd+JM2xCjlwG1EGW9Nuab64dhjO3+MvdyD+pSUeOTBaVAPhQblKIYmmX4RyBYbdzW0VWnJpjJmxWGr6w=="],
195 | 
196 |     "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
197 | 
198 |     "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
199 | 
200 |     "minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
201 | 
202 |     "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
203 | 
204 |     "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
205 | 
206 |     "next": ["next@15.3.3", "", { "dependencies": { "@next/env": "15.3.3", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.3", "@next/swc-darwin-x64": "15.3.3", "@next/swc-linux-arm64-gnu": "15.3.3", "@next/swc-linux-arm64-musl": "15.3.3", "@next/swc-linux-x64-gnu": "15.3.3", "@next/swc-linux-x64-musl": "15.3.3", "@next/swc-win32-arm64-msvc": "15.3.3", "@next/swc-win32-x64-msvc": "15.3.3", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw=="],
207 | 
208 |     "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
209 | 
210 |     "postcss": ["postcss@8.5.4", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w=="],
211 | 
212 |     "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
213 | 
214 |     "react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
215 | 
216 |     "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
217 | 
218 |     "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
219 | 
220 |     "sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="],
221 | 
222 |     "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
223 | 
224 |     "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
225 | 
226 |     "streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="],
227 | 
228 |     "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
229 | 
230 |     "tailwindcss": ["tailwindcss@4.1.8", "", {}, "sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og=="],
231 | 
232 |     "tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
233 | 
234 |     "tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
235 | 
236 |     "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
237 | 
238 |     "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
239 | 
240 |     "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
241 | 
242 |     "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
243 | 
244 |     "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
245 | 
246 |     "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
247 | 
248 |     "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="],
249 | 
250 |     "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.11", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.9.0" }, "bundled": true }, "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA=="],
251 | 
252 |     "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="],
253 | 
254 |     "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
255 | 
256 |     "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
257 |   }
258 | }
259 | 


--------------------------------------------------------------------------------
/liquid-glass-example/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rdev/liquid-glass-react/ac48eab18d1f7f444ae30002d240cae29c863a21/liquid-glass-example/bun.lockb


--------------------------------------------------------------------------------
/liquid-glass-example/next.config.ts:
--------------------------------------------------------------------------------
 1 | import type { NextConfig } from "next";
 2 | 
 3 | const nextConfig: NextConfig = {
 4 |   /* config options here */
 5 |   reactStrictMode: true,
 6 |   experimental: {
 7 |     externalDir: true,
 8 |   },
 9 | };
10 | 
11 | export default nextConfig;
12 | 


--------------------------------------------------------------------------------
/liquid-glass-example/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "liquid-glass-example",
 3 |   "version": "0.1.0",
 4 |   "private": true,
 5 |   "scripts": {
 6 |     "dev": "next dev --turbopack",
 7 |     "build": "next build",
 8 |     "start": "next start",
 9 |     "lint": "next lint"
10 |   },
11 |   "dependencies": {
12 |     "liquid-glass-react": "^1.0.2",
13 |     "lucide-react": "^0.514.0",
14 |     "next": "15.3.3",
15 |     "react": "^19.0.0",
16 |     "react-dom": "^19.0.0"
17 |   },
18 |   "devDependencies": {
19 |     "typescript": "^5",
20 |     "@types/node": "^20",
21 |     "@types/react": "^19",
22 |     "@types/react-dom": "^19",
23 |     "@tailwindcss/postcss": "^4",
24 |     "tailwindcss": "^4"
25 |   }
26 | }
27 | 


--------------------------------------------------------------------------------
/liquid-glass-example/postcss.config.mjs:
--------------------------------------------------------------------------------
1 | const config = {
2 |   plugins: ["@tailwindcss/postcss"],
3 | };
4 | 
5 | export default config;
6 | 


--------------------------------------------------------------------------------
/liquid-glass-example/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rdev/liquid-glass-react/ac48eab18d1f7f444ae30002d240cae29c863a21/liquid-glass-example/public/favicon.ico


--------------------------------------------------------------------------------
/liquid-glass-example/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "@/styles/globals.css"
2 | import type { AppProps } from "next/app"
3 | 
4 | export default function App({ Component, pageProps }: AppProps) {
5 |   return <Component {...pageProps} />
6 | }
7 | 


--------------------------------------------------------------------------------
/liquid-glass-example/src/pages/_document.tsx:
--------------------------------------------------------------------------------
 1 | import { Html, Head, Main, NextScript } from "next/document"
 2 | 
 3 | export default function Document() {
 4 |   return (
 5 |     <Html lang="en">
 6 |       <Head />
 7 |       <body className="antialiased">
 8 |         <Main />
 9 |         <NextScript />
10 |       </body>
11 |     </Html>
12 |   )
13 | }
14 | 


--------------------------------------------------------------------------------
/liquid-glass-example/src/pages/api/hello.ts:
--------------------------------------------------------------------------------
 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
 2 | import type { NextApiRequest, NextApiResponse } from "next"
 3 | 
 4 | type Data = {
 5 |   name: string
 6 | }
 7 | 
 8 | export default function handler(_req: NextApiRequest, res: NextApiResponse<Data>) {
 9 |   res.status(200).json({ name: "John Doe" })
10 | }
11 | 


--------------------------------------------------------------------------------
/liquid-glass-example/src/pages/index.tsx:
--------------------------------------------------------------------------------
  1 | import { Geist } from "next/font/google"
  2 | import { useState, useRef } from "react"
  3 | import LiquidGlass from "liquid-glass-react"
  4 | import { LogOutIcon, Github } from "lucide-react"
  5 | 
  6 | const geistSans = Geist({
  7 |   variable: "--font-geist-sans",
  8 |   subsets: ["latin"],
  9 | })
 10 | 
 11 | export default function Home() {
 12 |   // User Info Card Controls
 13 |   const [displacementScale, setDisplacementScale] = useState(100)
 14 |   const [blurAmount, setBlurAmount] = useState(0.5)
 15 |   const [saturation, setSaturation] = useState(140)
 16 |   const [aberrationIntensity, setAberrationIntensity] = useState(2)
 17 |   const [elasticity, setElasticity] = useState(0)
 18 |   const [cornerRadius, setCornerRadius] = useState(32)
 19 |   const [userInfoOverLight, setUserInfoOverLight] = useState(false)
 20 |   const [userInfoMode, setUserInfoMode] = useState<"standard" | "polar" | "prominent" | "shader">("standard")
 21 | 
 22 |   // Log Out Button Controls
 23 |   const [logoutDisplacementScale, setLogoutDisplacementScale] = useState(64)
 24 |   const [logoutBlurAmount, setLogoutBlurAmount] = useState(0.1)
 25 |   const [logoutSaturation, setLogoutSaturation] = useState(130)
 26 |   const [logoutAberrationIntensity, setLogoutAberrationIntensity] = useState(2)
 27 |   const [logoutElasticity, setLogoutElasticity] = useState(0.35)
 28 |   const [logoutCornerRadius, setLogoutCornerRadius] = useState(100)
 29 |   const [logoutOverLight, setLogoutOverLight] = useState(false)
 30 |   const [logoutMode, setLogoutMode] = useState<"standard" | "polar" | "prominent" | "shader">("standard")
 31 | 
 32 |   // Shared state
 33 |   const [activeTab, setActiveTab] = useState<"userInfo" | "logOut">("userInfo")
 34 |   const containerRef = useRef<HTMLDivElement>(null)
 35 | 
 36 |   const [scroll, setScroll] = useState(0)
 37 | 
 38 |   const handleScroll = (event: React.UIEvent<HTMLDivElement>) => {
 39 |     requestAnimationFrame(() => {
 40 |       setScroll((event?.target as any)?.scrollTop)
 41 |     })
 42 |   }
 43 | 
 44 |   const scrollingOverBrightSection = scroll > 230 && scroll < 500
 45 | 
 46 |   return (
 47 |     <div
 48 |       className={`${geistSans.className} grid grid-cols-1 grid-rows-2 md:grid-rows-1 md:grid-cols-3 shadow-2xl w-full max-w-5xl mx-auto md:my-10 h-screen md:max-h-[calc(100vh-5rem)] md:rounded-3xl overflow-hidden font-[family-name:var(--font-geist-sans)]`}
 49 |     >
 50 |       {/* Left Panel - Glass Effect Demo */}
 51 |       <div className="flex-1 relative overflow-auto min-h-screen md:col-span-2" ref={containerRef} onScroll={handleScroll}>
 52 |         <div className="w-full min-h-[200vh] absolute top-0 left-0 pb-96 mb-96">
 53 |           <img src="https://picsum.photos/2000/2000" className="w-full h-96 object-cover" />
 54 |           <div className="flex flex-col gap-2" id="bright-section">
 55 |             <h2 className="text-2xl font-semibold my-5 text-center">Some Heading</h2>
 56 |             <p className="px-10">
 57 |               Bacon ipsum dolor amet hamburger Bacon ipsum dolor amet hamburger <br />
 58 |               Bacon ipsum dolor amet hamburger Bacon ipsum dolor amet hamburger
 59 |               <br />
 60 |               Bacon ipsum dolor amet hamburger Bacon ipsum dolor amet hamburger
 61 |               <br />
 62 |               Bacon ipsum dolor amet hamburger Bacon ipsum dolor amet hamburger
 63 |               <br />
 64 |               Bacon ipsum dolor amet hamburger Bacon ipsum dolor amet hamburger
 65 |               <br />
 66 |               Bacon ipsum dolor amet hamburger Bacon ipsum dolor amet hamburger
 67 |             </p>
 68 |           </div>
 69 |           <img src="https://picsum.photos/1200/1200" className="w-full h-80 object-cover my-10" />
 70 |           <img src="https://picsum.photos/1400/1300" className="w-full h-72 object-cover my-10" />
 71 |           <img src="https://picsum.photos/1100/1200" className="w-full h-96 object-cover my-10 mb-96" />
 72 |         </div>
 73 | 
 74 |         {activeTab === "userInfo" && (
 75 |           <LiquidGlass
 76 |               displacementScale={displacementScale}
 77 |               blurAmount={blurAmount}
 78 |               saturation={saturation}
 79 |               aberrationIntensity={aberrationIntensity}
 80 |               elasticity={elasticity}
 81 |               cornerRadius={cornerRadius}
 82 |               mouseContainer={containerRef}
 83 |               overLight={scrollingOverBrightSection || userInfoOverLight}
 84 |               mode={userInfoMode}
 85 |               style={{
 86 |                 position: "fixed",
 87 |                 top: "25%",
 88 |                 left: "40%",
 89 |               }}
 90 |             >
 91 |               <div className="w-72 text-shadow-lg">
 92 |                 <h3 className="text-xl font-semibold mb-4">User Info</h3>
 93 |                 <div className="space-y-3">
 94 |                   <div className="flex items-center space-x-3">
 95 |                     <div className="w-12 h-12 bg-black/10 backdrop-blur rounded-full flex items-center justify-center text-white font-semibold">JD</div>
 96 |                     <div>
 97 |                       <p className="font-medium">John Doe</p>
 98 |                       <p className="text-sm text-white">Software Engineer</p>
 99 |                     </div>
100 |                   </div>
101 |                   <div className="pt-2 space-y-2">
102 |                     <div className="flex justify-between">
103 |                       <span className="text-sm text-white">Email:</span>
104 |                       <span className="text-sm">john.doe@example.com</span>
105 |                     </div>
106 |                     <div className="flex justify-between">
107 |                       <span className="text-sm text-white">Location:</span>
108 |                       <span className="text-sm">San Francisco, CA</span>
109 |                     </div>
110 |                     <div className="flex justify-between">
111 |                       <span className="text-sm text-white">Joined:</span>
112 |                       <span className="text-sm">March 2023</span>
113 |                     </div>
114 |                   </div>
115 |                 </div>
116 |               </div>
117 |             </LiquidGlass>
118 |         )}
119 | 
120 |         {activeTab === "logOut" && (
121 |           <LiquidGlass
122 |             displacementScale={logoutDisplacementScale}
123 |             blurAmount={logoutBlurAmount}
124 |             saturation={logoutSaturation}
125 |             aberrationIntensity={logoutAberrationIntensity}
126 |             elasticity={logoutElasticity}
127 |             cornerRadius={logoutCornerRadius}
128 |             mouseContainer={containerRef}
129 |             overLight={scrollingOverBrightSection || logoutOverLight}
130 |             mode={logoutMode}
131 |             padding="8px 16px"
132 |             onClick={() => {
133 |               console.log("Logged out")
134 |             }}
135 |             style={{
136 |               position: "fixed",
137 |               top: "20%",
138 |               left: "40%",
139 |             }}
140 |           >
141 |             <h3 className="text-lg font-medium flex items-center gap-2">
142 |               Log Out
143 |               <LogOutIcon className="w-5 h-5" />
144 |             </h3>
145 |           </LiquidGlass>
146 |         )}
147 |       </div>
148 | 
149 |       {/* Right Panel - Control Panel */}
150 |       <div className="row-start-2 rounded-t-3xl md:rounded-none md:col-start-3 bg-gray-900/80 h-full overflow-y-auto backdrop-blur-md border-l border-white/10 p-8 flex flex-col">
151 |         <div className="mb-8">
152 |           <div className="flex items-center justify-between mb-4">
153 |             <h2 className="text-2xl font-bold text-white">Glassy Boi but Web</h2>
154 |             <a href="https://github.com/rdev/liquid-glass-react" target="_blank" rel="noopener noreferrer" className="text-white/70 hover:text-white transition-colors p-2 hover:bg-white/10 rounded-lg" title="View on GitHub">
155 |               <Github className="w-6 h-6" />
156 |             </a>
157 |           </div>
158 |           <p className="text-white/60 text-sm">Liquid Glass container effect for React. With settings and effects and stuff.</p>
159 | 
160 |           <p className="font-semibold text-yellow-300 text-xs mt-2 leading-snug">⚠️ This doesn't fully work in Safari and Firefox. You will not see edge refraction on non-chromium browsers.</p>
161 |         </div>
162 | 
163 |         {/* Tab Switcher */}
164 |         <div className="flex mb-6 bg-white/5 rounded-lg p-1">
165 |           <button
166 |             onClick={() => setActiveTab("userInfo")}
167 |             className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all ${activeTab === "userInfo" ? "bg-blue-500 text-white shadow-lg" : "text-white/70 hover:text-white hover:bg-white/10"}`}
168 |           >
169 |             User Info Card
170 |           </button>
171 |           <button
172 |             onClick={() => setActiveTab("logOut")}
173 |             className={`flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all ${activeTab === "logOut" ? "bg-blue-500 text-white shadow-lg" : "text-white/70 hover:text-white hover:bg-white/10"}`}
174 |           >
175 |             Log Out Button
176 |           </button>
177 |         </div>
178 | 
179 |         <div className="space-y-8 flex-1">
180 |           {activeTab === "userInfo" && (
181 |             <>
182 |               <div>
183 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Refraction Mode</span>
184 |                 <div className="space-y-2">
185 |                   <div className="flex items-center space-x-3">
186 |                     <input
187 |                       type="radio"
188 |                       id="userInfoModeStandard"
189 |                       name="userInfoMode"
190 |                       value="standard"
191 |                       checked={userInfoMode === "standard"}
192 |                       onChange={(e) => setUserInfoMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
193 |                       className="w-4 h-4 accent-blue-500"
194 |                     />
195 |                     <label htmlFor="userInfoModeStandard" className="text-sm text-white/90">
196 |                       Standard
197 |                     </label>
198 |                   </div>
199 |                   <div className="flex items-center space-x-3">
200 |                     <input
201 |                       type="radio"
202 |                       id="userInfoModePolar"
203 |                       name="userInfoMode"
204 |                       value="polar"
205 |                       checked={userInfoMode === "polar"}
206 |                       onChange={(e) => setUserInfoMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
207 |                       className="w-4 h-4 accent-blue-500"
208 |                     />
209 |                     <label htmlFor="userInfoModePolar" className="text-sm text-white/90">
210 |                       Polar
211 |                     </label>
212 |                   </div>
213 |                   <div className="flex items-center space-x-3">
214 |                     <input
215 |                       type="radio"
216 |                       id="userInfoModeProminent"
217 |                       name="userInfoMode"
218 |                       value="prominent"
219 |                       checked={userInfoMode === "prominent"}
220 |                       onChange={(e) => setUserInfoMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
221 |                       className="w-4 h-4 accent-blue-500"
222 |                     />
223 |                     <label htmlFor="userInfoModeProminent" className="text-sm text-white/90">
224 |                       Prominent
225 |                     </label>
226 |                   </div>
227 |                   <div className="flex items-center space-x-3">
228 |                     <input
229 |                       type="radio"
230 |                       id="userInfoModeShader"
231 |                       name="userInfoMode"
232 |                       value="shader"
233 |                       checked={userInfoMode === "shader"}
234 |                       onChange={(e) => setUserInfoMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
235 |                       className="w-4 h-4 accent-blue-500"
236 |                     />
237 |                     <label htmlFor="userInfoModeShader" className="text-sm text-white/90">
238 |                       Shader (Experimental)
239 |                     </label>
240 |                   </div>
241 |                 </div>
242 |                 <p className="text-xs text-white/50 mt-2">Controls the refraction calculation method</p>
243 |               </div>
244 | 
245 |               <div>
246 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Displacement Scale</span>
247 |                 <div className="mb-2">
248 |                   <span className="text-xl font-mono text-blue-300">{displacementScale}</span>
249 |                 </div>
250 |                 <input type="range" min="0" max="200" step="1" value={displacementScale} onChange={(e) => setDisplacementScale(Number(e.target.value))} className="w-full" />
251 |                 <p className="text-xs text-white/50 mt-2">Controls the intensity of edge distortion</p>
252 |               </div>
253 | 
254 |               <div>
255 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Blur Amount</span>
256 |                 <div className="mb-2">
257 |                   <span className="text-xl font-mono text-green-300">{blurAmount.toFixed(1)}</span>
258 |                 </div>
259 |                 <input type="range" min="0" max="1" step="0.01" value={blurAmount} onChange={(e) => setBlurAmount(Number(e.target.value))} className="w-full" />
260 |                 <p className="text-xs text-white/50 mt-2">Controls backdrop blur intensity</p>
261 |               </div>
262 | 
263 |               <div>
264 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Saturation</span>
265 |                 <div className="mb-2">
266 |                   <span className="text-xl font-mono text-purple-300">{saturation}%</span>
267 |                 </div>
268 |                 <input type="range" min="100" max="300" step="10" value={saturation} onChange={(e) => setSaturation(Number(e.target.value))} className="w-full" />
269 |                 <p className="text-xs text-white/50 mt-2">Controls color saturation of the backdrop</p>
270 |               </div>
271 | 
272 |               <div>
273 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Chromatic Aberration</span>
274 |                 <div className="mb-2">
275 |                   <span className="text-xl font-mono text-cyan-300">{aberrationIntensity}</span>
276 |                 </div>
277 |                 <input type="range" min="0" max="20" step="1" value={aberrationIntensity} onChange={(e) => setAberrationIntensity(Number(e.target.value))} className="w-full" />
278 |                 <p className="text-xs text-white/50 mt-2">Controls RGB channel separation intensity</p>
279 |               </div>
280 | 
281 |               <div>
282 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Elasticity</span>
283 |                 <div className="mb-2">
284 |                   <span className="text-xl font-mono text-orange-300">{elasticity.toFixed(2)}</span>
285 |                 </div>
286 |                 <input type="range" min="0" max="1" step="0.05" value={elasticity} onChange={(e) => setElasticity(Number(e.target.value))} className="w-full" />
287 |                 <p className="text-xs text-white/50 mt-2">Controls how much the glass reaches toward the cursor</p>
288 |               </div>
289 | 
290 |               <div>
291 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Corner Radius</span>
292 |                 <div className="mb-2">
293 |                   <span className="text-xl font-mono text-pink-300">{cornerRadius === 999 ? "Full" : `${cornerRadius}px`}</span>
294 |                 </div>
295 |                 <input type="range" min="0" max="100" step="1" value={cornerRadius} onChange={(e) => setCornerRadius(Number(e.target.value))} className="w-full" />
296 |                 <p className="text-xs text-white/50 mt-2">Controls the roundness of the glass corners</p>
297 |               </div>
298 | 
299 |               <div>
300 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Over Light</span>
301 |                 <div className="flex items-center space-x-3">
302 |                   <input type="checkbox" id="userInfoOverLight" checked={userInfoOverLight} onChange={(e) => setUserInfoOverLight(e.target.checked)} className="w-5 h-5 accent-blue-500" />
303 |                   <label htmlFor="userInfoOverLight" className="text-sm text-white/90">
304 |                     Tint liquid glass dark (use for bright backgrounds)
305 |                   </label>
306 |                 </div>
307 |                 <p className="text-xs text-white/50 mt-2">Makes the glass darker for better visibility on light backgrounds</p>
308 |               </div>
309 |             </>
310 |           )}
311 | 
312 |           {activeTab === "logOut" && (
313 |             <>
314 |               <div>
315 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Refraction Mode</span>
316 |                 <div className="space-y-2">
317 |                   <div className="flex items-center space-x-3">
318 |                     <input
319 |                       type="radio"
320 |                       id="logoutModeStandard"
321 |                       name="logoutMode"
322 |                       value="standard"
323 |                       checked={logoutMode === "standard"}
324 |                       onChange={(e) => setLogoutMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
325 |                       className="w-4 h-4 accent-blue-500"
326 |                     />
327 |                     <label htmlFor="logoutModeStandard" className="text-sm text-white/90">
328 |                       Standard
329 |                     </label>
330 |                   </div>
331 |                   <div className="flex items-center space-x-3">
332 |                     <input
333 |                       type="radio"
334 |                       id="logoutModePolar"
335 |                       name="logoutMode"
336 |                       value="polar"
337 |                       checked={logoutMode === "polar"}
338 |                       onChange={(e) => setLogoutMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
339 |                       className="w-4 h-4 accent-blue-500"
340 |                     />
341 |                     <label htmlFor="logoutModePolar" className="text-sm text-white/90">
342 |                       Polar
343 |                     </label>
344 |                   </div>
345 |                   <div className="flex items-center space-x-3">
346 |                     <input
347 |                       type="radio"
348 |                       id="logoutModeProminent"
349 |                       name="logoutMode"
350 |                       value="prominent"
351 |                       checked={logoutMode === "prominent"}
352 |                       onChange={(e) => setLogoutMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
353 |                       className="w-4 h-4 accent-blue-500"
354 |                     />
355 |                     <label htmlFor="logoutModeProminent" className="text-sm text-white/90">
356 |                       Prominent
357 |                     </label>
358 |                   </div>
359 |                   <div className="flex items-center space-x-3">
360 |                     <input
361 |                       type="radio"
362 |                       id="logoutModeShader"
363 |                       name="logoutMode"
364 |                       value="shader"
365 |                       checked={logoutMode === "shader"}
366 |                       onChange={(e) => setLogoutMode(e.target.value as "standard" | "polar" | "prominent" | "shader")}
367 |                       className="w-4 h-4 accent-blue-500"
368 |                     />
369 |                     <label htmlFor="logoutModeShader" className="text-sm text-white/90">
370 |                       Shader
371 |                     </label>
372 |                   </div>
373 |                 </div>
374 |                 <p className="text-xs text-white/50 mt-2">Controls the refraction calculation method</p>
375 |               </div>
376 | 
377 |               <div>
378 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Displacement Scale</span>
379 |                 <div className="mb-2">
380 |                   <span className="text-xl font-mono text-blue-300">{logoutDisplacementScale}</span>
381 |                 </div>
382 |                 <input type="range" min="0" max="200" step="1" value={logoutDisplacementScale} onChange={(e) => setLogoutDisplacementScale(Number(e.target.value))} className="w-full" />
383 |                 <p className="text-xs text-white/50 mt-2">Controls the intensity of edge distortion</p>
384 |               </div>
385 | 
386 |               <div>
387 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Blur Amount</span>
388 |                 <div className="mb-2">
389 |                   <span className="text-xl font-mono text-green-300">{logoutBlurAmount.toFixed(1)}</span>
390 |                 </div>
391 |                 <input type="range" min="0" max="1" step="0.01" value={logoutBlurAmount} onChange={(e) => setLogoutBlurAmount(Number(e.target.value))} className="w-full" />
392 |                 <p className="text-xs text-white/50 mt-2">Controls backdrop blur intensity</p>
393 |               </div>
394 | 
395 |               <div>
396 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Saturation</span>
397 |                 <div className="mb-2">
398 |                   <span className="text-xl font-mono text-purple-300">{logoutSaturation}%</span>
399 |                 </div>
400 |                 <input type="range" min="100" max="300" step="10" value={logoutSaturation} onChange={(e) => setLogoutSaturation(Number(e.target.value))} className="w-full" />
401 |                 <p className="text-xs text-white/50 mt-2">Controls color saturation of the backdrop</p>
402 |               </div>
403 | 
404 |               <div>
405 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Chromatic Aberration</span>
406 |                 <div className="mb-2">
407 |                   <span className="text-xl font-mono text-cyan-300">{logoutAberrationIntensity}</span>
408 |                 </div>
409 |                 <input type="range" min="0" max="20" step="1" value={logoutAberrationIntensity} onChange={(e) => setLogoutAberrationIntensity(Number(e.target.value))} className="w-full" />
410 |                 <p className="text-xs text-white/50 mt-2">Controls RGB channel separation intensity</p>
411 |               </div>
412 | 
413 |               <div>
414 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Elasticity</span>
415 |                 <div className="mb-2">
416 |                   <span className="text-xl font-mono text-orange-300">{logoutElasticity.toFixed(2)}</span>
417 |                 </div>
418 |                 <input type="range" min="0" max="1" step="0.05" value={logoutElasticity} onChange={(e) => setLogoutElasticity(Number(e.target.value))} className="w-full" />
419 |                 <p className="text-xs text-white/50 mt-2">Controls how much the glass reaches toward the cursor</p>
420 |               </div>
421 | 
422 |               <div>
423 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Corner Radius</span>
424 |                 <div className="mb-2">
425 |                   <span className="text-xl font-mono text-pink-300">{logoutCornerRadius === 999 ? "Full" : `${logoutCornerRadius}px`}</span>
426 |                 </div>
427 |                 <input type="range" min="0" max="100" step="1" value={logoutCornerRadius} onChange={(e) => setLogoutCornerRadius(Number(e.target.value))} className="w-full" />
428 |                 <p className="text-xs text-white/50 mt-2">Controls the roundness of the glass corners</p>
429 |               </div>
430 | 
431 |               <div>
432 |                 <span className="block text-sm font-semibold text-white/90 mb-3">Over Light</span>
433 |                 <div className="flex items-center space-x-3">
434 |                   <input type="checkbox" id="logoutOverLight" checked={logoutOverLight} onChange={(e) => setLogoutOverLight(e.target.checked)} className="w-5 h-5 accent-blue-500" />
435 |                   <label htmlFor="logoutOverLight" className="text-sm text-white/90">
436 |                     Tint liquid glass dark (use for bright backgrounds)
437 |                   </label>
438 |                 </div>
439 |                 <p className="text-xs text-white/50 mt-2">Makes the glass darker for better visibility on light backgrounds</p>
440 |               </div>
441 |             </>
442 |           )}
443 |         </div>
444 |       </div>
445 |     </div>
446 |   )
447 | }
448 | 


--------------------------------------------------------------------------------
/liquid-glass-example/src/styles/globals.css:
--------------------------------------------------------------------------------
  1 | @import "tailwindcss";
  2 | 
  3 | :root {
  4 |   --background: #ffffff;
  5 |   --foreground: #171717;
  6 | }
  7 | 
  8 | @theme inline {
  9 |   --color-background: var(--background);
 10 |   --color-foreground: var(--foreground);
 11 |   --font-sans: var(--font-geist-sans);
 12 |   --font-mono: var(--font-geist-mono);
 13 | }
 14 | 
 15 | @media (prefers-color-scheme: dark) {
 16 |   :root {
 17 |     --background: #0a0a0a;
 18 |     --foreground: #ededed;
 19 |   }
 20 | }
 21 | 
 22 | body {
 23 |   background: var(--background);
 24 |   color: var(--foreground);
 25 |   font-family: Arial, Helvetica, sans-serif;
 26 | }
 27 | 
 28 | /* Custom range slider styling */
 29 | input[type="range"] {
 30 |   -webkit-appearance: none;
 31 |   appearance: none;
 32 |   background: #00000033;
 33 |   border-radius: 999px;
 34 |   cursor: pointer;
 35 |   height: 24px;
 36 | }
 37 | 
 38 | input[type="range"]::-webkit-slider-track {
 39 |   background: linear-gradient(90deg, rgba(59, 130, 246, 0.3), rgba(168, 85, 247, 0.3));
 40 |   height: 6px;
 41 |   border-radius: 3px;
 42 |   border: 1px solid rgba(255, 255, 255, 0.1);
 43 | }
 44 | 
 45 | input[type="range"]::-webkit-slider-thumb {
 46 |   -webkit-appearance: none;
 47 |   appearance: none;
 48 |   background: linear-gradient(135deg, #60a5fa, #a78bfa);
 49 |   height: 24px;
 50 |   width: 24px;
 51 |   border-radius: 50%;
 52 |   border: 2px solid rgba(255, 255, 255, 0.8);
 53 |   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 0 rgba(96, 165, 250, 0.4);
 54 |   transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 55 |   cursor: pointer;
 56 | }
 57 | 
 58 | input[type="range"]::-webkit-slider-thumb:hover {
 59 |   background: linear-gradient(135deg, #3b82f6, #8b5cf6);
 60 |   transform: scale(1.15);
 61 |   box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5), 0 0 0 8px rgba(96, 165, 250, 0.2);
 62 |   border-color: white;
 63 | }
 64 | 
 65 | input[type="range"]::-webkit-slider-thumb:active {
 66 |   transform: scale(1.05);
 67 |   box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6), 0 0 0 12px rgba(96, 165, 250, 0.3);
 68 | }
 69 | 
 70 | input[type="range"]::-moz-range-track {
 71 |   background: linear-gradient(90deg, rgba(59, 130, 246, 0.3), rgba(168, 85, 247, 0.3));
 72 |   height: 6px;
 73 |   border-radius: 3px;
 74 |   border: 1px solid rgba(255, 255, 255, 0.1);
 75 | }
 76 | 
 77 | input[type="range"]::-moz-range-thumb {
 78 |   background: linear-gradient(135deg, #60a5fa, #a78bfa);
 79 |   height: 24px;
 80 |   width: 24px;
 81 |   border-radius: 50%;
 82 |   border: 2px solid rgba(255, 255, 255, 0.8);
 83 |   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
 84 |   cursor: pointer;
 85 |   transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 86 | }
 87 | 
 88 | input[type="range"]::-moz-range-thumb:hover {
 89 |   background: linear-gradient(135deg, #3b82f6, #8b5cf6);
 90 |   transform: scale(1.15);
 91 |   box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5);
 92 |   border-color: white;
 93 | }
 94 | 
 95 | input[type="range"]:focus {
 96 |   outline: none;
 97 | }
 98 | 
 99 | input[type="range"]:focus::-webkit-slider-thumb {
100 |   box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 4px rgba(96, 165, 250, 0.3);
101 | }
102 | 


--------------------------------------------------------------------------------
/liquid-glass-example/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2017",
 4 |     "lib": ["dom", "dom.iterable", "esnext"],
 5 |     "allowJs": true,
 6 |     "skipLibCheck": true,
 7 |     "strict": true,
 8 |     "noEmit": true,
 9 |     "esModuleInterop": true,
10 |     "module": "esnext",
11 |     "moduleResolution": "bundler",
12 |     "resolveJsonModule": true,
13 |     "isolatedModules": true,
14 |     "jsx": "preserve",
15 |     "incremental": true,
16 |     "paths": {
17 |       "@/*": ["./src/*"]
18 |     }
19 |   },
20 |   "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
21 |   "exclude": ["node_modules"]
22 | }
23 | 


--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
  1 | {
  2 |   "name": "liquid-glass-react",
  3 |   "version": "1.0.0",
  4 |   "lockfileVersion": 3,
  5 |   "requires": true,
  6 |   "packages": {
  7 |     "": {
  8 |       "name": "liquid-glass-react",
  9 |       "version": "1.0.0",
 10 |       "license": "MIT",
 11 |       "devDependencies": {
 12 |         "@types/react": "^18.2.0",
 13 |         "@types/react-dom": "^18.2.0",
 14 |         "esbuild": "^0.19.0",
 15 |         "react": "^18.2.0",
 16 |         "react-dom": "^18.2.0",
 17 |         "typescript": "^5.0.0"
 18 |       },
 19 |       "peerDependencies": {
 20 |         "react": ">=16.8.0",
 21 |         "react-dom": ">=16.8.0"
 22 |       }
 23 |     },
 24 |     "node_modules/@esbuild/aix-ppc64": {
 25 |       "version": "0.19.12",
 26 |       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
 27 |       "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
 28 |       "cpu": [
 29 |         "ppc64"
 30 |       ],
 31 |       "dev": true,
 32 |       "optional": true,
 33 |       "os": [
 34 |         "aix"
 35 |       ],
 36 |       "engines": {
 37 |         "node": ">=12"
 38 |       }
 39 |     },
 40 |     "node_modules/@esbuild/android-arm": {
 41 |       "version": "0.19.12",
 42 |       "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
 43 |       "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
 44 |       "cpu": [
 45 |         "arm"
 46 |       ],
 47 |       "dev": true,
 48 |       "optional": true,
 49 |       "os": [
 50 |         "android"
 51 |       ],
 52 |       "engines": {
 53 |         "node": ">=12"
 54 |       }
 55 |     },
 56 |     "node_modules/@esbuild/android-arm64": {
 57 |       "version": "0.19.12",
 58 |       "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
 59 |       "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
 60 |       "cpu": [
 61 |         "arm64"
 62 |       ],
 63 |       "dev": true,
 64 |       "optional": true,
 65 |       "os": [
 66 |         "android"
 67 |       ],
 68 |       "engines": {
 69 |         "node": ">=12"
 70 |       }
 71 |     },
 72 |     "node_modules/@esbuild/android-x64": {
 73 |       "version": "0.19.12",
 74 |       "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
 75 |       "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
 76 |       "cpu": [
 77 |         "x64"
 78 |       ],
 79 |       "dev": true,
 80 |       "optional": true,
 81 |       "os": [
 82 |         "android"
 83 |       ],
 84 |       "engines": {
 85 |         "node": ">=12"
 86 |       }
 87 |     },
 88 |     "node_modules/@esbuild/darwin-arm64": {
 89 |       "version": "0.19.12",
 90 |       "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
 91 |       "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
 92 |       "cpu": [
 93 |         "arm64"
 94 |       ],
 95 |       "dev": true,
 96 |       "optional": true,
 97 |       "os": [
 98 |         "darwin"
 99 |       ],
100 |       "engines": {
101 |         "node": ">=12"
102 |       }
103 |     },
104 |     "node_modules/@esbuild/darwin-x64": {
105 |       "version": "0.19.12",
106 |       "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
107 |       "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
108 |       "cpu": [
109 |         "x64"
110 |       ],
111 |       "dev": true,
112 |       "optional": true,
113 |       "os": [
114 |         "darwin"
115 |       ],
116 |       "engines": {
117 |         "node": ">=12"
118 |       }
119 |     },
120 |     "node_modules/@esbuild/freebsd-arm64": {
121 |       "version": "0.19.12",
122 |       "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
123 |       "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
124 |       "cpu": [
125 |         "arm64"
126 |       ],
127 |       "dev": true,
128 |       "optional": true,
129 |       "os": [
130 |         "freebsd"
131 |       ],
132 |       "engines": {
133 |         "node": ">=12"
134 |       }
135 |     },
136 |     "node_modules/@esbuild/freebsd-x64": {
137 |       "version": "0.19.12",
138 |       "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
139 |       "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
140 |       "cpu": [
141 |         "x64"
142 |       ],
143 |       "dev": true,
144 |       "optional": true,
145 |       "os": [
146 |         "freebsd"
147 |       ],
148 |       "engines": {
149 |         "node": ">=12"
150 |       }
151 |     },
152 |     "node_modules/@esbuild/linux-arm": {
153 |       "version": "0.19.12",
154 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
155 |       "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
156 |       "cpu": [
157 |         "arm"
158 |       ],
159 |       "dev": true,
160 |       "optional": true,
161 |       "os": [
162 |         "linux"
163 |       ],
164 |       "engines": {
165 |         "node": ">=12"
166 |       }
167 |     },
168 |     "node_modules/@esbuild/linux-arm64": {
169 |       "version": "0.19.12",
170 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
171 |       "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
172 |       "cpu": [
173 |         "arm64"
174 |       ],
175 |       "dev": true,
176 |       "optional": true,
177 |       "os": [
178 |         "linux"
179 |       ],
180 |       "engines": {
181 |         "node": ">=12"
182 |       }
183 |     },
184 |     "node_modules/@esbuild/linux-ia32": {
185 |       "version": "0.19.12",
186 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
187 |       "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
188 |       "cpu": [
189 |         "ia32"
190 |       ],
191 |       "dev": true,
192 |       "optional": true,
193 |       "os": [
194 |         "linux"
195 |       ],
196 |       "engines": {
197 |         "node": ">=12"
198 |       }
199 |     },
200 |     "node_modules/@esbuild/linux-loong64": {
201 |       "version": "0.19.12",
202 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
203 |       "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
204 |       "cpu": [
205 |         "loong64"
206 |       ],
207 |       "dev": true,
208 |       "optional": true,
209 |       "os": [
210 |         "linux"
211 |       ],
212 |       "engines": {
213 |         "node": ">=12"
214 |       }
215 |     },
216 |     "node_modules/@esbuild/linux-mips64el": {
217 |       "version": "0.19.12",
218 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
219 |       "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
220 |       "cpu": [
221 |         "mips64el"
222 |       ],
223 |       "dev": true,
224 |       "optional": true,
225 |       "os": [
226 |         "linux"
227 |       ],
228 |       "engines": {
229 |         "node": ">=12"
230 |       }
231 |     },
232 |     "node_modules/@esbuild/linux-ppc64": {
233 |       "version": "0.19.12",
234 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
235 |       "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
236 |       "cpu": [
237 |         "ppc64"
238 |       ],
239 |       "dev": true,
240 |       "optional": true,
241 |       "os": [
242 |         "linux"
243 |       ],
244 |       "engines": {
245 |         "node": ">=12"
246 |       }
247 |     },
248 |     "node_modules/@esbuild/linux-riscv64": {
249 |       "version": "0.19.12",
250 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
251 |       "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
252 |       "cpu": [
253 |         "riscv64"
254 |       ],
255 |       "dev": true,
256 |       "optional": true,
257 |       "os": [
258 |         "linux"
259 |       ],
260 |       "engines": {
261 |         "node": ">=12"
262 |       }
263 |     },
264 |     "node_modules/@esbuild/linux-s390x": {
265 |       "version": "0.19.12",
266 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
267 |       "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
268 |       "cpu": [
269 |         "s390x"
270 |       ],
271 |       "dev": true,
272 |       "optional": true,
273 |       "os": [
274 |         "linux"
275 |       ],
276 |       "engines": {
277 |         "node": ">=12"
278 |       }
279 |     },
280 |     "node_modules/@esbuild/linux-x64": {
281 |       "version": "0.19.12",
282 |       "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
283 |       "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
284 |       "cpu": [
285 |         "x64"
286 |       ],
287 |       "dev": true,
288 |       "optional": true,
289 |       "os": [
290 |         "linux"
291 |       ],
292 |       "engines": {
293 |         "node": ">=12"
294 |       }
295 |     },
296 |     "node_modules/@esbuild/netbsd-x64": {
297 |       "version": "0.19.12",
298 |       "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
299 |       "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
300 |       "cpu": [
301 |         "x64"
302 |       ],
303 |       "dev": true,
304 |       "optional": true,
305 |       "os": [
306 |         "netbsd"
307 |       ],
308 |       "engines": {
309 |         "node": ">=12"
310 |       }
311 |     },
312 |     "node_modules/@esbuild/openbsd-x64": {
313 |       "version": "0.19.12",
314 |       "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
315 |       "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
316 |       "cpu": [
317 |         "x64"
318 |       ],
319 |       "dev": true,
320 |       "optional": true,
321 |       "os": [
322 |         "openbsd"
323 |       ],
324 |       "engines": {
325 |         "node": ">=12"
326 |       }
327 |     },
328 |     "node_modules/@esbuild/sunos-x64": {
329 |       "version": "0.19.12",
330 |       "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
331 |       "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
332 |       "cpu": [
333 |         "x64"
334 |       ],
335 |       "dev": true,
336 |       "optional": true,
337 |       "os": [
338 |         "sunos"
339 |       ],
340 |       "engines": {
341 |         "node": ">=12"
342 |       }
343 |     },
344 |     "node_modules/@esbuild/win32-arm64": {
345 |       "version": "0.19.12",
346 |       "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
347 |       "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
348 |       "cpu": [
349 |         "arm64"
350 |       ],
351 |       "dev": true,
352 |       "optional": true,
353 |       "os": [
354 |         "win32"
355 |       ],
356 |       "engines": {
357 |         "node": ">=12"
358 |       }
359 |     },
360 |     "node_modules/@esbuild/win32-ia32": {
361 |       "version": "0.19.12",
362 |       "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
363 |       "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
364 |       "cpu": [
365 |         "ia32"
366 |       ],
367 |       "dev": true,
368 |       "optional": true,
369 |       "os": [
370 |         "win32"
371 |       ],
372 |       "engines": {
373 |         "node": ">=12"
374 |       }
375 |     },
376 |     "node_modules/@esbuild/win32-x64": {
377 |       "version": "0.19.12",
378 |       "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
379 |       "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
380 |       "cpu": [
381 |         "x64"
382 |       ],
383 |       "dev": true,
384 |       "optional": true,
385 |       "os": [
386 |         "win32"
387 |       ],
388 |       "engines": {
389 |         "node": ">=12"
390 |       }
391 |     },
392 |     "node_modules/@types/prop-types": {
393 |       "version": "15.7.15",
394 |       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
395 |       "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
396 |       "dev": true
397 |     },
398 |     "node_modules/@types/react": {
399 |       "version": "18.3.23",
400 |       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
401 |       "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
402 |       "dev": true,
403 |       "dependencies": {
404 |         "@types/prop-types": "*",
405 |         "csstype": "^3.0.2"
406 |       }
407 |     },
408 |     "node_modules/@types/react-dom": {
409 |       "version": "18.3.7",
410 |       "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
411 |       "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
412 |       "dev": true,
413 |       "peerDependencies": {
414 |         "@types/react": "^18.0.0"
415 |       }
416 |     },
417 |     "node_modules/csstype": {
418 |       "version": "3.1.3",
419 |       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
420 |       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
421 |       "dev": true
422 |     },
423 |     "node_modules/esbuild": {
424 |       "version": "0.19.12",
425 |       "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
426 |       "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
427 |       "dev": true,
428 |       "hasInstallScript": true,
429 |       "bin": {
430 |         "esbuild": "bin/esbuild"
431 |       },
432 |       "engines": {
433 |         "node": ">=12"
434 |       },
435 |       "optionalDependencies": {
436 |         "@esbuild/aix-ppc64": "0.19.12",
437 |         "@esbuild/android-arm": "0.19.12",
438 |         "@esbuild/android-arm64": "0.19.12",
439 |         "@esbuild/android-x64": "0.19.12",
440 |         "@esbuild/darwin-arm64": "0.19.12",
441 |         "@esbuild/darwin-x64": "0.19.12",
442 |         "@esbuild/freebsd-arm64": "0.19.12",
443 |         "@esbuild/freebsd-x64": "0.19.12",
444 |         "@esbuild/linux-arm": "0.19.12",
445 |         "@esbuild/linux-arm64": "0.19.12",
446 |         "@esbuild/linux-ia32": "0.19.12",
447 |         "@esbuild/linux-loong64": "0.19.12",
448 |         "@esbuild/linux-mips64el": "0.19.12",
449 |         "@esbuild/linux-ppc64": "0.19.12",
450 |         "@esbuild/linux-riscv64": "0.19.12",
451 |         "@esbuild/linux-s390x": "0.19.12",
452 |         "@esbuild/linux-x64": "0.19.12",
453 |         "@esbuild/netbsd-x64": "0.19.12",
454 |         "@esbuild/openbsd-x64": "0.19.12",
455 |         "@esbuild/sunos-x64": "0.19.12",
456 |         "@esbuild/win32-arm64": "0.19.12",
457 |         "@esbuild/win32-ia32": "0.19.12",
458 |         "@esbuild/win32-x64": "0.19.12"
459 |       }
460 |     },
461 |     "node_modules/js-tokens": {
462 |       "version": "4.0.0",
463 |       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
464 |       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
465 |       "dev": true
466 |     },
467 |     "node_modules/loose-envify": {
468 |       "version": "1.4.0",
469 |       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
470 |       "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
471 |       "dev": true,
472 |       "dependencies": {
473 |         "js-tokens": "^3.0.0 || ^4.0.0"
474 |       },
475 |       "bin": {
476 |         "loose-envify": "cli.js"
477 |       }
478 |     },
479 |     "node_modules/react": {
480 |       "version": "18.3.1",
481 |       "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
482 |       "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
483 |       "dev": true,
484 |       "dependencies": {
485 |         "loose-envify": "^1.1.0"
486 |       },
487 |       "engines": {
488 |         "node": ">=0.10.0"
489 |       }
490 |     },
491 |     "node_modules/react-dom": {
492 |       "version": "18.3.1",
493 |       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
494 |       "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
495 |       "dev": true,
496 |       "dependencies": {
497 |         "loose-envify": "^1.1.0",
498 |         "scheduler": "^0.23.2"
499 |       },
500 |       "peerDependencies": {
501 |         "react": "^18.3.1"
502 |       }
503 |     },
504 |     "node_modules/scheduler": {
505 |       "version": "0.23.2",
506 |       "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
507 |       "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
508 |       "dev": true,
509 |       "dependencies": {
510 |         "loose-envify": "^1.1.0"
511 |       }
512 |     },
513 |     "node_modules/typescript": {
514 |       "version": "5.8.3",
515 |       "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
516 |       "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
517 |       "dev": true,
518 |       "bin": {
519 |         "tsc": "bin/tsc",
520 |         "tsserver": "bin/tsserver"
521 |       },
522 |       "engines": {
523 |         "node": ">=14.17"
524 |       }
525 |     }
526 |   }
527 | }
528 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "liquid-glass-react",
 3 |   "version": "1.1.1",
 4 |   "description": "Apple's Liquid Glass effect for React",
 5 |   "main": "dist/index.js",
 6 |   "module": "dist/index.esm.js",
 7 |   "types": "dist/index.d.ts",
 8 |   "files": ["dist"],
 9 |   "workspaces": ["liquid-glass"],
10 |   "scripts": {
11 |     "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:types",
12 |     "build:esm": "esbuild src/index.tsx --bundle --format=esm --outfile=dist/index.esm.js --external:react --external:react-dom",
13 |     "build:cjs": "esbuild src/index.tsx --bundle --format=cjs --outfile=dist/index.js --external:react --external:react-dom",
14 |     "build:types": "tsc --emitDeclarationOnly --outDir dist",
15 |     "clean": "rm -rf dist",
16 |     "dev": "npm run build:esm -- --watch",
17 |     "prepublishOnly": "npm run build"
18 |   },
19 |   "peerDependencies": {
20 |     "react": ">=18",
21 |     "react-dom": ">=18"
22 |   },
23 |   "devDependencies": {
24 |     "@biomejs/biome": "^1.9.4",
25 |     "@types/react": "^18.2.0",
26 |     "@types/react-dom": "^18.2.0",
27 |     "esbuild": "^0.19.0",
28 |     "react": "^18.2.0",
29 |     "react-dom": "^18.2.0",
30 |     "typescript": "^5.0.0"
31 |   },
32 |   "keywords": ["react", "component", "library", "typescript"],
33 |   "author": "",
34 |   "license": "MIT",
35 |   "repository": {
36 |     "type": "git",
37 |     "url": ""
38 |   }
39 | }
40 | 


--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
  1 | import { type CSSProperties, forwardRef, useCallback, useEffect, useId, useRef, useState } from "react"
  2 | import { ShaderDisplacementGenerator, fragmentShaders } from "./shader-utils"
  3 | import { displacementMap, polarDisplacementMap, prominentDisplacementMap } from "./utils"
  4 | 
  5 | // Generate shader-based displacement map using shaderUtils
  6 | const generateShaderDisplacementMap = (width: number, height: number): string => {
  7 |   const generator = new ShaderDisplacementGenerator({
  8 |     width,
  9 |     height,
 10 |     fragment: fragmentShaders.liquidGlass,
 11 |   })
 12 | 
 13 |   const dataUrl = generator.updateShader()
 14 |   generator.destroy()
 15 | 
 16 |   return dataUrl
 17 | }
 18 | 
 19 | const getMap = (mode: "standard" | "polar" | "prominent" | "shader", shaderMapUrl?: string) => {
 20 |   switch (mode) {
 21 |     case "standard":
 22 |       return displacementMap
 23 |     case "polar":
 24 |       return polarDisplacementMap
 25 |     case "prominent":
 26 |       return prominentDisplacementMap
 27 |     case "shader":
 28 |       return shaderMapUrl || displacementMap
 29 |     default:
 30 |       throw new Error(`Invalid mode: ${mode}`)
 31 |   }
 32 | }
 33 | 
 34 | /* ---------- SVG filter (edge-only displacement) ---------- */
 35 | const GlassFilter: React.FC<{ id: string; displacementScale: number; aberrationIntensity: number; width: number; height: number; mode: "standard" | "polar" | "prominent" | "shader"; shaderMapUrl?: string }> = ({
 36 |   id,
 37 |   displacementScale,
 38 |   aberrationIntensity,
 39 |   width,
 40 |   height,
 41 |   mode,
 42 |   shaderMapUrl,
 43 | }) => (
 44 |   <svg style={{ position: "absolute", width, height }} aria-hidden="true">
 45 |     <defs>
 46 |       <radialGradient id={`${id}-edge-mask`} cx="50%" cy="50%" r="50%">
 47 |         <stop offset="0%" stopColor="black" stopOpacity="0" />
 48 |         <stop offset={`${Math.max(30, 80 - aberrationIntensity * 2)}%`} stopColor="black" stopOpacity="0" />
 49 |         <stop offset="100%" stopColor="white" stopOpacity="1" />
 50 |       </radialGradient>
 51 |       <filter id={id} x="-35%" y="-35%" width="170%" height="170%" colorInterpolationFilters="sRGB">
 52 |         <feImage id="feimage" x="0" y="0" width="100%" height="100%" result="DISPLACEMENT_MAP" href={getMap(mode, shaderMapUrl)} preserveAspectRatio="xMidYMid slice" />
 53 | 
 54 |         {/* Create edge mask using the displacement map itself */}
 55 |         <feColorMatrix
 56 |           in="DISPLACEMENT_MAP"
 57 |           type="matrix"
 58 |           values="0.3 0.3 0.3 0 0
 59 |                  0.3 0.3 0.3 0 0
 60 |                  0.3 0.3 0.3 0 0
 61 |                  0 0 0 1 0"
 62 |           result="EDGE_INTENSITY"
 63 |         />
 64 |         <feComponentTransfer in="EDGE_INTENSITY" result="EDGE_MASK">
 65 |           <feFuncA type="discrete" tableValues={`0 ${aberrationIntensity * 0.05} 1`} />
 66 |         </feComponentTransfer>
 67 | 
 68 |         {/* Original undisplaced image for center */}
 69 |         <feOffset in="SourceGraphic" dx="0" dy="0" result="CENTER_ORIGINAL" />
 70 | 
 71 |         {/* Red channel displacement with slight offset */}
 72 |         <feDisplacementMap in="SourceGraphic" in2="DISPLACEMENT_MAP" scale={displacementScale * (mode === "shader" ? 1 : -1)} xChannelSelector="R" yChannelSelector="B" result="RED_DISPLACED" />
 73 |         <feColorMatrix
 74 |           in="RED_DISPLACED"
 75 |           type="matrix"
 76 |           values="1 0 0 0 0
 77 |                  0 0 0 0 0
 78 |                  0 0 0 0 0
 79 |                  0 0 0 1 0"
 80 |           result="RED_CHANNEL"
 81 |         />
 82 | 
 83 |         {/* Green channel displacement */}
 84 |         <feDisplacementMap in="SourceGraphic" in2="DISPLACEMENT_MAP" scale={displacementScale * ((mode === "shader" ? 1 : -1) - aberrationIntensity * 0.05)} xChannelSelector="R" yChannelSelector="B" result="GREEN_DISPLACED" />
 85 |         <feColorMatrix
 86 |           in="GREEN_DISPLACED"
 87 |           type="matrix"
 88 |           values="0 0 0 0 0
 89 |                  0 1 0 0 0
 90 |                  0 0 0 0 0
 91 |                  0 0 0 1 0"
 92 |           result="GREEN_CHANNEL"
 93 |         />
 94 | 
 95 |         {/* Blue channel displacement with slight offset */}
 96 |         <feDisplacementMap in="SourceGraphic" in2="DISPLACEMENT_MAP" scale={displacementScale * ((mode === "shader" ? 1 : -1) - aberrationIntensity * 0.1)} xChannelSelector="R" yChannelSelector="B" result="BLUE_DISPLACED" />
 97 |         <feColorMatrix
 98 |           in="BLUE_DISPLACED"
 99 |           type="matrix"
100 |           values="0 0 0 0 0
101 |                  0 0 0 0 0
102 |                  0 0 1 0 0
103 |                  0 0 0 1 0"
104 |           result="BLUE_CHANNEL"
105 |         />
106 | 
107 |         {/* Combine all channels with screen blend mode for chromatic aberration */}
108 |         <feBlend in="GREEN_CHANNEL" in2="BLUE_CHANNEL" mode="screen" result="GB_COMBINED" />
109 |         <feBlend in="RED_CHANNEL" in2="GB_COMBINED" mode="screen" result="RGB_COMBINED" />
110 | 
111 |         {/* Add slight blur to soften the aberration effect */}
112 |         <feGaussianBlur in="RGB_COMBINED" stdDeviation={Math.max(0.1, 0.5 - aberrationIntensity * 0.1)} result="ABERRATED_BLURRED" />
113 | 
114 |         {/* Apply edge mask to aberration effect */}
115 |         <feComposite in="ABERRATED_BLURRED" in2="EDGE_MASK" operator="in" result="EDGE_ABERRATION" />
116 | 
117 |         {/* Create inverted mask for center */}
118 |         <feComponentTransfer in="EDGE_MASK" result="INVERTED_MASK">
119 |           <feFuncA type="table" tableValues="1 0" />
120 |         </feComponentTransfer>
121 |         <feComposite in="CENTER_ORIGINAL" in2="INVERTED_MASK" operator="in" result="CENTER_CLEAN" />
122 | 
123 |         {/* Combine edge aberration with clean center */}
124 |         <feComposite in="EDGE_ABERRATION" in2="CENTER_CLEAN" operator="over" />
125 |       </filter>
126 |     </defs>
127 |   </svg>
128 | )
129 | 
130 | /* ---------- container ---------- */
131 | const GlassContainer = forwardRef<
132 |   HTMLDivElement,
133 |   React.PropsWithChildren<{
134 |     className?: string
135 |     style?: React.CSSProperties
136 |     displacementScale?: number
137 |     blurAmount?: number
138 |     saturation?: number
139 |     aberrationIntensity?: number
140 |     mouseOffset?: { x: number; y: number }
141 |     onMouseLeave?: () => void
142 |     onMouseEnter?: () => void
143 |     onMouseDown?: () => void
144 |     onMouseUp?: () => void
145 |     active?: boolean
146 |     overLight?: boolean
147 |     cornerRadius?: number
148 |     padding?: string
149 |     glassSize?: { width: number; height: number }
150 |     onClick?: () => void
151 |     mode?: "standard" | "polar" | "prominent" | "shader"
152 |   }>
153 | >(
154 |   (
155 |     {
156 |       children,
157 |       className = "",
158 |       style,
159 |       displacementScale = 25,
160 |       blurAmount = 12,
161 |       saturation = 180,
162 |       aberrationIntensity = 2,
163 |       onMouseEnter,
164 |       onMouseLeave,
165 |       onMouseDown,
166 |       onMouseUp,
167 |       active = false,
168 |       overLight = false,
169 |       cornerRadius = 999,
170 |       padding = "24px 32px",
171 |       glassSize = { width: 270, height: 69 },
172 |       onClick,
173 |       mode = "standard",
174 |     },
175 |     ref,
176 |   ) => {
177 |     const filterId = useId()
178 |     const [shaderMapUrl, setShaderMapUrl] = useState<string>("")
179 | 
180 |     const isFirefox = navigator.userAgent.toLowerCase().includes("firefox")
181 | 
182 |     // Generate shader displacement map when in shader mode
183 |     useEffect(() => {
184 |       if (mode === "shader") {
185 |         const url = generateShaderDisplacementMap(glassSize.width, glassSize.height)
186 |         setShaderMapUrl(url)
187 |       }
188 |     }, [mode, glassSize.width, glassSize.height])
189 | 
190 |     const backdropStyle = {
191 |       filter: isFirefox ? null : `url(#${filterId})`,
192 |       backdropFilter: `blur(${(overLight ? 12 : 4) + blurAmount * 32}px) saturate(${saturation}%)`,
193 |     }
194 | 
195 |     return (
196 |       <div ref={ref} className={`relative ${className} ${active ? "active" : ""} ${Boolean(onClick) ? "cursor-pointer" : ""}`} style={style} onClick={onClick}>
197 |         <GlassFilter mode={mode} id={filterId} displacementScale={displacementScale} aberrationIntensity={aberrationIntensity} width={glassSize.width} height={glassSize.height} shaderMapUrl={shaderMapUrl} />
198 | 
199 |         <div
200 |           className="glass"
201 |           style={{
202 |             borderRadius: `${cornerRadius}px`,
203 |             position: "relative",
204 |             display: "inline-flex",
205 |             alignItems: "center",
206 |             gap: "24px",
207 |             padding,
208 |             overflow: "hidden",
209 |             transition: "all 0.2s ease-in-out",
210 |             boxShadow: overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)",
211 |           }}
212 |           onMouseEnter={onMouseEnter}
213 |           onMouseLeave={onMouseLeave}
214 |           onMouseDown={onMouseDown}
215 |           onMouseUp={onMouseUp}
216 |         >
217 |           {/* backdrop layer that gets wiggly */}
218 |           <span
219 |             className="glass__warp"
220 |             style={
221 |               {
222 |                 ...backdropStyle,
223 |                 position: "absolute",
224 |                 inset: "0",
225 |               } as CSSProperties
226 |             }
227 |           />
228 | 
229 |           {/* user content stays sharp */}
230 |           <div
231 |             className="transition-all duration-150 ease-in-out text-white"
232 |             style={{
233 |               position: "relative",
234 |               zIndex: 1,
235 |               font: "500 20px/1 system-ui",
236 |               textShadow: overLight ? "0px 2px 12px rgba(0, 0, 0, 0)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
237 |             }}
238 |           >
239 |             {children}
240 |           </div>
241 |         </div>
242 |       </div>
243 |     )
244 |   },
245 | )
246 | 
247 | GlassContainer.displayName = "GlassContainer"
248 | 
249 | interface LiquidGlassProps {
250 |   children: React.ReactNode
251 |   displacementScale?: number
252 |   blurAmount?: number
253 |   saturation?: number
254 |   aberrationIntensity?: number
255 |   elasticity?: number
256 |   cornerRadius?: number
257 |   globalMousePos?: { x: number; y: number }
258 |   mouseOffset?: { x: number; y: number }
259 |   mouseContainer?: React.RefObject<HTMLElement | null> | null
260 |   className?: string
261 |   padding?: string
262 |   style?: React.CSSProperties
263 |   overLight?: boolean
264 |   mode?: "standard" | "polar" | "prominent" | "shader"
265 |   onClick?: () => void
266 | }
267 | 
268 | export default function LiquidGlass({
269 |   children,
270 |   displacementScale = 70,
271 |   blurAmount = 0.0625,
272 |   saturation = 140,
273 |   aberrationIntensity = 2,
274 |   elasticity = 0.15,
275 |   cornerRadius = 999,
276 |   globalMousePos: externalGlobalMousePos,
277 |   mouseOffset: externalMouseOffset,
278 |   mouseContainer = null,
279 |   className = "",
280 |   padding = "24px 32px",
281 |   overLight = false,
282 |   style = {},
283 |   mode = "standard",
284 |   onClick,
285 | }: LiquidGlassProps) {
286 |   const glassRef = useRef<HTMLDivElement>(null)
287 |   const [isHovered, setIsHovered] = useState(false)
288 |   const [isActive, setIsActive] = useState(false)
289 |   const [glassSize, setGlassSize] = useState({ width: 270, height: 69 })
290 |   const [internalGlobalMousePos, setInternalGlobalMousePos] = useState({ x: 0, y: 0 })
291 |   const [internalMouseOffset, setInternalMouseOffset] = useState({ x: 0, y: 0 })
292 | 
293 |   // Use external mouse position if provided, otherwise use internal
294 |   const globalMousePos = externalGlobalMousePos || internalGlobalMousePos
295 |   const mouseOffset = externalMouseOffset || internalMouseOffset
296 | 
297 |   // Internal mouse tracking
298 |   const handleMouseMove = useCallback(
299 |     (e: MouseEvent) => {
300 |       const container = mouseContainer?.current || glassRef.current
301 |       if (!container) {
302 |         return
303 |       }
304 | 
305 |       const rect = container.getBoundingClientRect()
306 |       const centerX = rect.left + rect.width / 2
307 |       const centerY = rect.top + rect.height / 2
308 | 
309 |       setInternalMouseOffset({
310 |         x: ((e.clientX - centerX) / rect.width) * 100,
311 |         y: ((e.clientY - centerY) / rect.height) * 100,
312 |       })
313 | 
314 |       setInternalGlobalMousePos({
315 |         x: e.clientX,
316 |         y: e.clientY,
317 |       })
318 |     },
319 |     [mouseContainer],
320 |   )
321 | 
322 |   // Set up mouse tracking if no external mouse position is provided
323 |   useEffect(() => {
324 |     if (externalGlobalMousePos && externalMouseOffset) {
325 |       // External mouse tracking is provided, don't set up internal tracking
326 |       return
327 |     }
328 | 
329 |     const container = mouseContainer?.current || glassRef.current
330 |     if (!container) {
331 |       return
332 |     }
333 | 
334 |     container.addEventListener("mousemove", handleMouseMove)
335 | 
336 |     return () => {
337 |       container.removeEventListener("mousemove", handleMouseMove)
338 |     }
339 |   }, [handleMouseMove, mouseContainer, externalGlobalMousePos, externalMouseOffset])
340 | 
341 |   // Calculate directional scaling based on mouse position
342 |   const calculateDirectionalScale = useCallback(() => {
343 |     if (!globalMousePos.x || !globalMousePos.y || !glassRef.current) {
344 |       return "scale(1)"
345 |     }
346 | 
347 |     const rect = glassRef.current.getBoundingClientRect()
348 |     const pillCenterX = rect.left + rect.width / 2
349 |     const pillCenterY = rect.top + rect.height / 2
350 |     const pillWidth = glassSize.width
351 |     const pillHeight = glassSize.height
352 | 
353 |     const deltaX = globalMousePos.x - pillCenterX
354 |     const deltaY = globalMousePos.y - pillCenterY
355 | 
356 |     // Calculate distance from mouse to pill edges (not center)
357 |     const edgeDistanceX = Math.max(0, Math.abs(deltaX) - pillWidth / 2)
358 |     const edgeDistanceY = Math.max(0, Math.abs(deltaY) - pillHeight / 2)
359 |     const edgeDistance = Math.sqrt(edgeDistanceX * edgeDistanceX + edgeDistanceY * edgeDistanceY)
360 | 
361 |     // Activation zone: 200px from edges
362 |     const activationZone = 200
363 | 
364 |     // If outside activation zone, no effect
365 |     if (edgeDistance > activationZone) {
366 |       return "scale(1)"
367 |     }
368 | 
369 |     // Calculate fade-in factor (1 at edge, 0 at activation zone boundary)
370 |     const fadeInFactor = 1 - edgeDistance / activationZone
371 | 
372 |     // Normalize the deltas for direction
373 |     const centerDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
374 |     if (centerDistance === 0) {
375 |       return "scale(1)"
376 |     }
377 | 
378 |     const normalizedX = deltaX / centerDistance
379 |     const normalizedY = deltaY / centerDistance
380 | 
381 |     // Calculate stretch factors with fade-in
382 |     const stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * fadeInFactor
383 | 
384 |     // X-axis scaling: stretch horizontally when moving left/right, compress when moving up/down
385 |     const scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * 0.3 - Math.abs(normalizedY) * stretchIntensity * 0.15
386 | 
387 |     // Y-axis scaling: stretch vertically when moving up/down, compress when moving left/right
388 |     const scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * 0.3 - Math.abs(normalizedX) * stretchIntensity * 0.15
389 | 
390 |     return `scaleX(${Math.max(0.8, scaleX)}) scaleY(${Math.max(0.8, scaleY)})`
391 |   }, [globalMousePos, elasticity, glassSize])
392 | 
393 |   // Helper function to calculate fade-in factor based on distance from element edges
394 |   const calculateFadeInFactor = useCallback(() => {
395 |     if (!globalMousePos.x || !globalMousePos.y || !glassRef.current) {
396 |       return 0
397 |     }
398 | 
399 |     const rect = glassRef.current.getBoundingClientRect()
400 |     const pillCenterX = rect.left + rect.width / 2
401 |     const pillCenterY = rect.top + rect.height / 2
402 |     const pillWidth = glassSize.width
403 |     const pillHeight = glassSize.height
404 | 
405 |     const edgeDistanceX = Math.max(0, Math.abs(globalMousePos.x - pillCenterX) - pillWidth / 2)
406 |     const edgeDistanceY = Math.max(0, Math.abs(globalMousePos.y - pillCenterY) - pillHeight / 2)
407 |     const edgeDistance = Math.sqrt(edgeDistanceX * edgeDistanceX + edgeDistanceY * edgeDistanceY)
408 | 
409 |     const activationZone = 200
410 |     return edgeDistance > activationZone ? 0 : 1 - edgeDistance / activationZone
411 |   }, [globalMousePos, glassSize])
412 | 
413 |   // Helper function to calculate elastic translation
414 |   const calculateElasticTranslation = useCallback(() => {
415 |     if (!glassRef.current) {
416 |       return { x: 0, y: 0 }
417 |     }
418 | 
419 |     const fadeInFactor = calculateFadeInFactor()
420 |     const rect = glassRef.current.getBoundingClientRect()
421 |     const pillCenterX = rect.left + rect.width / 2
422 |     const pillCenterY = rect.top + rect.height / 2
423 | 
424 |     return {
425 |       x: (globalMousePos.x - pillCenterX) * elasticity * 0.1 * fadeInFactor,
426 |       y: (globalMousePos.y - pillCenterY) * elasticity * 0.1 * fadeInFactor,
427 |     }
428 |   }, [globalMousePos, elasticity, calculateFadeInFactor])
429 | 
430 |   // Update glass size whenever component mounts or window resizes
431 |   useEffect(() => {
432 |     const updateGlassSize = () => {
433 |       if (glassRef.current) {
434 |         const rect = glassRef.current.getBoundingClientRect()
435 |         setGlassSize({ width: rect.width, height: rect.height })
436 |       }
437 |     }
438 | 
439 |     updateGlassSize()
440 |     window.addEventListener("resize", updateGlassSize)
441 |     return () => window.removeEventListener("resize", updateGlassSize)
442 |   }, [])
443 | 
444 |   const transformStyle = `translate(calc(-50% + ${calculateElasticTranslation().x}px), calc(-50% + ${calculateElasticTranslation().y}px)) ${isActive && Boolean(onClick) ? "scale(0.96)" : calculateDirectionalScale()}`
445 | 
446 |   const baseStyle = {
447 |     ...style,
448 |     transform: transformStyle,
449 |     transition: "all ease-out 0.2s",
450 |   }
451 | 
452 |   const positionStyles = {
453 |     position: baseStyle.position || "relative",
454 |     top: baseStyle.top || "50%",
455 |     left: baseStyle.left || "50%",
456 |   }
457 | 
458 |   return (
459 |     <>
460 |       {/* Over light effect */}
461 |       <div
462 |         className={`bg-black transition-all duration-150 ease-in-out pointer-events-none ${overLight ? "opacity-20" : "opacity-0"}`}
463 |         style={{
464 |           ...positionStyles,
465 |           height: glassSize.height,
466 |           width: glassSize.width,
467 |           borderRadius: `${cornerRadius}px`,
468 |           transform: baseStyle.transform,
469 |           transition: baseStyle.transition,
470 |         }}
471 |       />
472 |       <div
473 |         className={`bg-black transition-all duration-150 ease-in-out pointer-events-none mix-blend-overlay ${overLight ? "opacity-100" : "opacity-0"}`}
474 |         style={{
475 |           ...positionStyles,
476 |           height: glassSize.height,
477 |           width: glassSize.width,
478 |           borderRadius: `${cornerRadius}px`,
479 |           transform: baseStyle.transform,
480 |           transition: baseStyle.transition,
481 |         }}
482 |       />
483 | 
484 |       <GlassContainer
485 |         ref={glassRef}
486 |         className={className}
487 |         style={baseStyle}
488 |         cornerRadius={cornerRadius}
489 |         displacementScale={overLight ? displacementScale * 0.5 : displacementScale}
490 |         blurAmount={blurAmount}
491 |         saturation={saturation}
492 |         aberrationIntensity={aberrationIntensity}
493 |         glassSize={glassSize}
494 |         padding={padding}
495 |         mouseOffset={mouseOffset}
496 |         onMouseEnter={() => setIsHovered(true)}
497 |         onMouseLeave={() => setIsHovered(false)}
498 |         onMouseDown={() => setIsActive(true)}
499 |         onMouseUp={() => setIsActive(false)}
500 |         active={isActive}
501 |         overLight={overLight}
502 |         onClick={onClick}
503 |         mode={mode}
504 |       >
505 |         {children}
506 |       </GlassContainer>
507 | 
508 |       {/* Border layer 1 - extracted from glass container */}
509 |       <span
510 |         style={{
511 |           ...positionStyles,
512 |           height: glassSize.height,
513 |           width: glassSize.width,
514 |           borderRadius: `${cornerRadius}px`,
515 |           transform: baseStyle.transform,
516 |           transition: baseStyle.transition,
517 |           pointerEvents: "none",
518 |           mixBlendMode: "screen",
519 |           opacity: 0.2,
520 |           padding: "1.5px",
521 |           WebkitMask: "linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)",
522 |           WebkitMaskComposite: "xor",
523 |           maskComposite: "exclude",
524 |           boxShadow: "0 0 0 0.5px rgba(255, 255, 255, 0.5) inset, 0 1px 3px rgba(255, 255, 255, 0.25) inset, 0 1px 4px rgba(0, 0, 0, 0.35)",
525 |           background: `linear-gradient(
526 |           ${135 + mouseOffset.x * 1.2}deg,
527 |           rgba(255, 255, 255, 0.0) 0%,
528 |           rgba(255, 255, 255, ${0.12 + Math.abs(mouseOffset.x) * 0.008}) ${Math.max(10, 33 + mouseOffset.y * 0.3)}%,
529 |           rgba(255, 255, 255, ${0.4 + Math.abs(mouseOffset.x) * 0.012}) ${Math.min(90, 66 + mouseOffset.y * 0.4)}%,
530 |           rgba(255, 255, 255, 0.0) 100%
531 |         )`,
532 |         }}
533 |       />
534 | 
535 |       {/* Border layer 2 - duplicate with mix-blend-overlay */}
536 |       <span
537 |         style={{
538 |           ...positionStyles,
539 |           height: glassSize.height,
540 |           width: glassSize.width,
541 |           borderRadius: `${cornerRadius}px`,
542 |           transform: baseStyle.transform,
543 |           transition: baseStyle.transition,
544 |           pointerEvents: "none",
545 |           mixBlendMode: "overlay",
546 |           padding: "1.5px",
547 |           WebkitMask: "linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)",
548 |           WebkitMaskComposite: "xor",
549 |           maskComposite: "exclude",
550 |           boxShadow: "0 0 0 0.5px rgba(255, 255, 255, 0.5) inset, 0 1px 3px rgba(255, 255, 255, 0.25) inset, 0 1px 4px rgba(0, 0, 0, 0.35)",
551 |           background: `linear-gradient(
552 |           ${135 + mouseOffset.x * 1.2}deg,
553 |           rgba(255, 255, 255, 0.0) 0%,
554 |           rgba(255, 255, 255, ${0.32 + Math.abs(mouseOffset.x) * 0.008}) ${Math.max(10, 33 + mouseOffset.y * 0.3)}%,
555 |           rgba(255, 255, 255, ${0.6 + Math.abs(mouseOffset.x) * 0.012}) ${Math.min(90, 66 + mouseOffset.y * 0.4)}%,
556 |           rgba(255, 255, 255, 0.0) 100%
557 |         )`,
558 |         }}
559 |       />
560 | 
561 |       {/* Hover effects */}
562 |       {Boolean(onClick) && (
563 |         <>
564 |           <div
565 |             style={{
566 |               ...positionStyles,
567 |               height: glassSize.height,
568 |               width: glassSize.width + 1,
569 |               borderRadius: `${cornerRadius}px`,
570 |               transform: baseStyle.transform,
571 |               pointerEvents: "none",
572 |               transition: "all 0.2s ease-out",
573 |               opacity: isHovered || isActive ? 0.5 : 0,
574 |               backgroundImage: "radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 50%)",
575 |               mixBlendMode: "overlay",
576 |             }}
577 |           />
578 |           <div
579 |             style={{
580 |               ...positionStyles,
581 |               height: glassSize.height,
582 |               width: glassSize.width + 1,
583 |               borderRadius: `${cornerRadius}px`,
584 |               transform: baseStyle.transform,
585 |               pointerEvents: "none",
586 |               transition: "all 0.2s ease-out",
587 |               opacity: isActive ? 0.5 : 0,
588 |               backgroundImage: "radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 80%)",
589 |               mixBlendMode: "overlay",
590 |             }}
591 |           />
592 |           <div
593 |             style={{
594 |               ...baseStyle,
595 |               height: glassSize.height,
596 |               width: glassSize.width + 1,
597 |               borderRadius: `${cornerRadius}px`,
598 |               position: baseStyle.position,
599 |               top: baseStyle.top,
600 |               left: baseStyle.left,
601 |               pointerEvents: "none",
602 |               transition: "all 0.2s ease-out",
603 |               opacity: isHovered ? 0.4 : isActive ? 0.8 : 0,
604 |               backgroundImage: "radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%)",
605 |               mixBlendMode: "overlay",
606 |             }}
607 |           />
608 |         </>
609 |       )}
610 |     </>
611 |   )
612 | }
613 | 


--------------------------------------------------------------------------------
/src/shader-utils.ts:
--------------------------------------------------------------------------------
  1 | // Adapted from https://github.com/shuding/liquid-glass
  2 | 
  3 | export interface Vec2 {
  4 |   x: number
  5 |   y: number
  6 | }
  7 | 
  8 | export interface ShaderOptions {
  9 |   width: number
 10 |   height: number
 11 |   fragment: (uv: Vec2, mouse?: Vec2) => Vec2
 12 |   mousePosition?: Vec2
 13 | }
 14 | 
 15 | function smoothStep(a: number, b: number, t: number): number {
 16 |   t = Math.max(0, Math.min(1, (t - a) / (b - a)))
 17 |   return t * t * (3 - 2 * t)
 18 | }
 19 | 
 20 | function length(x: number, y: number): number {
 21 |   return Math.sqrt(x * x + y * y)
 22 | }
 23 | 
 24 | function roundedRectSDF(x: number, y: number, width: number, height: number, radius: number): number {
 25 |   const qx = Math.abs(x) - width + radius
 26 |   const qy = Math.abs(y) - height + radius
 27 |   return Math.min(Math.max(qx, qy), 0) + length(Math.max(qx, 0), Math.max(qy, 0)) - radius
 28 | }
 29 | 
 30 | function texture(x: number, y: number): Vec2 {
 31 |   return { x, y }
 32 | }
 33 | 
 34 | // Shader fragment functions for different effects
 35 | export const fragmentShaders = {
 36 |   liquidGlass: (uv: Vec2): Vec2 => {
 37 |     const ix = uv.x - 0.5
 38 |     const iy = uv.y - 0.5
 39 |     const distanceToEdge = roundedRectSDF(ix, iy, 0.3, 0.2, 0.6)
 40 |     const displacement = smoothStep(0.8, 0, distanceToEdge - 0.15)
 41 |     const scaled = smoothStep(0, 1, displacement)
 42 |     return texture(ix * scaled + 0.5, iy * scaled + 0.5)
 43 |   },
 44 | }
 45 | 
 46 | export type FragmentShaderType = keyof typeof fragmentShaders
 47 | 
 48 | export class ShaderDisplacementGenerator {
 49 |   private canvas: HTMLCanvasElement
 50 |   private context: CanvasRenderingContext2D
 51 |   private canvasDPI = 1
 52 | 
 53 |   constructor(private options: ShaderOptions) {
 54 |     this.canvas = document.createElement("canvas")
 55 |     this.canvas.width = options.width * this.canvasDPI
 56 |     this.canvas.height = options.height * this.canvasDPI
 57 |     this.canvas.style.display = "none"
 58 | 
 59 |     const context = this.canvas.getContext("2d")
 60 |     if (!context) {
 61 |       throw new Error("Could not get 2D context")
 62 |     }
 63 |     this.context = context
 64 |   }
 65 | 
 66 |   updateShader(mousePosition?: Vec2): string {
 67 |     const w = this.options.width * this.canvasDPI
 68 |     const h = this.options.height * this.canvasDPI
 69 | 
 70 |     let maxScale = 0
 71 |     const rawValues: number[] = []
 72 | 
 73 |     // Calculate displacement values
 74 |     for (let y = 0; y < h; y++) {
 75 |       for (let x = 0; x < w; x++) {
 76 |         const uv: Vec2 = { x: x / w, y: y / h }
 77 | 
 78 |         const pos = this.options.fragment(uv, mousePosition)
 79 |         const dx = pos.x * w - x
 80 |         const dy = pos.y * h - y
 81 | 
 82 |         maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy))
 83 |         rawValues.push(dx, dy)
 84 |       }
 85 |     }
 86 | 
 87 |     // Improved normalization to prevent artifacts while maintaining intensity
 88 |     if (maxScale > 0) {
 89 |       maxScale = Math.max(maxScale, 1) // Ensure minimum scale to prevent over-normalization
 90 |     } else {
 91 |       maxScale = 1
 92 |     }
 93 | 
 94 |     // Create ImageData and fill it
 95 |     const imageData = this.context.createImageData(w, h)
 96 |     const data = imageData.data
 97 | 
 98 |     // Convert to image data with smoother normalization
 99 |     let rawIndex = 0
100 |     for (let y = 0; y < h; y++) {
101 |       for (let x = 0; x < w; x++) {
102 |         const dx = rawValues[rawIndex++]
103 |         const dy = rawValues[rawIndex++]
104 | 
105 |         // Smooth the displacement values at edges to prevent hard transitions
106 |         const edgeDistance = Math.min(x, y, w - x - 1, h - y - 1)
107 |         const edgeFactor = Math.min(1, edgeDistance / 2) // Smooth within 2 pixels of edge
108 | 
109 |         const smoothedDx = dx * edgeFactor
110 |         const smoothedDy = dy * edgeFactor
111 | 
112 |         const r = smoothedDx / maxScale + 0.5
113 |         const g = smoothedDy / maxScale + 0.5
114 | 
115 |         const pixelIndex = (y * w + x) * 4
116 |         data[pixelIndex] = Math.max(0, Math.min(255, r * 255)) // Red channel (X displacement)
117 |         data[pixelIndex + 1] = Math.max(0, Math.min(255, g * 255)) // Green channel (Y displacement)
118 |         data[pixelIndex + 2] = Math.max(0, Math.min(255, g * 255)) // Blue channel (Y displacement for SVG filter compatibility)
119 |         data[pixelIndex + 3] = 255 // Alpha channel
120 |       }
121 |     }
122 | 
123 |     this.context.putImageData(imageData, 0, 0)
124 |     return this.canvas.toDataURL()
125 |   }
126 | 
127 |   destroy(): void {
128 |     this.canvas.remove()
129 |   }
130 | 
131 |   getScale(): number {
132 |     return this.canvasDPI
133 |   }
134 | }
135 | 


--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | export const displacementMap =
2 |   "data:image/jpeg;base64,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cUAUAkEkziomgGgkoxZGgxZFQFQlYnQHRdPfj/10KCSCKESCNiVkViPSLpD0h6I0Q0I0A2IoBWBIJIBKBIJoJIJ2R2J0JWBUJ0JUB0XTv479dFZDYiglYigkhEgjZFQjRFQjRFQjQigFYigHYigmgEgmglYlYnQlQlYlQHQlQnQ9P/kf1yVkNiNCNkNiVENiNiViNEViNkVCVgKCViViViSCViSCVgdCViVCViVCdgVCVCdD1D+U/XBWQ2I0I2Q2JUQ2I0JWQ0I2JUQ2JUI2JUI2J0JWJWJWA2R0BWJ0I2JUJ2BUJUJ0P//EABkQAQEBAQEBAAAAAAAAAAAAAAECABEDEP/aAAgBAQABAgB1atWrVq1atWrVq1atWrVq1atWrVq1atWrVq+OrVq1atWrVq1atWrVq1atWrVq1atWrVq1atXxVppppppdWrVq1atWrVq1NNNNNNNNNNNPVWmmmmms6tWrVq1atWpppppppppppppp6q0000uc51atWrVq1ammmmmmmmmmmmmt1Vpppc5znVq1atWrVqaaaaaaaaaaaaaeqtNLnOc51atWrVq1ammmmmmmmmmmmmnqrS5znOc6tWrVq16222mmmmmmlVppp6tKuc5znOrVq1a9TbbbbTTTTTSq000qtLnOc5zq1atWrW0222200000qqqtKqrnOc5zq1atTbbbbbbbbTTTSqqqqqq5znOc6tTTTbbbbbbbbTTTSqqqqrlVznOctNNNtttttttttNNNNKqqqrqznKqrTTTTbbbbbbbbbTTTSqqqqrqznOc5aaaabbbbbbbbbaaaaVVVVVdWc5znVq1NNttttttttttNNKqqqqudWc5znVq16tbbbbbbbbbbTTSqqqq5XVnOc6tWrVrb1tttttttttNNKqqqqrWrK5VWmmm2230bbbbbbaaaXOc5zlVa1KuVVppptttt9G22222mmlzlVznK6tWVVWmmmm2222222222mlznOc5znLWppVVWmmm22222229bTWrOc5znOcq1qaaVpWmm222222229erVqznOc5znKtatStK0rTbTTbbbberXr1as5znOc5aVpppppWlabaabbbb1ta9WrVnOc5znU0rTTTTTTTTTbTTbbbTWvVq1as5znOdTTStNNNNNNNNNtNNtttN6tWvVq1ZznOrU00rTTTTTTTTTTTTTbTWvVq1atWrOc6tTTTStNNNNNNNNNNtNNtNa9WrVq1Z1Z1NNNNNK1q1NNNNNNNNNNNtNatWrVq1atWrU00000rWrVq1atWrVq1alaaa1atWrVq1NNNammmmla1atWrVq1aterVq16tWrVnVqa1NK1qaaaVX/xAAWEAADAAAAAAAAAAAAAAAAAAAhgJD/2gAIAQEAAz8AaExf/8QAGhEBAQEBAQEBAAAAAAAAAAAAAQISEQADEP/aAAgBAgEBAgDx48ePHjx48ePHjx48ePHjx48ePHjx48ePHj86IiIiIiInjx48ePHjx48IiIiIj0oooooooooRERER73ve60UUUUUUVrWiiiiiihERERER73ve97ooooorRWiiiiihKERERER73ve973RRRRWtFFFFFFCIiIiIiPe973ve60UUVrRRRRRRQiIlCIiI973ve973pRRWiiiiiiiiiiiiiiihEe973ve973RRWtFFFFFFFFFFFFFFFFFFa13ve973WitaKKKKKKKKKKKKKKKKKK1rWtd1rutFa1oooooooooooosssooorWta1rWta1rRRRRRRRRRRZZZZZZZZZWta1rWta1rRRRRRRRRZZZZZZZZZZZZe9a1rWta1rWitaKLLLLLLLLLLLLLLLLL3rWta1rWtFbLLLLLLLLLLLLLLLLLLLL3vWta1rWita1ssssssss+hZZZZZZZZe961rWta0Vre97LLLLLLLLLLLPoWWWWWXrWta1oorWta3ssss+hZZZZ9Cyyyyyyyyiita1orWta1ve9llllllllllllllllFFa0VorWta1ve9llllllllllllllllllFFFaK1rWta1rWiyyyyyyyyyyyyiiiiiiitFFa1rWta1oosoosssssoooosoooorRRRWta1rWta0UUUUUWUUUUUUUUUUUVoooorWta1rWtaKKKKKKmiiiiiiiiiiiiiiitd73ve61oSiiipoqaKKKKKKKKKK0UUUVrve973vREREZoSihEooooorRRRRWtd73ve9EREREREoSiiiiitFllllla73ve9ERERERESiiiiiitH0PoWWWWVrXe96IiIiMoiJRRRRRRWjwlFFllllFFd6IiIiIlCUUUUUUUUUePHjx48ePCIiIiIiIiUUUUUUUUUUUePHjx48ePHjx48ePHjx48IiUUUUUUJRRRX//xAAWEQADAAAAAAAAAAAAAAAAAAABYJD/2gAIAQIBAz8AtEV7/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAECEP/aAAgBAwEBAgCtNNNNNNNNNNNNNNNNNNNNNNNNNNNNNcrTTTTTTTTTTTTTTTTTTTTTTTTTTTTTXKrTTTTTTTU000000000000000000001FVpppppqampqaaaaaaaaaaaaaaaaaaaa5Vaaaaampqampqammmmmmmmmmmlaaaaaaiq0001NTU1NTU1NTTTTTTTTTTSqqtNNNcqtNNSyzU1LNTU1NTTTTTTTTTSqqq001ytNLLLLNTU1NTU1NTbbbTTTTTSqqq001ytNLLLLLNTU1NTU3NttttNNNNNKqq001KrSyyyyyzU1NTU3Nzc02220000qqqqrSqqyyyyyzU1NTU3Nzc3NttttNNNKqqqqqqssssss1NTU3Nzc3NzbbbbTTTSqqqqqqrLLLLLNTU1Nzc3Nzc22220000qqqqqqqqssss1NTU3Nzc3NzbbbbbTTSqqqqqqqqqqzU1NTc3Nzc3Nzbc22000qqqqqqqqqqqtTU3Nzc3Nzc3NtzbTTSqqqqrKqqqqqtNNzc23Nzc3Nzc3NTU1KqqqrKqqqqqtNNNNttzc3Nzc3NzU1NLLLLLKqqqqqqqq0022223Nzc3NzU1NSyyyyyyqqqqqqqrTTbbbbc3Nzc3NTU1LLLLLLKsqqqqqqrTTTTbbbc3Nzc1NTUsssssssqqqqqqrTTTTTbbbTc3NTU1NTUsssssqqqqqqqq0000222023NTU1NTUsssssqqqqqqqq000000003NTU1NTU1LLLLLNKrTSqqqqtNNNNNNtNNTU1NSzUssss00qq0qqqqrTTTTTTTTTU1NTUs1LLLNNNKrTTTSqqq00000000001NTU1LNTU0000qtNNNKqqqtNNNNNNNNTU1NTUs1NNNNNKss1NNNK00qtK0000001NNTU0s000000qq000001NKrStNNNNK1NNNNStNNNNNKqtNNNNNNNK0000000rU0000rTTTTTSq00000rTTTTTTTTTTTTTTTTStNNNNKr/xAAUEQEAAAAAAAAAAAAAAAAAAACg/9oACAEDAQM/AAAf/9k="
3 | 
4 | export const polarDisplacementMap =
5 |   "data:image/jpeg;base64,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"
6 | 
7 | export const prominentDisplacementMap =
8 |   "data:image/png;base64,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"
9 | 


--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "lib": ["DOM", "DOM.Iterable", "ES6"],
 5 |     "allowJs": true,
 6 |     "skipLibCheck": true,
 7 |     "esModuleInterop": true,
 8 |     "allowSyntheticDefaultImports": true,
 9 |     "strict": true,
10 |     "forceConsistentCasingInFileNames": true,
11 |     "noFallthroughCasesInSwitch": true,
12 |     "module": "ESNext",
13 |     "moduleResolution": "node",
14 |     "resolveJsonModule": true,
15 |     "isolatedModules": true,
16 |     "noEmit": false,
17 |     "declaration": true,
18 |     "declarationMap": true,
19 |     "outDir": "dist",
20 |     "jsx": "react-jsx"
21 |   },
22 |   "include": [
23 |     "src"
24 |   ],
25 |   "exclude": [
26 |     "node_modules",
27 |     "dist"
28 |   ]
29 | }


--------------------------------------------------------------------------------