32 cyan bricks. One 6-pixel ball. Three lives and a paddle that decides the angle.
Left, right and the ceiling invert one velocity component and re-seat the ball flush against the surface so it can never sink into the frame.
Contact offset -1 → +1 maps to a ±62° exit vector. Center hits go up; edges rip sideways. A floor on vertical speed blocks infinite horizontal stalls.
Smallest penetration wins, so a corner graze pushes out the side instead of tunnelling through the row. Only the single closest brick is processed per frame.
The vector is renormalised every step to 3.44 → 3.90 px/frame as the wall thins. Bouncing never accelerates or decays the ball.
Drop the ball below y=600 and the run costs a life; the ball re-seats on the paddle and waits for launch input.
drawImage per frame.passive:false; mouse uses pointer events, so no double-fire on hybrid devices.