dcel-map-generator 0.2.2__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 (57) hide show
  1. dcel_map_generator-0.2.2/.github/workflows/deploy-pages.yml +52 -0
  2. dcel_map_generator-0.2.2/.github/workflows/release.yml +180 -0
  3. dcel_map_generator-0.2.2/.github/workflows/semver-release.yml +56 -0
  4. dcel_map_generator-0.2.2/.gitignore +68 -0
  5. dcel_map_generator-0.2.2/AGENTS.md +23 -0
  6. dcel_map_generator-0.2.2/LICENSE +21 -0
  7. dcel_map_generator-0.2.2/PKG-INFO +164 -0
  8. dcel_map_generator-0.2.2/README.md +148 -0
  9. dcel_map_generator-0.2.2/conftest.py +29 -0
  10. dcel_map_generator-0.2.2/dcel_builder/__init__.py +130 -0
  11. dcel_map_generator-0.2.2/dcel_builder/__main__.py +212 -0
  12. dcel_map_generator-0.2.2/dcel_builder/dcel.py +174 -0
  13. dcel_map_generator-0.2.2/dcel_builder/frontend_bundle.py +184 -0
  14. dcel_map_generator-0.2.2/dcel_builder/geometry.py +20 -0
  15. dcel_map_generator-0.2.2/dcel_builder/hierarchy.py +553 -0
  16. dcel_map_generator-0.2.2/dcel_builder/noise.py +89 -0
  17. dcel_map_generator-0.2.2/dcel_builder/raster_dcel.py +252 -0
  18. dcel_map_generator-0.2.2/dcel_builder/render.py +107 -0
  19. dcel_map_generator-0.2.2/dcel_builder/serializer.py +99 -0
  20. dcel_map_generator-0.2.2/dcel_builder/tree_loader.py +146 -0
  21. dcel_map_generator-0.2.2/docs/atlantis-map.png +0 -0
  22. dcel_map_generator-0.2.2/examples/atlantis/zone_edges.json +30 -0
  23. dcel_map_generator-0.2.2/examples/atlantis/zone_index.json +31 -0
  24. dcel_map_generator-0.2.2/examples/atlantis/zone_tree_stats.json +20 -0
  25. dcel_map_generator-0.2.2/frontend/index.html +12 -0
  26. dcel_map_generator-0.2.2/frontend/package-lock.json +2599 -0
  27. dcel_map_generator-0.2.2/frontend/package.json +41 -0
  28. dcel_map_generator-0.2.2/frontend/public/.gitkeep +1 -0
  29. dcel_map_generator-0.2.2/frontend/public/map_bundle.json +1473 -0
  30. dcel_map_generator-0.2.2/frontend/src/App.tsx +41 -0
  31. dcel_map_generator-0.2.2/frontend/src/MapView.tsx +513 -0
  32. dcel_map_generator-0.2.2/frontend/src/animations.ts +9 -0
  33. dcel_map_generator-0.2.2/frontend/src/bundle.ts +52 -0
  34. dcel_map_generator-0.2.2/frontend/src/index.ts +12 -0
  35. dcel_map_generator-0.2.2/frontend/src/main.tsx +10 -0
  36. dcel_map_generator-0.2.2/frontend/src/styles.css +177 -0
  37. dcel_map_generator-0.2.2/frontend/src/types.ts +57 -0
  38. dcel_map_generator-0.2.2/frontend/src/vite-env.d.ts +1 -0
  39. dcel_map_generator-0.2.2/frontend/tsconfig.json +21 -0
  40. dcel_map_generator-0.2.2/frontend/tsconfig.lib.json +10 -0
  41. dcel_map_generator-0.2.2/frontend/vite.config.ts +16 -0
  42. dcel_map_generator-0.2.2/frontend/vite.lib.config.ts +20 -0
  43. dcel_map_generator-0.2.2/pyproject.toml +44 -0
  44. dcel_map_generator-0.2.2/scripts/semver_release.py +169 -0
  45. dcel_map_generator-0.2.2/tests/__init__.py +0 -0
  46. dcel_map_generator-0.2.2/tests/integration/__init__.py +0 -0
  47. dcel_map_generator-0.2.2/tests/integration/test_cli.py +322 -0
  48. dcel_map_generator-0.2.2/tests/integration/test_pipeline.py +85 -0
  49. dcel_map_generator-0.2.2/tests/unit/__init__.py +0 -0
  50. dcel_map_generator-0.2.2/tests/unit/test_dcel.py +137 -0
  51. dcel_map_generator-0.2.2/tests/unit/test_frontend_bundle.py +75 -0
  52. dcel_map_generator-0.2.2/tests/unit/test_hierarchy.py +101 -0
  53. dcel_map_generator-0.2.2/tests/unit/test_package_metadata.py +29 -0
  54. dcel_map_generator-0.2.2/tests/unit/test_render.py +36 -0
  55. dcel_map_generator-0.2.2/tests/unit/test_semver_release.py +57 -0
  56. dcel_map_generator-0.2.2/tests/unit/test_serializer.py +140 -0
  57. dcel_map_generator-0.2.2/tests/unit/test_tree_loader.py +56 -0
@@ -0,0 +1,52 @@
1
+ name: Deploy Pages
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: pages
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ environment:
21
+ name: github-pages
22
+ url: ${{ steps.deployment.outputs.page_url }}
23
+ steps:
24
+ - name: Checkout
25
+ uses: actions/checkout@v4
26
+
27
+ - name: Setup Node
28
+ uses: actions/setup-node@v4
29
+ with:
30
+ node-version: "22"
31
+ cache: npm
32
+ cache-dependency-path: frontend/package-lock.json
33
+
34
+ - name: Install frontend dependencies
35
+ working-directory: frontend
36
+ run: npm ci
37
+
38
+ - name: Build frontend
39
+ working-directory: frontend
40
+ run: npm run build
41
+
42
+ - name: Setup Pages
43
+ uses: actions/configure-pages@v5
44
+
45
+ - name: Upload artifact
46
+ uses: actions/upload-pages-artifact@v3
47
+ with:
48
+ path: frontend/dist
49
+
50
+ - name: Deploy to GitHub Pages
51
+ id: deployment
52
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,180 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ release:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Setup Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.12"
24
+
25
+ - name: Setup uv
26
+ uses: astral-sh/setup-uv@v4
27
+
28
+ - name: Setup Node
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: "22"
32
+ cache: npm
33
+ cache-dependency-path: frontend/package-lock.json
34
+
35
+ - name: Verify release tag matches package version
36
+ run: |
37
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
38
+ PY_VERSION="$(python - <<'PY'
39
+ import tomllib
40
+ with open("pyproject.toml", "rb") as fh:
41
+ print(tomllib.load(fh)["project"]["version"])
42
+ PY
43
+ )"
44
+ FRONTEND_VERSION="$(python - <<'PY'
45
+ import json
46
+ with open("frontend/package.json", "r", encoding="utf-8") as fh:
47
+ print(json.load(fh)["version"])
48
+ PY
49
+ )"
50
+ if [ "$TAG_VERSION" != "$PY_VERSION" ]; then
51
+ echo "Tag version $TAG_VERSION does not match pyproject version $PY_VERSION"
52
+ exit 1
53
+ fi
54
+ if [ "$TAG_VERSION" != "$FRONTEND_VERSION" ]; then
55
+ echo "Tag version $TAG_VERSION does not match frontend version $FRONTEND_VERSION"
56
+ exit 1
57
+ fi
58
+
59
+ - name: Install Python dependencies
60
+ run: uv sync --dev
61
+
62
+ - name: Run Python tests
63
+ run: uv run pytest
64
+
65
+ - name: Build Python distributions
66
+ run: uv build
67
+
68
+ - name: Install frontend dependencies
69
+ working-directory: frontend
70
+ run: npm ci
71
+
72
+ - name: Build frontend
73
+ working-directory: frontend
74
+ run: npm run build
75
+
76
+ - name: Prepare release artifact directory
77
+ run: mkdir -p release-artifacts
78
+
79
+ - name: Pack frontend npm package
80
+ working-directory: frontend
81
+ run: npm pack --pack-destination ../release-artifacts
82
+
83
+ - name: Create release archives
84
+ run: |
85
+ cp frontend/public/map_bundle.json release-artifacts/map_bundle.json
86
+ cp docs/atlantis-map.png release-artifacts/atlantis-map.png
87
+ tar -C frontend/dist -czf release-artifacts/frontend-dist.tar.gz .
88
+ tar -C examples -czf release-artifacts/atlantis-example-inputs.tar.gz atlantis
89
+
90
+ - name: Upload Python distributions
91
+ uses: actions/upload-artifact@v4
92
+ with:
93
+ name: python-dist
94
+ path: dist/*
95
+
96
+ - name: Upload frontend distribution
97
+ uses: actions/upload-artifact@v4
98
+ with:
99
+ name: frontend-dist
100
+ path: |
101
+ release-artifacts/frontend-dist.tar.gz
102
+ release-artifacts/*.tgz
103
+
104
+ - name: Upload example assets
105
+ uses: actions/upload-artifact@v4
106
+ with:
107
+ name: example-assets
108
+ path: |
109
+ release-artifacts/map_bundle.json
110
+ release-artifacts/atlantis-map.png
111
+ release-artifacts/atlantis-example-inputs.tar.gz
112
+
113
+ - name: Publish GitHub release
114
+ uses: softprops/action-gh-release@v2
115
+ with:
116
+ generate_release_notes: true
117
+ files: |
118
+ dist/*
119
+ release-artifacts/frontend-dist.tar.gz
120
+ release-artifacts/*.tgz
121
+ release-artifacts/map_bundle.json
122
+ release-artifacts/atlantis-map.png
123
+ release-artifacts/atlantis-example-inputs.tar.gz
124
+
125
+ publish-pypi:
126
+ name: Publish to PyPI
127
+ runs-on: ubuntu-latest
128
+ needs: release
129
+ environment:
130
+ name: pypi
131
+ permissions:
132
+ id-token: write
133
+ steps:
134
+ - name: Download Python distributions
135
+ uses: actions/download-artifact@v4
136
+ with:
137
+ name: python-dist
138
+ path: dist
139
+
140
+ - name: Publish package to PyPI
141
+ uses: pypa/gh-action-pypi-publish@release/v1
142
+ with:
143
+ packages-dir: dist
144
+
145
+ publish-npm:
146
+ name: Publish to npm
147
+ runs-on: ubuntu-latest
148
+ needs: release
149
+ environment:
150
+ name: npm
151
+ permissions:
152
+ contents: read
153
+ id-token: write
154
+ steps:
155
+ - name: Download frontend package artifact
156
+ uses: actions/download-artifact@v4
157
+ with:
158
+ name: frontend-dist
159
+ path: release-artifacts
160
+
161
+ - name: Setup Node
162
+ uses: actions/setup-node@v4
163
+ with:
164
+ node-version: "22"
165
+ registry-url: "https://registry.npmjs.org"
166
+
167
+ - name: Resolve frontend package tarball
168
+ id: frontend-package
169
+ run: |
170
+ shopt -s nullglob
171
+ tarballs=(release-artifacts/*.tgz)
172
+ if [ "${#tarballs[@]}" -ne 1 ]; then
173
+ echo "Expected exactly one frontend package tarball, found ${#tarballs[@]}"
174
+ ls -la release-artifacts
175
+ exit 1
176
+ fi
177
+ echo "path=./${tarballs[0]}" >> "$GITHUB_OUTPUT"
178
+
179
+ - name: Publish renderer package to npm
180
+ run: npm publish "${{ steps.frontend-package.outputs.path }}" --access public --provenance
@@ -0,0 +1,56 @@
1
+ name: Semver Release
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ concurrency:
12
+ group: semver-release-main
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ version-and-tag:
17
+ if: github.actor != 'github-actions[bot]'
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - name: Checkout
21
+ uses: actions/checkout@v4
22
+ with:
23
+ fetch-depth: 0
24
+
25
+ - name: Setup Python
26
+ uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.12"
29
+
30
+ - name: Determine next version
31
+ id: semver
32
+ run: python scripts/semver_release.py plan
33
+
34
+ - name: Stop when no release is needed
35
+ if: steps.semver.outputs.changed != 'true'
36
+ run: echo "No unreleased commits since the latest semantic version tag."
37
+
38
+ - name: Apply release version
39
+ if: steps.semver.outputs.changed == 'true'
40
+ run: python scripts/semver_release.py apply --version "${{ steps.semver.outputs.version }}"
41
+
42
+ - name: Commit and tag release
43
+ if: steps.semver.outputs.changed == 'true'
44
+ run: |
45
+ git config user.name "github-actions[bot]"
46
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
47
+ git add pyproject.toml dcel_builder/__init__.py frontend/package.json frontend/package-lock.json
48
+ git commit -m "Release v${{ steps.semver.outputs.version }}"
49
+ git tag "v${{ steps.semver.outputs.version }}"
50
+ git push origin main --follow-tags
51
+
52
+ - name: Trigger release workflow
53
+ if: steps.semver.outputs.changed == 'true'
54
+ env:
55
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56
+ run: gh workflow run release.yml --ref "v${{ steps.semver.outputs.version }}"
@@ -0,0 +1,68 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.pyc
6
+ *.pyo
7
+ *.pyd
8
+ .Python
9
+
10
+ # Virtual environments
11
+ .venv/
12
+ venv/
13
+ env/
14
+ ENV/
15
+
16
+ # uv
17
+ .uv/
18
+ uv.lock
19
+
20
+ # Distribution / packaging
21
+ dist/
22
+ build/
23
+ node_modules/
24
+ frontend/dist-lib/
25
+ frontend/*.tgz
26
+ *.egg-info/
27
+ *.egg
28
+ .eggs/
29
+
30
+ # Testing
31
+ .pytest_cache/
32
+ .coverage
33
+ htmlcov/
34
+ .tox/
35
+ coverage.xml
36
+ *.cover
37
+
38
+ # Type checking
39
+ .mypy_cache/
40
+ .dmypy.json
41
+ *.tsbuildinfo
42
+
43
+ # Linting
44
+ .ruff_cache/
45
+
46
+ # IDE
47
+ .vscode/
48
+ .idea/
49
+ *.swp
50
+ *.swo
51
+ *.claude/
52
+ .claude/
53
+
54
+ # OS
55
+ .DS_Store
56
+ Thumbs.db
57
+
58
+ # Output files
59
+ dcel_map.json
60
+ dcel_map.png
61
+ debug_label_map.png
62
+ local/
63
+ scripts/__pycache__/
64
+
65
+ # Secrets / env
66
+ .env
67
+ .env.*
68
+ *.secret
@@ -0,0 +1,23 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+ `dcel_builder/` contains the application code and CLI entry point (`__main__.py`). The current runtime path is small: `tree_loader.py` validates the hierarchy input, `hierarchy.py` builds the recursive raster subdivision, `raster_dcel.py` converts the leaf raster into polygons/DCEL, and `render.py` produces preview PNGs. Core DCEL types and JSON I/O live in `dcel.py` and `serializer.py`. Tests are split into `tests/unit/` for module behavior and `tests/integration/` for CLI/pipeline coverage. Repository-root JSON files are the current sample inputs; generated outputs should stay untracked.
5
+
6
+ ## Build, Test, and Development Commands
7
+ Use Python 3.11+.
8
+
9
+ - `uv sync --dev`: install runtime and development dependencies.
10
+ - `uv run pytest`: run the full test suite.
11
+ - `uv run pytest tests/unit/test_hierarchy.py`: run a focused unit test file while iterating.
12
+ - `uv run ruff check .`: lint imports and basic style issues.
13
+ - `uv run ruff format .`: apply formatting before opening a PR.
14
+ - `uv run python -m dcel_builder` or `uv run dcel-map`: run the CLI locally.
15
+
16
+ ## Coding Style & Naming Conventions
17
+ Follow PEP 8 with 4-space indentation and a maximum line length of 100 characters, matching `ruff` settings in `pyproject.toml`. Use `snake_case` for modules, functions, variables, and test files; use `PascalCase` only for classes. Keep modules narrowly scoped by responsibility. Prefer explicit type-friendly function signatures and small pure helpers for geometry transforms.
18
+
19
+ ## Testing Guidelines
20
+ Tests use `pytest` and are discovered from `tests/`. Name new files `test_<feature>.py` and new tests `test_<behavior>`. Add unit tests for deterministic logic and integration tests when CLI behavior, JSON I/O, or full pipeline assembly changes. Run `uv run pytest` before submitting changes; update or add fixture data only when behavior intentionally changes.
21
+
22
+ ## Commit & Pull Request Guidelines
23
+ Recent history favors short, imperative commit subjects such as `Implement foundational modules`. Keep the first line concise and descriptive. Pull requests should explain the behavioral change, mention affected modules or specs, and note test coverage. Include sample command output or updated artifact references when CLI behavior or generated map outputs change.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alonso Cancino
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,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: dcel-map-generator
3
+ Version: 0.2.2
4
+ Summary: Generate a leaf-level DCEL map from a hierarchical zone tree
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: matplotlib>=3.10.8
8
+ Requires-Dist: networkx>=3.4
9
+ Requires-Dist: numpy>=1.26
10
+ Requires-Dist: scipy>=1.11
11
+ Requires-Dist: shapely>=2.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest>=7.0; extra == 'dev'
14
+ Requires-Dist: ruff; extra == 'dev'
15
+ Description-Content-Type: text/markdown
16
+
17
+ # DCEL Map Generator
18
+
19
+ Generate whimsical continent-style maps from a rooted hierarchy and export them as:
20
+
21
+ - a leaf-level DCEL
22
+ - a rendered preview image
23
+ - a frontend-ready bundle for an interactive zoomable map
24
+
25
+ This repo is the reusable core. Domain-specific map projects can keep their own hierarchy data and consume this generator/render stack.
26
+
27
+ [Live Demo](https://alonso-cancino.github.io/map-generator/)
28
+
29
+ ![Atlantis demo map](docs/atlantis-map.png)
30
+
31
+ ## What It Does
32
+
33
+ The pipeline is tree-first:
34
+
35
+ 1. load a rooted hierarchy from `examples/atlantis/zone_edges.json`
36
+ 2. generate a continent mask
37
+ 3. recursively partition each parent region among its children
38
+ 4. extract leaf polygons from the raster partition
39
+ 5. build a DCEL and optional frontend bundle
40
+
41
+ The bundled demo dataset is a small fantasy world centered on **Atlantis** so you can run the project immediately without bringing your own taxonomy first.
42
+
43
+ ## Quickstart
44
+
45
+ Requirements:
46
+
47
+ - Python 3.11+
48
+ - `uv`
49
+ - Node.js 20+ for the frontend demo
50
+
51
+ Install Python dependencies:
52
+
53
+ ```bash
54
+ uv sync --dev
55
+ ```
56
+
57
+ Generate the demo outputs:
58
+
59
+ ```bash
60
+ uv run python -m dcel_builder \
61
+ --zone-edges examples/atlantis/zone_edges.json \
62
+ --tree-stats examples/atlantis/zone_tree_stats.json \
63
+ --zone-index examples/atlantis/zone_index.json \
64
+ --output dcel_map.json \
65
+ --render \
66
+ --render-output docs/atlantis-map.png \
67
+ --frontend-bundle frontend/public/map_bundle.json \
68
+ --validate
69
+ ```
70
+
71
+ Run the interactive renderer locally:
72
+
73
+ ```bash
74
+ cd frontend
75
+ npm install
76
+ npm run dev
77
+ ```
78
+
79
+ Open `http://localhost:5173/`.
80
+
81
+ ## Input Files
82
+
83
+ The generator expects three JSON files:
84
+
85
+ - `zone_edges.json`: directed `[parent, child]` pairs forming a rooted tree
86
+ - `zone_index.json`: `{ "id": "name" }` mapping used for labels/tooling
87
+ - `zone_tree_stats.json`: optional sidecar metadata; the generator currently tolerates an empty object
88
+
89
+ The bundled example describes a three-level fantasy continent:
90
+
91
+ - `Atlantis`
92
+ - major regions such as `Aurelia Reach`, `Tidehollow`, `Cinder Crown`, `Mistwood`
93
+ - smaller subregions and leaf territories beneath them
94
+
95
+ The tracked demo inputs live in [`examples/atlantis`](/home/alosc/proyectos/map/examples/atlantis). Private or domain-specific datasets can stay in ignored folders such as `local/`.
96
+
97
+ ## Outputs
98
+
99
+ - `dcel_map.json`: serialized DCEL
100
+ - `docs/atlantis-map.png`: static render
101
+ - `frontend/public/map_bundle.json`: interactive bundle consumed by the frontend
102
+
103
+ ## GitHub Pages Demo
104
+
105
+ The frontend is configured for GitHub Pages static hosting. A workflow in `.github/workflows/deploy-pages.yml` builds `frontend/` and publishes the interactive demo using the bundled Atlantis example.
106
+
107
+ ## Versioning
108
+
109
+ This project uses Semantic Versioning and derives releases from commits on `main`.
110
+
111
+ - `BREAKING CHANGE` in a commit body, or `type!:` in the subject, increments `MAJOR`
112
+ - subjects starting with `feat`, `add`, or `implement` increment `MINOR`
113
+ - all other changes increment `PATCH`
114
+
115
+ The automation writes the chosen version into Python and frontend package metadata, commits `Release vX.Y.Z`, and creates the matching `vX.Y.Z` tag.
116
+
117
+ ## Releases
118
+
119
+ Pushing to `main` triggers the semantic version workflow in `.github/workflows/semver-release.yml`. That workflow computes the next version, commits the versioned files, and pushes the matching release tag. The tag then triggers `.github/workflows/release.yml`.
120
+
121
+ Each release publishes consumable artifacts:
122
+
123
+ - Python source distribution and wheel from `dist/`
124
+ - a production frontend archive, `frontend-dist.tar.gz`
125
+ - an npm package tarball for the renderer, `alonso-cancino-dcel-map-frontend-<version>.tgz`
126
+ - the example frontend bundle, `map_bundle.json`
127
+ - the Atlantis example inputs as `atlantis-example-inputs.tar.gz`
128
+ - the demo screenshot, `atlantis-map.png`
129
+
130
+ You can consume the renderer package from npm by installing the published tarball, or later from the npm registry once it is published there. The library entrypoint exports `MapView`, `loadBundle`, `parseBundle`, and the bundle/type definitions.
131
+
132
+ When the repository is configured for trusted publishing, the same release workflow also publishes:
133
+
134
+ - the Python package to PyPI
135
+ - the renderer package to npm
136
+
137
+ ### One-time registry setup
138
+
139
+ To make automated publishing work, you still need to configure each registry once:
140
+
141
+ 1. PyPI:
142
+ Create the `dcel-map-generator` project on PyPI, then add a Trusted Publisher for this GitHub repository and the workflow file `release.yml`.
143
+
144
+ 2. npm:
145
+ Create the `@alonso-cancino/dcel-map-frontend` package on npm, then add a Trusted Publisher for this GitHub repository and the workflow file `release.yml`.
146
+
147
+ 3. GitHub:
148
+ If you want deployment protection, create `pypi` and `npm` environments in the repository settings to match the workflow.
149
+
150
+ After that, pushing to `main` will create the next semantic version release and publish both packages automatically.
151
+
152
+ ## Development
153
+
154
+ ```bash
155
+ uv run pytest
156
+ uv run ruff check .
157
+ cd frontend && npm run build
158
+ ```
159
+
160
+ Contributor conventions live in `AGENTS.md`.
161
+
162
+ ## License
163
+
164
+ MIT. See [LICENSE](LICENSE).