Skip to main content

Saga2D

A small Python framework for 2D games where the developer writes game logic, not engine plumbing. It renders sprites and simple shapes on the GPU through pyglet, lays out a small UI toolkit, runs a scene stack, hosts online matches and packages standalone builds. Game code never touches the backend.

Three games prove it, each in its own repository: Tribes (turn-based, Polytopia-style), Warband (real-time strategy) and Shardbound (an Eador-inspired campaign). Procedural assets — sound synthesis and a software low-poly renderer — live in sagaforge; the hosted server and website in saga-online.

Install

Requires Python 3.12 or newer. Pin the engine in a game so engine development cannot change that game's build:

uv add 'saga2d==0.3.0'
# or: python -m pip install 'saga2d==0.3.0'

Commit the game's pyproject.toml and lockfile. Upgrade the pin deliberately, then run that game's tests before committing the upgrade. See the release guide for compatibility policy, publishing and testing a local engine checkout.

Develop the engine

uv sync --extra dev
uv run pytest -q          # headless suite on the mock backend

Set SAGA2D_SILENT=1 to keep any pyglet-backed script off the speakers (SAGA2D_HEADLESS=1 implies it and also hides windows).

A complete game

This example needs no image or sound files:

from saga2d import Anchor, Button, Column, Game, Label, Scene


class World(Scene):
    background_color = (18, 20, 30, 255)
    controls = {"escape": "close"}

    def on_enter(self):
        self.gold = 0
        self.ui.add(Column(
            Label(lambda: f"Gold: {self.gold}", text_style="heading"),
            Button("Collect a coin", shortcut="Space", on_click=self.collect, width=220),
            Label("Esc closes the window.", text_style="caption"),
            spacing=16, anchor=Anchor.TOP_LEFT, margin=24,
        ))

    def draw(self):
        self.draw_circle(360, 220, 32, (230, 190, 90, 255))

    def collect(self):
        self.gold += 1

    def close(self):
        self.game.quit()


Game("My Game", resolution=(640, 400)).run(World())

What you get

  • Two coordinate spaces. "world" is transformed by the scene's Camera (pan, zoom, shake) on the GPU; "screen" is for UI. Sprites default to world space; draw_rect, draw_circle, draw_line, draw_polygon, draw_text and draw_image take space=.
  • Measured text. Scene.layout_text(text, width) returns wrapped lines and height; Scene.draw_paragraph draws the same layout. Both accept max_lines, and Scene.fit_text fits a single line with ellipsis. See the text layout cookbook.
  • Hex boards. HexGrid supplies centers, corners, picking, neighbours, weighted movement ranges and shortest paths; the game supplies terrain costs. See the cookbook.
  • Sprites with a logical size. Sprite("name", size=(64, 64)) draws any texture at that size, so procedural textures rendered at the display's pixel density stay crisp on HiDPI screens.
  • Declarative input. controls maps keys and chords to methods; bind_key does the same at runtime; mouse events carry world coordinates and modifier keys.
  • A scene stack with transparent overlays, deferred push/pop, and per-scene ownership of sprites, timers and particle emitters.
  • UI: reactive Label, Button with keycap shortcuts, KeyHints, Panel, Row, Column, ProgressBar, Minimap, anchors, flow layout, wrapped text and a Theme. Text is measured by the backend, so layout fits. See wrapped labels, measuring a tree and button shortcuts. Opt-in keyboard focus, custom activation and pointer capture work across the same tree; blocks_pointer=True keeps HUD clicks out of the world. See focus and pointer handling.
  • Actions, tweens, timers, particle emitters, frame animation, transient effects, audio with master/music/sfx channels and a silent driver, JSON save slots and persisted settings.
  • Multiplayer. MatchHost/MatchClient for LAN, OnlineClient and the shared MatchMenu/MatchLobby for hosted rooms, and saga2d.server, the authoritative room server any game registers with through a GameSpec. Follow the counter-room tutorial and the transport notes.
  • Packaging. saga2d.packaging builds, verifies and installs standalone games with PyInstaller from a ten-line tools/package.py.
  • Testing. A mock backend that records every draw call, render_scene for offscreen screenshots you can look at, a CPU budget for long checks, paced native frames, and a counter test game for the server.

See DESIGN.md for the architecture and the reasoning behind the cuts. The September 2026 engine review prioritizes game extractions and proposed improvements beyond the current genres.

Release files for saga2d 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for saga2d 0.3.2
File Size Uploaded
saga2d-0.3.2.tar.gz 449.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for saga2d 0.3.2
File Interpreter ABI Platform
saga2d-0.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 777.6 kB

Release files / saga2d-0.3.2.tar.gz

Download URL saga2d-0.3.2.tar.gz
Size 449.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2210df2c4d81951d15c1b64c9fd7f7e60ffc4251cc76aa5c6657eb7fe82dca61
BLAKE2b-256 checksum
How to use checksums
8e4e3a2549502155772f73cb4fcb506e4d3aa60cdd73433d0c550af484eff447
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.10

Release files / saga2d-0.3.2-py3-none-any.whl

Download URL saga2d-0.3.2-py3-none-any.whl
Size 328.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c95d75024a3afd4a4159b975b2d27e0f01f427816ec20d7aef34bd84823c0a2a
BLAKE2b-256 checksum
How to use checksums
6e51bca558c0ade7661e1dcf096f50cad5ae8e34960631d3ec918bc1ee3087f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.10

Release history Release notifications | RSS feed

0.3.14

2 release files

0.3.13

2 release files

0.3.12

2 release files

0.3.11

2 release files

0.3.10

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

This release

0.3.2 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page