By yielding on every iteration you're restricting your simulation to at most 60 steps per second, because Observable uses requestAnimationFrame() to produce new values from a generator cell.
I would instead suggest to only yield every nth frame. E.g., this would yield every 100th frame:
let n = 0;
while(true) {
// ...
if(++n >= 100) yield (n=0, context.canvas);
}
Small correction of my earlier comment (for posterity):
"I would instead suggest to only yield every nth iteration. E.g., this would yield every 100th iteration:"