liquid-gl 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +117 -40
  2. package/liquidGL.js +519 -136
  3. package/package.json +3 -10
package/README.md CHANGED
@@ -2,17 +2,43 @@
2
2
 
3
3
  <a href="https://liquidgl.naughtyduk.com"><img src="https://raw.githubusercontent.com/naughtyduk/liquidGL/main/assets/liquidGL-npm-preview.gif" alt="liquidGL" width="100%" height="auto"/></a>
4
4
 
5
- **v1.0.6**
5
+ **v2.0.0**
6
6
 
7
7
  > [!NOTE]
8
8
  > `liquidGL` is free to use for both non-commercial and commercial purposes. _BETA_ has now ended and the library is now ready for production use.
9
9
 
10
+ > [!WARNING]
11
+ > **v2.0.0 changes tilt behaviour.** The tilt interaction now eases symmetrically over the new `tiltEase` option (default `400`ms) in both directions, replacing the previous hard-coded `0.12s` ease-in and `0.4s` ease-out. If you depended on the old timing, set `tiltEase` explicitly. All other defaults are unchanged and existing configurations render identically.
12
+
10
13
  `liquidGL` turns any fixed-position element into a perfectly refracted, glossy "glass pane" rendered in WebGL.
11
14
 
12
15
  <a href="https://liquidgl.naughtyduk.com" target="_blank" rel="noopener noreferrer"><img src="https://raw.githubusercontent.com/naughtyduk/liquidGL/main/assets/try-it-out-npm.png" alt="Try It Out" width="120"></a>
13
16
 
14
17
  <a href="https://liquidgl.naughtyduk.com/demos/demo-1.html" target="_blank" rel="noopener noreferrer"><strong>DEMO 1</strong></a> | <a href="https://liquidgl.naughtyduk.com/demos/demo-2.html" target="_blank" rel="noopener noreferrer"><strong>DEMO 2</strong></a> | <a href="https://liquidgl.naughtyduk.com/demos/demo-3.html" target="_blank" rel="noopener noreferrer"><strong>DEMO 3</strong></a> | <a href="https://liquidgl.naughtyduk.com/demos/demo-4.html" target="_blank" rel="noopener noreferrer"><strong>DEMO 4</strong></a> | <a href="https://liquidgl.naughtyduk.com/demos/demo-5.html" target="_blank" rel="noopener noreferrer"><strong>DEMO 5</strong></a>
15
18
 
19
+ ---
20
+
21
+ ## What's new in v2.0.0
22
+
23
+ **New features**
24
+
25
+ - **Chromatic aberration** — the new `aberration` option disperses the red and blue channels either side of the refraction vector, blue displaced further than red, matching the way real glass disperses shorter wavelengths more strongly. Dispersion scales with the refraction offset, so it concentrates at the bevelled edge and vanishes at the flat centre. Defaults to `0` (off).
26
+ - **Configurable tilt easing** — the new `tiltEase` option sets the settle duration, in milliseconds, of the tilt on both hover-in and hover-out.
27
+
28
+ **Bug fixes**
29
+
30
+ - **Refraction drift caused by ignored elements** — elements marked `data-liquid-ignore` were removed from the snapshot entirely, collapsing them out of layout and shifting every element below them. Ignored elements now retain their layout box, so the refraction stays aligned with the live page.
31
+ - **Lens and content diverging during tilt** — the pane could separate from its content mid-tilt because the element was being measured while transformed. Metrics are now taken from the untilted box.
32
+ - **Tilt snapping on hover** — the refraction jumped straight to its new angle on hover-in while easing on hover-out. Both directions now share a single curve and duration, and cursor movement during entry retargets the in-flight ease rather than snapping.
33
+ - **Displacement while pinch-zoomed** — the pane drifted diagonally away from its element when the page was pinch-zoomed, because `visualViewport` offsets were applied twice. Offset compensation is now correctly gated.
34
+
35
+ **Performance**
36
+
37
+ - Video frames are no longer re-composited or re-uploaded when neither the frame time nor the destination region has changed. Paused, ended and unmoved videos now cost nothing per frame.
38
+ - The snapshot bounding box is read once per frame and shared across every lens, instead of twice per lens per frame, removing repeated forced layout from the render loop.
39
+
40
+ ---
41
+
16
42
  ## Install from npm
17
43
 
18
44
  ```sh
@@ -28,7 +54,7 @@ const glassEffect = liquidGL({
28
54
  });
29
55
  ```
30
56
 
31
- > `html2canvas` is installed automatically as a package dependency. `three` is optional and only required when using `liquidGL` with 3D model workflows.
57
+ > `html2canvas` is installed automatically as a package dependency, so there is nothing else to add. `liquidGL` renders with raw WebGL and has no other runtime dependencies.
32
58
 
33
59
  ---
34
60
 
@@ -38,17 +64,18 @@ const glassEffect = liquidGL({
38
64
 
39
65
  ### Key Features
40
66
 
41
- | Feature | Supported | Feature | Supported |
42
- | :------------------------------------- | :-------: | :----------------------- | :-------: |
43
- | Real-time Refraction (static content) | ✅ | Magnification Control | ✅ |
44
- | Real-time Refraction (video) | ✅ | Dynamic Element Support | ✅ |
45
- | Real-time Refraction (text animations) | ✅ | GSAP-Ready Animations | ✅ |
46
- | Real-time Refraction (CSS animations) | ❌ | Lightweight & Performant | ✅ |
47
- | Adjustable Bevel | ✅ | Seamless Scroll Sync | ✅ |
48
- | Frosted Glass Effect | ✅ | Auto-Resize Handling | ✅ |
49
- | Dynamic Shadows | ✅ | Auto Video Refraction | ✅ |
50
- | Specular Highlights | ✅ | Animate Lenses | ✅ |
51
- | Interactive Tilt Effect | ✅ | `on.init` Callback | ✅ |
67
+ | Feature | Supported | Feature | Supported |
68
+ | :------------------------------------- | :-------: | :------------------------------- | :-------: |
69
+ | Real-time Refraction (static content) | ✅ | Magnification Control | ✅ |
70
+ | Real-time Refraction (video) | ✅ | Dynamic Element Support | ✅ |
71
+ | Real-time Refraction (text animations) | ✅ | GSAP-Ready Animations | ✅ |
72
+ | Real-time Refraction (CSS animations) | ❌ | Lightweight & Performant | ✅ |
73
+ | Adjustable Bevel | ✅ | Seamless Scroll Sync | ✅ |
74
+ | Frosted Glass Effect | ✅ | Auto-Resize Handling | ✅ |
75
+ | Dynamic Shadows | ✅ | Auto Video Refraction | ✅ |
76
+ | Specular Highlights | ✅ | Animate Lenses | ✅ |
77
+ | Interactive Tilt Effect `[UPDATED]` | ✅ | `on.init` Callback | ✅ |
78
+ | Chromatic Aberration `[NEW]` | ✅ | Configurable Tilt Easing `[NEW]` | ✅ |
52
79
 
53
80
  ---
54
81
 
@@ -79,6 +106,7 @@ const glassEffect = liquidGL({
79
106
  target: ".liquidGL",
80
107
  resolution: 2.0,
81
108
  refraction: 0.01,
109
+ aberration: 0,
82
110
  bevelDepth: 0.08,
83
111
  bevelWidth: 0.15,
84
112
  frost: 0,
@@ -87,6 +115,7 @@ const glassEffect = liquidGL({
87
115
  reveal: "fade",
88
116
  tilt: false,
89
117
  tiltFactor: 5,
118
+ tiltEase: 400,
90
119
  magnify: 1,
91
120
  on: {
92
121
  init(instance) {
@@ -125,36 +154,58 @@ liquidGL.registerDynamic(mySplitText.lines);
125
154
 
126
155
  > Simply call `liquidGL.syncWith()` after initialising `liquidGL`.
127
156
 
157
+ When installed from npm, pass your libraries in directly. Imported modules are not attached to `window`, so the helper cannot auto-detect them the way it does with browser script tags.
158
+
128
159
  ```js
160
+ import liquidGL from "liquid-gl";
161
+ import Lenis from "lenis";
162
+ import gsap from "gsap";
163
+ import ScrollTrigger from "gsap/ScrollTrigger";
164
+
165
+ gsap.registerPlugin(ScrollTrigger);
166
+
129
167
  const glassEffect = liquidGL({
130
168
  target: ".liquidGL",
131
169
  });
132
170
 
133
- const { lenis, locomotiveScroll } = liquidGL.syncWith();
171
+ const lenis = new Lenis();
172
+
173
+ liquidGL.syncWith({ gsap, lenis });
134
174
  ```
135
175
 
136
- > Make sure to include the scroll library scripts before your main script. The `syncWith()` helper must be called **after** `liquidGL()` has been called.
176
+ Passing `gsap` lets `liquidGL` drive its render loop from the GSAP ticker and keep `ScrollTrigger` updating on scroll. `ScrollTrigger` is read from the `gsap` object once registered, or you can pass it explicitly as `ScrollTrigger`.
177
+
178
+ | Option | Type | Description |
179
+ | ------------------ | ------ | -------------------------------------------------------------------------------------- |
180
+ | `gsap` | object | The `gsap` module. Enables ticker-driven rendering and `ScrollTrigger` sync. |
181
+ | `ScrollTrigger` | object | Optional. Only needed if `ScrollTrigger` has not been registered on the `gsap` object. |
182
+ | `lenis` | object | An existing `Lenis` instance. |
183
+ | `locomotiveScroll` | object | An existing `LocomotiveScroll` instance. |
184
+
185
+ > `syncWith()` must be called **after** `liquidGL()`. Passing `gsap: false` opts out of the GSAP ticker and uses a `requestAnimationFrame` loop instead.
137
186
 
138
187
  ---
139
188
 
140
189
  ## Parameters
141
190
 
142
- | Option | Type | Default | Description |
143
- | ------------ | -------- | ------------- | ------------------------------------------------------------------------------------------------ |
144
- | `target` | string | `'.liquidGL'` | **Required.** CSS selector for the element(s) to glassify. |
145
- | `snapshot` | string | `'body'` | CSS selector for the element to snapshot. |
146
- | `resolution` | number | `2.0` | Resolution of the background snapshot (clamped 0.1–3.0). Higher is sharper but uses more memory. |
147
- | `refraction` | number | `0.01` | Base refraction offset applied across the pane (0–1). |
148
- | `bevelDepth` | number | `0.08` | Additional refraction on the edge to simulate depth (0–1). |
149
- | `bevelWidth` | number | `0.15` | Width of the bevel zone as a fraction of the shortest side (0–1). |
150
- | `frost` | number | `0` | Blur radius in pixels for a frosted look. `0` is clear. |
151
- | `shadow` | boolean | `true` | Toggles a subtle drop-shadow under the pane. |
152
- | `specular` | boolean | `true` | Enables animated specular highlights that move with time. |
153
- | `reveal` | string | `'fade'` | Reveal animation.<br>- `'none'`: Renders immediately.<br>- `'fade'`: Smoothly fades in. |
154
- | `tilt` | boolean | `false` | Enables 3D tilt interaction on cursor movement. |
155
- | `tiltFactor` | number | `5` | Depth of the tilt in degrees (0–25 recommended). |
156
- | `magnify` | number | `1` | Magnification factor of the lens (clamped 0.0013.0). `1` is no magnification. |
157
- | `on.init` | function | `—` | Callback that runs once the first render completes. Receives the lens instance. |
191
+ | Option | Type | Default | Description |
192
+ | ------------ | -------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
+ | `target` | string | `'.liquidGL'` | **Required.** CSS selector for the element(s) to glassify. |
194
+ | `snapshot` | string | `'body'` | CSS selector for the element to snapshot. |
195
+ | `resolution` | number | `2.0` | Resolution of the background snapshot (clamped 0.1–3.0). Higher is sharper but uses more memory. |
196
+ | `refraction` | number | `0.01` | Base refraction offset applied across the pane (0–1). |
197
+ | `aberration` | number | `0` | Chromatic aberration strength (0–1). Scales with the refraction offset, so dispersion is strongest at the bevel. `0` disables it and skips the extra texture samples. |
198
+ | `bevelDepth` | number | `0.08` | Additional refraction on the edge to simulate depth (0–1). |
199
+ | `bevelWidth` | number | `0.15` | Width of the bevel zone as a fraction of the shortest side (0–1). |
200
+ | `frost` | number | `0` | Blur radius in pixels for a frosted look. `0` is clear. |
201
+ | `shadow` | boolean | `true` | Toggles a subtle drop-shadow under the pane. |
202
+ | `specular` | boolean | `true` | Enables animated specular highlights that move with time. |
203
+ | `reveal` | string | `'fade'` | Reveal animation.<br>- `'none'`: Renders immediately.<br>- `'fade'`: Smoothly fades in. |
204
+ | `tilt` | boolean | `false` | Enables 3D tilt interaction on cursor movement. |
205
+ | `tiltFactor` | number | `5` | Depth of the tilt in degrees (0–25 recommended). |
206
+ | `tiltEase` | number | `400` | Duration in ms for the tilt to settle, applied symmetrically on hover-in and hover-out. `0` applies the tilt instantly. |
207
+ | `magnify` | number | `1` | Magnification factor of the lens (clamped 0.001–3.0). `1` is no magnification. |
208
+ | `on.init` | function | `—` | Callback that runs once the first render completes. Receives the lens instance. |
158
209
 
159
210
  > The `target` parameter is required; all others are optional.
160
211
 
@@ -174,15 +225,16 @@ const { lenis, locomotiveScroll } = liquidGL.syncWith();
174
225
 
175
226
  ## FAQ
176
227
 
177
- | Question | Answer |
178
- | :----------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179
- | Is there a resize handler? | Yes resize is handled in the library and debounced to 250ms for performance. |
180
- | Does the effect work on mobile? | Yes the library handles all 3 versions of WebGL and provides a frosted CSS `backdrop-filter` as a backup for older devices. |
181
- | I have a preloader, how should I initialise `liquidGL()`? | Add the `data-liquid-ignore` attribute to your preloader's top-level container to exclude it from the snapshot. You can then call `liquidGL()` inside a `DOMContentLoaded` listener as you normally would. |
182
- | What is the correct way to use `liquidGL` with page animations? | Lets say you have a preloader, above the fold intro animations and scroll animations on your page. You would:<br><br>1) set the `data-liquid-ignore` attribute on your preloader<br>2) animate your preloader and set up your initial animation states<br>3) then call `liquidGL();`<br>4) optionally, in the `on.init();` callback, you can run post snapshot scripts, such as animating the `target` element |
183
- | Can I use `liquidGL` on multiple elements? | Yes, any element which has the class declared as your `target` will be glassified. Note **all elements must use the same `z-index`** due to shared canvas optimisations, if you use different `z-index` values for multiple targets, the highest value will be used by `liquidGL`. |
184
- | Will the library exceed WebGL contexts or have other performance issues? | No, the library uses a shared canvas for all instances, we have tested up to 30 elements on one page and we were not able to cause performance problems or crashes. |
185
- | Are there any animation limitations? | It depends on what you're trying to do, rotation and scale are expensive CPU/GPU processes, additionally `shadow` `specular` and `tilt` should be used with care when you have lots of instances or complex animations as they can clog the render pipeline. |
228
+ | Question | Answer |
229
+ | :----------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
230
+ | Is there a resize handler? | Yes resize is handled in the library and debounced to 250ms for performance. |
231
+ | Does the effect work on mobile? | Yes the library handles all 3 versions of WebGL and provides a frosted CSS `backdrop-filter` as a backup for older devices. |
232
+ | I have a preloader, how should I initialise `liquidGL()`? | Add the `data-liquid-ignore` attribute to your preloader's top-level container to exclude it from the snapshot. You can then call `liquidGL()` inside a `DOMContentLoaded` listener as you normally would. |
233
+ | What is the correct way to use `liquidGL` with page animations? | Lets say you have a preloader, above the fold intro animations and scroll animations on your page. You would:<br><br>1) set the `data-liquid-ignore` attribute on your preloader<br>2) animate your preloader and set up your initial animation states<br>3) then call `liquidGL();`<br>4) optionally, in the `on.init();` callback, you can run post snapshot scripts, such as animating the `target` element |
234
+ | Can I use `liquidGL` on multiple elements? | Yes, any element which has the class declared as your `target` will be glassified. Note **all elements must use the same `z-index`** due to shared canvas optimisations, if you use different `z-index` values for multiple targets, the highest value will be used by `liquidGL`. |
235
+ | Will the library exceed WebGL contexts or have other performance issues? | No, the library uses a shared canvas for all instances, we have tested up to 30 elements on one page and we were not able to cause performance problems or crashes. |
236
+ | Are there any animation limitations? | It depends on what you're trying to do, rotation and scale are expensive CPU/GPU processes, additionally `shadow` `specular` and `tilt` should be used with care when you have lots of instances or complex animations as they can clog the render pipeline. |
237
+ | Why does `liquidGL` still use `html2canvas` rather than `snapdom`? | We evaluated `snapdom` and chose not to adopt it. It is faster at capture in isolation, but it rasterises through `foreignObject`, which introduces correctness problems that matter for a full-page background snapshot: CSS `background-image` does not paint inside `foreignObject` on WebKit, Chromium clips the output beyond the first viewport on long pages, and only in-viewport content is rasterised, so off-screen dynamic elements need re-capturing. Working around each of those needs image shims, output validation and an `html2canvas` fallback regardless, which adds weight and failure modes. The capture happens once on load and is not part of the per-frame budget, so the reliability of `html2canvas` outweighs a negligible practical gain. |
186
238
 
187
239
  ---
188
240
 
@@ -231,6 +283,31 @@ The `liquidGL` library is compatible with all WebGL enabled browsers on desktop,
231
283
 
232
284
  ---
233
285
 
286
+ ## Contributors
287
+
288
+ Thank you to the following people for their contributions to `liquidGL`.
289
+
290
+ <table>
291
+ <tr>
292
+ <td align="center" width="140">
293
+ <a href="https://github.com/codedgar">
294
+ <img src="https://github.com/codedgar.png?size=100" width="100" height="100" alt="Edgar Pérez" /><br />
295
+ <sub><b>Edgar Pérez</b></sub><br />
296
+ <sub>@codedgar</sub>
297
+ </a>
298
+ </td>
299
+ <td align="center" width="140">
300
+ <a href="https://github.com/AbhinavRobinson">
301
+ <img src="https://github.com/AbhinavRobinson.png?size=100" width="100" height="100" alt="Abhinav Robinson" /><br />
302
+ <sub><b>Abhinav Robinson</b></sub><br />
303
+ <sub>@AbhinavRobinson</sub>
304
+ </a>
305
+ </td>
306
+ </tr>
307
+ </table>
308
+
309
+ ---
310
+
234
311
  ## License
235
312
 
236
313
  MIT © NaughtyDuk