Skip to main content

The fastest 2D object rendering library for Python

Project description

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()
  • Window opens a native GLFW window with an OpenGL 3.3 core context and drives the frame loop (run() calls your @win.frame callback every frame with dt). win.keys[fo.KEY_X] and win.mouse expose polled input state.
  • SpriteBatch holds up to capacity textured sprites; spawn() returns a SpriteGroup whose .pos, .size, .rot, and .color are 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.
  • ShapeBatch works 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):

  1. No Python objects per sprite. State lives in flat NumPy columns (structure-of-arrays); updates are vectorized array math, never a per-object loop.
  2. One instanced draw call per batch. The quad is generated in the vertex shader; per-instance attributes stream from one VBO per column.
  3. 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

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastobjects-0.5.0.tar.gz (163.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastobjects-0.5.0-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

File details

Details for the file fastobjects-0.5.0.tar.gz.

File metadata

  • Download URL: fastobjects-0.5.0.tar.gz
  • Upload date:
  • Size: 163.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastobjects-0.5.0.tar.gz
Algorithm Hash digest
SHA256 a5d6dc0552957f099d572e84523e4a3ef171c858a19ae03cb5c9781a36efc3ea
MD5 88708cdea0b94e26b7b76d1a511efae0
BLAKE2b-256 bc24034f462880eb99206f3af502efd4fe7a55fb5f79a746592a23e10760529e

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastobjects-0.5.0.tar.gz:

Publisher: publish.yml on Enzo-Azevedo/FastObjects

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastobjects-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: fastobjects-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 22.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastobjects-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 58c0bf7990f83e9824de0b18663491d3d5e637dc082250fa6d458ff96f48b6a7
MD5 fd641f5e95cfd4ba7a2dd7d0beba5d58
BLAKE2b-256 d06d74cf7599344dbc5b7dc81d493559e18e4db38b7610565e79c76e23de18b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastobjects-0.5.0-py3-none-any.whl:

Publisher: publish.yml on Enzo-Azevedo/FastObjects

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page