Making An Animated JavaScript and WebGL Gradient
By: Johnny Simpson
Tags: JavaScript, UX, Web Design, Web Development, Design

Getting Started —three.js

I’m using three.js for this experiment because it makes WebGL very easy. To start I created a new file called index.html and another called script.js in the same folder. In index.html, paste the following hollow HTML structure.

<!DOCTYPE html> <html> <head> <title>The best gradient effect of your life</title> <script src="script.js"></script> </head> <body> </body> </html>

Concept

WebGL is a pretty overwhelming concept if you don’t know anything about it, as I didn’t before I started on my gradient fill journey. As I learned, there are essentially three parts to a successful WebGL — two shaders and a bit of JavaScript to manipulate the shapes produced.

What is a shader?

Shaders, as we describe here, are essentially functions which adjust the output of a 3D rendering. They’re part of a pipeline of tasks that happen when something is rendered in 3D on your screen.

One of these shaders is called the vertex shader — this will adjust every ‘vertex’ point on the page. It basically iterates over every point, and adjusts it based on what you have in the function. The other is the fragment shader. Think of this as adjusting the colour of each point on the page.

The shader is not in JavaScript, it is written GLSL, a C-like language which is passed straight to your GPU by three.js. You can paste these straight into the <body /> of your HTML page. As someone used to writing in JavaScript, these shaders look very foreign, but it basically breaks down into a few key pieces.

snoise() or simplex noise is a function within both of our shaders for generating noise or random vertices. You’ll see how this works, but in our vertex shader, we adjust the x and z positions of each point to create a cloth like effect. How did I come up with this? As it turns out, many have tried this before. See here for all your shader noise functions: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83

is a function within both of our shaders for generating noise or random vertices. You’ll see how this works, but in our vertex shader, we adjust the x and z positions of each point to create a cloth like effect. How did I come up with this? As it turns out, many have tried this before. See here for all your shader noise functions: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83 uniform variables are variables we can manipulate straight from JavaScript in real time with three.js. We define them in our code below, and simply by updating these in JavaScript, we will update the 3D shape on our page (this was the coolest discovery from this experiment)

are variables we can manipulate straight from JavaScript in real time with three.js. We define them in our code below, and simply by updating these in JavaScript, we will update the 3D shape on our page (this was the coolest discovery from this experiment) gl_Position and gl_FragColor are reserved variables which control the final output of our shaders.

and are reserved variables which control the final output of our shaders. vUv and uv are variables which carry information on the vertex we are currently adjusting.

The best way to learn about these more is to download the files in this article and try changing a few things in the shaders and JavaScript. Below is the final output of the shaders which you can paste straight into the body of your HTML:

The shader code is in the HTML, although can be pulled into Javascript through any means (for example, a variable containing the code within the Javascript itself)

JavaScript

I’ve imported the Three.js file in the codepen at the top, just remember, if you want to do that you must have your code on a server. You can’t just open the file in your browser. You can use your own computer’s localhost for this as well.

To understand a bit more about three, you can check out the three documentation. Essentially, we need to create a camera (for viewing), a renderer (for putting it all on the screen), and a scene (for placing the objects). We will then place a sheet or rectangle on the scene.

This is where uniform variables come in. We will define these in JavaScript, and we can then update them to alter the rendering process with JavaScript. We have a few other utility functions here, so please see the full code in the codepen or in the git at the end for more information.

If you adjust line 42, multiplyScalar(5) to multiplyScalar(1), you can see the object fully without the massive zoom in. This will give you an idea about how this is working, since you’ll see it is just a sheet being warped, and the sharp lines produced in the gradient are actually just parts of the sheet overlapping with itself.

Alright — now comes the animation. We will use JavaScript animation frames as this process can become quite CPU/GPU intensive. Again, the code is minimal here, we can re-render the scene and update its values for every frame produced by requestAnimationFrame().

Conclusion

When I started this, I knew the effect I wanted to produce, but had no idea how to do it. The applications and adjustments you can make to this effect give you a lot of flexibility for backgrounds to websites, header elements, or anything like that.

Relevant Links