1# random-points-in-disk
3How many random points does it take before a disk *looks* like a disk?
5[**View the live visualizer**](https://concept-collection.github.io/random-points-in-disk/)
7Draw *N* points uniformly at random from a disk, bin them into a grid of voxels, and
8compare the resulting density map against the exact one. Each voxel's count is
9essentially Poisson with mean μ = points per voxel, so its relative noise is 1/√μ —
10which depends only on how many points land in a voxel, not on the size of the disk or
11the resolution per se. The app plots three panels side by side:
13- **Ideal** — exact density, each voxel shaded by the fraction of it inside the disk
14- **Sampled** — counts from *N* random points, on the same color scale
15- **Noise** — the error in units of its expected standard deviation, (count − ideal)/√ideal
17Sliding *N* and the resolution shows the tradeoff directly: quadrupling the resolution
18quadruples the number of voxels, so it takes 4× the points to hold the same noise level.
19The stats row reports the measured coefficient of variation next to the 1/√μ prediction,
20and how many points a target noise level would require.
22Statistics are computed only over voxels lying *entirely* inside the disk; boundary
23voxels have a smaller expected count and would otherwise inflate the measured spread.
25## Sampling backend
27Binning the points is the entire cost here and it parallelizes perfectly, so when WebGPU
28is available a compute shader draws the points and accumulates the histogram with atomics
29— which lifts the usable range from ~30M points to a billion. Coarse grids would
30serialize on a handful of global counters, so for 32×32 and below each workgroup
31accumulates into a private histogram in workgroup memory and flushes once per bin at the
32end. Random numbers come from a PCG hash seeded per thread; since this demo is *about*
33uniformity, that generator was checked against the 1/√μ prediction before being trusted
34(a hash with visible structure would paint that structure straight into the heatmap).
36There is a plain-JS fallback for browsers without WebGPU, and the badge next to
37"New sample" shows which backend is live. The point count is capped lower on the CPU path.
39## Motivation
41This is the discretization question behind isochromat-based MRI simulation: a voxel's
42signal is a sum over the isochromats that landed in it, so randomly placed isochromats
43inject noise of order 1/√μ on top of the physics being modeled.
45## Running locally
47No build step — it is a single static `index.html`. Open it directly, or serve the
48directory:
50```bash
51python3 -m http.server 8000
52```