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";
}