Композиция сделала свое дело.Вот этап затухания:
// painter = canvas.getContext("2d")
painter.save();
painter.globalAlpha = 1;
painter.globalCompositeOperation = "destination-in";
const fadeOutAmount = 0.99;
painter.fillStyle = "rgba(0, 0, 0, fadeOutAmount)";
painter.fillRect(0, 0, canvas.width, canvas.height);
painter.restore();
При использовании составного режима «приемник» для рисования фигур новая непрозрачность фигур применяется к фону.
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing
Пример ( также на CodePen ):
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 300;
canvas.height = 300;
ctx.fillStyle = "rgb(250, 0, 0)";
// rectangle is filled with solid red
ctx.fillRect(50, 50, 100, 100);
ctx.globalCompositeOperation = "destination-in";
ctx.fillStyle = "rgba(250, 250, 250, 0.5)";
ctx.fillRect(75, 75, 100, 100);
// after the line above, only the part where the two squares show is overlappped, and it only has the opacity of the latter square. Doing this many frames in a row fully fades out the background.
ctx.globalCompositeOperation = "source-over"
document.getElementById("test").appendChild(canvas);
<div id="test"></div>