Quick answer: pygame.mask.from_threshold with default args producing a mask smaller than the visible sprite? Anti-aliased edge pixels have partial alpha and get rejected.

Mask collision misses glancing hits near sprite edges because the anti-aliased halo isn’t included in the mask.

Threshold Picks Strong Pixels

Default threshold compares against (R,G,B) values. Alpha is not the criterion unless you use from_surface. For alpha-based masks, prefer from_surface(threshold=127).

from_surface for Alpha

mask = pygame.mask.from_surface(image, threshold=127)

Picks pixels with alpha > threshold. 127 includes mid-alpha edges; 50 includes more; 200 keeps only solid pixels.

Choose Per Game Feel

Tight masks feel precise but harsh. Loose masks feel forgiving but produce phantom hits on glow / motion-blur. Test with players; tune to feel.

Per-Sprite Tuning

Action games often loosen the player mask (more forgiving) and tighten enemy masks (precise hitboxes). Different thresholds, same code.

Verifying

Mask covers the visible sprite to whatever degree your gameplay needs. Glancing collisions register or don’t register intentionally.

“Default mask drops AA edges. from_surface(threshold=127) includes them.”

Visualize masks during dev (draw the mask as an overlay) — mismatched mask vs sprite is a constant source of “why did this hit” questions.