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 vMore 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:
| Force | Typical code |
|---|---|
| Gravity | ay = 200 (px/s²) |
| Spring | F = -k * (x - rest) |
| Drag | F = -c * v |
| Gravity (N-body) | F = G * m1 * m2 / r² toward other body |
Stability tips
- Prefer semi-implicit Euler for springs and orbits.
- Soften gravity singularities: skip or clamp when
dist < 1. - Cap speeds if explosions blow up:
v = Math.min(v, vmax). - For stiff springs (large
k), lowerkor 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/sSame for angular speed: angle += omega * dt, or use time * omega if you want phase locked to time.