Ambient Canvas Backgrounds

Five ambient webpage backgrounds created using the HTML5 Canvas API and jwagner's Simplex Noise library.
Ambient_featured

Today we’ll be exploring some ambient webpage background animations. The idea here was to create a collection of animations that are interesting to look at without being (too) distractive, and could be easily applied to the background of a webpage. Each animation is created using vanilla (es6+) JavaScript with the Canvas API, and 3 of 5 use Jonas Wagner’s Simplex Noise library.

There are a couple useful techniques I use in each demo to make things run more efficiently.

One is offscreen drawing or buffering. The idea is to have an in-memory canvas and context to handle all of the complex drawing, and an onscreen canvas to draw each new frame in the rendering loop. This technique also allows for re-drawing the same reference frame multiple times, which can be combined with filtering and compositing techniques to create some interesting effects.

Example:


  function render() {
    ctx.onscreen.drawImage(canvas.offscreen, 0, 0); // render offscreen canvas to onscreen
  }

  function draw() {
    ctx.offscreen.fillStyle = 'hsla(220,50%,50%,1)';
    ctx.offscreen.fillRect(0, 0, canvas.offscreen.width, canvas.offscreen.height); // fill offscreen canvas background
    
    // draw objects to offscreen canvas here
    
    render();
    window.requestAnimationFrame(draw);
  }

Another technique I use is to reduce all complex objects’ properties down into a single array.

For example, let’s say we want to draw a particle. A 2D particle tends to have the following basic properties:

  • position (x, y)
  • velocity (x, y)
  • color

Rather than storing these values as object properties, we can store them in a single typed array, thereby eliminating the need for a large array of complex particle objects.

Example:


  const particleCount = 200;
  const propCount = 5; // x, y, vx, vy, hue (hsla color)
  const propsLength = particleCount * propCount; // length of the props array  

  let props;

  function createParticles() {
    props = new Float32Array(propCount);

    // iterate for the length of the props array
    // increment by the number of props per particle
    for (let i = 0; i < propsLength; i += propCount) { 
      createParticle(i);
    }
  }
  
  function createParticle(i) {
    let x, y, vx, vy, hue;

    // initialize values here, can randomize, use simplex noise or anything really :)

    props.set([x, y, vx, vy, hue], i);
  }
Attention: Some of these techniques are very experimental and won’t work in all browsers.

Demo #1: Aurora

aurora

The first step in creating this effect was setting up the rays. The basic idea was to place them randomly along the x-axis and centered along the y-axis, then offset by the simplex noise field value at each position and draw as a gradient.

To achieve the blur effect, I initially draw everything to an offscreen canvas as mentioned above, then I copy and blur the image, then render in the onscreen canvas.

Demo #2: Swirl

swirl

To create this effect I use the simplex noise library to determine the noise value at each particle’s position at the current time in the animation. I then multiply that value by tau, or 2 * pi to get an angle in radians. I multiply that value by the number of noise steps, in this case 8, and apply that final value to the particles’ velocity. Multiplying by a number of steps creates the “banding” look in the particle movement.

To achieve the glow effect, I use the same blur technique as in the aurora demo, and then I re-draw the reference (offscreen) canvas without a blur and composite the frame with the current onscreen canvas.

Demo #3: Shift

shift

For this effect, I create a number of large circles and place them randomly on the screen. I move them along at random and update their color values using the current noise value at their position and time. Then I blur and draw the reference frame to the onscreen canvas.

Demo #4: Coalesce

coalesce

This effect uses the same technique for creating a glow effect as the swirl demo.

What I wanted to do here was to have each particle start out rushing for the center and then get caught in a spiral toward the center. To do this I store the direction value in my props array, then in my update loop I interpolate their direction from pointing directly at the center to pointing slightly off-center, also slowing the speed along the way.

To keep the squares from always facing the same direction, I used the .translate() and .rotate() functions to rotate each particle.

Demo #5: Pipeline

pipeline

Although they may look like pipes, this is also a particle animation. Each particle is drawn only as a circle with a stroke, no fill and low opacity. They move along slowly and each previous frame is retained onscreen, which creates the look of pipes.

For the pipe turns, I setup an initial count for the number of possible turns, 8 for this animation. I get the value in radians of a single turn, and randomly decide for each pipe when to allow a turn and also decide if the turn should be negative or positive.

Browser Support:
  • ChromeSupported
  • FirefoxSupported
  • Internet ExplorerNot supported
  • SafariNot supported
  • OperaSupported

References and Credits

Previous:
Next:

Tagged with:

Consultant @ Rural Sourcing. Currently on contract with Cars.com. Full-stack capable, front-end focused. Creative coder by night.

View all contributions by

Related Articles

Receive our bi-weekly Collective or official newsletter right in your inbox.

Which newsletter would you like to receive?

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.