Show code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>2D Wave Field</title>
<style>
html,body{margin:0;height:100%;background:#05070d;overflow:hidden}
body{display:flex;align-items:center;justify-content:center}
canvas{width:100vw;height:100vh;display:block;image-rendering:auto}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const W=240,H=180;
const cv=document.getElementById('c'),ctx=cv.getContext('2d',{alpha:false});
const buf=document.createElement('canvas');buf.width=W;buf.height=H;
const bx=buf.getContext('2d',{alpha:false});
const img=bx.createImageData(W,H),data=img.data;
const N=W*H;
let u0=new Float32Array(N),u1=new Float32Array(N),u2=new Float32Array(N);
const C2=0.36,DAMP=0.9985;
function resize(){cv.width=Math.floor(innerWidth*devicePixelRatio);cv.height=Math.floor(innerHeight*devicePixelRatio);ctx.imageSmoothingEnabled=true;}
addEventListener('resize',resize);resize();
function pulse(){
const cx=8+Math.random()*(W-16),cy=8+Math.random()*(H-16);
const r=4+Math.random()*7,amp=(Math.random()<0.5?-1:1)*(0.9+Math.random()*0.8);
const r2=r*r;
for(let y=Math.max(1,(cy-r-2)|0);y<Math.min(H-1,cy+r+2);y++){
for(let x=Math.max(1,(cx-r-2)|0);x<Math.min(W-1,cx+r+2);x++){
const dx=x-cx,dy=y-cy,d2=dx*dx+dy*dy;
if(d2<r2*2.2){
const d=Math.sqrt(d2);
const g=Math.exp(-d2/(2*r2*0.35))*Math.cos(d/r*2.0);
u1[y*W+x]+=amp*g;u0[y*W+x]+=amp*g*0.92;
}
}
}
}
function step(){
for(let y=1;y<H-1;y++){
const row=y*W;
for(let x=1;x<W-1;x++){
const i=row+x;
const lap=u1[i-1]+u1[i+1]+u1[i-W]+u1[i+W]-4*u1[i];
u2[i]=(2*u1[i]-u0[i]+C2*lap)*DAMP;
}
}
for(let x=0;x<W;x++){u2[x]=u2[x+W];u2[(H-1)*W+x]=u2[(H-2)*W+x];}
for(let y=0;y<H;y++){u2[y*W]=u2[y*W+1];u2[y*W+W-1]=u2[y*W+W-2];}
const t=u0;u0=u1;u1=u2;u2=t;
}
function draw(){
for(let i=0,p=0;i<N;i++,p+=4){
let v=u1[i]*2.6;
if(v>1)v=1;else if(v<-1)v=-1;
const a=Math.abs(v),s=a*a*0.55+a*0.45;
let r,g,b;
if(v>=0){
r=18+237*s*s;
g=22+205*s;
b=46+90*s*s*s;
}else{
r=12+70*s*s*s;
g=26+150*s;
b=54+201*s;
}
const glow=s*s*s*s*70;
data[p]=r+glow;data[p+1]=g+glow;data[p+2]=b+glow;data[p+3]=255;
}
bx.putImageData(img,0,0);
ctx.drawImage(buf,0,0,cv.width,cv.height);
}
let last=performance.now(),acc=0,nextPulse=0.4;
function frame(now){
let dt=(now-last)/1000;last=now;
if(dt>0.1)dt=0.1;
acc+=dt;
nextPulse-=dt;
if(nextPulse<=0){pulse();nextPulse=1.6+Math.random()*2.4;}
let steps=0;
while(acc>1/120&&steps<4){step();acc-=1/120;steps++;}
if(steps===0)step();
draw();
requestAnimationFrame(frame);
}
pulse();
requestAnimationFrame(frame);
</script>
</body>
</html>