FastObjects
The fastest 2D object rendering library for Python.
Documentation · Documentação em português
Sprites sustained at 60 fps in the bunnymark arena, measured on the same machine (AMD Radeon RX 580, Python 3.13, 2026-07-07) against other Python rendering libraries:
| Framework | Sprites @ 60 fps |
|---|---|
| fastobjects | 328,213 |
| arcade | 3,795 |
| raylib | 3,795 |
| pygame-ce | 2,530 |
| pyglet | 2,530 |
That is 86x the closest competitor. Numbers vary between runs by one ramp
step (±1.5x); see benchmarks/RESULTS.md for the
full dated series, methodology, and hardware details before quoting a number
as "current".
Installation
pip install fastobjects
Requires Python ≥ 3.11 and OpenGL 3.3 core.
Quick start
import fastobjects as fo
win = fo.Window(800, 600, title="FastObjects demo")
sprites = fo.SpriteBatch("player.png", capacity=1000) # any image file
group = sprites.spawn(1, x=400, y=300)
@win.frame
def update(dt: float) -> None:
if win.keys[fo.KEY_RIGHT]:
group.pos[:, 0] += 200 * dt
win.clear(0.1, 0.1, 0.1)
win.draw(sprites)
if win.keys[fo.KEY_ESCAPE]:
win.request_close()
win.run()
Windowopens a native GLFW window with an OpenGL 3.3 core context and drives the frame loop (run()calls your@win.framecallback every frame withdt).win.keys[fo.KEY_X]andwin.mouseexpose polled input state.SpriteBatchholds up tocapacitytextured sprites;spawn()returns aSpriteGroupwhose.pos,.size,.rot, and.colorare NumPy views into the batch — writing to them updates the sprites directly, no per-object overhead.batch.despawn(group)removes a group and frees its capacity; the other groups' handles stay valid.ShapeBatchworks the same way for rectangles, circles, and lines (batch.rects(...),batch.circles(...),batch.lines(...)), useful for debug overlays or non-textured geometry.win.draw(*batches)issues one draw call per batch, in the order given.
Why it's fast
Three decisions, each validated by benchmark (every experiment — winners and
losers — is recorded in benchmarks/RESULTS.md):
- No Python objects per sprite. State lives in flat NumPy columns (structure-of-arrays); updates are vectorized array math, never a per-object loop.
- One instanced draw call per batch. The quad is generated in the vertex shader; per-instance attributes stream from one VBO per column.
- You pay for change, not existence. Positions upload every frame; size, rotation, and color upload only in the frames you touch them (automatic, conservative dirty tracking). A typical frame uploads 8 bytes per sprite instead of 40.
The result: at 100,000 moving objects, FastObjects sustains 384 fps —
above the 353 fps of a minimal hand-written moderngl renderer used as the
technique's reference ceiling (which pays extra CPU copies per frame that
FastObjects avoids).
Use it inside pygame
pygame owns the window, events, input, and sound; FastObjects owns object
insertion, update, removal, and rendering. Classic pygame drawing
(pygame.draw, pygame.font) composites on top via SurfaceLayer:
import pygame
import fastobjects as fo
pygame.init()
pygame.display.set_mode((1280, 720), pygame.OPENGL | pygame.DOUBLEBUF)
ext = fo.attach(view_size=(1280, 720))
batch = fo.SpriteBatch("player.png", capacity=10_000)
group = batch.spawn(1000, x=640, y=360)
hud_surface = pygame.Surface((1280, 720), pygame.SRCALPHA)
hud = fo.SurfaceLayer(hud_surface)
while True:
for event in pygame.event.get():
...
ext.clear(0.1, 0.1, 0.1)
batch.draw()
hud.update()
hud.draw()
pygame.display.flip()
Examples
-
examples/pygame_interop.pyfor the complete, runnable version (click to spawn, D to despawn, pygame-font HUD). -
examples/bunnymark.py— 100k bouncing bunnies, native window, FPS counter. -
examples/shapes_input.py— shapes + polled keyboard/mouse input.
Development
Install with development dependencies:
pip install -e ".[dev,bench]"
Run the test suite (98 tests, pixel-verified against an offscreen OpenGL
context) with pytest, and the benchmark arena with
python benchmarks/arena/run_all.py.
Metadata
Release files for fastobjects 0.6.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastobjects-0.6.2.tar.gz | 216.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastobjects-0.6.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 245.6 kB
Release files / fastobjects-0.6.2.tar.gz
| Download URL | fastobjects-0.6.2.tar.gz |
|---|---|
| Size | 216.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ef3a172d234f007511c6dfef7bf9b7974a02a0b5a321e406f9749a0085a2079e
|
|
BLAKE2b-256 checksum How to use checksums |
95f4ec000775e02828614c317f814b1f916345754d40c86777b9875e9ec1fbc8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.
Transparency logRelease files / fastobjects-0.6.2-py3-none-any.whl
| Download URL | fastobjects-0.6.2-py3-none-any.whl |
|---|---|
| Size | 29.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8e934ac1845e269ad5588e6f810db5a1d58ba35bbdaa23fadd9e25541268df2a
|
|
BLAKE2b-256 checksum How to use checksums |
fa764e3ad88e5a8f7b797a5df2ac19c2d616afdd43f8133ae3889574b6457385
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 13, 2026.
Transparency log