Here is some more HTML5 canvas particle fun for you. I modify my earlier particles bouncing off a circular wall example to create colorful, fiery trails behind the particles. The effect is achieved by a simple manipulation of pixel values over time. Click here or on the screenshot below to see the effect, then read below to learn more about the code.

html5 particles fire trails

Download

The complete code can be downloaded here: FireTrails.zip

Creating the effect

The basic particle code here is exactly the same as my previous example, so I will only comment on the fire trail effect.

The idea behind the fading trails is simple: when it is time to draw the particles in their new positions after a screen refresh, we do not erase the previous picture but instead fade it out and draw on top of it. This fading trail technique is similar to that used in an earlier post, where the trails were caused by alpha fading (also see that post for a discussion of browser differences in handling alpha values).

Here we fade out the previous picture by simply subtracting fixed amounts from the red, green, and blue channels. The colorful effect is achieved by fading these color components at different rates: red fades the slowest, blue fades the fastest. Since the particles start out colored white, when their images fade the colors transition from white to yellow to orange to red. If you experiment with these fading amounts, you can achieve differently colored trails.

An alternate approach would be to multiply the color components by numbers less than one, which will also create a fading effect. But multiplication is slower than subtraction, and in my testing I have found that some browsers slow down considerably when the multiplication method is used.

Here is the complete code for the fading effect, but note that it is missing an optimization step, which I will correct below:

//image fade - NOT OPTIMIZED!
lastImage = context.getImageData(0,0,displayWidth,displayHeight);
pixelData = lastImage.data;
len = pixelData.length;
for (i=0; i<len; i += 4) {
    r = pixelData[i]-redFade;
    g = pixelData[i+1]-greenFade;
    b = pixelData[i+2]-blueFade;
    pixelData[i] = (r < 0) ? 0 : r;
    pixelData[i+1] = (g < 0) ? 0 : g;
    pixelData[i+2] = (b < 0) ? 0 : b;
}
context.putImageData(lastImage,0,0);

Here is what is happening in this code. First, we retrieve the current canvas image and its pixel data. Then in a loop we modify the red, green, and blue channels of this data by subtracting the fixed fade amounts. (Note that in groups of four, the red, green, blue, and alpha values for each pixel are stored in sequential order in the pixel data array.) We are careful to clamp these values to non-negative numbers before setting the new values. After the pixel data has all been modified, we use the putImageData() method to draw the modifed image back into the canvas.

The fade amounts we are using here are assigned earlier in the code:

redFade = 4;
greenFade = 9;
blueFade = 32;

As promised, there is one way to optimize this code. We simply need to realize that once the pixels have faded to black, that we should not continue to fade them further. Since red fades the slowest, we can tell if a pixel is black by reading the red value and seeing if it is zero. If so, we will skip the fading code and move on to the next pixel. The optimized fading code is as follows:

lastImage = context.getImageData(0,0,displayWidth,displayHeight);
pixelData = lastImage.data;
len = pixelData.length;
for (i=0; i<len; i += 4) {
if ((r = pixelData[i]) != 0) {
    r -= redFade;
    g = pixelData[i+1]-greenFade;
    b = pixelData[i+2]-blueFade;
    pixelData[i] = (r < 0) ? 0 : r;
    pixelData[i+1] = (g < 0) ? 0 : g;
    pixelData[i+2] = (b < 0) ? 0 : b;
}
context.putImageData(lastImage,0,0);

A lot of calculations are being done on each refresh of the screen, but in my testing the effect runs rather smoothly, with some variance between browsers. Smaller canvases will certainly run faster.

Have fun and try some different colors!