Quick answer: Pass vsync=1 to pygame.display.set_mode((W, H), vsync=1). Then display.flip() blocks until the next vsync. Use clock.tick(0) or skip the tick cap.

Frame rate hits 1000 fps even with Clock.tick(60). Tick caps at 60 but doesn’t align with the monitor; you get tearing. vsync=1 fixes both.

The Symptom

Visible screen tearing or frame rate exceeding monitor refresh. Clock.tick alone doesn’t prevent.

The Fix

import pygame
pygame.init()

screen = pygame.display.set_mode(
    (1920, 1080),
    pygame.SCALED | pygame.RESIZABLE,
    vsync=1
)

clock = pygame.time.Clock()
while running:
    # draw
    pygame.display.flip()   # blocks until vsync
    clock.tick(0)            # no extra cap

Vsync handles timing. Clock.tick(0) yields delta time without capping.

Verifying

Frame rate matches monitor refresh (60, 120, 144). No tearing. Without vsync: tearing or uncapped fps.

“vsync=1. flip blocks. Clock.tick(0).”

Related Issues

For Clock.tick busy loop, see tick CPU. For window icon, see window icon.

Vsync. Refresh-locked. No tearing.