Painting in Canvas which fades with time | Strange alpha layering behaviour

I'm painting to a canvas which isn't being cleared and making it so that the canvas either fades to a solid colour over time, or fades in alpha revealing the layer behind.

My first instinct was to simply fill a rectangle over the drawing with a low alpha each frame so that the fill colour accumulates gradually fading out the painting.

But I found some strange behaviour (to me at least, I'm sure there's a reason). The fill colour never fully accumulates. And the results change depending on wether paint & fill colours are lighter/darker than each other.

I found this question where someone was doing the same as me: fade out lines after drawing canvas?

The top answer looks good, and it's the same as what I tried. BUT it only works with black on white. Here's another version of the same fiddle with different colours, you'll see the drawing never disappears, it leaves a ghost:

var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    painting = false,
    lastX = 0,
    lastY = 0;

canvas.width = canvas.height = 600;

canvas.onmousedown = function (e) {
    if (!painting) {
        painting = true;
    } else {
        painting = false;

    lastX = e.pageX - this.offsetLeft;
    lastY = e.pageY - this.offsetTop;

canvas.onmousemove = function (e) {
    if (painting) {
        mouseX = e.pageX - this.offsetLeft;
        mouseY = e.pageY - this.offsetTop;

        ctx.strokeStyle = "rgba(255,255,255,1)";
        ctx.moveTo(lastX, lastY);
        ctx.lineTo(mouseX, mouseY);

        lastX = mouseX;
        lastY = mouseY;

function fadeOut() {
    ctx.fillStyle = "rgba(60,30,50,0.2)";
    ctx.fillRect(0, 0, canvas.width, canvas.height);


Also if you change the fill opacity to 0.01, and the timing to something like 20ms, it never even fills the correct colour, leaving it grey.

Other things I've tried all suffer from this same root problem. I've tried bouncing between two canvasses, taking canvas A and drawing it with a reduced alpha to canvas B, before drawing canvas B back to canvas A - same problem, there's a threshold where it doesn't disappear.

As a test I've even tried the super slow thing of getting the image data, looping through all pixels alpha channels and multiplying by 0.95 before putting the data back. It still leaves a ghost, I have to do something like this in the loop (it never even gets below 10 for some reason):

if (alpha<25) {
    alpha = 0;

I'm thinking I might be able to divide the canvas into a grid or rows and do the imageData thing one cell per frame, it might not be noticeable with low fade times.

But if anyone knows a better way or what the core thing I'm not getting is I'd be hugely grateful!

  • oh should also note, I'm letting it rasterise on the canvas because I'm painting with particles/algorithms so I'm not looking for solutions that mean I keep refreshing and redrawing the same points. Thanks!
user3202 Asked at March 19, 2018, 2:55 pm.
0 Answer(s)