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.
Files changed (138) hide show
  1. saga2d-0.2.0/.github/workflows/tests.yml +39 -0
  2. saga2d-0.2.0/.gitignore +15 -0
  3. saga2d-0.2.0/AGENTS.md +87 -0
  4. saga2d-0.2.0/CHANGELOG.md +16 -0
  5. saga2d-0.2.0/CLAUDE.md +1 -0
  6. saga2d-0.2.0/DESIGN.md +526 -0
  7. saga2d-0.2.0/LICENSE +21 -0
  8. saga2d-0.2.0/PKG-INFO +138 -0
  9. saga2d-0.2.0/README.md +113 -0
  10. saga2d-0.2.0/docs/framework-button-shortcuts.md +71 -0
  11. saga2d-0.2.0/docs/framework-display.md +90 -0
  12. saga2d-0.2.0/docs/framework-frame-pacing.md +63 -0
  13. saga2d-0.2.0/docs/framework-game-lifetime.md +49 -0
  14. saga2d-0.2.0/docs/framework-hexgrid.md +119 -0
  15. saga2d-0.2.0/docs/framework-icon-controls.md +46 -0
  16. saga2d-0.2.0/docs/framework-match-menu.md +126 -0
  17. saga2d-0.2.0/docs/framework-scene-return.md +31 -0
  18. saga2d-0.2.0/docs/framework-screen-layers.md +46 -0
  19. saga2d-0.2.0/docs/framework-settings.md +78 -0
  20. saga2d-0.2.0/docs/framework-ui-measurement.md +41 -0
  21. saga2d-0.2.0/docs/framework-wrapped-label.md +80 -0
  22. saga2d-0.2.0/docs/multiplayer.md +97 -0
  23. saga2d-0.2.0/docs/releases.md +90 -0
  24. saga2d-0.2.0/pyproject.toml +43 -0
  25. saga2d-0.2.0/saga2d/__init__.py +43 -0
  26. saga2d-0.2.0/saga2d/_fileio.py +52 -0
  27. saga2d-0.2.0/saga2d/_scene_stack.py +192 -0
  28. saga2d-0.2.0/saga2d/actions.py +496 -0
  29. saga2d-0.2.0/saga2d/animation.py +202 -0
  30. saga2d-0.2.0/saga2d/assets/fonts/Nunito-ExtraBold.ttf +0 -0
  31. saga2d-0.2.0/saga2d/assets/fonts/Nunito-SemiBold.ttf +0 -0
  32. saga2d-0.2.0/saga2d/assets/fonts/Nunito.ttf +0 -0
  33. saga2d-0.2.0/saga2d/assets/fonts/OFL.txt +93 -0
  34. saga2d-0.2.0/saga2d/assets.py +114 -0
  35. saga2d-0.2.0/saga2d/audio.py +177 -0
  36. saga2d-0.2.0/saga2d/backends/__init__.py +3 -0
  37. saga2d-0.2.0/saga2d/backends/base.py +263 -0
  38. saga2d-0.2.0/saga2d/backends/mock_backend.py +298 -0
  39. saga2d-0.2.0/saga2d/backends/pyglet_backend.py +797 -0
  40. saga2d-0.2.0/saga2d/effects.py +398 -0
  41. saga2d-0.2.0/saga2d/fonts.py +29 -0
  42. saga2d-0.2.0/saga2d/game.py +512 -0
  43. saga2d-0.2.0/saga2d/hexgrid.py +138 -0
  44. saga2d-0.2.0/saga2d/input.py +131 -0
  45. saga2d-0.2.0/saga2d/multiplayer_ui.py +362 -0
  46. saga2d-0.2.0/saga2d/network.py +264 -0
  47. saga2d-0.2.0/saga2d/online.py +253 -0
  48. saga2d-0.2.0/saga2d/packaging/__init__.py +205 -0
  49. saga2d-0.2.0/saga2d/packaging/entry.py +40 -0
  50. saga2d-0.2.0/saga2d/packaging/game.iss +39 -0
  51. saga2d-0.2.0/saga2d/packaging/game.spec +22 -0
  52. saga2d-0.2.0/saga2d/packaging/install.py +82 -0
  53. saga2d-0.2.0/saga2d/packaging/verify.py +212 -0
  54. saga2d-0.2.0/saga2d/release.py +95 -0
  55. saga2d-0.2.0/saga2d/rendering/__init__.py +6 -0
  56. saga2d-0.2.0/saga2d/rendering/_text.py +58 -0
  57. saga2d-0.2.0/saga2d/rendering/camera.py +351 -0
  58. saga2d-0.2.0/saga2d/rendering/layers.py +60 -0
  59. saga2d-0.2.0/saga2d/rendering/particles.py +177 -0
  60. saga2d-0.2.0/saga2d/rendering/shapes.py +81 -0
  61. saga2d-0.2.0/saga2d/rendering/sprite.py +390 -0
  62. saga2d-0.2.0/saga2d/save.py +231 -0
  63. saga2d-0.2.0/saga2d/scene.py +387 -0
  64. saga2d-0.2.0/saga2d/server/__init__.py +412 -0
  65. saga2d-0.2.0/saga2d/server/__main__.py +52 -0
  66. saga2d-0.2.0/saga2d/server/games.py +73 -0
  67. saga2d-0.2.0/saga2d/server/storage.py +89 -0
  68. saga2d-0.2.0/saga2d/settings.py +184 -0
  69. saga2d-0.2.0/saga2d/testing/__init__.py +190 -0
  70. saga2d-0.2.0/saga2d/testing/cpu_budget.py +33 -0
  71. saga2d-0.2.0/saga2d/testing/fixtures.py +18 -0
  72. saga2d-0.2.0/saga2d/testing/native_frames.py +15 -0
  73. saga2d-0.2.0/saga2d/testing/online.py +132 -0
  74. saga2d-0.2.0/saga2d/ui/__init__.py +12 -0
  75. saga2d-0.2.0/saga2d/ui/base.py +346 -0
  76. saga2d-0.2.0/saga2d/ui/components.py +570 -0
  77. saga2d-0.2.0/saga2d/ui/layout.py +75 -0
  78. saga2d-0.2.0/saga2d/ui/minimap.py +97 -0
  79. saga2d-0.2.0/saga2d/ui/theme.py +182 -0
  80. saga2d-0.2.0/saga2d/util/__init__.py +1 -0
  81. saga2d-0.2.0/saga2d/util/collision.py +51 -0
  82. saga2d-0.2.0/saga2d/util/reactive.py +112 -0
  83. saga2d-0.2.0/saga2d/util/timer.py +60 -0
  84. saga2d-0.2.0/saga2d/util/tween.py +217 -0
  85. saga2d-0.2.0/tests/__init__.py +1 -0
  86. saga2d-0.2.0/tests/conftest.py +2 -0
  87. saga2d-0.2.0/tests/framework/__init__.py +0 -0
  88. saga2d-0.2.0/tests/framework/test_audio.py +237 -0
  89. saga2d-0.2.0/tests/framework/test_button_shortcuts.py +252 -0
  90. saga2d-0.2.0/tests/framework/test_camera.py +77 -0
  91. saga2d-0.2.0/tests/framework/test_cpu_budget.py +60 -0
  92. saga2d-0.2.0/tests/framework/test_display.py +111 -0
  93. saga2d-0.2.0/tests/framework/test_effects.py +113 -0
  94. saga2d-0.2.0/tests/framework/test_frame_pacing.py +90 -0
  95. saga2d-0.2.0/tests/framework/test_frame_timer.py +31 -0
  96. saga2d-0.2.0/tests/framework/test_game_close.py +43 -0
  97. saga2d-0.2.0/tests/framework/test_hexgrid.py +113 -0
  98. saga2d-0.2.0/tests/framework/test_input.py +165 -0
  99. saga2d-0.2.0/tests/framework/test_match_room_demo.py +97 -0
  100. saga2d-0.2.0/tests/framework/test_native_frames.py +41 -0
  101. saga2d-0.2.0/tests/framework/test_network.py +132 -0
  102. saga2d-0.2.0/tests/framework/test_online_client.py +135 -0
  103. saga2d-0.2.0/tests/framework/test_online_menu.py +231 -0
  104. saga2d-0.2.0/tests/framework/test_packaging.py +81 -0
  105. saga2d-0.2.0/tests/framework/test_pyglet_backend.py +143 -0
  106. saga2d-0.2.0/tests/framework/test_release.py +100 -0
  107. saga2d-0.2.0/tests/framework/test_rendering.py +292 -0
  108. saga2d-0.2.0/tests/framework/test_save.py +199 -0
  109. saga2d-0.2.0/tests/framework/test_scene_return.py +210 -0
  110. saga2d-0.2.0/tests/framework/test_scene_stack.py +307 -0
  111. saga2d-0.2.0/tests/framework/test_screen_layers.py +143 -0
  112. saga2d-0.2.0/tests/framework/test_server.py +296 -0
  113. saga2d-0.2.0/tests/framework/test_settings.py +224 -0
  114. saga2d-0.2.0/tests/framework/test_settings_and_saves.py +70 -0
  115. saga2d-0.2.0/tests/framework/test_shapes.py +60 -0
  116. saga2d-0.2.0/tests/framework/test_text.py +125 -0
  117. saga2d-0.2.0/tests/framework/test_text_overlap.py +80 -0
  118. saga2d-0.2.0/tests/framework/test_transition_input.py +76 -0
  119. saga2d-0.2.0/tests/framework/test_ui.py +171 -0
  120. saga2d-0.2.0/tests/framework/test_ui_icons.py +162 -0
  121. saga2d-0.2.0/tests/framework/test_ui_measurement.py +69 -0
  122. saga2d-0.2.0/tests/framework/test_wrapped_label.py +188 -0
  123. saga2d-0.2.0/tools/build_fonts.py +48 -0
  124. saga2d-0.2.0/tools/check_distribution.py +82 -0
  125. saga2d-0.2.0/tools/demo_button_shortcuts.py +78 -0
  126. saga2d-0.2.0/tools/demo_display.py +183 -0
  127. saga2d-0.2.0/tools/demo_game_close.py +52 -0
  128. saga2d-0.2.0/tools/demo_icon_controls.py +167 -0
  129. saga2d-0.2.0/tools/demo_match_room.py +227 -0
  130. saga2d-0.2.0/tools/demo_screen_layers.py +161 -0
  131. saga2d-0.2.0/tools/demo_settings.py +52 -0
  132. saga2d-0.2.0/tools/demo_ui_measurement.py +145 -0
  133. saga2d-0.2.0/tools/demo_wrapped_label.py +174 -0
  134. saga2d-0.2.0/tools/verify_audio.py +109 -0
  135. saga2d-0.2.0/tools/verify_frame_pacing.py +128 -0
  136. saga2d-0.2.0/tools/verify_text_measurement.py +99 -0
  137. saga2d-0.2.0/uv.lock +296 -0
  138. 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"
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ build/
5
+ dist/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .mypy_cache/
10
+ .idea/
11
+ .claude/*
12
+ !.claude/launch.json
13
+ *.png
14
+ *.gif
15
+ docs/evidence/
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