This is my first time making anything resembling a game (unless you like playing with engineering simulations), so I appreciate it!
I started with a pretty naive implementation where normal/tangential impulses are applied to velocity only, followed by a single position update which integrates velocity at each time step. This probably would've worked better for very small time steps, but at 60Hz it caused all sorts of no-clip issues, balls slowly sinking, balls being pushed through walls by other balls, etc.
Apparently a solution for this is called sequential impulses, where you update velocity/position multiple times each frame to iteratively separate colliding entities, but obviously it hurt performance (I don't think it helped that I was using float64 for everything either). I ended up just adding a step right before integration where any two objects still intersecting will have their normal velocities clamped to 0 (I only did ball-wall intersections for the submission, but ball-ball also ended up working pretty well).
Your game looks so much more polished and like a game, can't believe you had time to squeeze my game into yours :P