| Ball always launches straight up | Launch vector (±2, −2.8) → ‖v‖ = 3.44 px/frame, a fixed ~54° slant; the horizontal sign is randomised per serve. |
| Paddle bounce always perpendicular | Offset ratio drives the angle: centre tap goes vertical, edge taps reach ±60°, magnitude preserved. |
| Ball tunnels through the paddle | Vertical sweep test only runs while dy > 0, and the ball is re-seated on the paddle top each tick. |
| Ball stuck inside a brick | Only the single minimum-penetration brick resolves per frame; the ball is ejected along the collision normal by depth + 0.5 and the brick is cooled for 4 ticks. |
| Two bricks in one frame | The candidate scan keeps the closest brick; the survivor is tested again on the next tick. |
| Ball skims sideways forever | Every reflection re-clamps |dy| ≥ 0.22‖v‖, so the grid can never be outrun horizontally. |
| Paddle clipped off-screen | clamp(0, 340) applied after key, mouse, and touch input alike. |
| Frame spikes / tab return | Fixed 16.67 ms accumulator with at most 5 catch-up steps, so physics stays deterministic at any refresh rate. |
| Retina blur / DPR change | Backing store scaled by devicePixelRatio (capped 2.5) and re-fitted on resize and orientationchange. |