Euler Integration Ruins Orbits. Swapping Two Lines Fixes It.
If you update position using the old velocity, your simulation quietly gains energy every step and orbits spiral outward. Update velocity first, then move using the new velocity, and the error stops accumulating in one direction. Same four lines, same cost, reordered. It's called semi-implicit or symplectic Euler and it is the highest-value two-line change in gamedev physics.
the symptom
You've written a gravity simulator. The maths is right. You've checked it three times, it's just F = Gm₁m₂/r², there's nowhere to hide. You load a planet into a circular orbit and it goes round. Lovely.
Then you leave it running while you make a cup of tea, and when you come back the planet is somewhere near Belgium.
Not flung out dramatically. Just.. further. And a bit further. The orbit is very slowly getting bigger, in a way that's invisible over ten seconds and unmistakable over ten minutes. Nothing crashed and no equation is wrong.
the cause is smaller than you'd like
Here is the naive way to move things forward. Take current velocity, move position by it. Take current acceleration, update velocity.
// Explicit Euler - the intuitive version, and the broken one
b.x += b.vx * dt;
b.y += b.vy * dt;
b.vx += ax * dt;
b.vy += ay * dt;That reads correctly to a human. Where is it going, move it there, then update how fast it's going. Perfectly reasonable sentence.
Here's mine:
// Semi-implicit (symplectic) Euler - velocity first
b.vx += ax * dt;
b.vy += ay * dt;
b.x += b.vx * dt;
b.y += b.vy * dt;That's the entire difference. Velocity is updated before position, so position moves using the velocity the body will have at the end of the step, not the one it had at the start.
I want to be honest that when I first read about this I assumed it was the kind of distinction that mattered to people with physics degrees and not to people making things with glowing circles in them. It is not. It's the difference between orbits that hold indefinitely and orbits that don't.
why the order matters
A tick of simulation is a lie. The body isn't really teleporting in straight-line hops. It's supposed to be following a curve, and we're approximating that curve with tiny straight segments. Every segment is slightly wrong. The only question is whether the wrongness cancels out or piles up.
With explicit Euler, you move the body using a velocity measured before gravity had its say for this step. On an orbit, that consistently places the body slightly further out than it should be. Slightly further out, every single step, always in the same direction. The errors don't cancel. They queue up politely and hand you a spiral.
Semi-implicit Euler moves using the post-gravity velocity, and the error it makes wobbles around the true answer instead of drifting away from it. Energy in the system oscillates slightly but stays bounded. Your orbit breathes a bit. It does not leave.
The proper name for this property is that the method is symplectic: it preserves a certain structure in the maths that happens to correspond to "doesn't invent free energy". You do not need to understand the structure to benefit from it, which is my favourite kind of physics.
what it does not fix
I should be careful not to oversell two lines of code.
Symplectic Euler is still first-order and still approximate. Close encounters (a body whipping past a black hole at speed) will still be inaccurate, because your timestep is too coarse to resolve something that violent. If you need real precision you want Velocity Verlet or a Runge-Kutta method, and if you need actual precision you want an adaptive timestep that shrinks when things get exciting.
And it does nothing about a timestep that's simply too big. In my sandbox, dt is literally the speed slider:
const dt = timeScale;So pushing the speed up to 5× doesn't just make things faster, it makes them less accurate. The straight-line segments get five times longer and the approximation gets correspondingly rougher. That's a slightly uncomfortable design decision that I made on purpose, because for a sandbox, being able to fast-forward is worth more than being right to eight decimal places. But it's a trade, and I'd rather say so than let someone discover it by wondering why fast-forwarding a delicate orbit destroys it.
the actual takeaway
If you're building anything with orbits, springs, or pendulums and it slowly gains or loses energy for no reason you can find: before you rewrite your force calculation for the fourth time, go and look at the order of your integration lines.
It costs nothing. It's the same four operations. It's not a clever optimisation and there's no trade-off, which almost never happens in this line of work.
You can watch it holding up in the gravity sandbox. Load the solar system preset and leave it running. The kinetic energy bar sits between 31 and 36 per cent essentially forever. That flat line is the integrator quietly doing its job.
If you want the rest of the physics, the full JavaScript is here, and the n-body explainer covers what's actually being integrated.
Keep reading
Written by Oliver
I build browser games and simulations on my own, everything here runs in a tab, with no installer and no account. The biggest is Oliver's Racers: procedural circuits in Godot 4, online multiplayer relayed by a Raspberry Pi in my room, and an Android build. Almost nothing here is imported artwork; the cars, trees and grandstands are built out of boxes and cylinders in code at load time.