HTML5 Canvas · Vanilla JS · Zero Libraries

Break/out

32 cyan blocks in an 8 × 4 lattice. One 3-pixel ball at a constant 3.5 px/frame. Three lives. Clear the wall.

READY 400 × 600 AABB PHYSICS 60 FPS
READYtap · click · space to launch

Under the hood

No engine, no math library — just a fixed 60 Hz accumulator and explicit collision maths on a 400 × 600 backing store.

01

Minimum-penetration side resolution

For every ball↔brick overlap we measure ox = (w/2 + r) − |Δcx| and oy = (h/2 + r) − |Δcy|, then flip the axis with the smaller overlap — top/bottom flips dy, sides flip dx — and eject the ball by exactly that depth so it never re-enters the block.

02

Sub-stepped sweep

Motion is split into ceil(speed / 2) sub-steps. Only the closest overlapping brick is processed per step, and a last-brick lockout ID blocks double-hits in the same frame.

03

Paddle angle map

Contact offset normalises to −1…1 across the 60 px bat and maps to ±62°. Centre hits go near-vertical, edge hits skim — and a side strike reflects dx instead. Velocity magnitude is renormalised after every bounce.

04

Frame-rate independence

Physics runs on a fixed 1000/60 accumulator (max 5 catch-up steps), so 120 Hz phones and 144 Hz monitors get identical trajectories. The canvas backing store is scaled by devicePixelRatio while logic stays in 400 × 600 space; touch and pointer input map through the CSS rect.