Eight columns. Four rows. Thirty-two blocks of cyan. One three-pixel ball at four pixels a frame — and three lives to spend.
COLLISION MODEL
Velocity is split into slices of 2 px or less before anything is tested, so a 3 px ball travelling 4 px a frame can never tunnel a 17 px brick. That gives two to three collision passes per 60 Hz tick.
The ball is boxed as a square of side 6 and tested against every live brick rect. Bricks live in an 8-column grid addressed as cell = row × 8 + col, so the scan is a flat 32-cell loop with zero allocation.
Overlap is measured on both axes. The shallower axis is the one that was crossed, so it gets flipped and the ball is pushed clear of the face. Top/bottom hits invert vy, side hits invert vx.
Where several bricks overlap the box, only the shallowest resolves; the brick dies immediately and the ball is displaced out of the face, so a re-collision on the next slice is impossible and the speed magnitude is never altered.
rel = (ballX − paddleCentre) ÷ 30, mapped to ±62°. Edges send the ball flat and wide, dead centre sends it straight back up, and paddle travel is added as sidespin before the vector is renormalised.