Root causeIn the buffer allocation:js const MAX_ROCKETS = 67; const MAX_PARTICLES = 1200; const solidBuffer = device.createBuffer({ size: (8 + MAX_ROCKETS * 6 + MAX_PARTICLES * 6) * 6 * 4, ... }); const solidData = new Float32Array((8 + MAX_ROCKETS * 6 + MAX_PARTICLES * 6) * 6); This reserves space for 7610 vertices.But buildGeometry() actually writes:2 background quads → 12 vertices 1 glow quad per rocket → rockets.length * 6 vertices 1 particle quad per particle → particles.length * 6 vertices When rockets.length === 67 and particles.length === 1200 (which happens quickly because every rocket continuously emits particles): 12 + 67×6 + 1200×6 = 7614 vertices 7614 > 7610 → the data[o++] = ... assignments inside pushQuad go past the end of the Float32Array.That throws an uncaught RangeError. Because the error happens inside the requestAnimationFrame callback, the animation loop dies and everything freezes.Why only at 67?With 66 rockets the total is 7608 ≤ 7610 → safe. The background is allocated as only 8 vertices instead of the 12 that are actually written. That 4-vertex deficit only becomes fatal once the rocket term reaches its maximum of 67. (The MAX_ROCKETS = 67 itself is also why new rockets stop appearing, but the freeze is the overflow, not the early-return in addRocket.)Quick confirmationYou can temporarily lower MAX_PARTICLES to 1190 (or raise the magic 8 to 12 or higher) and the freeze disappears even at 67 rockets.