Generative Art for Website Backgrounds

Since my personal website Semicolon Software doesn't need to contain much more than a few links into different places on the web, I wanted to make it more interesting by doing some JavaScript experimentation. The result of this is a beautiful piece of randomly generated background art every time that you reload the page!

This article is a brief summary of the techniques used to create this background.


The website is written in ES2015 and cross-compiled into today's EcmaScript using babel. Drawing operations are performed using svg.js. chroma.js is used for color manipulations and the built-in support for the ColorBrewer palettes.

How it's made

The generated backgrounds consist of two parts, both randomly selected: A color palette and a randomly generated pattern. We'll first discuss the two currently implemented pattern algorithms and then talk about how to randomly generate color palettes.

Generating Patterns


Triangulation example

This pattern is heavily inspired by the Trianglify package by Quinn Rohlf although I've implemented this myself, making some of my own choices in the process.

To start out, we generate a square grid of varying pixel size between 150-200px:

An undisturbed grid

We then shift all grid points by a random offset of ±30% of the grid size in both dimensions:

A shifted grid

Finally, every quadrilateral cell on this grid is split into two triangles:

Triangulated grid

We map color onto the grid points by defining separate color scales for the X and Y dimensions, determining a color according to the X and Y coordinates separately, and then mixing the two colors using chroma.mix.

Contour Lines

Contour example

This pattern is a mixture of two well-known algorithms, Simplex Noise to generate a 2D field of heights and Marching Squares to translate the 2D field into a set of isocontour polygons.

Simplex Noise

Simplex noise is an improved version of Perlin Noise also invented by Ken Perlin that can generate random cloudy shapes in any number of dimensions. I use noise.js by Stefan Gustavson and Joseph Gentle to generate a coarse-grained grid of Simplex Noise points:

Simplex Noise example Image taken from

Marching Squares

Next on our workflow is the Marching Squares Algorithm that is used to translate the grid of noise values into iso-contour polygons. I created my own implementation for both Marching Squares and a subsequent edge joining step to merge the individual edges into polygons1.

Marching Squares Example Image credit: Bananenfalter on Wikimedia Commons

We repeat this for several isocontour levels that will be mapped to different levels of the color palette.

Generating Color Palettes

There are many semi-automatic color palette generators on the internet that typically work by choosing a point on the color wheel and then deriving points at different angles from the original point (and possibly modifying saturation and brightness) to generate a color palette.

I've implemented three strategies for choosing pleasing color scales to paint the previously described patterns with. One of them is picked at random every time the page is loaded.

Analogous Colors

First, we simply choose a random hue and a complimentary color that is on the opposite site of the color wheel. We then use chroma.scale initializing it with both the original random and its complementary at 50% saturation and lightness with a hsl interpolation mode to generate a pleasing color scale.

Neighboring Colors

Alternatively, we choose a random hue from the color wheel and then offset that hue by ±45° to derive two neighboring hues. Again, we use chroma.scale and initialize it with a gradient going from left-neighbor → random-color → right-neighbor.

ColorBrewer Colors

Finally, we can also just randomly choose a palette from the beautiful ColorBrewer2 palette library.


By having several random components that can be mixed together freely, the method described in this article can generate many interesting-looking backgrounds for my personal webpage. Check the results out yourself and see which ones you like best by refreshing the page!

See also

  1. Contact me if you are curious about my implementation of Marching Squares.