Finding order in a cloud of points.
Clustering 3D Lab
Four clustering methods. One spatial laboratory. A way to see not just where an algorithm lands, but why it gets there.
- TypeScript
- React
- Three.js
- React Three Fiber
- Vite
Public source

The premise
An algorithm can converge and still miss the structure in front of it. This lab puts K-means, K-medoids, DBSCAN, and Gaussian mixtures against the same three-dimensional datasets, including deliberately awkward ones: interlocking moons, concentric shells, and a double helix.
One operation at a time
Assignment and representative updates are separate states. The interface can pause between them, so the relationship between a changed assignment, a moving centroid, and a lower objective becomes inspectable. Gaussian mixtures expose expectation and maximization; DBSCAN performs a density expansion rather than pretending to share the same steps.
INPUT MODEL VIEW
13 datasets → assign / update → 3D observations
seed + settings convergence state hulls + diagnostics
↑ │
└──── step / inspect ───┘The model advances; the scene explains each step.
- 01 / ready
Dataset + initialization
makePoints(seed, dataset)
initializeCentroids(strategy)
- centroid / mixture methods → 2. Membership step
- density method → 5. DBSCAN
- 02 / assigned
Membership step
Nearest representative
Or Gaussian expectation
- advanceModel → 3. Representative step
- 03 / updated
Representative step
Means / medoids
Or Gaussian maximization
- not yet converged → 2. Membership step
- movement threshold → 4. Movement < 0.001
- model → 6. PointCloud + diagnostics
- 04 / converged
Movement < 0.001
Retain final model
Otherwise assign again
- final model → 6. PointCloud + diagnostics
- 05 / density expansion
DBSCAN
Neighbour radius + min points
Cluster labels / noise
- labels + noise → 6. PointCloud + diagnostics
- 06 / view
PointCloud + diagnostics
Instanced meshes + convex hulls
Inertia / cost / NLL / noise
- 1Dataset + initialization Membership stepcentroid / mixture methods
- 2Membership step Representative stepadvanceModel
- 3Representative step Membership stepnot yet converged
- 4Representative step Movement < 0.001movement threshold
- 5Dataset + initialization DBSCANdensity method
- 6Representative step PointCloud + diagnosticsmodel
- 7Movement < 0.001 PointCloud + diagnosticsfinal model
- 8DBSCAN PointCloud + diagnosticslabels + noise
Read from the implementation
app/KMeansLab.tsx · makePointsinitializeCentroids / advanceModelrunDbscan / expectationStepPointCloud / ClusterShell
A visual layer with a job to do
Instanced meshes render observations. Convex hulls outline the extent of each cluster. Point inspection reveals coordinates and membership, while algorithm-specific diagnostics report inertia, medoid cost, density noise, or negative log-likelihood. The picture and the numbers describe the same model.
Five years, eight familiar points
The original 2021 Python project grouped eight 2D observations and printed its iterations. That exact dataset is still an option in this lab. The newer project adds seeded datasets, initialization choices, automatic playback, and an interface for testing the assumptions behind the result.
The useful limitation
The Gaussian model uses spherical components, and centroid methods do not preserve curved topology. Those constraints are part of the experiment. A neat-looking partition is an invitation to inspect the model, not proof that it found the right answer.