Skip to content

Instantly share code, notes, and snippets.

@Staars
Created February 25, 2026 12:52
Show Gist options
  • Select an option

  • Save Staars/766701fe7e6a0ee7afd6f4ba44250c44 to your computer and use it in GitHub Desktop.

Select an option

Save Staars/766701fe7e6a0ee7afd6f4ba44250c44 to your computer and use it in GitHub Desktop.
GL analyzer
<!DOCTYPE html>
<html><head><meta charset='utf-8'><title>16-Band Visualizer</title>
<style>body{margin:0;overflow:hidden;background:#000}canvas{display:block}</style>
</head><body>
<canvas id='c'></canvas><script>
// ================================================================
// TUNING
var AMP = 2.75; // wave height multiplier (try 1.0 .. 5.0)
var SPEED = 5.6; // scroll rate rad/s (try 0.1 .. 2.0)
var HZ = 50; // input packet rate Hz (50=dev 5x, 10=real)
// ================================================================
var c=document.getElementById('c'),gl=c.getContext('webgl2');
if(!gl)alert('no webgl2');
function rsz(){var d=devicePixelRatio||1;c.width=innerWidth*d;c.height=innerHeight*d;c.style.width=innerWidth+'px';c.style.height=innerHeight+'px';gl.viewport(0,0,c.width,c.height);}
window.onresize=rsz;rsz();
var TW=512,TH=16,head=0;
var tex=gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D,tex);
gl.texImage2D(gl.TEXTURE_2D,0,gl.R32F,TW,TH,0,gl.RED,gl.FLOAT,new Float32Array(TW*TH));
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);
function push(b16){
var n=b16.length,t=new Float32Array(n),o=new Float32Array(n);
for(var i=0;i<n;i++)t[i]=b16[Math.max(0,i-1)]*.2+b16[i]*.6+b16[Math.min(n-1,i+1)]*.2;
for(var i=0;i<n;i++)o[i]=t[Math.max(0,i-1)]*.2+t[i]*.6+t[Math.min(n-1,i+1)]*.2;
gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,tex);
gl.texSubImage2D(gl.TEXTURE_2D,0,head,0,1,TH,gl.RED,gl.FLOAT,o);
head=(head+1)%TW;
}
function mksh(t,s){var x=gl.createShader(t);gl.shaderSource(x,s);gl.compileShader(x);if(!gl.getShaderParameter(x,gl.COMPILE_STATUS))console.error(gl.getShaderInfoLog(x));return x;}
var VS='#version 300 es\n'+'layout(location=0)in vec2 p;\n'+'void main(){gl_Position=vec4(p,0.,1.);}\n';
var FS='#version 300 es\n'+'precision highp float;\n'+'uniform float iTime;uniform vec2 iRes;uniform sampler2D H;uniform float F;uniform float SC;uniform float AMP;\n'+'out vec4 fragColor;\n'+'#define pal(t,a,b,c,d) (a+b*cos(6.28318*(c*t+d)))\n'+'#define S(x,y,z) smoothstep(x,y,z)\n'+'float bamp(float sx,float ln){\n'+' float cf=mod(F-1.0-(1.0-sx)*511.0,512.0);\n'+' float u=(cf+0.5)/512.0;\n'+' float row=clamp(ln+8.0,0.0,15.0);\n'+' float v=(row+0.5)/16.0;\n'+' return clamp(texture(H,vec2(u,v)).r,0.0,1.0);\n'+'}\n'+'float w(float x,float sx,float ln){\n'+' x*=5.0;\n'+' float t=ln*0.5+SC;\n'+' float amp=bamp(sx,ln);\n'+' return(sin(x*.25+t)*5.+sin(x*4.5+t*3.)*.2+sin(x+t*3.)*2.3+sin(x*.8+t*1.1)*2.5)*AMP*(0.05+amp*0.95);\n'+'}\n'+'void main(){\n'+' vec2 r=iRes,st=(gl_FragCoord.xy*2.0-r)/r.y;\n'+' float sx=gl_FragCoord.x/r.x;\n'+' float th=.05,sm=28./r.y+.85*length(S(vec2(.01,.2),vec2(2.,.7),abs(st)));\n'+' float cc=0.,n=floor(st.y/.1),y=fract(st.y/.1);\n'+' vec3 clr=vec3(0.);\n'+' for(float i=-5.;i<5.;i++){\n'+' float ln=n-i,f=w(st.x,sx,ln)-y-i;\n'+' cc=mix(cc,0.,S(-.3,abs(st.y),f));\n'+' cc+=S(th+sm,th-sm,abs(f))*(1.-abs(st.y)*.75)+S(5.5-abs(f*.5),0.,f)*.25;\n'+' clr=mix(clr,pal(sin(ln*.15),vec3(.5),vec3(.5),vec3(.27),vec3(0.,.05,.15))*cc,S(-.3,abs(st.y),f));\n'+' }\n'+' fragColor=vec4(clr,1.0);\n'+'}\n';
var prog=gl.createProgram();
gl.attachShader(prog,mksh(gl.VERTEX_SHADER,VS));
gl.attachShader(prog,mksh(gl.FRAGMENT_SHADER,FS));
gl.linkProgram(prog);
if(!gl.getProgramParameter(prog,gl.LINK_STATUS))console.error(gl.getProgramInfoLog(prog));
gl.useProgram(prog);
var vb=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,vb);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);gl.vertexAttribPointer(0,2,gl.FLOAT,false,0,0);
var uT=gl.getUniformLocation(prog,'iTime');
var uR=gl.getUniformLocation(prog,'iRes');
var uH=gl.getUniformLocation(prog,'H');
var uF=gl.getUniformLocation(prog,'F');
var uSC=gl.getUniformLocation(prog,'SC');
var uAMP=gl.getUniformLocation(prog,'AMP');
gl.uniform1i(uH,0);
var NB=16,ph=new Float32Array(NB),sp=new Float32Array(NB),va=new Float32Array(NB);
for(var b=0;b<NB;b++){ph[b]=Math.random()*6.28;sp[b]=0.4+Math.random()*1.2;}
function dummy(){
var t=performance.now()*.001,pkt=new Float32Array(NB);
for(var b=0;b<NB;b++){
va[b]=Math.max(0,Math.min(1,va[b]*.75+(0.5+0.45*Math.sin(ph[b]+t*sp[b]*.3))*.25+(Math.random()-.5)*.1));
pkt[b]=va[b];
}
push(pkt);
}
setInterval(dummy,1000/HZ);
var sc=0.0,t0=performance.now(),pt=t0;
function loop(now){
var dt=Math.min((now-pt)*.001,.05);pt=now;
sc+=SPEED*dt;
gl.useProgram(prog);gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,tex);
gl.uniform1f(uT,(now-t0)*.001);
gl.uniform2f(uR,c.width,c.height);
gl.uniform1f(uF,head);
gl.uniform1f(uSC,sc);
gl.uniform1f(uAMP,AMP);
gl.drawArrays(gl.TRIANGLE_STRIP,0,4);
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script></body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment