The context.fill() method comes with a lot of overhead. Check this to do one fill() call per color used.

Check this to filter out cells that will be obscured by subsequent paint operations.

Horizontally adjactent cells with square geometry are grouped into a rectangle, thus reducing the number of calls to the canvas.

Don't use the marching squares algorithm to paint smoothed edges, just paint very big pixels.

Toggle the optimization settings to see the impact they have on the frame rate.

Modulate the intensity of the fire over time. This can cause uneven cpu load.

Also check out my more realistic noise fire simulation .

If you're using a fairly new browser, you should see a cartoonish fire simulation to the left. When you're done playing with it, you can scroll down and read about it.

About the simulation

The implementation and what I learned

The simulation is written in javascript and visualized using HTML5 canvas using the Marching Squares algorithm.

Simulation

The simulation at a glance:

The representation is a grid of cells with different intensity (heat)

Each cell gets its intensity updated using its current value, the neighbours on the side and below it, and a random value.

The bottom row of the grid is initialized with random numbers every cycle (or actually, an off-screen row)

The intensity of each cell is mapped onto one of five different colors

The action happens in js/objects/firems.js and the method tick()

The algorithm should be pretty common, but I failed to Google a name for it. I based it on what I remember from when a co-worker explained his implementation of a fire in 80x50 char mode ages ago.

Visualization

I originally wrote this simulation representing it only as pixels. The other day a post on programming reddit about an ASCII fluids simulation inspired me and I learned about the Marching Squares algorithm.

Briefly put, the algorithm generates contours from grids containing numerical values, where values over a threshold value will represent a contour. The algorithm only generates a contour, so I used it several times with different thresholds to create the fire representation.

I apply the algorithm five times, using different thresholds, to create different contours that I overlay.

What I learned about HTML5 canvas

These are my findings when developing for Google Chrome, but are likely to hold true for other browsers as well.

Draw operations often incur a big overhead, but not all operations are equal:

The number of calls to canvas context matters more than the area painted

context.fill() has a lot of overhead - do your drawRect() , lineTo() etc. operations in as big batches as possible.

What I learned about optimizing

This is something that's always repeated, but here it really hit me: Do measurements!

I have made a framework for my canvas experiments, where I can manipulate a parameters in run-time. I made this originally to manipulate parameters for visualizations. It is, however also a very good way to get immediate feedback if an optimization is doing any good or not, by putting on off switches for optimizations in. If the frame rate rises, it was probably a good idea.

Source code

You can fork the code on github: https://github.com/zufallsgenerator/firesimulation