Physics · Electromagnetism · advanced
Charged Particle Motion
B bends, E pushes, together they drift
The Lorentz force curls a charge around magnetic field lines and crossed E and B make it drift sideways. Integrate it with Boris, not Euler.
The orange charge leaves a cyan trail and the yellow stub is its velocity; faint yellow arrows show E (up) and grey dots show B coming out of the screen. Change E, B and speed, and switch the integrator to explicit Euler to watch the orbit spiral outward.
What it is
A moving charge in a magnetic field feels a force q·v × B that is always perpendicular to its velocity. It changes the direction of motion but never the speed, so in a uniform field the particle circles at the Larmor radius r = mv⊥/(|q|B) with a period that does not depend on speed.
Add an electric field perpendicular to B and the circle becomes a cycloid that drifts sideways at E/B in the direction of E × B, the same for positive and negative charges. That drift is why plasmas move across magnetic fields and why the particle in the visual walks to the right instead of falling along E.
Numerically this is a great integrator test. Explicit Euler spirals outward because each step adds a little speed; RK4 is very accurate but slowly loses energy; the Boris push splits the electric kick in two and applies the magnetic part as an exact rotation, so speed is conserved to round-off at any step size. Run it at a fixed timestep so the orbit does not depend on frame rate.
Key formulas
- Lorentz force
- Larmor radius and cyclotron frequency
- E × B drift
Independent of charge sign and mass.
- Boris rotation
v⁻ and the final velocity each get half an electric kick qEΔt/(2m).
Rules of thumb
- Keep
ω_c·Δtbelow ~0.1 for a smooth trail (≥ 60 steps per gyration); Boris stays stable up to ω_c·Δt ≈ 2 but the phase drifts. - With q/m = 1 and B = 1.4 the period is 2π/1.4 ≈ 4.5 s; speed the sim up 2× for readable motion.
- Start the particle at the guiding centre offset
(v − E/B)/Bso the cycloid stays centred on screen. - Pick E perpendicular to B to see pure drift; any E component along B accelerates the particle without limit.
- Need energy conservation over minutes of play (orbits, magnets, tractor beams)? Use Boris or another symplectic method, not RK4.
Implementation
type P = { x: number; y: number; z: number; vx: number; vy: number; vz: number }
type V3 = readonly [number, number, number]
export function boris(p: P, E: V3, B: V3, qm: number, dt: number) {
const h = 0.5 * qm * dt
let vx = p.vx + h * E[0], vy = p.vy + h * E[1], vz = p.vz + h * E[2]
const tx = h * B[0], ty = h * B[1], tz = h * B[2]
const f = 2 / (1 + tx * tx + ty * ty + tz * tz)
const px = vx + (vy * tz - vz * ty)
const py = vy + (vz * tx - vx * tz)
const pz = vz + (vx * ty - vy * tx)
vx += f * (py * tz - pz * ty)
vy += f * (pz * tx - px * tz)
vz += f * (px * ty - py * tx)
p.vx = vx + h * E[0]; p.vy = vy + h * E[1]; p.vz = vz + h * E[2]
p.x += p.vx * dt; p.y += p.vy * dt; p.z += p.vz * dt
}Common mistakes
- Integrating v × B with explicit Euler: the orbit spirals outward and the particle gains energy from nothing.
- Assuming the particle drifts along E. In crossed fields it drifts along E × B, perpendicular to both.
- Getting the cross-product order wrong (B × v), which reverses the direction of rotation.
- Stepping with the render delta: the gyration radius then depends on frame rate.
- Allocating a new Vector3 per step for v × B inside the render loop.
Prompt
Implement charged-particle motion in TypeScript for a Three.js scene. Write three allocation-free steppers that mutate {x,y,z,vx,vy,vz}: explicit Euler, classic RK4 (module-level scratch Float64Array) and the Boris push, each taking uniform E and B tuples, q/m and dt. Drive them from a 120 Hz fixed-step accumulator, keep a 240-point trail in a Float32Array ring written into an existing line geometry, and restart the particle when it leaves a ±5 × ±3.4 box. Expose larmorRadius(v, B, qm) and exbDrift(E, B). Tests: Boris keeps speed within 1e-12 over 20,000 steps in pure B; RK4 orbit radius matches v/(qm·B) to 1e-3; Euler speed grows; the mean x-velocity over 20 whole periods with E = 0.3ŷ, B = 1.5ẑ equals 0.2.Related
Further reading
Updated 2026-11-01