cvs1 ={
const ctx = DOM.context2d(W, H);
ctx.fillStyle = "#000";
ctx.fillRect(0,0,W,H);
const points = Array.from({length:300}, _=> [Math.random()*W, Math.random()*H]);
ctx.globalAlpha = 0.4;
let frame = 0;
let af = requestAnimationFrame(function tick() {
points.forEach(([x,y],i) => {
const d = worley([x,y]);
ctx.strokeStyle = palette[i%palette.length];
ctx.beginPath();
ctx.moveTo(x,y);
points[i] = add([x,y], cossin(d, (1+i%10)));
if (d<ditch || d>ditch+20){
// having computed and stored the next position of current point, I'm calling lineTo canvas function to draw a line to the new point position.
ctx.lineTo(...points[i]);
ctx.stroke();
}
});
// Here I am drawing as red circles the seed points I have used to define the Worley noise. This is just for illustrantion purposes in order for the reader to see te relation with the final rendering.
ctx.fillStyle = "red";
seeds.forEach(([x,y])=> {
ctx.beginPath();
ctx.arc(x,y, 3, 0, Math.PI*2);
ctx.fill();
});
// here I'm letting the browser know I want to draw one more frame. Of course, if I reached the maximum number of frames I want to draw, I can skip requesting a new frame
(frame++<2000) && (af = requestAnimationFrame(tick));
});
// this part is necesary on observablehq platform in order to avoid running invisible frames in background. Basically it said that if the current cell was run again, just stop the previously running animation.
invalidation.then(_=> cancelAnimationFrame(af));
// this is also a requirement of the platform. In order to render something the block needs to return a DOM element.
return ctx.canvas;
}