Circle vs AABB. Candidate bricks resolved from the grid index, the shallowest-penetrating box wins the frame, and the exited box is id-tagged so a single frame never double-flips.
Angle model
Paddle contact maps hit offset to ±62° off vertical and inherits a slice of paddle momentum. Vertical floor on |dy| keeps the ball from grinding sideways forever.
Timing
Fixed 60 Hz accumulator on top of requestAnimationFrame — 60 Hz, 120 Hz and thermal-dropped frames all trace the same arc.
Scoring
32 bricks · +10 each · 320 max. Velocity ramps 3.2 → 4.0 px/frame as the wall thins. Three drops and the cabinet eats the run.