Skip to content

Numerical Integration

Open the editor to try integration methods live.

Eyedially runs at a variable frame rate. Always step with dt so motion stays consistent.

Euler (default)

javascript
// a = F / m  (or constant g)
state.vx += ax * dt;
state.vy += ay * dt;
state.x += state.vx * dt;
state.y += state.vy * dt;

Simple and fine for demos. Error grows with large dt or stiff springs.

TIP

dt is clamped to 0.05. After a long pause, you get one capped step — not a multi-second jump.

Semi-implicit Euler

Update velocity first, then position with the new velocity (what most sketches already do):

javascript
state.v += a * dt;
state.x += state.v * dt;  // uses updated v

More stable than classic Euler for orbits and springs at the same step size.

Verlet (optional)

Useful when you care about position history more than explicit velocity:

javascript
if (!state.init) {
  state.x = w / 2;
  state.prevX = state.x - 80 * dt; // imply initial velocity
  state.init = true;
}

const ax = /* acceleration from forces */;
const nextX = 2 * state.x - state.prevX + ax * dt * dt;
state.prevX = state.x;
state.x = nextX;

Forces → acceleration

javascript
const Fx = /* sum of forces */;
const Fy = /* ... */;
const ax = Fx / mass;
const ay = Fy / mass;

Examples:

ForceTypical code
Gravityay = 200 (px/s²)
SpringF = -k * (x - rest)
DragF = -c * v
Gravity (N-body)F = G * m1 * m2 / r² toward other body

Stability tips

  1. Prefer semi-implicit Euler for springs and orbits.
  2. Soften gravity singularities: skip or clamp when dist < 1.
  3. Cap speeds if explosions blow up: v = Math.min(v, vmax).
  4. For stiff springs (large k), lower k or accept more damping — you cannot substep the engine today.

Frame independence checklist

javascript
// BAD — speed depends on FPS
state.x += 2;

// GOOD
state.x += 120 * dt;  // 120 px/s

Same for angular speed: angle += omega * dt, or use time * omega if you want phase locked to time.