Dark Matter — galaxy rotation curves and the evidence for invisible mass
Stars at the edge of a spiral galaxy orbit almost as fast as stars near its centre — something that should be impossible if the visible stars and gas were all the mass there is. The mismatch is the single strongest piece of evidence for dark matter, and it's simple enough to reproduce with a rotation-curve calculator and a Three.js halo.
1. What is a rotation curve?
A galaxy rotation curve is a plot of the orbital speed of stars and gas clouds against their distance from the galactic centre. Astronomers measure it using the Doppler shift of the 21 cm hydrogen line: gas moving toward us is blue-shifted, gas moving away is red-shifted, and the shift's magnitude gives the line-of-sight velocity at each radius.
If the only mass in a galaxy were the stars, gas and dust we can photograph, the rotation curve should fall off the same way planets in the Solar System do: fast near the centre, slower further out. That is not what is observed.
2. The Newtonian expectation
For a test mass orbiting a spherically symmetric distribution of
mass M(r) enclosed within radius r,
Newtonian gravity predicts a circular orbital speed of:
Beyond the edge of the visible disk, M(r) stops
growing — almost all the light-emitting matter is inside a fairly
well-defined radius. So M(r) becomes roughly constant,
and the formula predicts:
This is exactly how the outer planets of the Solar System behave: Neptune orbits far slower than Mercury, because almost all the Solar System's mass (the Sun) is concentrated at the centre. Applying the same logic to a galaxy, the rotation curve should fall past the edge of the visible disk.
3. Vera Rubin and the flat curve
In the 1970s, astronomer Vera Rubin, working with Kent Ford, measured the rotation curves of dozens of spiral galaxies using a sensitive spectrograph. Instead of the expected Keplerian decline, she found that rotation curves stayed flat — sometimes even rising slightly — far beyond the edge of the visible disk.
- Stars and gas at large radii were moving much faster than the visible mass could explain gravitationally.
- The effect was seen in essentially every spiral galaxy studied, not a handful of outliers.
-
The only way to explain a flat curve is if
M(r)keeps growing with radius, well past the point where the visible light fades out — meaning there is a vast reservoir of unseen mass in an extended halo.
Rubin's work, building on earlier hints from Fritz Zwicky's 1933 study of the Coma galaxy cluster, turned dark matter from a speculative footnote into one of the central problems of modern astrophysics. Independent evidence — gravitational lensing, galaxy cluster dynamics, and the cosmic microwave background — has since converged on the same conclusion.
4. The mass-velocity relationship
Rearranging the orbital speed formula lets us go the other way:
given an observed flat velocity v, work out how the
enclosed mass must grow with radius.
If v(r) = v₀ = constant (flat curve)
then M(r) ∝ r ← mass grows linearly with radius, not bounded
A mass that grows linearly with radius, with the density falling
off as ρ(r) ∝ 1/r², describes an
isothermal sphere — a simple first model of a dark
matter halo. It reproduces flat rotation curves almost by
construction, which is exactly why it became the starting point for
more detailed halo models.
// Given an assumed density profile rho(r), integrate to get enclosed mass
function enclosedMass(r, densityFn, steps = 200) {
let M = 0;
const dr = r / steps;
for (let i = 0; i < steps; i++) {
const ri = (i + 0.5) * dr;
M += 4 * Math.PI * ri * ri * densityFn(ri) * dr;
}
return M;
}
function orbitalVelocity(r, densityFn, G = 6.674e-11) {
const M = enclosedMass(r, densityFn);
return Math.sqrt(G * M / r);
}
5. The NFW halo profile
N-body cosmological simulations of structure formation (Navarro, Frenk & White, 1996) found that cold dark matter halos settle into a remarkably universal density shape, now called the NFW profile:
ρ₀ — characteristic density
rₛ — scale radius (where the slope transitions)
Near the centre (r ≪ rₛ) the density diverges as 1/r
— a steep "cuspy" core that is still debated versus flatter
"cored" profiles suggested by some dwarf galaxy observations
(the core–cusp problem). Far out (r ≫ rₛ) the
density falls as 1/r³, steeper than the isothermal
sphere, which is why real rotation curves gently decline at very
large radii instead of staying perfectly flat forever.
| Component | Mass share | Extent | Rotation-curve role |
|---|---|---|---|
| Stars + gas (baryons) | ~10–15% | Visible disk, ~50k ly | Dominates inner rise |
| Dark matter halo | ~85–90% | Extends to ~300k ly+ | Keeps the curve flat |
6. The alternative: MOND
Modified Newtonian Dynamics (MOND), proposed by
Mordehai Milgrom in 1983, takes a different route: instead of
adding unseen mass, it modifies the law of gravity itself at very
low accelerations (below roughly a₀ ≈ 1.2 × 10⁻¹⁰ m/s²).
In that regime, MOND replaces F = ma with a modified
relation that naturally produces flat rotation curves without any
dark matter.
MOND fits individual galaxy rotation curves impressively well with very few free parameters, but it struggles to explain cluster-scale gravitational lensing and the detailed structure of the cosmic microwave background, both of which fit a cold dark matter model cleanly. Most cosmologists treat dark matter as the leading explanation, with MOND remaining an active but minority research program.
7. Simulating a halo in Three.js
The dark matter simulation on this site renders a luminous stellar disk (visible, bright, InstancedMesh — the same technique used for the spiral-arms simulation) surrounded by a much larger, mostly invisible halo of "dark" particles following an NFW-like radial distribution. A live rotation-curve graph is drawn alongside, comparing the "stars-only" Keplerian prediction against the flat curve produced once the halo's gravity is included.
// Sample halo particle radii following an NFW-like profile via inverse CDF sampling
function sampleNFWRadius(rs, rMax) {
// Rejection sampling: draw r uniformly, accept with probability proportional to r^2 * rho(r)
while (true) {
const r = Math.random() * rMax;
const x = r / rs;
const weight = (r * r) / (x * Math.pow(1 + x, 2));
const wMax = rs * rs * 0.25; // rough normalising bound
if (Math.random() * wMax < weight) return r;
}
}
// Halo particles: faint, additive-blended, mostly transparent
const haloMat = new THREE.PointsMaterial({
size: 0.6,
color: 0x6a5acd,
transparent: true,
opacity: 0.05,
blending: THREE.AdditiveBlending,
depthWrite: false,
});
The rotation curve overlay is drawn on a 2D canvas overlay (or an
HTML <canvas> chart library) rather than in the
3D scene — mixing a precise data plot with a WebGL viewport keeps
both readable, instead of forcing numeric labels into 3D space.
// Two curves: stars-only Keplerian decline vs stars+halo flat curve
function drawRotationCurve(ctx, starsMass, haloMass, rMaxDraw) {
ctx.beginPath();
for (let r = 1; r < rMaxDraw; r++) {
const vStarsOnly = orbitalVelocity(r, starsMass);
// plot vStarsOnly(r) — dashed line, falls off past disk edge
}
ctx.beginPath();
for (let r = 1; r < rMaxDraw; r++) {
const vTotal = orbitalVelocity(r, (rr) => starsMass(rr) + haloMass(rr));
// plot vTotal(r) — solid line, stays flat
}
}
8. Extensions and improvements
- Gravitational lensing overlay: render background "galaxies" as a grid, and bend the grid lines around the halo using a simple deflection-angle approximation — visually ties rotation curves to the independent lensing evidence.
- Bullet Cluster mode: show two colliding galaxy clusters where the hot gas (X-ray, tracked by collision) and the dark matter (traced by lensing) separate — one of the most direct pieces of evidence that dark matter is not just "missing baryons".
- Cored vs cuspy toggle: let users switch between an NFW cusp and a flatter Burkert/pseudo-isothermal core profile, and watch the inner rotation curve change shape.
-
Live parameter sliders: expose
rsandρ₀as sliders so users can fit the simulated curve to a target shape by hand, building intuition for how halo parameters map to observables.
🌑 Dark Matter
The live simulation renders a stellar disk plus an invisible NFW-like halo, with a real-time rotation-curve graph comparing stars-only vs stars+halo predictions.