gbc-scene-forge 0.1.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 (28) hide show
  1. gbc_scene_forge-0.1.0/LICENSE +21 -0
  2. gbc_scene_forge-0.1.0/Makefile +33 -0
  3. gbc_scene_forge-0.1.0/PKG-INFO +155 -0
  4. gbc_scene_forge-0.1.0/README.md +137 -0
  5. gbc_scene_forge-0.1.0/docs/RELEASING.md +56 -0
  6. gbc_scene_forge-0.1.0/poetry.lock +1074 -0
  7. gbc_scene_forge-0.1.0/pyproject.toml +49 -0
  8. gbc_scene_forge-0.1.0/src/gbc_scene_forge/__init__.py +3 -0
  9. gbc_scene_forge-0.1.0/src/gbc_scene_forge/apply.py +392 -0
  10. gbc_scene_forge-0.1.0/src/gbc_scene_forge/contract.py +85 -0
  11. gbc_scene_forge-0.1.0/src/gbc_scene_forge/documents.py +210 -0
  12. gbc_scene_forge-0.1.0/src/gbc_scene_forge/paths.py +15 -0
  13. gbc_scene_forge-0.1.0/src/gbc_scene_forge/progress.py +49 -0
  14. gbc_scene_forge-0.1.0/src/gbc_scene_forge/server.py +218 -0
  15. gbc_scene_forge-0.1.0/src/gbc_scene_forge/static/app.js +686 -0
  16. gbc_scene_forge-0.1.0/src/gbc_scene_forge/static/index.html +109 -0
  17. gbc_scene_forge-0.1.0/src/gbc_scene_forge/static/model.mjs +83 -0
  18. gbc_scene_forge-0.1.0/src/gbc_scene_forge/static/progress.mjs +22 -0
  19. gbc_scene_forge-0.1.0/src/gbc_scene_forge/static/style.css +49 -0
  20. gbc_scene_forge-0.1.0/src/gbc_scene_forge/transactions.py +176 -0
  21. gbc_scene_forge-0.1.0/tests/browser.mjs +106 -0
  22. gbc_scene_forge-0.1.0/tests/fixture_connector.py +223 -0
  23. gbc_scene_forge-0.1.0/tests/model.mjs +43 -0
  24. gbc_scene_forge-0.1.0/tests/serve_fixture.py +14 -0
  25. gbc_scene_forge-0.1.0/tests/test_contract.py +199 -0
  26. gbc_scene_forge-0.1.0/tests/test_progress.py +149 -0
  27. gbc_scene_forge-0.1.0/tools/bootstrap_poetry.py +15 -0
  28. gbc_scene_forge-0.1.0/tools/check_dist.py +43 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Clifford
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,33 @@
1
+ PYTHON ?= python3
2
+ POETRY ?= .tools/poetry/bin/poetry
3
+ NODE ?= node
4
+ .DEFAULT_GOAL := test
5
+
6
+ .PHONY: setup deps test lint build check-dist clean
7
+ setup:
8
+ $(PYTHON) tools/bootstrap_poetry.py
9
+ $(MAKE) deps
10
+
11
+ deps:
12
+ test -x .venv/bin/python || .tools/poetry/bin/python -m venv .venv
13
+ $(POETRY) config virtualenvs.in-project true --local
14
+ $(POETRY) check --lock --strict
15
+ $(POETRY) sync
16
+
17
+ test:
18
+ $(POETRY) run python -m unittest discover -s tests -p 'test_*.py'
19
+ $(NODE) tests/model.mjs
20
+
21
+ lint:
22
+ $(POETRY) run ruff check .
23
+ $(POETRY) run ruff format --check .
24
+
25
+ build:
26
+ $(POETRY) run python -m build
27
+ $(POETRY) run twine check --strict dist/*
28
+ $(POETRY) run python tools/check_dist.py
29
+
30
+ check-dist: build
31
+
32
+ clean:
33
+ rm -rf build dist
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.4
2
+ Name: gbc-scene-forge
3
+ Version: 0.1.0
4
+ Summary: Local browser scene editor with game-owned connectors
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Keywords: game-boy-color,scene-editor,tilemap
8
+ Requires-Python: >=3.10
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Topic :: Games/Entertainment
13
+ Project-URL: Documentation, https://github.com/cliffom/gbc-scene-forge/blob/main/README.md
14
+ Project-URL: Issues, https://github.com/cliffom/gbc-scene-forge/issues
15
+ Project-URL: Repository, https://github.com/cliffom/gbc-scene-forge
16
+ Description-Content-Type: text/markdown
17
+
18
+ # GBC Scene Forge
19
+
20
+ Version 0.1.0 is a local browser editor with an explicitly supplied Python game
21
+ connector. It has no runtime Python dependencies. The package contains its HTTP
22
+ service, browser UI, document storage, task runner and durable transaction store.
23
+ Atlas decoding, rendering, source translation and game builds belong to the host
24
+ connector. No connector is discovered or executed automatically.
25
+
26
+ ## Development
27
+
28
+ ```sh
29
+ make setup PYTHON=python3.12
30
+ make lint test build
31
+ ```
32
+
33
+ The build creates `dist/gbc_scene_forge-0.1.0-py3-none-any.whl` and a source
34
+ archive, and tests the wheel in a clean environment. See
35
+ [building and releasing](docs/RELEASING.md) for tooling and manual PyPI publication.
36
+ There is no published release yet. Local hosts can install this checkout with
37
+ `python -m pip install -e ../gbc-scene-forge` or use their dependency manager's
38
+ editable path support.
39
+
40
+ ## Launching
41
+
42
+ Install the package through the host project's locked dependencies. A host launcher
43
+ constructs its connector and calls:
44
+
45
+ ```python
46
+ from gbc_scene_forge.server import serve
47
+
48
+ serve(connector, port=8765)
49
+ ```
50
+
51
+ The connector supplies an explicit `Workspace(root, drafts, history, reviews)`.
52
+ The service binds to loopback and uses a per-session mutation token. Connectors
53
+ are trusted local Python code, not a sandboxed plugin system. The host must recover
54
+ existing transactions before importing game modules that require approved sources.
55
+
56
+ ## Connector contract version 1
57
+
58
+ `gbc_scene_forge.contract.Connector` specifies the interface. Its implementation
59
+ supplies:
60
+
61
+ | Method | Responsibility |
62
+ | --- | --- |
63
+ | `catalog()` | Project identity, capabilities, target profiles, image families and asset entries |
64
+ | `load(target, template=False)` | Working scene, fixed cells, constraints, marker annotations and draft revision |
65
+ | `normalize(scene)` / `check_shape(scene)` | Legacy document interpretation and structural game validity |
66
+ | `source_revision(target)` | Opaque revision of relevant source dependencies |
67
+ | `preview(scene, light, state, frame)` | PNG data URL, collision grid and authoritative comparison result |
68
+ | `validate(scene)` | Validity, errors/warnings and structured issues |
69
+ | `compare(scene)` | Whether game-relevant content differs; not restricted to the cell grid |
70
+ | `asset(name)` / `export(scene)` | Encoded image bytes and the connector's portable handoff |
71
+ | `input_files(root)` / `output_files(root)` | Explicit workspace file inventories |
72
+ | `prepare(scene, stage, review_id)` | Staged candidate and a `BuildPlan` |
73
+ | `approve(plan, stage, review_id)` | Bind project-specific approval metadata after explicit review confirmation |
74
+ | `activity(text, fallback)` / `refresh()` | Project-specific activity descriptions and cache invalidation |
75
+
76
+ Catalog profiles declare `cell_size`, `erase_cell`, `lighting`, `states`, optional
77
+ `guide` dimensions and `animation_frames`/`animation_interval_ms`/`animation_label`. Asset entries declare
78
+ opaque `id`, display label, family, compatible profiles, and either an explicit
79
+ image `rect` or a stamp's `cells`. Sprite references set `reference: true`; their
80
+ rectangles may declare an origin. The browser never decodes IDs or map characters.
81
+
82
+ Capabilities control Apply, export, templates and composition references. Every
83
+ project supplies at least one profile and preview mode. Required contract methods
84
+ remain available even when an operation reports unsupported capabilities.
85
+
86
+ The working grid schema retains `profile` as the opaque target key and
87
+ `source_digest` as an opaque revision for compatibility. Fixed coordinates are
88
+ returned as `locked`; `constraints` supplies reasons. Conditional game rules stay
89
+ authoritative in connector validation. Issue objects contain `code`, `message`
90
+ and, when available, a cell or region location.
91
+
92
+ ## Documents
93
+
94
+ New saves and JSON downloads use envelope version 2:
95
+
96
+ ```json
97
+ {
98
+ "version": 2,
99
+ "connector": "example-game",
100
+ "id": "draft-name",
101
+ "name": "Draft name",
102
+ "target": "room",
103
+ "source_revision": "opaque-revision",
104
+ "content": {
105
+ "width": 7,
106
+ "height": 5,
107
+ "cells": [],
108
+ "references": []
109
+ }
110
+ }
111
+ ```
112
+
113
+ The illustrative `cells` must contain the declared number of rows and columns in
114
+ a real document. Connector extensions live inside `content` and survive saves.
115
+ Version-1 flat documents pass through connector normalization. Loading leaves
116
+ their original bytes untouched; saving migrates that file with its existing ID
117
+ and raw-byte revision guard. Unsupported versions, connector identities and
118
+ unrecognized envelope fields are rejected without rewriting files. Existing
119
+ source-staleness checks still apply to migrated drafts.
120
+
121
+ ## Apply and recovery
122
+
123
+ `BuildPlan` declares candidate source paths, allowed outputs, required artifacts,
124
+ ordered `CheckStep` commands, environment, review views and approval data. Commands
125
+ are argument arrays, run in an isolated candidate directory. Preparation and
126
+ approval operate on that directory; connectors must not mutate live sources.
127
+
128
+ The runner checks source, candidate and installed editor-package fingerprints, rejects escaping paths,
129
+ requires declared artifacts, excludes only declared outputs from the frozen-source
130
+ comparison, and promotes only declared sources/outputs. It preserves process-group
131
+ cleanup, bounded output, worker health, reconnectable status, conflict-aware
132
+ rollback and interrupted-transaction recovery. Existing transaction/job formats
133
+ are retained; history paths come from the workspace.
134
+
135
+ ## Independent acceptance fixture
136
+
137
+ `tests/fixture_connector.py` provides a different 7 × 5 scene with four-pixel cells,
138
+ opaque asset IDs, non-grid game content, JSON sources and a small Python compiler.
139
+ It imports no host game, atlas library or imaging library. Run:
140
+
141
+ ```sh
142
+ .venv/bin/python -m unittest discover -s tests -p 'test_*.py'
143
+ .venv/bin/python tests/serve_fixture.py --root /tmp/forge-fixture --port 8777
144
+ node tests/browser.mjs http://127.0.0.1:8777/
145
+ ```
146
+
147
+ The browser check requires a local Chrome installation; its third argument can
148
+ override the default macOS executable. The fixture proves this contract is
149
+ independent of one game. Additional real games may require explicit future
150
+ capabilities rather than game-specific branches in the editor.
151
+
152
+ ## License
153
+
154
+ [MIT](LICENSE). Copyright (c) 2026 Michael Clifford.
155
+
@@ -0,0 +1,137 @@
1
+ # GBC Scene Forge
2
+
3
+ Version 0.1.0 is a local browser editor with an explicitly supplied Python game
4
+ connector. It has no runtime Python dependencies. The package contains its HTTP
5
+ service, browser UI, document storage, task runner and durable transaction store.
6
+ Atlas decoding, rendering, source translation and game builds belong to the host
7
+ connector. No connector is discovered or executed automatically.
8
+
9
+ ## Development
10
+
11
+ ```sh
12
+ make setup PYTHON=python3.12
13
+ make lint test build
14
+ ```
15
+
16
+ The build creates `dist/gbc_scene_forge-0.1.0-py3-none-any.whl` and a source
17
+ archive, and tests the wheel in a clean environment. See
18
+ [building and releasing](docs/RELEASING.md) for tooling and manual PyPI publication.
19
+ There is no published release yet. Local hosts can install this checkout with
20
+ `python -m pip install -e ../gbc-scene-forge` or use their dependency manager's
21
+ editable path support.
22
+
23
+ ## Launching
24
+
25
+ Install the package through the host project's locked dependencies. A host launcher
26
+ constructs its connector and calls:
27
+
28
+ ```python
29
+ from gbc_scene_forge.server import serve
30
+
31
+ serve(connector, port=8765)
32
+ ```
33
+
34
+ The connector supplies an explicit `Workspace(root, drafts, history, reviews)`.
35
+ The service binds to loopback and uses a per-session mutation token. Connectors
36
+ are trusted local Python code, not a sandboxed plugin system. The host must recover
37
+ existing transactions before importing game modules that require approved sources.
38
+
39
+ ## Connector contract version 1
40
+
41
+ `gbc_scene_forge.contract.Connector` specifies the interface. Its implementation
42
+ supplies:
43
+
44
+ | Method | Responsibility |
45
+ | --- | --- |
46
+ | `catalog()` | Project identity, capabilities, target profiles, image families and asset entries |
47
+ | `load(target, template=False)` | Working scene, fixed cells, constraints, marker annotations and draft revision |
48
+ | `normalize(scene)` / `check_shape(scene)` | Legacy document interpretation and structural game validity |
49
+ | `source_revision(target)` | Opaque revision of relevant source dependencies |
50
+ | `preview(scene, light, state, frame)` | PNG data URL, collision grid and authoritative comparison result |
51
+ | `validate(scene)` | Validity, errors/warnings and structured issues |
52
+ | `compare(scene)` | Whether game-relevant content differs; not restricted to the cell grid |
53
+ | `asset(name)` / `export(scene)` | Encoded image bytes and the connector's portable handoff |
54
+ | `input_files(root)` / `output_files(root)` | Explicit workspace file inventories |
55
+ | `prepare(scene, stage, review_id)` | Staged candidate and a `BuildPlan` |
56
+ | `approve(plan, stage, review_id)` | Bind project-specific approval metadata after explicit review confirmation |
57
+ | `activity(text, fallback)` / `refresh()` | Project-specific activity descriptions and cache invalidation |
58
+
59
+ Catalog profiles declare `cell_size`, `erase_cell`, `lighting`, `states`, optional
60
+ `guide` dimensions and `animation_frames`/`animation_interval_ms`/`animation_label`. Asset entries declare
61
+ opaque `id`, display label, family, compatible profiles, and either an explicit
62
+ image `rect` or a stamp's `cells`. Sprite references set `reference: true`; their
63
+ rectangles may declare an origin. The browser never decodes IDs or map characters.
64
+
65
+ Capabilities control Apply, export, templates and composition references. Every
66
+ project supplies at least one profile and preview mode. Required contract methods
67
+ remain available even when an operation reports unsupported capabilities.
68
+
69
+ The working grid schema retains `profile` as the opaque target key and
70
+ `source_digest` as an opaque revision for compatibility. Fixed coordinates are
71
+ returned as `locked`; `constraints` supplies reasons. Conditional game rules stay
72
+ authoritative in connector validation. Issue objects contain `code`, `message`
73
+ and, when available, a cell or region location.
74
+
75
+ ## Documents
76
+
77
+ New saves and JSON downloads use envelope version 2:
78
+
79
+ ```json
80
+ {
81
+ "version": 2,
82
+ "connector": "example-game",
83
+ "id": "draft-name",
84
+ "name": "Draft name",
85
+ "target": "room",
86
+ "source_revision": "opaque-revision",
87
+ "content": {
88
+ "width": 7,
89
+ "height": 5,
90
+ "cells": [],
91
+ "references": []
92
+ }
93
+ }
94
+ ```
95
+
96
+ The illustrative `cells` must contain the declared number of rows and columns in
97
+ a real document. Connector extensions live inside `content` and survive saves.
98
+ Version-1 flat documents pass through connector normalization. Loading leaves
99
+ their original bytes untouched; saving migrates that file with its existing ID
100
+ and raw-byte revision guard. Unsupported versions, connector identities and
101
+ unrecognized envelope fields are rejected without rewriting files. Existing
102
+ source-staleness checks still apply to migrated drafts.
103
+
104
+ ## Apply and recovery
105
+
106
+ `BuildPlan` declares candidate source paths, allowed outputs, required artifacts,
107
+ ordered `CheckStep` commands, environment, review views and approval data. Commands
108
+ are argument arrays, run in an isolated candidate directory. Preparation and
109
+ approval operate on that directory; connectors must not mutate live sources.
110
+
111
+ The runner checks source, candidate and installed editor-package fingerprints, rejects escaping paths,
112
+ requires declared artifacts, excludes only declared outputs from the frozen-source
113
+ comparison, and promotes only declared sources/outputs. It preserves process-group
114
+ cleanup, bounded output, worker health, reconnectable status, conflict-aware
115
+ rollback and interrupted-transaction recovery. Existing transaction/job formats
116
+ are retained; history paths come from the workspace.
117
+
118
+ ## Independent acceptance fixture
119
+
120
+ `tests/fixture_connector.py` provides a different 7 × 5 scene with four-pixel cells,
121
+ opaque asset IDs, non-grid game content, JSON sources and a small Python compiler.
122
+ It imports no host game, atlas library or imaging library. Run:
123
+
124
+ ```sh
125
+ .venv/bin/python -m unittest discover -s tests -p 'test_*.py'
126
+ .venv/bin/python tests/serve_fixture.py --root /tmp/forge-fixture --port 8777
127
+ node tests/browser.mjs http://127.0.0.1:8777/
128
+ ```
129
+
130
+ The browser check requires a local Chrome installation; its third argument can
131
+ override the default macOS executable. The fixture proves this contract is
132
+ independent of one game. Additional real games may require explicit future
133
+ capabilities rather than game-specific branches in the editor.
134
+
135
+ ## License
136
+
137
+ [MIT](LICENSE). Copyright (c) 2026 Michael Clifford.
@@ -0,0 +1,56 @@
1
+ # Building and releasing
2
+
3
+ Python 3.10+ and Make are required. The commands below select Python 3.12;
4
+ set `PYTHON` to another supported interpreter if needed. Node 24 runs the browser-model tests; the
5
+ editor itself needs no Node installation. Development dependencies are locked in
6
+ `poetry.lock`; `make setup` bootstraps Poetry 2.4.2 into `.tools/poetry` and installs
7
+ the development environment into `.venv`.
8
+
9
+ ```sh
10
+ make setup PYTHON=python3.12
11
+ make lint test
12
+ make build
13
+ ```
14
+
15
+ `make build` uses the standard isolated Python build frontend: it creates the
16
+ source distribution, then builds the wheel from that source distribution. It
17
+ checks metadata with Twine, installs the wheel without dependencies into a clean
18
+ environment, verifies bundled browser files and runs the Python contracts against
19
+ that installed wheel. Artifacts appear in `dist/`. Use `make clean` before building
20
+ a different version. No command above uploads packages.
21
+
22
+ CI runs these checks on Python 3.10, 3.12 and 3.14. The independent browser
23
+ acceptance check is optional and requires Chrome; see the README.
24
+
25
+ ## Publication
26
+
27
+ The project uses the MIT license, included in both distribution formats. Before a
28
+ first release, confirm the package name is available on the intended index.
29
+ Keep the version in `pyproject.toml` and `src/gbc_scene_forge/__init__.py` in sync;
30
+ the installed-wheel check enforces this.
31
+
32
+ Create GitHub environments `testpypi` and `pypi`. Register a trusted publisher on
33
+ each index with:
34
+
35
+ - Owner: `cliffom`
36
+ - Repository: `gbc-scene-forge`
37
+ - Workflow: `publish.yml`
38
+ - Environment: `testpypi` or `pypi`, matching the index
39
+ - Package name: `gbc-scene-forge`
40
+
41
+ For a new package, register a pending publisher through the index account's
42
+ publishing page. Use the official [trusted publisher setup guide](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/).
43
+ The workflow follows the [Python Packaging User Guide](https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/)
44
+ and uses short-lived OIDC credentials; no PyPI API token is stored in the repository.
45
+
46
+ After reviewing and committing a release, create and push an annotated `v0.1.0`
47
+ tag (or the matching next version). Run **Publish package** manually against that
48
+ tag, selecting `testpypi` first. Check that installation and the host connector
49
+ work before manually running the workflow for `pypi`. The workflow rebuilds and
50
+ checks the distributions, checks the tag against the package version, then uploads
51
+ only those verified artifacts. Pushing a tag alone does not publish.
52
+
53
+ Once a real release is available, consumers can pin `gbc-scene-forge==0.1.0`.
54
+ Until then, Settlement uses a sibling editable path dependency, so clone both
55
+ repositories beside one another. Its CI also checks out the sibling repository;
56
+ it needs this repository's initial commit pushed before it can run successfully.