HTML5 Canvas Experiment: A cool flame/fire effect using particles

View code Play Walkthrough

Description

This is a simple flame effect, created using particles. Random particles colored using fading out gradients originate from mouse coordinates(or the center of the canvas by default) to create the effect.

The colored particles are blended together using the canvas's globalCompositeOperation property.

Add New Comment

21 Comments

(close)
19_ploT

19_ploT

Very slow in Firefox. Comment out the line `ctx.globalCompositeOperation = “lighter”` and it becomes fine

Jamy Golden

Jamy Golden

Works normal speed (compared to Chrome) in my Firefox.

Great effect! Very cool.

nsnc

nsnc

I love these tutorials, but the canvas preview is almost constantly blinking. I’m not epileptic but I have to cover that half of the screen with paper to watch these. Any way I (or you) can fix this?

chrisH

chrisH

Brilliant walkthrough!

@nsnc add body {background-color: black;} to the CSS will stop the flashing as the code updates.

RootShell

RootShell

EXCELENT!!! I love it… very fast in Chrome :)

Doug Webster

Doug Webster

Loved this, and happy to find this website. Fun way to learn.

Question, I get sub 20 FPS in both Chrome and FF. Would making a particle pool and resetting the particle at the end of its lifespan get better performance rather than instantiating a new particle (or would the difference be negligible)

mgorla

mgorla

Very cool! I’ve a question.
Each time draw() is called, in the canvas is created a rectangle and a new position/opacity state of each particles but what happens to the particles created in the previous call of draw()?
I commented the line
ctx.fillRect(0, 0, W, H);
and I see they don’t “die”, isn’t this a problem for performance?

Thank you! :) You’re doing a GREAT job with these tutorials!

ginger

ginger

love this

Ethan Buck

Ethan Buck

I would like to know how I could change the code a bit to attach it to specific buttons or divs so it doesn’t follow the mouse and also what would I have to do to make the flame purple only?

marop

marop

Cool, but very slow performance on firefox. how could it be fixed?
Opera and chrome are OK
thanxs!

Icetea

Icetea

nice

achaykillz

achaykillz

i’m wondering if you can use this over a website? as tried and doesnt seem to work like that :/

Mike

Mike

Can someone help me with this. I am new to writing code. I have so much as copied and pasted this and I cannot get it to work. Can someone show me there exact code because I am assuming there are additional steps to this that I do not know. Thanks

Anh Le

Anh Le

how add background image ?

Andrey

Andrey

I can’t get this to work on JS Fiddle. Are there any special libraries that I need to include?

Looks great, by the way, awesome work!

Thanks.

Andrey

Andrey

Nevermind, I got it to work on JS Fiddle. Just had to change “onLoad” to “onDomready”.

Great work!

Marco

Marco

This is so cool. But it would be perfect if we could add background image to canvas. Sorry for my bad English, but can somebody help with this? :) To replace black color with bg picture

gl

gl

How to remove that black background? Make canvas transparent? It would be cool to be able to put this over website content.

 
<!-- Lets make a cool flame effect -->
<canvas id="canvas"></canvas>
 
/*Some styles*/
* {margin: 0; padding: 0;}
#canvas {display: block;}
 
window.onload = function(){
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    
    //Make the canvas occupy the full page
    var W = window.innerWidth, H = window.innerHeight;
    canvas.width = W;
    canvas.height = H;
    
    var particles = [];
    var mouse = {};
    
    //Lets create some particles now
    var particle_count = 100;
    for(var i = 0; i < particle_count; i++)
    {
        particles.push(new particle());
    }
    
    //finally some mouse tracking
    canvas.addEventListener('mousemove', track_mouse, false);
    
    function track_mouse(e)
    {
        //since the canvas = full page the position of the mouse 
        //relative to the document will suffice
        mouse.x = e.pageX;
        mouse.y = e.pageY;
    }
    
    function particle()
    {
        //speed, life, location, life, colors
        //speed.x range = -2.5 to 2.5 
        //speed.y range = -15 to -5 to make it move upwards
        //lets change the Y speed to make it look like a flame
        this.speed = {x: -2.5+Math.random()*5, y: -15+Math.random()*10};
        //location = mouse coordinates
        //Now the flame follows the mouse coordinates
        if(mouse.x && mouse.y)
        {
            this.location = {x: mouse.x, y: mouse.y};
        }
        else
        {
            this.location = {x: W/2, y: H/2};
        }
        //radius range = 10-30
        this.radius = 10+Math.random()*20;
        //life range = 20-30
        this.life = 20+Math.random()*10;
        this.remaining_life = this.life;
        //colors
        this.r = Math.round(Math.random()*255);
        this.g = Math.round(Math.random()*255);
        this.b = Math.round(Math.random()*255);
    }
    
    function draw()
    {
        //Painting the canvas black
        //Time for lighting magic
        //particles are painted with "lighter"
        //In the next frame the background is painted normally without blending to the 
        //previous frame
        ctx.globalCompositeOperation = "source-over";
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, W, H);
        ctx.globalCompositeOperation = "lighter";
        
        for(var i = 0; i < particles.length; i++)
        {
            var p = particles[i];
            ctx.beginPath();
            //changing opacity according to the life.
            //opacity goes to 0 at the end of life of a particle
            p.opacity = Math.round(p.remaining_life/p.life*100)/100
            //a gradient instead of white fill
            var gradient = ctx.createRadialGradient(p.location.x, p.location.y, 0, p.location.x, p.location.y, p.radius);
            gradient.addColorStop(0, "rgba("+p.r+", "+p.g+", "+p.b+", "+p.opacity+")");
            gradient.addColorStop(0.5, "rgba("+p.r+", "+p.g+", "+p.b+", "+p.opacity+")");
            gradient.addColorStop(1, "rgba("+p.r+", "+p.g+", "+p.b+", 0)");
            ctx.fillStyle = gradient;
            ctx.arc(p.location.x, p.location.y, p.radius, Math.PI*2, false);
            ctx.fill();
            
            //lets move the particles
            p.remaining_life--;
            p.radius--;
            p.location.x += p.speed.x;
            p.location.y += p.speed.y;
            
            //regenerate particles
            if(p.remaining_life < 0 || p.radius < 0)
            {
                //a brand new particle replacing the dead one
                particles[i] = new particle();
            }
        }
    }
    
    setInterval(draw, 33);
}

5x 10x 15x 20x

21 Comments

Description