Merge Sort Visualisation JS
There is nothing wrong with your code when changing the data size to a larger number, except that the draw() method doesn't adjust the width of the columns by the ratio between the canvas size and the number of columns to be drawn.
You'll have to do some math like:
  let offset = Math.round(canvaswidth / len);
  let rectWidth = Math.round(offset * 0.9);

The rounding is because you want integer values (pixels).


ctx.fillStyle = &quot;#000000&quot;
ctx.fillRect(15 * i, 500 - arr[i], 10, arr[i])
if (seen[i]) {
  ctx.fillStyle = &quot;#00ff00&quot;
  ctx.fillRect(15 * i, 500 - arr[i], 10, arr[i])
}


This seems inefficient as you draw more and more columns twice through the sorting. A better solution would be something like:
ctx.fillStyle = seen[i] ? &quot;#00ff00&quot; : &quot;#000000&quot;;
ctx.fillRect(offset * i, 500 - arr[i], rectWidth, arr[i]);



for (let i = s; i &lt;= e; i++) {
    ctx.fillStyle = &quot;#ffffff&quot;
    ctx.fillRect(15 * i, 500 - arr[i], 10, arr[i])
    ctx.fillStyle = &quot;#0000ff&quot;
    ctx.fillRect(15 * i, 500, 10, arr[i])
    seen[i] = 1
}


You shouldn't &quot;undraw&quot; a column by drawing a white column over it. Instead you could use clearRect with the same dimensions.


let m = parseInt((s + e) / 2)

You can integer divide by two by right shifting by one:
(s + e) &gt;&gt; 1


You should really be careful to end each statement with a ';' (see here)


await merge(s, e)
// await console.log(`merged ${s} to ${e} now draw...`)
await draw(s, e)


You call these with await but they are not defined as async?

Your algorithm seems to works like a merge sort - as I recall it. I think I would encapsulate the parts into a class instead of having the functions in the global scope.

Besides that, I find you graphics very illustrative.