READY
Move the paddle, then tap / click / hit SPACE to launch. The launch angle follows your paddle.
GAME OVER
The ball escaped the paddle three times.
YOU WON!
Full clear. Every one of the 32 bricks is gone.
PAUSED
Field frozen. Physics halted.
Move the paddle, then tap / click / hit SPACE to launch. The launch angle follows your paddle.
The ball escaped the paddle three times.
Full clear. Every one of the 32 bricks is gone.
Field frozen. Physics halted.
Every frame the ball is tested against all 32 AABBs. Among the overlapping bricks, only the one with the smallest penetration depth is resolved — so a corner strike never triggers a phantom double bounce. The overlap axes ox / oy decide the normal: shallower on X means it struck a side, shallower on Y means top or bottom, and only that single velocity component flips.
Reflections only ever invert a sign, and paddle strikes rebuild the vector from an angle — so |v| is preserved forever at 3.0 – 4.0 px/frame. Fixed 60 Hz accumulator steps keep a phone's variable frame rate from changing the game's feel.
Contact point maps to a −65°…+65° exit vector, edges fling the ball wide. A gentle vertical bias is renormalised each frame so the ball can never grind horizontally forever, and the launch angle aims off the paddle offset while you're waiting to serve.
Three escapes below y = 600 end the run. One mercy exists: a near-miss directly above a well-placed paddle becomes a top-edge save with a shower of sparks instead of a lost ball.