The Three Body Problem
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!

So I built this:
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.
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 and masses , 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:
- Gravitational force:
The system we're solving looks like this:
// 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.
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!
// The heart of the simulation: RK4 integrationfunction 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:
Where:
- → slope at start
- → slope at midpoint using
- → slope at midpoint using
- → slope at end using
The React Hooks Magic
The real challenge wasn't the physics – it was making React play nice with 60fps animation without melting your CPU.
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
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 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
Solution | Discovered By | Year | Special Property |
---|---|---|---|
Figure-8 | Chenciner & Montgomery | 2000 | Perfect symmetry, equal masses |
Yin-Yang | Šuvakov & Dmitrašinović | 2013 | Part of 13 new solution families |
Bumblebee | Šuvakov & Dmitrašinović | 2013 | Unique oscillating pattern |
Goggles | Šuvakov & Dmitrašinović | 2013 | Resembles 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 patterns → Mathematically proven periodic solutions
What I Learned (Besides Procrastination)
- Physics simulation is basically game development - same performance challenges, same need for smooth animation
- Numerical methods are everywhere - RK4 shows up in everything from climate models to rocket guidance systems
- Chaos is beautiful - small changes in initial conditions lead to wildly different outcomes
- 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 bodies, we need to calculate 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:
- The original Chenciner-Montgomery paper on the Figure-8 solution
- Belgrade Three-Body Problem database: http://three-body.ipb.ac.rs/
- "Chaos: Making a New Science" by James Gleick
- Numerical Recipes (for more RK4 goodness)
- Wikipedia's Three-body problem article (source of several visualizations used in this post)
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:
// 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?