32 bricks, 8 × 4. Each cell is 50 × 20: x = col × 50, y = brickTop + row × 20. Paddle 60 × 10 at y = 580, clamped to 0 – 340.
Velocity is renormalized every fixed step to the target speed (3.0 → 4.0 px/frame as the field clears). Reflections flip a component; they never stretch the vector.
Contact offset from paddle centre maps to a ±60° exit cone, with a touch of paddle momentum as english. A vertical-only bounce is impossible.
AABB tests pick the shallowest-penetration brick, resolve it on its own axis, then lock that brick id for 8 steps. No double burns, no brick tunneling, no stuck ball.
requestAnimationFrame feeds a 60 Hz accumulator, so 120 Hz phones and 60 Hz monitors see identical physics and identical collision behaviour.
Edge cases handled 08