Naively picking r = R·random() bunches points near the centre, because the disc's area grows with r. The fix is r = R·√random() — sampling r² uniformly cancels the radial area-weighting. Toggle between the two methods to see the difference.
See also: Uniform random point in an annulus — the same idea applied to a ring.
// Correct: sample r² uniformly
angle = 2π · random()
r = R · sqrt(random())
x = cx + r · cos(angle)
y = cy + r · sin(angle)
function uniformInCircle(cx, cy, R) {
const angle = 2 * Math.PI * Math.random()
const r = R * Math.sqrt(Math.random()) // sqrt is the key
return { x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle) }
}
// Biased version (don't use): r = R * Math.random() bunches points near centre