I added a full check of the set of placed spheres for each newly chosen random point and it worked!
Note how the number of collision checks sharply rises when the screen becomes crowded. This must be capped to avoid an infinite loop (when there are no more spaces left). The last space can take 26 times as long to find as the next to last space so beware. That’s approx. 120 vs. 4000 iterations! I picked a cap of 150.
Generally speaking, this is not a good algorithm because of it’s unpredictable, ballooning search times near the end. To completely fill a space, you’re better off pre-calculating a grid of non-overlapping rectangles and putting the spheres in them with some small center offsets for the appearance of randomness. Only sheer programmer’s OCD made me keep at this.