pyglet: pure Python windowing and OpenGL, with a version 3 rewrite in progress
pyglet is a cross-platform windowing and multimedia library for Python, for developing games and other visually rich applications.
At a glance
- What is it?
- A cross-platform windowing and multimedia library for Python that calls native libraries through ctypes, ships no compiled dependencies, and is midway through its largest rewrite.
- Who is it for?
- pyglet fits Python developers who want a window, an OpenGL context and audio without a C toolchain and without an SDL-style binding layer, and who are willing to read the migration guide before upgrading. The dependency story is its strongest argument: there is nothing to compile, so a wheel is the whole install, and PyInstaller or Nuitka packaging works without special handling.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What pure Python buys, and what ctypes costs
The defining technical decision is that pyglet contains no C extension code. It is written entirely in Python and reaches native system libraries through the standard library's `ctypes` module. The README's claim is that you can modify the codebase without a second language compilation step or any compiler setup.
For distribution, that means the package installs cleanly from PyPI with no wheel variants per platform and no system libraries to resolve:
pip install --upgrade --user pygletThe same property is what makes packaging straightforward. The README names Nuitka and PyInstaller as tools that work easily, because there is no native extension to bundle and no build toolchain to reproduce.
The cost of the ctypes approach is visible in how the library reaches hardware. Windowing, input, audio and OpenGL all go through FFI calls, so behaviour depends on what the underlying platform libraries do. pyglet addresses this by making the native boundary explicit and small, and the README attributes its performance to advanced batching, which lets thousands of objects be drawn without a Python-level call per object.
The topic list includes `scientific-visualization` alongside `gamedev` and `opengl`, which reflects the second audience: people using pyglet to put an interactive OpenGL view into a scientific tool rather than to ship a game.
Platform requirements that go beyond pip
No external dependencies does not mean no system requirements. pyglet runs on Python 3.8 or later, and the README notes that because it is pure Python it also works on other interpreters such as PyPy.
The listed platforms are Windows 7 or later, Mac OS X 10.3 or later, and Linux. On Linux the requirements are spelled out because distributions differ: OpenGL and GLX, GDK 2.0 or newer or Pillow for loading images other than PNG and BMP, and OpenAL or Pulseaudio for audio. The README adds that recent distributions ship most of these by default.
One line matters more than the rest. As of pyglet 2.0, OpenGL 3.3 or newer is required. That is a real constraint on older machines, on remote desktops, and on virtual machines where the graphics driver does not expose a modern context.
Media support is split into two tiers. Without FFmpeg, pyglet handles the standard formats such as wav, png and bmp using built-in support. With FFmpeg available, it can additionally play MP3, OGG and Vorbis, WMA, and video in MPEG2, H.264, H.265, WMV and Xvid. So the same application behaves differently depending on whether FFmpeg happens to be installed, which is a deployment detail worth pinning down deliberately rather than discovering on a user's machine.
Version 3.0 and the migration decision it forces
The most consequential thing in the README is a warning at the top, above the feature list. The project is preparing a major release, version 3.0, which brings an extensive internal rewrite, support for multiple rendering backends, significant performance improvements, new WebGL support, and the return of some legacy platforms that earlier versions had dropped.
The line that decides whether you have work to do is this: the high level APIs will be largely the same, but adjustments will be necessary if you use OpenGL directly in your game or application. In other words, if you stay inside pyglet's own drawing calls, 3.0 should be close to a drop-in. If your project drops down to raw OpenGL for shaders, framebuffers or custom rendering, you have a migration to plan.
The release tags show where that leaves you. The stable line is at v2.1.16, published 2026-08-01, and the prerelease line is at v3.0.dev10, published 2026-09-18, with v3.0.dev7 in between on 2026-08-02. The README points prerelease users at the migration guide on readthedocs and at installing with a pre-release flag:
pip install --upgrade pyglet --preIt also asks pull requests intended for the previous release to target the appropriate maintenance branch, naming `pyglet-1.5-maintenance` as an example. That is how the project supports two lines at once, and it is worth checking which branch you are on before filing anything.
The last push was on 2026-09-28, and the repository is not archived, so both lines are being worked on.
Two build systems in one repository
The tree carries both a `pyproject.toml` and a `setup.py`, which is a genuine inconsistency worth understanding rather than guessing at.
The `pyproject.toml` is the modern declaration. It specifies a build backend of `flit_core` with a requirement of `flit_core >=3.2,<5`, names the project `pyglet`, lists Alex Holkner and contributors as authors, and marks the version and description as dynamic. Dynamic versioning with flit means the version is read from the package source rather than duplicated in the manifest, which is what keeps a release from having to edit two files.
The `setup.py` is the older setuptools path, and it does something the pyproject does not: it parses the version out of `pyglet/__init__.py` by scanning for the line starting with `version` and executing it. It also carries the long tail of metadata that pyproject omits, including classifiers listing Python 3.8 through 3.11, the BSD licence identifier, and project URLs.
Both paths are still referenced in the README, which suggests the setuptools file is retained for contributors and downstream packagers who need it. It also means the declared Python support differs slightly between the two files, since pyproject says `requires-python = '>=3.8'` with no upper bound while the setup.py classifiers stop at 3.11.
For an application developer this does not change what you type. For someone packaging pyglet themselves it does, and the two files are the thing to read before trusting a build.
How the project tests and documents itself
Testing uses pytest, and the README's contribution section makes a point of it: any pull request should address the corresponding documentation, both in docstrings and in the programming guide, and a mismatch between the docs and the code counts as a bug worth a ticket.
The test setup is straightforward, with the requirements installed from the tests directory:
pip install -r tests/requirements.txt --user
pytest tests/unitRunning the unit tests alone is the quick loop; the README points at the testing section of the development guide for running the full suite, which for a windowing library necessarily involves real windows and a display.
There is also a `.coveragerc` at the root, and a PyTest badge in the README tied to a GitHub Actions workflow named `unittests.yml`, so unit tests run on every change while the rest is a matter for local or manual runs.
Documentation is built with a script rather than a documentation tool invoked directly:
pip install -r doc/requirements.txt
python make.py docsThat `make.py` at the repository root is a custom task runner rather than a Makefile. Documentation is hosted on Readthedocs, indicated by a `.readthedocs.yml` at the root and a badge in the README, and the repository also carries `doc/`, `examples/`, `contrib/`, `tools/`, `website/` and an `experimental/` directory. The presence of `experimental/` is a useful signal about how this project handles new work: things land there before being committed to the public API.
There is a `RELEASE_NOTES` file at the root rather than a changelog directory, and a dedicated guide on documentation and type hints linked from the README, which tells you the project treats type annotations as part of the documented interface rather than an afterthought.
How pyglet compares with Pygame
The comparison that comes up most often is with Pygame, and the difference is architectural rather than a matter of taste.
Pygame wraps SDL2. That gives it a very wide surface immediately, because SDL already handles windows, audio and input, and it means Pygame depends on native libraries that must be present on the machine. It also means Pygame's renderer is SDL's, and reaching past it for custom shaders or framebuffers means SDL specific calls.
pyglet calls the platform's own libraries through ctypes: Win32 on Windows, Cocoa on macOS, and Xlib or Wayland-adjacent libraries on Linux. There is no SDL in the middle. The practical consequences run both ways. On the distribution side pyglet is easier, since a wheel is the whole dependency story. On the media side, the formats you can play depend on whether FFmpeg is installed rather than on what SDL bundles, and the OpenGL 3.3 floor since version 2.0 is a constraint Pygame users are less likely to hit.
The third option worth naming is moderngl or vispy for the OpenGL work with a separate UI toolkit, or arcade, which layers a friendlier API on top of Pygame and pyglet both. Choosing arcade means accepting its abstraction; choosing pyglet directly means owning the raw OpenGL path when you need it, which is also the path that 3.0 will force you to review.
Either way, the decision is not hard to reverse, because both are pip installs. Pick the one whose failure modes you would rather debug.
Editorial conclusion
pyglet fits Python developers who want a window, an OpenGL context and audio without a C toolchain and without an SDL-style binding layer, and who are willing to read the migration guide before upgrading. The dependency story is its strongest argument: there is nothing to compile, so a wheel is the whole install, and PyInstaller or Nuitka packaging works without special handling. The version question is the one to settle first. The 2.x line is the stable release, currently v2.1.16 from 2026-08-01, while 3.0 is available as prereleases such as v3.0.dev10 from 2026-09-18, and the README says the high level API will be largely unchanged while code using OpenGL directly will need adjustments for the multiple rendering backends. Install from PyPI without `--pre` for production, and read the migration guide at readthedocs before adopting 3.0.
Frequently asked questions
What is pyglet used for?
pyglet is for writing games and other visually rich applications in Python. It provides windowing, input event handling, controller and joystick support, OpenGL graphics, image and video loading, and sound and music playback, on Windows, macOS and Linux, with no external dependencies to install for most applications.
How do I install pyglet?
Install it from PyPI with pip install --upgrade --user pyglet. There are no compilation steps, since pyglet is pure Python and calls system libraries through ctypes. For development, use an editable install with pip install -e ., or install a prerelease of version 3 with pip install --upgrade pyglet --pre.
What are the key differences between pyglet and Pygame?
Pygame wraps SDL2, so it depends on native libraries that must be present on the machine, while pyglet calls the platform's own windowing, audio and OpenGL libraries through ctypes and needs nothing beyond Python. Pygame therefore tends to offer more out of the box from the SDL surface, whereas pyglet is easier to distribute and lets you reach raw OpenGL without an SDL layer in between.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pyglet-pyglet)