JSFiddle - React, Tailwind, and code Playground

JavaScript

var canv=document.createElement('canvas');
var w=640,h=480;
canv.width = w; 
canv.height = h; 
var ctx = canv.getContext('2d'); 
document.body.appendChild(canv);
loopableSoftNoise(canv,["0,0,0","255,128,0","255,0,255","255,0,128","128,95,255","128,0,127"]);

function loopableSoftNoise(canvas,colors)
{
    var i,x,y,c,r,w,h,ctx,l,dx,dy,e;
    w=canvas.width;
    h=canvas.height;
    ctx = canvas.getContext("2d");
    //ctx.fillStyle="rgba(0,255,0,1)";
    //ctx.fillRect(20,20,w-40,h-40);
   	for(i=0;i<15;i++)
	{
        e=false;
        if(Math.random()<0.5) e=true; // erase!
		x=Math.floor(Math.random()*w);
		y=Math.floor(Math.random()*h);
		r=Math.floor(w/3+Math.random()*w/3);
        c=Math.floor(Math.random()*colors.length);
        
        // draw it 9 times, to make it always loopable!
        console.log("------");
        for(l=0;l<9;l++)
        {
            dx=(l%3)-1;
            dy=Math.floor(l/3)-1;
            dx=(x+dx*w);
            dy=(y+dy*h);
            var grd=ctx.createRadialGradient(dx,dy,1,dx,dy,r);
            if(e)
                ctx.globalCompositeOperation = "destination-out"; // erase
            else
                ctx.globalCompositeOperation = "source-over";
            grd.addColorStop(0,"rgba("+colors[c]+",0.7)");
            grd.addColorStop(1,"rgba("+colors[c]+",0.0)");
            ctx.fillStyle=grd;
            ctx.fillRect(0,0,w,h);
            ctx.fill();
        }
	}
    // reset!
    ctx.globalCompositeOperation = "source-over";
}