WebGL Enhanced Drag Slider Tutorial With curtains.js — Part 3

Improve the overall performance of the slider by removing any layout repaint calls

Martin Laxenaire
Aug 1, 2019 · 4 min read
Image for post
Image for post

This piece is the third and last part of our tutorial. In the first part, we created a JavaScript drag slider. In the second part, we added WebGL with curtains.js to improve the animations. Please check them out if you haven’t done so already.

In this final part, we’ll see how to improve the overall performance of the slider by removing any layout repaint calls.

Here’s the final pen:

As a reminder, we used curtains.js to add everything related to WebGL.

curtains.js is an open-source Vanilla JavaScript library. It is particularly useful here as its main purpose is to enhance DOM elements with WebGL effects.

With a few lines of JavaScript, you were able to create WebGL textured planes, bound to our slider items’ HTML elements, and then post-process the whole scene.

We can then see the advantages of using curtains.js:

  • Clean and SEO-friendly HTML code.
  • You don’t have to worry about your WebGL objects’ sizes and positions as most of the stuff (like resize) will be handled under the hood by the library.
  • If, in any case, there’s an error during the WebGL initialization or in your shaders, the slider will still work!

Layout Repaint Calls / Reflow

Overall concept

First of all, you’ll need to understand what layout repaint and reflow are and what causes them. There’s a neat article written by Paul Irish, explaining it on GitHub.

Basically, every time you’re using a JavaScript method to get an HTML element style or position (such as element.getComputedStyle() or element.getBoundingClientRect()), or every time you’re trying to access the window scroll value via window.scrollY, the browser needs to redraw the whole web page to calculate those values.

This could lead to a performance bottleneck and could cause jank issues.

Using curtains.js

As a matter of fact, curtains.js does internally use getBoundingClientRect each time you’re adding a plane, or each time you resize your window to copy the plane’s HTML size and position, and apply it to its associated WebGL plane object.

There’s no way to avoid that, but, fortunately, this does not happen often so it’s not really a big deal.

But, we used the updatePosition method in our slider’s onTranslation hook and this function also calls getBoundingClientRect, therefore triggering a reflow call.

We’ll now see how to improve our slider to get rid of those layout repaint calculations.

Another Way to Translate Our Planes

Using the setRelativePosition method

The library provides another way to translate a plane: the setRelativePosition function.

It takes an X and a Y value in pixels as parameters and applies it to your plane by updating its model-view matrix.

Use Cases

Usually, when you’re using curtains.js, you’ll be using the updatePosition inside a scroll event listener to update the positions of your planes according to the window scroll value.

Because there’s no way to get your scroll or HTML element’s position without triggering a reflow call, that’s still the best way to handle planes’ positions when using a native scroll.

But, if you are using a virtual scroll library, for example, you’ll have access to scroll values that get calculated without causing reflow calls and you’ll be able to update your planes’ positions accordingly, with our setRelativePosition method!

Now, back to our slider. At any given time, we have access to its current translation (which gets calculated without triggering reflow) so why not use it to update our positions instead? That’s precisely what we are going to do.

The Idea

The overall concept is fairly simple: we will apply our translation to the planes using the setRelativePosition function.

As our planes’ positions are automatically updated each time we resize our browser window, we’ll have to reset their relative positions there.

By doing that, we’ll break the sync between the slider’s current translation and our relative positions’ values. We then have to keep track of our slider’s previous translation and subtract those values to our relative position.

The slider and the WebGL are now synced again!

Updating the Code

First of all, we’ll add a previousTranslation property to our WebGL slider class.

Let’s update our WebGLSlider class constructor:

Next, we’ll have to update our onTranslation Hook to use the setRelativePosition function instead of the previous updatePosition one:

The last thing we need to do is rewrite our onSliderResized Hook to update our previousTranslation property values, reset our planes’ relative positions, and we’re done!

And that’s all folks!

Now you’re ready to use curtains.js on your website with minimal performance impact.

You can try to change some values in your shader pass fragment shaders to tweak the effect a bit. You can also try to use a different displacement image (remember, you’ll have to use a pattern to obtain a seamless effect).

Here’s a bonus example with a different displacement image and a few variations in the shaders:


I hope you liked this article and found it useful. I also hope you saw how easy it is to use curtains.js to enhance your UI with neat WebGL effects.

Have a look at the library’s documentation and examples or check out its GitHub repo if you want to know more.

Be creative!

Better Programming

Advice for programmers.

Sign up for The Best of Better Programming

By Better Programming

A weekly newsletter sent every Friday with the best articles we published that week. Code tutorials, advice, career opportunities, and more! Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Martin Laxenaire

Written by

Webdesigner / Front-end developer. Javascript, WebGL and stuff. Author of https://www.curtainsjs.com

Better Programming

Advice for programmers.

Martin Laxenaire

Written by

Webdesigner / Front-end developer. Javascript, WebGL and stuff. Author of https://www.curtainsjs.com

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store