screenager.dev

The Three Body Problem

published: 10min read
author:
Tejas MahajanTejas Mahajan@the_screenager
updated:

I was watching Netflix's "3 Body Problem" series when I should've been writing my summer internship report (due this week, btw). Instead, I fell down a rabbit hole about the actual three-body problem. You know, that thing where three objects in space are gravitationally pulling on each other and the math just... breaks. No closed-form solution exists. The universe said "nah, figure it out yourself."

NOTE

The three-body problem is one of the oldest unsolved problems in classical mechanics. Even Newton struggled with it back in the 1600s!

Three-body problem

So I built this:

Figure-8

Wait, what am I looking at?

Those are three bodies (think planets, stars, whatever) pulling on each other with gravity. The colored trails show their paths through space. Each preset shows a different solution to the three-body problem that smart people discovered over the years.

That figure-8 one? That's the famous solution discovered by Alain Chenciner and Richard Montgomery in 2000. Three equal masses chasing each other in a perfect figure-8 for eternity. Chef's kiss for mathematical beauty.

WARNING

Full disclosure: Except for the figure-8 solution, the other presets might not be perfectly accurate. This could be due to calculation precision errors or imprecise initial positions. But hey, it still looks cool!

The Problem That Broke Newton's Brain

Here's the thing that blew my mind: Newton solved the two-body problem (like Earth orbiting the Sun) back in the 1600s. Clean, elegant, predictable. But add just ONE more object? Chaos. Literal chaos.

Gravitational vs elastic three-body systems

Comparison of gravitational vs elastic three-body systems. The left shows chaotic gravitational interactions, while the right shows predictable elastic collisions. Note how the gravitational system becomes unpredictable while the elastic one remains orderly. Animation by Jacopo Bertolotti, CC0, via Wikimedia Commons

The three-body problem is what mathematicians call "non-integrable" - fancy speak for "your calculator can't solve this exactly, deal with it."

WARNING

Small changes in initial conditions can lead to wildly different outcomes. This is the essence of chaos theory!

For three bodies with positions r1,r2,r3\vec{r}_1, \vec{r}_2, \vec{r}_3 and masses m1,m2,m3m_1, m_2, m_3, we're solving Newton's law of universal gravitation for each body simultaneously. The math gets complex fast because each body influences every other body.

Some key physics equations:

  • Einstein's mass-energy: E=mc2E = mc^2
  • Gravitational force: F=Gm1m2/r2F = Gm_1m_2/r^2

The system we're solving looks like this:

r¨1=Gm2r1r2r1r23Gm3r1r3r1r33\ddot{\vec{r}}_1 = -G m_2 \frac{\vec{r}_1 - \vec{r}_2}{|\vec{r}_1 - \vec{r}_2|^3} - G m_3 \frac{\vec{r}_1 - \vec{r}_3}{|\vec{r}_1 - \vec{r}_3|^3} r¨2=Gm3r2r3r2r33Gm1r2r1r2r13\ddot{\vec{r}}_2 = -G m_3 \frac{\vec{r}_2 - \vec{r}_3}{|\vec{r}_2 - \vec{r}_3|^3} - G m_1 \frac{\vec{r}_2 - \vec{r}_1}{|\vec{r}_2 - \vec{r}_1|^3} r¨3=Gm1r3r1r3r13Gm2r3r2r3r23\ddot{\vec{r}}_3 = -G m_1 \frac{\vec{r}_3 - \vec{r}_1}{|\vec{r}_3 - \vec{r}_1|^3} - G m_2 \frac{\vec{r}_3 - \vec{r}_2}{|\vec{r}_3 - \vec{r}_2|^3}
three-body-system.ts
// This is what we're trying to solve numerically:
// For 3 bodies with positions r₁, r₂, r₃ and masses m₁, m₂, m₃
// Each body's acceleration from gravitational forces:
r̈₁ = -G*m*(r-r)/|r-r|³ - G*m*(r-r)/|r-r|³
r̈₂ = -G*m*(r-r)/|r-r|³ - G*m*(r-r)/|r-r|³
r̈₃ = -G*m*(r-r)/|r-r|³ - G*m*(r-r)/|r-r|³
// No closed-form solution exists. Period.
// That's why we need numerical methods like RK4!

Translation: Each body's acceleration depends on where the other two bodies are RIGHT NOW. But where they are depends on where they were, which depends on... you get the idea. It's recursive madness.

Restricted three-body problem energy analysis

Energy potential analysis of the restricted three-body problem showing how gravitational and centrifugal forces combine to create the complex potential landscape. The Lagrange points (marked in blue) occur where the gradient is zero, indicating equilibrium positions. This is why spacecraft can "park" at L1 and L2 points! Diagram by Invent2HelpAll, CC0, via Wikimedia Commons

Enter RK4: The Numerical Wizard

Since we can't solve it exactly, we approximate. And the gold standard for this kind of differential equation is the Runge-Kutta 4th order method (RK4).

Think of it like this: instead of trying to predict where a drunk person will be in an hour, you follow them step by step, checking their direction every few seconds.

TIP

RK4 is the gold standard for numerical integration. It's used in everything from climate models to rocket guidance systems!

rk4-integration.ts
// The heart of the simulation: RK4 integration
function rk4Step(y: number[], dt: number, temp: RK4Temp): void {
const n = y.length;
if (n === 0) return;
const { k1, k2, k3, k4, y_temp } = temp;
// k1: slope at beginning of interval
getSystemDerivatives(y, k1);
// k2: slope at midpoint using k1
for (let i = 0; i < n; i++) y_temp[i] = y[i] + 0.5 * dt * k1[i];
getSystemDerivatives(y_temp, k2);
// k3: slope at midpoint using k2
for (let i = 0; i < n; i++) y_temp[i] = y[i] + 0.5 * dt * k2[i];
getSystemDerivatives(y_temp, k3);
// k4: slope at end using k3
for (let i = 0; i < n; i++) y_temp[i] = y[i] + dt * k3[i];
getSystemDerivatives(y_temp, k4);
// Weighted average: y_next = y + (dt/6)(k1 + 2k2 + 2k3 + k4)
for (let i = 0; i < n; i++) {
y[i] += (dt / 6) * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]);
}
}

RK4 is basically asking "what if I go forward a little, check the slope, go forward from the middle, check again, then combine all these slopes intelligently?" It's like GPS recalculating your route in real-time, but for physics.

The mathematical magic of RK4 works like this:

yn+1=yn+h6(k1+2k2+2k3+k4)y_{n+1} = y_n + \frac{h}{6}(k_1 + 2k_2 + 2k_3 + k_4)

Where:

  • k1=f(tn,yn)k_1 = f(t_n, y_n) → slope at start
  • k2=f(tn+h/2,yn+hk1/2)k_2 = f(t_n + h/2, y_n + hk_1/2) → slope at midpoint using k1k_1
  • k3=f(tn+h/2,yn+hk2/2)k_3 = f(t_n + h/2, y_n + hk_2/2) → slope at midpoint using k2k_2
  • k4=f(tn+h,yn+hk3)k_4 = f(t_n + h, y_n + hk_3) → slope at end using k3k_3

The React Hooks Magic

The real challenge wasn't the physics – it was making React play nice with 60fps animation without melting your CPU.

react-animation-hooks.ts
const simStateRef = useRef<{
y: number[], // [x1,y1,vx1,vy1, x2,y2,vx2,vy2, x3,y3,vx3,vy3]
trails: TrailPoint[][], // Pretty colored trails for each body
rk4_temp: RK4Temp, // Pre-allocated arrays for RK4 (no GC thrashing!)
colors: string[] // Body colors
}>({
y: [], trails: [], rk4_temp: {}, colors: []
});
const animate = useCallback(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const { y, trails, rk4_temp, colors } = simStateRef.current;
// Run multiple physics sub-steps per frame for stability
for (let i = 0; i < PHYSICS_CONFIG.subSteps; i++) {
rk4Step(y, PHYSICS_CONFIG.timeStep, rk4_temp);
}
// Draw everything
drawBodiesAndTrails(canvas, y, trails, colors);
// Keep the loop alive
animationFrameRef.current = requestAnimationFrame(animate);
}, [/* dependencies */]);

Performance Optimization Checklist

  • Pre-allocated arrays (no GC pressure)
  • Multiple physics sub-steps per frame
  • Trail point skipping for smooth rendering
  • useRef for animation state (avoid re-renders)
  • Web Workers for heavy calculations
  • OffscreenCanvas for background rendering

The Sandbox Mode Surprise

The coolest part? Click on "Sandbox" mode and start placing bodies by clicking. Watch them interact in real-time.

I added a 10-body limit because beyond that, your browser starts crying. But honestly, even 3-4 bodies create fascinating emergent behavior. Sometimes they'll dance around each other for a while, then one gets ejected into space. Classic three-body chaos.

🤓 Click to see the sandbox click handler code
sandbox-interaction.ts
const handleCanvasClick = (event: React.MouseEvent<HTMLCanvasElement>) => {
if (isSandbox) {
const { x, y } = fromCanvasCoords(canvasX, canvasY, canvas);
// Add new body at click position with zero initial velocity
simStateRef.current.y.push(x, y, 0, 0);
simStateRef.current.trails.push([]);
simStateRef.current.colors.push(SANDBOX_COLORS[numBodies % SANDBOX_COLORS.length]);
// Update RK4 temp arrays for new system size
const vec_len = simStateRef.current.y.length;
simStateRef.current.rk4_temp = {
k1: new Array(vec_len).fill(0),
k2: new Array(vec_len).fill(0),
k3: new Array(vec_len).fill(0),
k4: new Array(vec_len).fill(0),
y_temp: new Array(vec_len).fill(0),
};
}
};

The Real Data (For the Nerds)

All those presets? They're not random. They're actual solutions from the Belgrade Three-Body Problem Database – real research from physicists who spent years finding stable periodic orbits.

Twenty periodic three-body solutions

Twenty different examples of periodic solutions to the three-body problem, showing the incredible variety of stable orbital patterns that exist. From figure-8s to spirals to complex braided orbits - each represents a carefully calculated set of initial conditions that produce repeating motion. These aren't random patterns; they're mathematical poetry in motion! Animation by Perosello, CC BY-SA 4.0, via Wikimedia Commons

SolutionDiscovered ByYearSpecial Property
Figure-8Chenciner & Montgomery2000Perfect symmetry, equal masses
Yin-YangŠuvakov & Dmitrašinović2013Part of 13 new solution families
BumblebeeŠuvakov & Dmitrašinović2013Unique oscillating pattern
GogglesŠuvakov & Dmitrašinović2013Resembles eyeglasses shape

IMPORTANT

These aren't just pretty patterns - they represent actual possible orbital configurations that could exist in space (if you could somehow set up the initial conditions perfectly).

Random orbital patternsMathematically proven periodic solutions

What I Learned (Besides Procrastination)

  1. Physics simulation is basically game development - same performance challenges, same need for smooth animation
  2. Numerical methods are everywhere - RK4 shows up in everything from climate models to rocket guidance systems
  3. Chaos is beautiful - small changes in initial conditions lead to wildly different outcomes
  4. React refs > useState for animation - avoid re-render hell when doing 60fps updates

TIP

Pro tip: Always use useRef for values that change frequently but don't need to trigger re-renders. Your animation performance will thank you!

Try This: Your Own Experiments

Want to mess around? Here's what to try:

  • Sandbox mode: Place 3 bodies in a triangle, watch the chaos.
  • Fullscreen mode: Hit the expand button, place bodies across your entire screen
  • Study the presets: Notice how some solutions are stable, others slowly drift apart
  • Time the chaos: See how long different configurations stay stable

The fact that we can simulate this level of physics complexity in a web browser, in real-time, using JavaScript... honestly, that's pretty wild.

Consider the computational complexity: for nn bodies, we need to calculate O(n2)O(n^2) gravitational interactions per time step. Our 10-body limit means roughly 45 force calculations per frame, at 60 FPS. That's about 2,700 gravitational force computations per second!


Further Reading & References

If this got you interested in the intersection of physics and programming, check out:

Image Credits: This post includes educational visualizations from Wikipedia/Wikimedia Commons under Creative Commons licenses. All images are properly attributed with their respective authors and licensing information.

Want to see the full code? Check out the ThreeBodySimulation component on GitHub.

Build Your Own

Or better yet, build your own version and add features like:

feature-ideas.ts
// Cool features to implement:
const features = [
'Variable mass bodies',
'Different force laws (inverse cube, spring forces)',
'4th-body mode (if you hate your CPU)',
'Save/load initial conditions',
'Collision detection',
'Energy conservation tracking',
'Poincaré section plots'
];

Hit me up in the comments if you build something cool. I'd love to see what chaotic masterpieces you create.

P.S. - Still have that internship report to finish. But hey, at least I learned that the universe is fundamentally unpredictable. That's gotta count for something on the experience, right? ...Right?