Skip to content

Physics · Thermodynamics · core

Ideal Gas Kinetics

pressure is just particles bouncing off walls

Temperature is average kinetic energy and pressure is momentum delivered to the walls. Bounce point particles in a box and PV = NkT falls out.

View .md
Interactive visual

Particles are coloured by speed from cyan (slow) to orange (fast) inside a translucent box; the right wall is a piston that glows yellow with the measured pressure. Raise temperature or particle count, or narrow the box, and watch the glow and the P = NkT/V readout rise together.

What it is

An ideal gas is a crowd of tiny particles that never interact except by bouncing elastically off the container. Every bounce reverses one velocity component and hands the wall a momentum of 2m|v⊥|. Add up those impulses per second per square metre and you get pressure.

Temperature is the average kinetic energy per particle: ½m⟨v²⟩ = (3/2)kT. Double T and the root-mean-square speed grows by √2, particles hit walls more often and harder, and pressure doubles. Halve the volume and the same particles hit each wall twice as often. That is the whole of PV = NkT, recovered from mechanics.

Velocities in equilibrium follow the Maxwell–Boltzmann distribution: each component is a Gaussian with variance kT/m. Seeding a sim with Gaussian velocities from a proper PRNG gives the right spread of speeds from the first frame.

For games this is the template for every cheap particle system with box collisions: integrate positions at a fixed timestep, reflect on walls, and measure aggregate quantities instead of tracking every interaction. Real gases add collisions between particles, which needs spatial partitioning.

Key formulas

Ideal gas law
Temperature from kinetic energy
RMS speed
Pressure from wall impulses
Maxwell–Boltzmann velocity component

Rules of thumb

  • Room-temperature nitrogen: v_rms ≈ 517 m/s. In sim units set m = k_B = 1 so v_rms = √(3T).
  • Store unit-temperature velocities and scale by √T when stepping; changing the temperature slider then rescales speeds instantly and correctly.
  • Reflect position about the wall (p = 2b − p) and flip the velocity; just clamping loses distance and biases pressure.
  • Average pressure over ~1–2 s of hits; with 100–300 particles single-frame readings are noisy.
  • 300 instanced spheres at 120 Hz is trivial; per-particle collisions are where costs explode (O(N²) without a grid).

Implementation

Box step that also measures pressure (m = k = 1):
export function stepGas(pos: Float32Array, vel: Float32Array, n: number,
                        dt: number, T: number, half: [number, number, number]) {
  const s = Math.sqrt(T) // vel holds unit-temperature velocities
  let impulse = 0
  for (let i = 0; i < n * 3; i++) {
    const b = half[i % 3]
    const v = vel[i] * s
    let p = pos[i] + v * dt
    if (p > b || p < -b) {
      p = 2 * (p > 0 ? b : -b) - p // specular reflection
      vel[i] = -vel[i]
      impulse += 2 * Math.abs(v)
    }
    pos[i] = p
  }
  const area = 8 * (half[0] * half[1] + half[1] * half[2] + half[0] * half[2])
  return impulse / (area * dt) // instantaneous pressure; average it
}

Common mistakes

  • Seeding random velocities with a weak or correlated generator (e.g. an LCG seeded with the particle index), which gives nearly identical speeds instead of a Maxwellian spread.
  • Using uniform random velocities: the mean energy can be right but the speed distribution is wrong.
  • Clamping particles to the wall without reflecting, which slowly drains kinetic energy.
  • Comparing measured pressure with NkT/V using the slider temperature instead of the gas's actual kinetic temperature for a small N.

Prompt

Build an ideal-gas box in TypeScript with Three.js. Create N ≤ 300 particles with uniform positions and Gaussian unit-temperature velocities from a seeded mulberry32 + Box–Muller generator. Each 1/120 s fixed step, advance positions by v·√T·dt, reflect specularly off the walls of a box whose width is adjustable, and return the summed wall impulse 2|v⊥|. Render with one InstancedMesh, colouring each instance from slow (cyan) to fast (orange), with no per-frame allocation. Tests: over 40,000 steps the measured pressure impulse/(area·time) matches N·T_kin/V within 3%, and 2,000 seeded particles have kinetic temperature ≈ 1.

Further reading

Updated 2026-11-01