Cabinet No.04 · Vector-free · Canvas 2D

BREAK·OUT

8×4 brick matrix · 32 targets
3 balls · 320 point ceiling
Paddle 60×10 · Ball r3 · 3.44 px/frame

PWR · 400×600 · 60HZ

System spec

The hard parts of breakout are collisions and edge cases — here is exactly how each one is handled.

Collision test
Circle vs AABB via closest-point distance. Penetration is resolved on the shallower axis, which yields the true bounce side: top/bottom flips dy, left/right flips dx.
One hit per frame
All 32 boxes are scanned, the deepest overlap wins, and that brick id is stamped with the current frame so it can never re-trigger. The ball is pushed clear of the grid — no brick sticking.
Constant speed
Velocity is re-normalised to 3.44 px/frame after every bounce, so paddle angle changes direction but never pace. A vertical-speed floor stops flat stalls.
Paddle angle
Contact offset from centre (−1…1) maps to a ±60° exit angle. Dead centre ≈ vertical, edges throw hard flats. Side faces are solid, so the ball can't slip past.
Sub-stepping
Motion splits into up to 4 sub-steps per frame with a collision pass in each, so r3 at speed can't tunnel a 20px brick or the 10px paddle lip.
Refresh independence
Position integrates by dt/16.67, so the trajectory is identical on 60, 90 and 120 Hz panels, and a backgrounded tab can't teleport the ball.
Fail states
Ball leaving the bottom costs one of 3 balls, re-seats the ball on the paddle, and never resets score. 32 bricks cleared = You Won. Both end screens carry a restart control.
Mobile
Touch-drag with pointer capture and eased follow, touch-action:none, dpr backing store capped at 3×, particle pool capped, screen letterboxed from 320 px up.