Show code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Quicksort Visualizer</title>
<style>
html,body{margin:0;height:100%;background:#0b0f1a;color:#e6ecff;
font:14px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow:hidden}
#wrap{position:fixed;inset:0}
canvas{display:block;width:100%;height:100%}
#hud{position:fixed;left:18px;top:14px;display:flex;gap:18px;align-items:baseline;
pointer-events:none;text-shadow:0 2px 8px #000}
#hud b{font-size:22px;font-weight:600;color:#fff}
.k{opacity:.55;letter-spacing:.08em;text-transform:uppercase;font-size:11px}
#leg{position:fixed;left:18px;bottom:14px;display:flex;gap:16px;font-size:11px;
pointer-events:none;opacity:.8}
.leg i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:6px}
</style>
</head>
<body>
<div id="wrap"><canvas id="c"></canvas></div>
<div id="hud">
<div><span class="k">swaps</span> <b id="sw">0</b></div>
<div><span class="k">range</span> <b id="rg">-</b></div>
<div><span class="k">pass</span> <b id="ps">1</b></div>
</div>
<div id="leg">
<span class="leg"><i style="background:#3b4463"></i>idle</span>
<span class="leg"><i style="background:#3d8bfd"></i>partition</span>
<span class="leg"><i style="background:#ffd166"></i>scan</span>
<span class="leg"><i style="background:#ff3d71"></i>pivot</span>
</div>
<script>
var c=document.getElementById('c'),x=c.getContext('2d'),W=0,H=0,D=1;
function fit(){D=window.devicePixelRatio||1;W=c.clientWidth;H=c.clientHeight;
c.width=W*D|0;c.height=H*D|0;x.setTransform(D,0,0,D,0,0);}
addEventListener('resize',fit);fit();
var N=80,a=[],st=[],cur=null,swaps=0,fl=[],pass=1;
function reset(){a=[];for(var k=0;k<N;k++)a.push(Math.random()*.9+.06);
st=[[0,N-1]];cur=null;swaps=0;fl=[];}
reset();
function sw(i,j){if(i===j)return;var t=a[i];a[i]=a[j];a[j]=t;swaps++;
fl.push([i,1],[j,1]);}
function pick(){while(!cur){if(!st.length)return false;var r=st.pop();
if(r[0]>=r[1])continue;cur={lo:r[0],hi:r[1],p:a[r[1]],i:r[0],j:r[0]};}return true;}
function step(){if(!pick()){pass++;reset();return;}
var s=cur;
if(s.j<s.hi){if(a[s.j]<s.p)sw(s.i++,s.j);s.j++;}
else{sw(s.i,s.hi);st.push([s.i+1,s.hi],[s.lo,s.i-1]);cur=null;}}
function rr(px,py,pw,ph,r){x.beginPath();
r=Math.min(r,pw/2,ph/2);
x.moveTo(px+r,py);x.lineTo(px+pw-r,py);x.quadraticCurveTo(px+pw,py,px+pw,py+r);
x.lineTo(px+pw,py+ph);x.lineTo(px,py+ph);x.lineTo(px,py+r);
x.quadraticCurveTo(px,py,px+r,py);x.closePath();x.fill();}
function draw(){
var g=x.createLinearGradient(0,0,0,H);
g.addColorStop(0,'#0d1220');g.addColorStop(1,'#070a12');
x.fillStyle=g;x.fillRect(0,0,W,H);
var pad=Math.min(60,W*.05),top=90,bot=H-58;
var aw=W-pad*2,bw=aw/N,gap=Math.min(2.5,bw*.22),iw=Math.max(1,bw-gap);
var hh=bot-top;
x.fillStyle='rgba(255,255,255,.06)';x.fillRect(pad,bot+1,aw,1);
var hl={},i;
for(i=0;i<fl.length;i++)hl[fl[i][0]]=Math.max(hl[fl[i][0]]||0,fl[i][1]);
var lo=cur?cur.lo:-1,hi=cur?cur.hi:-2;
if(cur){x.fillStyle='rgba(61,139,253,.09)';
x.fillRect(pad+lo*bw-gap/2,top-10,(hi-lo+1)*bw,hh+10);}
for(i=0;i<N;i++){
var h=Math.max(2,a[i]*hh),px=pad+i*bw+gap/2,py=bot-h,col;
if(cur&&i===hi)col='#ff3d71';
else if(cur&&i===cur.j)col='#ffd166';
else if(cur&&i===cur.i)col='#8affc1';
else if(i>=lo&&i<=hi)col='#3d8bfd';
else col='#3b4463';
x.fillStyle=col;rr(px,py,iw,h,2);
var f=hl[i]||0;
if(f>0){x.globalAlpha=f*.85;x.fillStyle='#ffffff';rr(px,py,iw,h,2);
x.globalAlpha=1;}
if(col==='#ff3d71'||col==='#ffd166'){x.globalAlpha=.35;x.fillStyle=col;
rr(px-1.5,py-3,iw+3,h+3,3);x.globalAlpha=1;}
}
if(cur){var pyy=bot-Math.max(2,cur.p*hh);
x.strokeStyle='rgba(255,61,113,.4)';x.setLineDash([4,6]);x.lineWidth=1;
x.beginPath();x.moveTo(pad,pyy);x.lineTo(pad+aw,pyy);x.stroke();
x.setLineDash([]);}
for(i=fl.length-1;i>=0;i--){fl[i][1]-=.09;if(fl[i][1]<=0)fl.splice(i,1);}
document.getElementById('sw').textContent=swaps;
document.getElementById('rg').textContent=cur?cur.lo+'-'+cur.hi:'done';
document.getElementById('ps').textContent=pass;
}
function frame(){for(var k=0;k<3;k++)step();draw();requestAnimationFrame(frame);}
requestAnimationFrame(frame);
</script>
</body>
</html>