# pgzero: teaching 2D games in Python without an event loop or an import

> Pygame Zero wraps Pygame in a runner and a set of builtins so a beginner can write a complete game with no imports, no class and no explicit main loop, which is why it became a standard choice for teaching Python game programming rather than for shipping games.

**lordmauve/pgzero** — A zero-boilerplate games programming framework for Python 3, based on Pygame.

- Repository: https://github.com/lordmauve/pgzero
- Website: https://pygame-zero.readthedocs.io/
- Stars: 610 · Forks: 211
- Language: Python
- License: LGPL-3.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/lordmauve-pgzero

## The runner is the whole architecture

Pygame Zero is described as a zero-boilerplate games programming framework for Python 3, based on Pygame, and the project description calls it a zero-boilerplate 2D games framework. The mechanism is one sentence in the README: Pygame Zero consists of a runner, pgzrun, that will run a Pygame Zero script with a full game loop and a range of useful builtins. That is the entire design. You write a script, the runner finds it, starts the loop, and injects the builtins into its namespace. The consequence the README highlights is that each example is a self-contained script, with no need for any imports or anything else in the file. The audience is explicit in the repository topics, which include education and python-game-development, and the documentation is written for a first-time programmer rather than for someone who already knows Pygame's event loop.

## Draw, update and named functions instead of a loop

The examples in the README show what that means in practice. Graphics are drawn in a function named draw, where you clear the screen and blit an image, assuming a file like images/dog.png or images/dog.jpg exists. The game loop picks that function up automatically.

```python
    def draw():
        screen.clear()
        screen.blit('dog', (10, 50))
```

Motion is expressed in a function named update, and an actor is created by calling Actor with a sprite name, then positioned by assigning to its pos. The update function moves the actor and wraps it around the screen when it goes past the width.

```python
    alien = Actor('alien')
    alien.pos = 10, 10

    def draw():
        screen.clear()
        alien.draw()

    def update():
        alien.x += 1
        if alien.left > WIDTH:
            alien.right = 0
```

The actor's attributes are read and written as if they were plain properties, and the boundary check uses a named constant WIDTH rather than a magic number, which is a small piece of pedagogy baked into the example. Input is handled the same way, with a function named on_mouse_down that plays a sound file.

```python
    def on_mouse_down():
        sounds.eep.play()
```

## The builtins are a fixed global vocabulary

The names available in a Pygame Zero script are not discovered at runtime, they are a fixed list, and the project configuration states it. The builtins are Actor, Rect, ZRect, animate, clock, exit, images, keyboard, keymods, keys, mouse, music, screen, sounds, storage and tone. That list is the API surface of the framework, and it is short enough to print on a sheet of paper, which is the point for a teaching tool. It also tells you what the framework has deliberately left out. There is no camera object, no scene manager, no sprite group, no particle system, no shader, and no explicit surface or render layer beyond the single screen. A learner who moves beyond the examples will eventually hit the edge of that vocabulary, and the honest path at that point is to drop down to Pygame, which is what the built on Pygame framing prepares you for.

## Installing it and running your first script

The package is on PyPI as pgzero, and the manifest declares the requirements: Python 3.6 or newer, Pygame 2.1 or later, numpy, and pyfxr, the latter being a sound effect generator rather than a sound player. The requirements file lists the same set. Installation runs through pip in the usual way, and the console entry point is registered as pgzrun, mapping to pgzero.runner:main, so the runner is invoked by name rather than by a Python module path.

The README does not spell out the install command itself, and instead refers to the installation instructions in the documentation, so the definitive steps live at the installation page of the docs site. Once installed, the usage pattern is to write a script and hand it to the runner as a filename, which is what the pgzrun entry point is for. The documentation is hosted at pygame-zero.readthedocs.io, with a tutorial at the introduction page and a contributing page that covers setting up a development version of the project, which is the path to take if you intend to change the framework rather than use it.

## Eleven example games that double as the curriculum

The examples directory is the teaching material, and there are eleven of them, which tells you how the framework expects people to learn. There is a basic example, then asteroids, flappybird, lander, maze, memory, mines, pong, snake, tetra_puzzle and tron. Read as a progression, that is a move from one moving object to a complete arcade game, then to a puzzle, then to a maze, then to a memory match, then to a minesweeper clone with mouse input, then to paddle games, then to a falling block puzzle and finally to a networked-looking arcade game. Each of those exercises a different corner of the builtins, and each is a single self-contained script with no imports, which means a learner can read one file end to end and understand a complete program. The repository also carries source-vectors/ for artwork, doc/ for the documentation sources, an AUTHORS file, and a tox.ini plus a pre-commit configuration for development.

## Maintenance, packaging and the shape of the project

The project is MIT licensed, with a COPYING file at the top level, and the licence is listed as LGPL-3.0 in the repository metadata, so the terms are worth confirming from the COPYING file before you build on it. The last push was on 2026-10-11 and the repository is not archived, so the tree is being worked on, but the only recent release listed is 1.2.1 from 2025-01-18, which suggests releases are infrequent while maintenance commits continue. The build system moved to modern packaging: setuptools 64 or newer with setuptools-scm 8 or newer as the build backend, with the version derived from the Git tags and written to src/pgzero/_version.py, which is why the manifest lists the version as dynamic. The ruff configuration in the same file declares the builtins, which is how the linter knows about the injected names in user scripts. The test suite sits in test/, driven by tox.ini, and there is a GitHub Actions workflow for tests.

## Where Pygame Zero is the wrong tool

The limits follow from the abstraction. Because the game loop and the event handling are implicit, you cannot easily take over the loop, and a game that needs precise frame timing, multiple screens with their own state, or a large number of entities has nowhere to put that logic inside the builtins list. Because everything is global, the builtins shadow anything you name the same, and a script is a flat namespace rather than a set of classes, which is fine for a lesson and wrong for a codebase. The dependency on Pygame also means the framework inherits Pygame's platform limits and its own setup burden, so the zero-boilerplate promise applies to your game code and not to the environment. The alternative worth naming is writing Pygame directly, which the framework itself prepares you for, and the difference in approach is that Pygame Zero trades the explicit event loop for automatic callbacks, so learning the underlying library afterwards is an extra step rather than a wasted one. For a shipped game, most teams end up in plain Pygame or a different engine entirely, and pgzero's real value stays in the classroom and the first hour of a project.

## Conclusion

Adopt pgzero when you are teaching Python to people who have never written a game, or when you want a weekend prototype that runs with a single command and no class boilerplate. Do not adopt it for a commercial game, since the abstraction that makes it teachable removes the control you would need for anything beyond simple 2D work. Verify first that Python 3.6 or newer and a working Pygame install are available, and read the contributing instructions before setting up a development checkout, because the project publishes a separate setup path for contributors.

## FAQ

### What is Pygame Zero and what does pgzrun do?

Pygame Zero is a zero-boilerplate 2D games framework for Python 3 built on Pygame. It consists of a runner, pgzrun, which runs a Pygame Zero script with a full game loop and a range of useful builtins, so a script needs no imports at all.

### How do I install Pygame Zero?

The package is on PyPI as pgzero and requires Python 3.6 or newer with Pygame 2.1 or later, numpy and pyfxr. The README refers to the installation instructions in the documentation, and the project registers a console entry point named pgzrun.

### Which builtins does Pygame Zero provide to a script?

Actor, Rect, ZRect, animate, clock, exit, images, keyboard, keymods, keys, mouse, music, screen, sounds, storage and tone. The list is fixed in the project configuration, which is also what the linter is told about.

### How do I write a moving character in Pygame Zero?

Create an Actor with a sprite name, set its pos, draw it in a draw function and change its position in an update function. The example wraps the actor around by setting alien.right to 0 when alien.left passes WIDTH.

## Sources

- [License: LGPL-3.0](https://github.com/lordmauve/pgzero/blob/main/LICENSE)
- [lordmauve/pgzero on GitHub](https://github.com/lordmauve/pgzero)
- [Project website](https://pygame-zero.readthedocs.io/)
- [README](https://github.com/lordmauve/pgzero/blob/main/README.md)
- [Releases](https://github.com/lordmauve/pgzero/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lordmauve-pgzero
