Building Preset Solar Systems — Figure-Eight Orbits and Galaxy Collisions
A blank canvas is terrifying
When I first shipped Cosmic Gravity Sandbox, you opened it and got... an empty black screen. You could click to place bodies, sure. But most people didn't know what to do. They'd drop a couple of planets, watch them fly off into the void, and close the tab.
I needed presets — curated starting conditions that show off what the simulator can actually do.
What makes a preset work
A preset is just a function that returns an array of body objects. Each body has a position, a velocity, a mass, a radius, and a type (planet, star, black hole, etc):
function figurEightPreset(centerX, centerY) {
const scale = 150;
const v = 0.45;
return [
{
x: centerX - scale, y: centerY,
vx: 0, vy: v,
mass: 100, radius: 12, type: "star",
},
{
x: centerX + scale, y: centerY,
vx: 0, vy: -v,
mass: 100, radius: 12, type: "star",
},
{
x: centerX, y: centerY,
vx: -v * 2, vy: 0,
mass: 100, radius: 12, type: "star",
},
];
}The critical insight: position and velocity must be paired precisely. You can't just plop three bodies down and hope. Gravity simulations are chaotic — tiny errors in initial conditions get amplified exponentially. So getting a stable orbit means tuning the numbers until the bodies trace a repeating path instead of spiraling off.
The figure-eight three-body problem
This one blew my mind when I first read about it. In 2000, Alain Chenciner and Richard Montgomery proved that three equal-mass bodies can orbit in a figure-eight pattern — all three chasing each other around the same infinity-shaped loop.
The math behind the initial conditions is precise to many decimal places. In my simulator, I don't need that level of accuracy because the simulation is discrete (we step forward in fixed time increments), so the orbit will drift over time anyway. But I needed to get close enough that it looks stable for at least 30-60 seconds before perturbations build up.
I spent a solid afternoon tweaking velocities by hand. The process was: set values, run the sim, watch if the bodies stay on the figure-eight or diverge, adjust by 0.001, repeat. Very scientific.
The magic is that all three bodies have equal mass. If one is even slightly heavier, the symmetry breaks and the orbit collapses within seconds. I also found that the ratio of velocity to separation distance matters more than their absolute values. So I parameterised it by a single scale factor and derived everything else from that.
Galaxy collision: controlled chaos
The galaxy collision preset is my favorite because it's the most visually dramatic. Two clusters of bodies, each orbiting their own center of mass, set on a collision course.
function galaxyCollisionPreset(centerX, centerY) {
const bodies = [];
const clusterSize = 25;
// Cluster A — left side, moving right
const cxA = centerX - 300;
const cyA = centerY;
bodies.push({
x: cxA, y: cyA, vx: 0.3, vy: 0,
mass: 800, radius: 18, type: "star",
});
for (let i = 0; i < clusterSize; i++) {
const angle = (i / clusterSize) * Math.PI * 2;
const dist = 40 + Math.random() * 100;
const orbitalV = Math.sqrt(800 / dist) * 0.4;
bodies.push({
x: cxA + Math.cos(angle) * dist,
y: cyA + Math.sin(angle) * dist,
vx: 0.3 + Math.sin(angle) * orbitalV,
vy: -Math.cos(angle) * orbitalV,
mass: 5 + Math.random() * 10,
radius: 4, type: "planet",
});
}
// Cluster B — right side, moving left (mirror of A)
// ... same structure, opposite velocity
return bodies;
}Each satellite body gets an orbital velocity calculated from sqrt(centralMass / distance) — that's the classic circular orbit speed. I multiply by a fudge factor (0.4) so the orbits aren't perfectly circular; they're slightly elliptical, which looks more natural.
The two clusters drift toward each other at 0.3 units per frame. When they collide, the gravitational interactions go haywire — bodies get flung out, captured by the wrong star, or slingshot into deep space. Every run plays out differently.
Other presets that clicked
- Binary star with planets: Two heavy stars orbiting each other, with lighter planets orbiting the pair. The trick is giving the planets enough velocity to orbit the center of mass of the two stars, not either star individually.
- Slingshot: One massive body in the center, one small body aimed just off-center. It curves around the heavy body and shoots off at high speed. A nice demonstration of gravitational assist.
- Random soup: 50 bodies with random positions and zero velocity. They collapse under their own gravity into a chaotic cluster. Usually one body gobbles up most of the mass (if you have collision merging turned on).
The fun is emergent
What I love about presets is that they're not scripted animations. I'm setting up the dominoes — the physics does the rest. The figure-eight is beautiful because it's genuinely stable (for a while). The galaxy collision is exciting because I don't know exactly how it'll play out.
The best compliment I got was someone messaging me: "I've been watching the figure-eight for five minutes." That's the sweet spot — simple setup, hypnotic result.
Written by Oliver
Indie game developer building 3D web experiences in Godot and Next.js. I write about creative coding, procedural generation, and game feel.