Show code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Wave Grid</title>
<style>
html,body{margin:0;height:100%;overflow:hidden;background:#05070b}
canvas{display:block;width:100vw;height:100vh;image-rendering:auto}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const W=160,H=110,N=W*H,c=document.getElementById("c"),x=c.getContext("2d");
let u=new Float32Array(N),p=new Float32Array(N),v=new Float32Array(N),img=x.createImageData(W,H);
let last=0,next=0;
function resize(){c.width=innerWidth;c.height=innerHeight}
addEventListener("resize",resize);resize();
function pulse(){
const cx=10+Math.random()*(W-20),cy=10+Math.random()*(H-20),r=7+Math.random()*5,a=(Math.random()<.5?-1:1)*(1.6+Math.random()*.8);
for(let y=Math.max(1,cy-r|0);y<Math.min(H-1,cy+r|0);y++)for(let xx=Math.max(1,cx-r|0);xx<Math.min(W-1,cx+r|0);xx++){
const dx=xx-cx,dy=y-cy,d=dx*dx+dy*dy;
if(d<r*r)u[y*W+xx]+=a*(1+Math.cos(Math.PI*Math.sqrt(d)/r))*.5;
}
}
function step(){
for(let y=1;y<H-1;y++)for(let xx=1;xx<W-1;xx++){
const i=y*W+xx,lap=u[i-1]+u[i+1]+u[i-W]+u[i+W]-4*u[i];
v[i]=(2*u[i]-p[i]+.34*lap)*.995;
}
for(let xx=0;xx<W;xx++){v[xx]=v[W+xx];v[(H-1)*W+xx]=v[(H-2)*W+xx]}
for(let y=0;y<H;y++){v[y*W]=v[y*W+1];v[y*W+W-1]=v[y*W+W-2]}
[p,u,v]=[u,v,p];
}
function draw(t){
if(!last){last=t;next=t+600;pulse()}
let n=Math.min(5,Math.max(1,((t-last)/16)|0));last=t;
while(n--)step();
if(t>next){pulse();next=t+2400+Math.random()*1800}
const d=img.data;
for(let i=0,j=0;i<N;i++,j+=4){
let a=Math.max(-1,Math.min(1,u[i]*1.2)),m=Math.abs(a),q=255*m;
d[j]=a>0?q:20+30*m;d[j+1]=30+130*(1-m);d[j+2]=a<0?q:35+80*m;d[j+3]=255;
}
x.putImageData(img,0,0);
x.globalCompositeOperation="screen";x.filter="blur(5px)";x.drawImage(c,0,0,W,H,0,0,c.width,c.height);x.filter="none";x.globalCompositeOperation="source-over";
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
</script>
</body>
</html>