             y += wobbleAmp * Math.sin lfoAngle
 
         # Update velocity; use the XZ plane
-        p.velocity[0] += (x + origin[0] - p.point[0]) * gain
-        p.velocity[2] += (y + origin[2] - p.point[2]) * gain
+        p.velocity[0] += (x + origin[0] - p.point[0]) * (gain / numPhysicsTimesteps)
+        p.velocity[2] += (y + origin[2] - p.point[2]) * (gain / numPhysicsTimesteps)
 
         # Fixed timestep physics
-        for i in [1 .. numTimesteps]
+        for i in [1 .. numPhysicsTimesteps]
             p.point[0] += p.velocity[0]
             p.point[1] += p.velocity[1]
             p.point[2] += p.velocity[2]
 
-        p.life -= timeStep / particleLifetime
+        p.life -= timestepSize / particleLifetime
 
     # Filter out dead particles
     particles = particles.filter (p) -> p.life > 0

    # Render particles to the LEDs
    client.mapParticles particles, model

setInterval draw, 5


    # Time delta calculations
    now = clock()

    # Global spin update
    spinAngle = (spinAngle + timestepSize * spinRate) % (Math.PI * 2)

    # Launch new particles for all active notes
    for key, note of particleNotes
