Some text distortion experiments using the Blotter.js library. The idea is to distort text as we scroll or move the mouse.

Distortion effects have become quite popular over the past two years and now many extraordinary website designs have some unique form of this intriguing trend. Today we’d like to share two demos with you that show how to use Blotter, a three.js and Underscore.js powered API for drawing artsy text effects. We used it to distort text on scroll and on mouse move.

The inspiration for this experiment comes from the project page of Bounce where you can see decorative letters being distorted on scroll.

If you enjoy this little experiment, you might also like Yannis’ Liquid Distortion Effects or Robin’s WebGL Distortion Hover Effects or Lucas’ Animated Heat Distortion Effects with WebGL.

Attention: Note that this is experimental and that we use modern CSS properties that might not be supported in older browsers.

Blotter gives us an easy to use interface for creating text effects that utilize GLSL shaders. You can use one of the many configurable effects (materials) or, if you are familiar with GLSL, implement completely new ones. Read the basics to understand how to use it and play with one of the materials to see it in action.

The main idea in our demos is to change the value of the material’s uniform as we scroll the page. The faster the scrolling the more the value changes. Here’s a simplified example on how to achieve this:

<span data-blotter>text here</span>

const MathUtils = { // Equation of a line. lineEq: (y2, y1, x2, x1, currentVal) => { var m = (y2 - y1) / (x2 - x1), b = y1 - m * x1; return m * currentVal + b; }, // Linear Interpolation function. lerp: (a, b, n) => (1 - n) * a + n * b }; // Create the blotter material. const material = new Blotter.LiquidDistortMaterial(); // Set the default material uniform values. material.uniforms.uSpeed.value = .5; material.uniforms.uVolatility.value = 0; material.uniforms.uSeed.value = 0.4; // Create the Blotter instance. const blotter = new Blotter(material); // Initialize the Blotter Text on all HTML elements with data-blotter. const blotterElems = [...document.querySelectorAll('[data-blotter]')]; blotterElems.forEach((el) => { const text = new Blotter.Text(el.innerHTML); blotter.addText(text); // Now delete the html content. el.innerHTML = ''; // The created canvas. const scope = blotter.forText(text); // Append it to the main element. scope.appendTo(el); }); // Now, change one (or more) uniform value as we scroll. // The faster the scrolling the more the value changes. let currentScroll = window.pageYOffset; // The volatility is the uniform that will change. let volatility = 0; // It will go from 0 (not scrolling) to 0.9 (scrolling at a speed of maxscroll). const maxscroll = 10; const uniformValuesRange = [0,0.9]; // Using requestAnimationFrame + linear interpolation for the effect. const render = () => { // Current scroll position const newScroll = window.pageYOffset; // How much was scrolled from the last repaint. const scrolled = Math.abs(newScroll - currentScroll); // Get the new value of volatility. volatility = MathUtils.lerp(volatility, Math.min(MathUtils.lineEq(uniformValuesRange[1], uniformValuesRange[0], maxscroll, 0, scrolled), 0.9), 0.05); // Set the volatility. material.uniforms.uVolatility.value = volatility; // Update the current scroll. currentScroll = newScroll; // Repeat. requestAnimationFrame(render); } requestAnimationFrame(render);

In the first demo the scroll speed determines the distortion amount:

And in the second demo, the speed of the mouse movement controls the intensity of the effect:

We hope you like this experiment and find it useful!

References and Credits