saga2d 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- saga2d-0.2.0/.github/workflows/tests.yml +39 -0
- saga2d-0.2.0/.gitignore +15 -0
- saga2d-0.2.0/AGENTS.md +87 -0
- saga2d-0.2.0/CHANGELOG.md +16 -0
- saga2d-0.2.0/CLAUDE.md +1 -0
- saga2d-0.2.0/DESIGN.md +526 -0
- saga2d-0.2.0/LICENSE +21 -0
- saga2d-0.2.0/PKG-INFO +138 -0
- saga2d-0.2.0/README.md +113 -0
- saga2d-0.2.0/docs/framework-button-shortcuts.md +71 -0
- saga2d-0.2.0/docs/framework-display.md +90 -0
- saga2d-0.2.0/docs/framework-frame-pacing.md +63 -0
- saga2d-0.2.0/docs/framework-game-lifetime.md +49 -0
- saga2d-0.2.0/docs/framework-hexgrid.md +119 -0
- saga2d-0.2.0/docs/framework-icon-controls.md +46 -0
- saga2d-0.2.0/docs/framework-match-menu.md +126 -0
- saga2d-0.2.0/docs/framework-scene-return.md +31 -0
- saga2d-0.2.0/docs/framework-screen-layers.md +46 -0
- saga2d-0.2.0/docs/framework-settings.md +78 -0
- saga2d-0.2.0/docs/framework-ui-measurement.md +41 -0
- saga2d-0.2.0/docs/framework-wrapped-label.md +80 -0
- saga2d-0.2.0/docs/multiplayer.md +97 -0
- saga2d-0.2.0/docs/releases.md +90 -0
- saga2d-0.2.0/pyproject.toml +43 -0
- saga2d-0.2.0/saga2d/__init__.py +43 -0
- saga2d-0.2.0/saga2d/_fileio.py +52 -0
- saga2d-0.2.0/saga2d/_scene_stack.py +192 -0
- saga2d-0.2.0/saga2d/actions.py +496 -0
- saga2d-0.2.0/saga2d/animation.py +202 -0
- saga2d-0.2.0/saga2d/assets/fonts/Nunito-ExtraBold.ttf +0 -0
- saga2d-0.2.0/saga2d/assets/fonts/Nunito-SemiBold.ttf +0 -0
- saga2d-0.2.0/saga2d/assets/fonts/Nunito.ttf +0 -0
- saga2d-0.2.0/saga2d/assets/fonts/OFL.txt +93 -0
- saga2d-0.2.0/saga2d/assets.py +114 -0
- saga2d-0.2.0/saga2d/audio.py +177 -0
- saga2d-0.2.0/saga2d/backends/__init__.py +3 -0
- saga2d-0.2.0/saga2d/backends/base.py +263 -0
- saga2d-0.2.0/saga2d/backends/mock_backend.py +298 -0
- saga2d-0.2.0/saga2d/backends/pyglet_backend.py +797 -0
- saga2d-0.2.0/saga2d/effects.py +398 -0
- saga2d-0.2.0/saga2d/fonts.py +29 -0
- saga2d-0.2.0/saga2d/game.py +512 -0
- saga2d-0.2.0/saga2d/hexgrid.py +138 -0
- saga2d-0.2.0/saga2d/input.py +131 -0
- saga2d-0.2.0/saga2d/multiplayer_ui.py +362 -0
- saga2d-0.2.0/saga2d/network.py +264 -0
- saga2d-0.2.0/saga2d/online.py +253 -0
- saga2d-0.2.0/saga2d/packaging/__init__.py +205 -0
- saga2d-0.2.0/saga2d/packaging/entry.py +40 -0
- saga2d-0.2.0/saga2d/packaging/game.iss +39 -0
- saga2d-0.2.0/saga2d/packaging/game.spec +22 -0
- saga2d-0.2.0/saga2d/packaging/install.py +82 -0
- saga2d-0.2.0/saga2d/packaging/verify.py +212 -0
- saga2d-0.2.0/saga2d/release.py +95 -0
- saga2d-0.2.0/saga2d/rendering/__init__.py +6 -0
- saga2d-0.2.0/saga2d/rendering/_text.py +58 -0
- saga2d-0.2.0/saga2d/rendering/camera.py +351 -0
- saga2d-0.2.0/saga2d/rendering/layers.py +60 -0
- saga2d-0.2.0/saga2d/rendering/particles.py +177 -0
- saga2d-0.2.0/saga2d/rendering/shapes.py +81 -0
- saga2d-0.2.0/saga2d/rendering/sprite.py +390 -0
- saga2d-0.2.0/saga2d/save.py +231 -0
- saga2d-0.2.0/saga2d/scene.py +387 -0
- saga2d-0.2.0/saga2d/server/__init__.py +412 -0
- saga2d-0.2.0/saga2d/server/__main__.py +52 -0
- saga2d-0.2.0/saga2d/server/games.py +73 -0
- saga2d-0.2.0/saga2d/server/storage.py +89 -0
- saga2d-0.2.0/saga2d/settings.py +184 -0
- saga2d-0.2.0/saga2d/testing/__init__.py +190 -0
- saga2d-0.2.0/saga2d/testing/cpu_budget.py +33 -0
- saga2d-0.2.0/saga2d/testing/fixtures.py +18 -0
- saga2d-0.2.0/saga2d/testing/native_frames.py +15 -0
- saga2d-0.2.0/saga2d/testing/online.py +132 -0
- saga2d-0.2.0/saga2d/ui/__init__.py +12 -0
- saga2d-0.2.0/saga2d/ui/base.py +346 -0
- saga2d-0.2.0/saga2d/ui/components.py +570 -0
- saga2d-0.2.0/saga2d/ui/layout.py +75 -0
- saga2d-0.2.0/saga2d/ui/minimap.py +97 -0
- saga2d-0.2.0/saga2d/ui/theme.py +182 -0
- saga2d-0.2.0/saga2d/util/__init__.py +1 -0
- saga2d-0.2.0/saga2d/util/collision.py +51 -0
- saga2d-0.2.0/saga2d/util/reactive.py +112 -0
- saga2d-0.2.0/saga2d/util/timer.py +60 -0
- saga2d-0.2.0/saga2d/util/tween.py +217 -0
- saga2d-0.2.0/tests/__init__.py +1 -0
- saga2d-0.2.0/tests/conftest.py +2 -0
- saga2d-0.2.0/tests/framework/__init__.py +0 -0
- saga2d-0.2.0/tests/framework/test_audio.py +237 -0
- saga2d-0.2.0/tests/framework/test_button_shortcuts.py +252 -0
- saga2d-0.2.0/tests/framework/test_camera.py +77 -0
- saga2d-0.2.0/tests/framework/test_cpu_budget.py +60 -0
- saga2d-0.2.0/tests/framework/test_display.py +111 -0
- saga2d-0.2.0/tests/framework/test_effects.py +113 -0
- saga2d-0.2.0/tests/framework/test_frame_pacing.py +90 -0
- saga2d-0.2.0/tests/framework/test_frame_timer.py +31 -0
- saga2d-0.2.0/tests/framework/test_game_close.py +43 -0
- saga2d-0.2.0/tests/framework/test_hexgrid.py +113 -0
- saga2d-0.2.0/tests/framework/test_input.py +165 -0
- saga2d-0.2.0/tests/framework/test_match_room_demo.py +97 -0
- saga2d-0.2.0/tests/framework/test_native_frames.py +41 -0
- saga2d-0.2.0/tests/framework/test_network.py +132 -0
- saga2d-0.2.0/tests/framework/test_online_client.py +135 -0
- saga2d-0.2.0/tests/framework/test_online_menu.py +231 -0
- saga2d-0.2.0/tests/framework/test_packaging.py +81 -0
- saga2d-0.2.0/tests/framework/test_pyglet_backend.py +143 -0
- saga2d-0.2.0/tests/framework/test_release.py +100 -0
- saga2d-0.2.0/tests/framework/test_rendering.py +292 -0
- saga2d-0.2.0/tests/framework/test_save.py +199 -0
- saga2d-0.2.0/tests/framework/test_scene_return.py +210 -0
- saga2d-0.2.0/tests/framework/test_scene_stack.py +307 -0
- saga2d-0.2.0/tests/framework/test_screen_layers.py +143 -0
- saga2d-0.2.0/tests/framework/test_server.py +296 -0
- saga2d-0.2.0/tests/framework/test_settings.py +224 -0
- saga2d-0.2.0/tests/framework/test_settings_and_saves.py +70 -0
- saga2d-0.2.0/tests/framework/test_shapes.py +60 -0
- saga2d-0.2.0/tests/framework/test_text.py +125 -0
- saga2d-0.2.0/tests/framework/test_text_overlap.py +80 -0
- saga2d-0.2.0/tests/framework/test_transition_input.py +76 -0
- saga2d-0.2.0/tests/framework/test_ui.py +171 -0
- saga2d-0.2.0/tests/framework/test_ui_icons.py +162 -0
- saga2d-0.2.0/tests/framework/test_ui_measurement.py +69 -0
- saga2d-0.2.0/tests/framework/test_wrapped_label.py +188 -0
- saga2d-0.2.0/tools/build_fonts.py +48 -0
- saga2d-0.2.0/tools/check_distribution.py +82 -0
- saga2d-0.2.0/tools/demo_button_shortcuts.py +78 -0
- saga2d-0.2.0/tools/demo_display.py +183 -0
- saga2d-0.2.0/tools/demo_game_close.py +52 -0
- saga2d-0.2.0/tools/demo_icon_controls.py +167 -0
- saga2d-0.2.0/tools/demo_match_room.py +227 -0
- saga2d-0.2.0/tools/demo_screen_layers.py +161 -0
- saga2d-0.2.0/tools/demo_settings.py +52 -0
- saga2d-0.2.0/tools/demo_ui_measurement.py +145 -0
- saga2d-0.2.0/tools/demo_wrapped_label.py +174 -0
- saga2d-0.2.0/tools/verify_audio.py +109 -0
- saga2d-0.2.0/tools/verify_frame_pacing.py +128 -0
- saga2d-0.2.0/tools/verify_text_measurement.py +99 -0
- saga2d-0.2.0/uv.lock +296 -0
- saga2d-0.2.0/vision.md +32 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
path: saga2d
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: uv sync --locked --extra dev
|
|
22
|
+
working-directory: saga2d
|
|
23
|
+
- name: Run tests
|
|
24
|
+
run: uv run --locked pytest -q
|
|
25
|
+
working-directory: saga2d
|
|
26
|
+
- name: Build distributions
|
|
27
|
+
run: uv build --no-sources
|
|
28
|
+
working-directory: saga2d
|
|
29
|
+
- name: Check distribution metadata
|
|
30
|
+
run: uvx twine check --strict dist/*
|
|
31
|
+
working-directory: saga2d
|
|
32
|
+
- name: Exercise the installed wheel
|
|
33
|
+
working-directory: saga2d
|
|
34
|
+
run: |
|
|
35
|
+
uv venv "$RUNNER_TEMP/saga2d-wheel"
|
|
36
|
+
uv pip install --python "$RUNNER_TEMP/saga2d-wheel/bin/python" dist/*.whl pytest
|
|
37
|
+
mkdir "$RUNNER_TEMP/saga2d-wheel-check"
|
|
38
|
+
cd "$RUNNER_TEMP/saga2d-wheel-check"
|
|
39
|
+
"$RUNNER_TEMP/saga2d-wheel/bin/python" -I "$GITHUB_WORKSPACE/saga2d/tools/check_distribution.py"
|
saga2d-0.2.0/.gitignore
ADDED
saga2d-0.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Saga2D — the framework
|
|
2
|
+
|
|
3
|
+
A small Python framework for 2D games: scenes, GPU rendering through pyglet, a
|
|
4
|
+
UI toolkit, input, audio, saves and settings, LAN and online matches, a room
|
|
5
|
+
server, a PyInstaller recipe, and a mock backend that makes all of it testable
|
|
6
|
+
without a window. Read `DESIGN.md` before changing the framework.
|
|
7
|
+
|
|
8
|
+
Part of the Saga stack (`~/saga/`, see `../AGENTS.md`). Games pin a PyPI engine
|
|
9
|
+
release; changes here are isolated until a game deliberately upgrades. After
|
|
10
|
+
changing public behaviour, explicitly install this checkout in the affected
|
|
11
|
+
game's environment and run its suite with `uv run --no-sync pytest -q`, then
|
|
12
|
+
restore its released engine. See [releases](docs/releases.md) for the commands,
|
|
13
|
+
version policy and package verification. `__version__` in `saga2d/__init__.py`
|
|
14
|
+
is the single version source. Commit stable release increments; publishing
|
|
15
|
+
to PyPI and pushing release tags require the maintainer's go-ahead.
|
|
16
|
+
Procedural asset generation (sound synthesis, the software 3D renderer) lives
|
|
17
|
+
in `../sagaforge`; the framework does not depend on it.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
uv sync --extra dev
|
|
23
|
+
uv run pytest -q # headless suite (mock backend)
|
|
24
|
+
uv run python tools/demo_match_room.py --serve # a two-seat counter room; then run it twice more to play
|
|
25
|
+
uv run python -m saga2d.server --games saga2d.testing.online:GAMES # the room server with the test game
|
|
26
|
+
uv run python tools/verify_frame_pacing.py # real-backend checks; see each tool's docstring
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Layout
|
|
30
|
+
|
|
31
|
+
- `saga2d/game.py` — game loop (`tick`), subsystems, scene stack glue.
|
|
32
|
+
- `saga2d/scene.py` — `Scene` hooks, `controls`, draw helpers, ownership.
|
|
33
|
+
- `saga2d/backends/pyglet_backend.py` — GPU backend: view matrices per space,
|
|
34
|
+
triangle soup for shapes, cached labels, texture atlas. `mock_backend.py`
|
|
35
|
+
records every call for tests.
|
|
36
|
+
- `saga2d/rendering/`, `saga2d/ui/`, `saga2d/util/` — camera, layers, sprites,
|
|
37
|
+
particles; components, layout math, theme, minimap; collision, reactive
|
|
38
|
+
values, timers, tweens.
|
|
39
|
+
- `saga2d/effects.py`, `fonts.py`, `hexgrid.py`, `animation.py`, `actions.py`,
|
|
40
|
+
`audio.py`, `assets.py`, `save.py`, `settings.py`, `release.py` — pieces the
|
|
41
|
+
games share.
|
|
42
|
+
- `saga2d/network.py`, `online.py`, `multiplayer_ui.py` — LAN host/client, the
|
|
43
|
+
online client and the shared match menu and lobby.
|
|
44
|
+
- `saga2d/server/` — the authoritative room server. Games register a
|
|
45
|
+
`GameSpec` table (`<game>.multiplayer:ONLINE`); `python -m saga2d.server
|
|
46
|
+
--games ...` hosts any set of them.
|
|
47
|
+
- `saga2d/packaging/` — build, verify and install standalone games (each game
|
|
48
|
+
has a ten-line `tools/package.py` describing itself as a `GamePackage`).
|
|
49
|
+
- `saga2d/testing/` — `render_scene`, text-overlap checks, `cpu_budget`,
|
|
50
|
+
`native_frames.tick`, the pytest fixtures plugin and `online` (the counter
|
|
51
|
+
test game plus helpers that drive a real server process).
|
|
52
|
+
- `tools/` — demos and real-backend verification scripts; `docs/framework-*.md`
|
|
53
|
+
are small runnable cookbooks.
|
|
54
|
+
|
|
55
|
+
## Rules
|
|
56
|
+
|
|
57
|
+
- Framework additions need a concrete game need; two games needing the same
|
|
58
|
+
thing is the strongest case. Features exist because a game needed them in
|
|
59
|
+
that exact form. Delete rather than deprecate.
|
|
60
|
+
- Clear exceptions over silent fallbacks.
|
|
61
|
+
- Game code imports from `saga2d`, never from `saga2d.backends`.
|
|
62
|
+
- Visual changes must be looked at. Mock tests prove logic, not pixels. After
|
|
63
|
+
any change to rendering, the pyglet backend or UI components, render a real
|
|
64
|
+
frame and open the PNG:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from saga2d.testing import render_scene
|
|
68
|
+
|
|
69
|
+
def setup(game):
|
|
70
|
+
game.push(MyScene())
|
|
71
|
+
|
|
72
|
+
render_scene(setup, resolution=(1280, 800), tick_count=3).save("/tmp/check.png")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Real input goes through pyglet's dispatch on the hidden window:
|
|
76
|
+
`game.backend.window.dispatch_event("on_key_press", key.TAB, 0)`. pyglet
|
|
77
|
+
handlers must return `True` or ESC closes the window. The display must be
|
|
78
|
+
awake for pyglet to open windows (a `get_default_screen` IndexError means it
|
|
79
|
+
is asleep; `caffeinate -u` wakes it).
|
|
80
|
+
- Tests: `Game("t", backend="mock")`, `game.tick(dt)`, `backend.inject_key(...)`,
|
|
81
|
+
`backend.inject_click(x, y)`; assert on `backend.texts/rects/sprites`. The
|
|
82
|
+
`game` and `backend` fixtures come from `saga2d.testing.fixtures`. Tests
|
|
83
|
+
exercise public behaviour; no mocking of internals; a regression test for
|
|
84
|
+
every bug found.
|
|
85
|
+
- Run at most one expensive local test or verification job at a time; native
|
|
86
|
+
loops use `saga2d.testing.native_frames.tick(game)` (30 FPS cap).
|
|
87
|
+
- Commit each working increment.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 — 2026-09-16
|
|
4
|
+
|
|
5
|
+
First standalone PyPI release of the engine after the Saga repository split.
|
|
6
|
+
This is the baseline for games switching from an editable engine checkout to
|
|
7
|
+
an explicitly pinned release.
|
|
8
|
+
|
|
9
|
+
- Scene lifecycle, input, cameras, sprites, animation, audio, saves and settings.
|
|
10
|
+
- GPU rendering through pyglet, a UI toolkit and bundled Nunito fonts.
|
|
11
|
+
- LAN and online sessions, shared match screens and the authoritative room server.
|
|
12
|
+
- Standalone game packaging and headless integration-test support.
|
|
13
|
+
- Source and wheel distributions with one version source and installed-package
|
|
14
|
+
verification in CI.
|
|
15
|
+
|
|
16
|
+
Game rules and procedural asset generation are separate packages.
|
saga2d-0.2.0/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|