Astrophysics · Space
📅 July 2026 ⏱ ≈ 13 min read 🎯 Intermediate · Last updated: 3 July 2026

Binary Star Systems — two-body orbits, Roche lobes, and simulating them in Three.js

Most stars are not lonely suns like ours — more than half of all stars belong to binary or multiple systems. Two stars locked in mutual orbit obey the same physics as a single planet around a sun, but with a twist: both bodies move, and if they get close enough, one can literally strip material from the other.

1. What is a binary star system?

A binary star system consists of two stars bound together by their mutual gravity, orbiting a common centre of mass (the barycentre). Surveys of nearby stars suggest that roughly 50–85% of solar-type stars have at least one stellar companion, depending on spectral type — massive O and B stars are almost always multiple, while low-mass red dwarfs are more often single. Our own Sun is unusual in being (as far as we know) a solitary star.

Binaries range enormously in scale. Some pairs orbit with periods of hours, nearly touching; others take hundreds of thousands of years to complete one orbit, separated by a light-year or more. The famous star Alpha Centauri is actually a triple system: Alpha Centauri A and B form a close binary with an 80-year period, while the faint red dwarf Proxima Centauri orbits the pair at a distance of roughly 13 000 AU.

Why binaries matter: because both masses can be measured directly from the orbit (via Kepler's third law), binary stars are the primary source of accurate stellar mass measurements. Almost everything we know about the mass-luminosity relation for stars traces back to binary-star orbits.

2. The two-body problem and reduction to one body

Two point masses m₁ and m₂ attract each other with Newtonian gravity. Naively this looks like it needs two separate equations of motion, but a classic trick — reducing to the relative coordinate — turns it into a single one-body problem, exactly like a planet orbiting the Sun.

Relative position: r = r₂ − r₁
Reduced mass: μ = (m₁·m₂) / (m₁ + m₂)

Equation of motion for the relative vector:
d²r/dt² = −G(m₁ + m₂)·r / |r|³

This is identical in form to a single particle of mass μ orbiting a fixed centre with total mass M = m₁ + m₂.

In other words: solve the ordinary Kepler two-body orbit for the separation vector between the stars, using the combined mass M = m₁ + m₂. Then split that relative orbit between the two actual stars in inverse proportion to their masses — the more massive star traces a smaller ellipse closer to the barycentre.

Position of star 1 relative to barycentre:
r₁ = −(m₂ / M) · r

Position of star 2 relative to barycentre:
r₂ = (m₁ / M) · r

3. Kepler's third law for binaries

For an elliptical relative orbit with semi-major axis a (the sum of the two stars' individual semi-major axes, a = a₁ + a₂), the orbital period follows directly from Newton's generalisation of Kepler's third law:

P² = 4π² · a³ / [G·(m₁ + m₂)]

or, in convenient astronomical units:
(years) = a³(AU) / M(solar masses)

This single equation is why binaries are so valuable: if you can measure the orbital period P and the physical separation a (from parallax and angular separation), you immediately get the total mass of the system. Combined with the mass ratio from the centre-of-mass motion, both individual masses fall out.

// Kepler's third law solved for total mass, SI-friendly units
const G = 6.674e-11;           // m^3 kg^-1 s^-2

function totalMassFromOrbit(semiMajorAxisM, periodSeconds) {
  return (4 * Math.PI * Math.PI * Math.pow(semiMajorAxisM, 3))
       / (G * periodSeconds * periodSeconds);
}

// Example: Alpha Centauri A+B, a ≈ 23.5 AU, P ≈ 79.9 years
const AU = 1.496e11;
const YEAR = 3.156e7;
const Msun = 1.989e30;
const M = totalMassFromOrbit(23.5 * AU, 79.9 * YEAR);
console.log(M / Msun);  // ≈ 2.0 solar masses combined

4. Centre of mass and mass ratio

Because both stars orbit the shared barycentre, their individual semi-major axes are inversely proportional to their masses. A heavy primary star barely moves; a light companion swings through a much wider orbit:

m₁·a₁ = m₂·a₂

Mass ratio: q = m₂ / m₁ (usually defined with m₂ ≤ m₁)
a₁ / a₂ = m₂ / m₁ = q

This is exactly how astronomers detect exoplanets and even black holes indirectly — a visible star "wobbling" around an invisible companion's shared centre of mass reveals the companion's existence through the same equations that describe two visible stars orbiting each other. The Doppler radial-velocity method for finding exoplanets is a direct descendant of binary-star orbit analysis.

System Mass ratio q Separation Period Notes
Sirius A/B 0.50 ~20 AU ~50 yr B is a white dwarf remnant
Alpha Centauri A/B 0.92 ~23.5 AU ~80 yr Nearly equal-mass pair
Cygnus X-1 0.55 ~0.2 AU 5.6 days Blue supergiant + black hole
Algol (Beta Persei) 0.22 ~0.06 AU 2.87 days Classic eclipsing / Algol paradox

5. Roche lobes and mass transfer

Real stars are not points — they have finite size and, in a close binary, can even change shape under their companion's gravity. The Roche lobe is the teardrop-shaped equipotential surface around each star inside which material is gravitationally bound to that star. If a star expands (say, as it evolves off the main sequence and becomes a giant) until it fills its Roche lobe, gas can flow through the inner Lagrange point L1 onto the companion — a process called Roche lobe overflow.

Eggleton's widely used approximation gives the effective radius of the Roche lobe (as a fraction of the orbital separation a) purely as a function of mass ratio q = m₁/m₂:

R_L / a ≈ 0.49·q^(2/3) / [0.6·q^(2/3) + ln(1 + q^(1/3))]

Valid for the full range 0 < q < ∞, accurate to about 1%.
// Eggleton (1983) Roche lobe radius approximation
function rocheLobeRadius(q, separation) {
  const q23 = Math.pow(q, 2 / 3);
  const q13 = Math.pow(q, 1 / 3);
  const ratio = (0.49 * q23) / (0.6 * q23 + Math.log(1 + q13));
  return ratio * separation;
}

Mass transfer through Roche lobe overflow drives some of the most spectacular phenomena in astrophysics: novae (thermonuclear explosions on an accreting white dwarf's surface), X-ray binaries (accretion onto a neutron star or black hole, heating infalling gas to millions of kelvin), and the Algol paradox — where the less massive star in the Algol system is, counter-intuitively, the more evolved one, because it used to be the heavier star before it dumped most of its mass onto its companion.

Common misconception: mass transfer doesn't require the stars to touch. Gas only needs to reach the L1 point between the two Roche lobes, where the combined gravitational and centrifugal potential has a saddle point — the material then falls "downhill" onto the companion, often forming an accretion disk first.

6. Classifying binaries: visual, spectroscopic, eclipsing

Astronomers detect and classify binary systems by how they can observe the orbital motion:

7. Simulating an eclipsing light curve

A simplified light curve model treats each star as a uniform disk and computes the overlapping area between the two disks as seen in projection. The combined flux drops whenever one disk overlaps the other:

// Circle-circle overlap area (for simple limb-darkening-free eclipses)
function circleOverlapArea(r1, r2, d) {
  if (d >= r1 + r2) return 0;                 // no overlap
  if (d <= Math.abs(r1 - r2)) {
    const rMin = Math.min(r1, r2);
    return Math.PI * rMin * rMin;             // full eclipse
  }
  const d1 = (d*d - r2*r2 + r1*r1) / (2*d);
  const d2 = d - d1;
  const a1 = r1*r1 * Math.acos(d1 / r1) - d1 * Math.sqrt(r1*r1 - d1*d1);
  const a2 = r2*r2 * Math.acos(d2 / r2) - d2 * Math.sqrt(r2*r2 - d2*d2);
  return a1 + a2;
}

// Combined flux, in units of the two stars' individual luminosities
function combinedFlux(L1, L2, r1, r2, projectedSeparation, primaryInFront) {
  const overlap = circleOverlapArea(r1, r2, projectedSeparation);
  const eclipsedFraction = overlap / (Math.PI * (primaryInFront ? r2 : r1) ** 2);
  const hiddenLum = primaryInFront ? L2 : L1;
  return L1 + L2 - hiddenLum * eclipsedFraction;
}

Two distinct dips appear per orbital cycle: a primary minimum when the fainter, usually cooler star passes in front of (or behind) the brighter one, and a shallower secondary minimum half an orbit later. The relative depth and width of the two dips let astronomers back out both stars' radii and temperatures — this is exactly how the TESS and Kepler space telescopes measure properties of eclipsing binaries (and, with the same technique, transiting exoplanets).

8. Three.js: rendering two orbiting stars

To animate a binary visually, integrate the reduced two-body equation of motion (Section 2) with a simple symplectic integrator — velocity Verlet keeps the orbit stable over many revolutions, unlike naive Euler integration which spirals the orbit outward.

import * as THREE from 'three';

const G = 1.0;          // scene units, not SI
const m1 = 1.6;        // solar masses (primary)
const m2 = 0.9;        // solar masses (companion)
const M  = m1 + m2;

// Relative separation vector state (star2 - star1)
let rel = new THREE.Vector3(6, 0, 0);
let vel = new THREE.Vector3(0, 0, 0.65);  // initial relative velocity

function acceleration(r) {
  const dist = r.length();
  const factor = -G * M / (dist * dist * dist);
  return r.clone().multiplyScalar(factor);
}

function stepVelocityVerlet(dt) {
  const a0 = acceleration(rel);
  rel.add(vel.clone().multiplyScalar(dt).add(
       a0.clone().multiplyScalar(0.5 * dt * dt)));
  const a1 = acceleration(rel);
  vel.add(a0.clone().add(a1).multiplyScalar(0.5 * dt));
}

// Each frame: advance the relative orbit, then split by mass ratio
function animate() {
  requestAnimationFrame(animate);
  stepVelocityVerlet(0.01);

  star1Mesh.position.copy(rel.clone().multiplyScalar(-m2 / M));
  star2Mesh.position.copy(rel.clone().multiplyScalar( m1 / M));

  renderer.render(scene, camera);
}

Trail rendering

A fading orbital trail behind each star makes the ellipse shape immediately visible. Push each frame's position into a fixed-size ring buffer and update a THREE.Line geometry:

const TRAIL_LEN = 400;
const trailPositions = new Float32Array(TRAIL_LEN * 3);
const trailGeo = new THREE.BufferGeometry();
trailGeo.setAttribute('position',
  new THREE.BufferAttribute(trailPositions, 3));
const trail = new THREE.Line(trailGeo,
  new THREE.LineBasicMaterial({ color: 0x60a5fa, transparent: true, opacity: 0.5 }));
scene.add(trail);

let trailIndex = 0;
function pushTrail(pos) {
  trailPositions[trailIndex*3]   = pos.x;
  trailPositions[trailIndex*3+1] = pos.y;
  trailPositions[trailIndex*3+2] = pos.z;
  trailIndex = (trailIndex + 1) % TRAIL_LEN;
  trailGeo.attributes.position.needsUpdate = true;
}
Colour by temperature: give each star a THREE.PointLight tinted by its spectral class (see the colour table in the spiral galaxy article) so the more massive, hotter star visibly outshines a cooler companion — a nice touch for an eclipsing red-dwarf/blue-star pair.

9. Stability, chaos, and circumbinary planets

Two stars alone in an elliptical orbit are perfectly stable forever (in the idealised Newtonian two-body problem — no energy loss, no perturbations). Add a third body — another star or a planet — and the system generally becomes chaotic, as in the classic three-body problem. Planets can still orbit stably around a binary pair if they are either:

Orbits in between these two stable zones are dynamically unstable and get ejected or collide within a few thousand orbits — a direct, testable consequence of the chaotic three-body dynamics that a simple N-body integrator (see the N-body article) can demonstrate by scanning initial planet distances and checking which survive after a long integration.

Numerical gotcha: even the stable Kepler two-body orbit will visibly drift if you integrate it with plain Euler stepping — energy is not conserved, and the orbit spirals outward or inward over hundreds of periods. Always use a symplectic integrator (velocity Verlet or leapfrog) for orbital mechanics simulations, as shown in Section 8.

10. Extensions and improvements

⭐ Binary Star System

The live binary star simulation animates two orbiting stars with real Newtonian gravity, mass-proportional orbits, and trail rendering.

Launch simulation →