Quick answer: Build with --add-data 'assets:assets'. Resolve runtime via sys._MEIPASS.

Game runs in dev. Onefile build can’t open assets/player.png. Bundle extracted to a temp dir; relative path doesn’t reach there.

The Fix

import sys, os

def resource_path(rel: str) -> str:
    if getattr(sys, "frozen", False):
        base = sys._MEIPASS   # onefile temp dir
    else:
        base = os.path.dirname(__file__)
    return os.path.join(base, rel)

img = pygame.image.load(resource_path("assets/player.png"))

# Build command:
# pyinstaller --onefile --add-data "assets:assets" main.py

Helper resolves dev and frozen paths transparently. Onefile extracts assets/ to _MEIPASS at startup; helper joins correctly.

Verifying

Run the .exe / binary: assets load. Logs print resource_path correctly. Onedir build also works.

“_MEIPASS in frozen. dir in dev. Assets resolve.”

Related Issues

For Pygame image extension, see image extension. For HiDPI text, see HiDPI.

_MEIPASS resolves. Assets load.