mapwright 0.16.0__tar.gz → 0.18.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.
- {mapwright-0.16.0 → mapwright-0.18.0}/CHANGELOG.md +42 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/PKG-INFO +62 -5
- {mapwright-0.16.0 → mapwright-0.18.0}/README.md +61 -4
- mapwright-0.18.0/docs/gallery/atlas.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/README.md +17 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/city_castle_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/city_large_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/city_town_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/city_village_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/decoration_compass_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/decoration_creature_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/decoration_ship_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/dune_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/hill_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/hill_2.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/manifest.json +122 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/mountain_mid_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/mountain_old_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/mountain_old_2.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/mountain_young_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/mountain_young_2.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/tree_cactus_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/tree_deciduous_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/tree_deciduous_2.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/tree_pine_1.png +0 -0
- mapwright-0.18.0/docs/gallery/atlas_pack/tree_pine_2.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-blueprint.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-blueprint.svg +1 -0
- mapwright-0.18.0/docs/gallery/theme-citadel-neon.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-citadel-neon.svg +1 -0
- mapwright-0.18.0/docs/gallery/theme-dune.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-dune.svg +1 -0
- mapwright-0.18.0/docs/gallery/theme-dungeon-blueprint.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-dungeon-blueprint.svg +1 -0
- mapwright-0.18.0/docs/gallery/theme-neon.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-neon.svg +1 -0
- mapwright-0.18.0/docs/gallery/theme-parchment.png +0 -0
- mapwright-0.18.0/docs/gallery/theme-parchment.svg +1 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/examples/gallery.py +73 -4
- {mapwright-0.16.0 → mapwright-0.18.0}/pyproject.toml +1 -1
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/__init__.py +12 -1
- mapwright-0.18.0/src/mapwright/affordances.py +168 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/dungeon_renderer.py +19 -17
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/settlement_renderer.py +28 -46
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/svg_renderer.py +28 -45
- mapwright-0.18.0/src/mapwright/themes.py +291 -0
- mapwright-0.18.0/tests/test_affordances.py +158 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_api_contract.py +5 -0
- mapwright-0.18.0/tests/test_themes.py +172 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/.github/workflows/ci.yml +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/.github/workflows/publish.yml +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/.gitignore +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/LICENSE +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/NOTICE +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/age-old.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/age-old.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/age-young.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/age-young.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/archipelago.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/archipelago.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/arctic.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/arctic.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/citadel.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/citadel.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/continent.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/continent.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/desert.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/desert.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/dungeon.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/dungeon.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/highlands.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/highlands.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/islands.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/islands.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/pangaea.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/pangaea.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/port.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/port.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/regions.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/regions.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/roads.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/roads.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/template-atoll.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/template-atoll.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/template-isthmus.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/template-isthmus.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/town.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/town.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/tropical.png +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/docs/gallery/tropical.svg +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/examples/benchmark.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/_geometry.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/_graph.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/_serde.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/atlas_renderer.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/config.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/dungeon.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/names.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/regions.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/rng.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/roads.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/settlement.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/src/mapwright/terrain.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_atlas_renderer.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_config.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_dungeon.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_dungeon_renderer.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_geometry.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_graph.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_names.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_properties.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_regions.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_rng.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_roads.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_serialize.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_settlement.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_svg_renderer.py +0 -0
- {mapwright-0.16.0 → mapwright-0.18.0}/tests/test_terrain.py +0 -0
|
@@ -8,6 +8,48 @@ All notable changes to mapwright are documented here. The format follows
|
|
|
8
8
|
`tests/test_api_contract.py`). While the version is `0.x`, minor versions may
|
|
9
9
|
make breaking changes; these will always be noted here.
|
|
10
10
|
|
|
11
|
+
## [0.18.0] — 2026-06-02
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Environmental affordances + cell aggregation — `affordances` module.** Two
|
|
15
|
+
domain-neutral helpers for turning terrain into a place's *environment*:
|
|
16
|
+
- `environment_affordances(biome, temperature, moisture)` → neutral
|
|
17
|
+
ecology-level tags (`scarce_water`, `disease_vector`, `predator`,
|
|
18
|
+
`extreme_heat`, …). Biome-base tags plus climate-driven additions, so a
|
|
19
|
+
hot+wet forest reads as a steamy jungle. A host app decides what, if
|
|
20
|
+
anything, tags mean mechanically; this library never touches game rules.
|
|
21
|
+
- `summarize_cells(cells)` → `CellSummary` (dominant biome, mean climate,
|
|
22
|
+
hydrology flags, water fraction, affordances) for a footprint / explored
|
|
23
|
+
area / whole map. Deterministic; ties broken by lowest `Biome` value.
|
|
24
|
+
- New exports: `environment_affordances`, `summarize_cells`, `CellSummary`
|
|
25
|
+
(purely additive to `__all__`).
|
|
26
|
+
- **Themes extended to the town & dungeon renderers.** A `Theme` now carries
|
|
27
|
+
nested `SettlementPalette` + `DungeonPalette` sub-palettes, and
|
|
28
|
+
`SettlementSVGRenderer` / `DungeonSVGRenderer` take a `theme=` just like the
|
|
29
|
+
regional renderer — so one theme skins all three. The four built-ins
|
|
30
|
+
(`parchment`, `neon`, `dune`, `blueprint`) now style towns and dungeons
|
|
31
|
+
cohesively (e.g. a neon citadel, a blueprint dungeon). Sub-palettes default to
|
|
32
|
+
parchment, so a theme that only restyles the regional map still drives the
|
|
33
|
+
other renderers, and the default output is **byte-identical**. `SettlementPalette`
|
|
34
|
+
/ `DungeonPalette` are importable from `mapwright.themes` for authoring custom
|
|
35
|
+
themes. Gallery gains a themed town + dungeon.
|
|
36
|
+
|
|
37
|
+
## [0.17.0] — 2026-06-02
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **Render themes — `Theme` + `THEMES`.** `RegionalSVGRenderer` now takes a
|
|
41
|
+
`theme=` (a name or a `Theme`): a palette plus an optional biome *vocabulary*
|
|
42
|
+
that re-skins the same neutral terrain without regenerating anything. The
|
|
43
|
+
`Biome` enum is unchanged — a theme only decides how each biome looks and is
|
|
44
|
+
named — so this is purely additive and the contract is stable. Built-ins:
|
|
45
|
+
`parchment` (default, **byte-identical** to the previous output), `neon`
|
|
46
|
+
(Tron / digital-grid), `dune` (Tatooine / sand medium), and `blueprint`.
|
|
47
|
+
`Theme` is plain hex-string data (JSON-friendly), so a host or image service
|
|
48
|
+
can author new ones; `Theme.biome_label()` exposes the vocabulary (e.g.
|
|
49
|
+
`OCEAN` → "Void"). This is the first slice of the "Dominant Medium" /
|
|
50
|
+
render-theme direction — pair a theme with a matching `ArtPack` for a full
|
|
51
|
+
restyle. Gallery gains a same-continent neon/dune/blueprint showcase.
|
|
52
|
+
|
|
11
53
|
## [0.16.0] — 2026-06-02
|
|
12
54
|
|
|
13
55
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mapwright
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
4
4
|
Summary: Domain-neutral procedural fantasy map & world generation: Voronoi terrain, hydraulic erosion, biomes, rivers, Markov place-names, and shaded-relief SVG.
|
|
5
5
|
Project-URL: Homepage, https://github.com/sligara7/mapwright
|
|
6
6
|
Project-URL: Repository, https://github.com/sligara7/mapwright
|
|
@@ -41,7 +41,36 @@ own tiles/entities however you like.
|
|
|
41
41
|
|
|
42
42
|
## Gallery
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
**`AtlasRenderer`** — the same neutral terrain, skinned with a hand-drawn *art pack*.
|
|
45
|
+
The art here is original, generated through mapwright's companion image service and
|
|
46
|
+
stamped where the physics put it (mountains on the ranges, forests by climate, sea
|
|
47
|
+
serpents offshore). mapwright itself ships no art — the pack is the skin:
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<img width="640" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/atlas.png" alt="hand-drawn atlas rendered from a sample art pack">
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
**Render themes** — the *same* continent (same cells, rivers, roads, settlements),
|
|
54
|
+
re-skinned by swapping a `Theme` (palette + biome vocabulary). No regeneration:
|
|
55
|
+
|
|
56
|
+
<table>
|
|
57
|
+
<tr>
|
|
58
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-neon.png" alt="neon (Tron) theme"><br><sub><code>theme="neon"</code></sub></td>
|
|
59
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-dune.png" alt="dune (sand) theme"><br><sub><code>theme="dune"</code></sub></td>
|
|
60
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-blueprint.png" alt="blueprint theme"><br><sub><code>theme="blueprint"</code></sub></td>
|
|
61
|
+
</tr>
|
|
62
|
+
</table>
|
|
63
|
+
|
|
64
|
+
The same `theme=` drives the **town and dungeon** renderers too — one skin across all three:
|
|
65
|
+
|
|
66
|
+
<table>
|
|
67
|
+
<tr>
|
|
68
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-citadel-neon.png" alt="neon-themed walled citadel"><br><sub><code>Settlement, theme="neon"</code></sub></td>
|
|
69
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-dungeon-blueprint.png" alt="blueprint-themed dungeon"><br><sub><code>Dungeon, theme="blueprint"</code></sub></td>
|
|
70
|
+
</tr>
|
|
71
|
+
</table>
|
|
72
|
+
|
|
73
|
+
Below: deterministic shaded-relief renders of each built-in preset (or a dungeon),
|
|
45
74
|
produced by [`examples/gallery.py`](examples/gallery.py):
|
|
46
75
|
|
|
47
76
|
<table>
|
|
@@ -197,14 +226,16 @@ Settlement presets: `hamlet`, `village`, `town`, `city`, `port`, `citadel`.
|
|
|
197
226
|
| `NameGenerator` | Order-k character Markov names over hand-authored culture namebases; reproducible across processes. |
|
|
198
227
|
| `RegionalTerrainGenerator` | Voronoi cells (Lloyd-relaxed) → **tectonic-plate** heightmap (organic coasts + mountain ranges at plate collisions; percentile sea level) → Planchon–Darboux depression fill → flux + hydraulic/creep erosion → rivers + inland lakes → latitude/elevation climate with **rain-shadow** → Whittaker biomes. |
|
|
199
228
|
| `compute_cell_polygons` | Reconstructs convex Voronoi polygons (half-plane clipping) for vector rendering. |
|
|
200
|
-
| `RegionalSVGRenderer` | Shaded-relief (hillshade) SVG: biome polygons, coastline, rivers, roads, labelled markers. |
|
|
229
|
+
| `RegionalSVGRenderer` | Shaded-relief (hillshade) SVG: biome polygons, coastline, rivers, roads, labelled markers. Takes a `theme=`. |
|
|
230
|
+
| `Theme` / `THEMES` | A render palette + biome vocabulary; re-skins the same terrain — and its towns and dungeons — via one `theme=` (parchment / neon / dune / blueprint, or your own). The "Dominant Medium" layer. |
|
|
231
|
+
| `environment_affordances` / `summarize_cells` | Neutral *ecology* helpers: biome + climate → affordance tags (`scarce_water`, `predator`, …); reduce a set of cells to a `CellSummary` (dominant biome, mean climate, hydrology, affordances). A host decides what tags mean mechanically. |
|
|
201
232
|
| `AtlasRenderer` / `ArtPack` | Hand-drawn / themed PNG: stamps symbols from an external *art pack* (mountains, forests, hills, settlements, sea decorations) onto the terrain. mapwright ships no art — a pack is a skin. Needs `pip install "mapwright[atlas]"`. |
|
|
202
233
|
| `RegionalRoadGenerator` | Connects settlement sites with trade routes — an MST whose edges are A*-routed over the terrain (avoids sea, climbs/crosses rivers at a cost). |
|
|
203
234
|
| `RegionGenerator` | Partitions land into named factions/territories: spread capitals seed a flood fill over the land graph (sea divides them); each `Region` is Markov-named. |
|
|
204
235
|
| `DungeonGenerator` | BSP-partitioned rooms + minimum-spanning-tree corridors → rooms, corridor cells, and a walkable grid (with `Dungeon.ascii()`). |
|
|
205
|
-
| `DungeonSVGRenderer` | Renders a `Dungeon` to SVG: walls, carved floor, room outlines, optional tile grid and per-room labels. |
|
|
236
|
+
| `DungeonSVGRenderer` | Renders a `Dungeon` to SVG: walls, carved floor, room outlines, optional tile grid and per-room labels. Takes a `theme=`. |
|
|
206
237
|
| `SettlementGenerator` | Self-contained town layout: an organic footprint divided into named Voronoi **wards** (market, docks, …), each subdivided into building **lots**, a **street** network (MST over ward adjacency + main roads from gates to the market), an optional defensive **wall** (towers + gate gaps, opened at the harbour when coastal), and optional coastline. |
|
|
207
|
-
| `SettlementSVGRenderer` | Renders a `Settlement` to SVG: sea, footprint, kind-coloured wards, building lots, streets, wall with towers/gatehouses, labels. |
|
|
238
|
+
| `SettlementSVGRenderer` | Renders a `Settlement` to SVG: sea, footprint, kind-coloured wards, building lots, streets, wall with towers/gatehouses, labels. Takes a `theme=`. |
|
|
208
239
|
|
|
209
240
|
Everything is neutral: `RegionalTerrainGenerator` returns a `TerrainResult` of `TerrainCell`s
|
|
210
241
|
(each with a `Biome`), and you decide how a `Biome` maps to your world.
|
|
@@ -259,6 +290,32 @@ sibling (`mountain.mid` → any `mountain.*`), so partial packs still render. Wi
|
|
|
259
290
|
folder layout. Because packs are pure data, a host like an image-generation service can
|
|
260
291
|
**produce them on demand** in any style — the generation stays the same; the pack is the skin.
|
|
261
292
|
|
|
293
|
+
### Render themes
|
|
294
|
+
|
|
295
|
+
The vector `RegionalSVGRenderer` takes a **`Theme`** — a palette plus an optional biome
|
|
296
|
+
*vocabulary* — so the same neutral terrain re-skins into wildly different worlds without
|
|
297
|
+
regenerating anything. The neutral `Biome` enum never changes; a theme just decides how
|
|
298
|
+
each biome looks and is named:
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
from mapwright import RegionalSVGRenderer, SettlementSVGRenderer, DungeonSVGRenderer, THEMES
|
|
302
|
+
|
|
303
|
+
svg = RegionalSVGRenderer(theme="neon").render(terrain, markers, roads=roads)
|
|
304
|
+
town = SettlementSVGRenderer(theme="neon").render(settlement) # same theme skins the town
|
|
305
|
+
dgn = DungeonSVGRenderer(theme="blueprint").render(dungeon) # …and the dungeon
|
|
306
|
+
# built-ins: "parchment" (default), "neon" (Tron/digital-grid), "dune" (sand), "blueprint"
|
|
307
|
+
THEMES["neon"].biome_label(Biome.OCEAN) # -> "Void" (the vocabulary layer)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
All three renderers take the same `theme=`, so one theme skins the world map, its towns,
|
|
311
|
+
and its dungeons together (a `Theme` carries nested `SettlementPalette` + `DungeonPalette`,
|
|
312
|
+
importable from `mapwright.themes` for custom packs). A `Theme` is plain hex-string data
|
|
313
|
+
(JSON-friendly), so a host — or the same image service that makes art packs — can author
|
|
314
|
+
new ones. This is the "Dominant Medium" idea from mapwright's longer-term vision: a sand
|
|
315
|
+
planet, a digital grid, and an irradiated waste are the *same map* wearing different skins.
|
|
316
|
+
Pair a theme with a matching `ArtPack` for a full restyle of both the vector and hand-drawn
|
|
317
|
+
renders.
|
|
318
|
+
|
|
262
319
|
## Determinism
|
|
263
320
|
|
|
264
321
|
Every generator draws from a `SeededRNG`. The same seed (and parameters) reproduces an
|
|
@@ -14,7 +14,36 @@ own tiles/entities however you like.
|
|
|
14
14
|
|
|
15
15
|
## Gallery
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
**`AtlasRenderer`** — the same neutral terrain, skinned with a hand-drawn *art pack*.
|
|
18
|
+
The art here is original, generated through mapwright's companion image service and
|
|
19
|
+
stamped where the physics put it (mountains on the ranges, forests by climate, sea
|
|
20
|
+
serpents offshore). mapwright itself ships no art — the pack is the skin:
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img width="640" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/atlas.png" alt="hand-drawn atlas rendered from a sample art pack">
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
**Render themes** — the *same* continent (same cells, rivers, roads, settlements),
|
|
27
|
+
re-skinned by swapping a `Theme` (palette + biome vocabulary). No regeneration:
|
|
28
|
+
|
|
29
|
+
<table>
|
|
30
|
+
<tr>
|
|
31
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-neon.png" alt="neon (Tron) theme"><br><sub><code>theme="neon"</code></sub></td>
|
|
32
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-dune.png" alt="dune (sand) theme"><br><sub><code>theme="dune"</code></sub></td>
|
|
33
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-blueprint.png" alt="blueprint theme"><br><sub><code>theme="blueprint"</code></sub></td>
|
|
34
|
+
</tr>
|
|
35
|
+
</table>
|
|
36
|
+
|
|
37
|
+
The same `theme=` drives the **town and dungeon** renderers too — one skin across all three:
|
|
38
|
+
|
|
39
|
+
<table>
|
|
40
|
+
<tr>
|
|
41
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-citadel-neon.png" alt="neon-themed walled citadel"><br><sub><code>Settlement, theme="neon"</code></sub></td>
|
|
42
|
+
<td align="center"><img width="240" src="https://raw.githubusercontent.com/sligara7/mapwright/main/docs/gallery/theme-dungeon-blueprint.png" alt="blueprint-themed dungeon"><br><sub><code>Dungeon, theme="blueprint"</code></sub></td>
|
|
43
|
+
</tr>
|
|
44
|
+
</table>
|
|
45
|
+
|
|
46
|
+
Below: deterministic shaded-relief renders of each built-in preset (or a dungeon),
|
|
18
47
|
produced by [`examples/gallery.py`](examples/gallery.py):
|
|
19
48
|
|
|
20
49
|
<table>
|
|
@@ -170,14 +199,16 @@ Settlement presets: `hamlet`, `village`, `town`, `city`, `port`, `citadel`.
|
|
|
170
199
|
| `NameGenerator` | Order-k character Markov names over hand-authored culture namebases; reproducible across processes. |
|
|
171
200
|
| `RegionalTerrainGenerator` | Voronoi cells (Lloyd-relaxed) → **tectonic-plate** heightmap (organic coasts + mountain ranges at plate collisions; percentile sea level) → Planchon–Darboux depression fill → flux + hydraulic/creep erosion → rivers + inland lakes → latitude/elevation climate with **rain-shadow** → Whittaker biomes. |
|
|
172
201
|
| `compute_cell_polygons` | Reconstructs convex Voronoi polygons (half-plane clipping) for vector rendering. |
|
|
173
|
-
| `RegionalSVGRenderer` | Shaded-relief (hillshade) SVG: biome polygons, coastline, rivers, roads, labelled markers. |
|
|
202
|
+
| `RegionalSVGRenderer` | Shaded-relief (hillshade) SVG: biome polygons, coastline, rivers, roads, labelled markers. Takes a `theme=`. |
|
|
203
|
+
| `Theme` / `THEMES` | A render palette + biome vocabulary; re-skins the same terrain — and its towns and dungeons — via one `theme=` (parchment / neon / dune / blueprint, or your own). The "Dominant Medium" layer. |
|
|
204
|
+
| `environment_affordances` / `summarize_cells` | Neutral *ecology* helpers: biome + climate → affordance tags (`scarce_water`, `predator`, …); reduce a set of cells to a `CellSummary` (dominant biome, mean climate, hydrology, affordances). A host decides what tags mean mechanically. |
|
|
174
205
|
| `AtlasRenderer` / `ArtPack` | Hand-drawn / themed PNG: stamps symbols from an external *art pack* (mountains, forests, hills, settlements, sea decorations) onto the terrain. mapwright ships no art — a pack is a skin. Needs `pip install "mapwright[atlas]"`. |
|
|
175
206
|
| `RegionalRoadGenerator` | Connects settlement sites with trade routes — an MST whose edges are A*-routed over the terrain (avoids sea, climbs/crosses rivers at a cost). |
|
|
176
207
|
| `RegionGenerator` | Partitions land into named factions/territories: spread capitals seed a flood fill over the land graph (sea divides them); each `Region` is Markov-named. |
|
|
177
208
|
| `DungeonGenerator` | BSP-partitioned rooms + minimum-spanning-tree corridors → rooms, corridor cells, and a walkable grid (with `Dungeon.ascii()`). |
|
|
178
|
-
| `DungeonSVGRenderer` | Renders a `Dungeon` to SVG: walls, carved floor, room outlines, optional tile grid and per-room labels. |
|
|
209
|
+
| `DungeonSVGRenderer` | Renders a `Dungeon` to SVG: walls, carved floor, room outlines, optional tile grid and per-room labels. Takes a `theme=`. |
|
|
179
210
|
| `SettlementGenerator` | Self-contained town layout: an organic footprint divided into named Voronoi **wards** (market, docks, …), each subdivided into building **lots**, a **street** network (MST over ward adjacency + main roads from gates to the market), an optional defensive **wall** (towers + gate gaps, opened at the harbour when coastal), and optional coastline. |
|
|
180
|
-
| `SettlementSVGRenderer` | Renders a `Settlement` to SVG: sea, footprint, kind-coloured wards, building lots, streets, wall with towers/gatehouses, labels. |
|
|
211
|
+
| `SettlementSVGRenderer` | Renders a `Settlement` to SVG: sea, footprint, kind-coloured wards, building lots, streets, wall with towers/gatehouses, labels. Takes a `theme=`. |
|
|
181
212
|
|
|
182
213
|
Everything is neutral: `RegionalTerrainGenerator` returns a `TerrainResult` of `TerrainCell`s
|
|
183
214
|
(each with a `Biome`), and you decide how a `Biome` maps to your world.
|
|
@@ -232,6 +263,32 @@ sibling (`mountain.mid` → any `mountain.*`), so partial packs still render. Wi
|
|
|
232
263
|
folder layout. Because packs are pure data, a host like an image-generation service can
|
|
233
264
|
**produce them on demand** in any style — the generation stays the same; the pack is the skin.
|
|
234
265
|
|
|
266
|
+
### Render themes
|
|
267
|
+
|
|
268
|
+
The vector `RegionalSVGRenderer` takes a **`Theme`** — a palette plus an optional biome
|
|
269
|
+
*vocabulary* — so the same neutral terrain re-skins into wildly different worlds without
|
|
270
|
+
regenerating anything. The neutral `Biome` enum never changes; a theme just decides how
|
|
271
|
+
each biome looks and is named:
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from mapwright import RegionalSVGRenderer, SettlementSVGRenderer, DungeonSVGRenderer, THEMES
|
|
275
|
+
|
|
276
|
+
svg = RegionalSVGRenderer(theme="neon").render(terrain, markers, roads=roads)
|
|
277
|
+
town = SettlementSVGRenderer(theme="neon").render(settlement) # same theme skins the town
|
|
278
|
+
dgn = DungeonSVGRenderer(theme="blueprint").render(dungeon) # …and the dungeon
|
|
279
|
+
# built-ins: "parchment" (default), "neon" (Tron/digital-grid), "dune" (sand), "blueprint"
|
|
280
|
+
THEMES["neon"].biome_label(Biome.OCEAN) # -> "Void" (the vocabulary layer)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
All three renderers take the same `theme=`, so one theme skins the world map, its towns,
|
|
284
|
+
and its dungeons together (a `Theme` carries nested `SettlementPalette` + `DungeonPalette`,
|
|
285
|
+
importable from `mapwright.themes` for custom packs). A `Theme` is plain hex-string data
|
|
286
|
+
(JSON-friendly), so a host — or the same image service that makes art packs — can author
|
|
287
|
+
new ones. This is the "Dominant Medium" idea from mapwright's longer-term vision: a sand
|
|
288
|
+
planet, a digital grid, and an irradiated waste are the *same map* wearing different skins.
|
|
289
|
+
Pair a theme with a matching `ArtPack` for a full restyle of both the vector and hand-drawn
|
|
290
|
+
renders.
|
|
291
|
+
|
|
235
292
|
## Determinism
|
|
236
293
|
|
|
237
294
|
Every generator draws from a `SeededRNG`. The same seed (and parameters) reproduces an
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Sample art pack (`atlas_pack`)
|
|
2
|
+
|
|
3
|
+
A small **example** art pack for `AtlasRenderer`, used only to render the
|
|
4
|
+
hand-drawn atlas thumbnail in the project README (`docs/gallery/atlas.png`,
|
|
5
|
+
produced by `examples/gallery.py`).
|
|
6
|
+
|
|
7
|
+
- **Provenance:** the symbols were generated by an OpenRouter image model through
|
|
8
|
+
mapwright's companion service (storyflow `media_service`), via
|
|
9
|
+
`scripts/gen_mapwright_pack.py` there. They are original, model-generated art —
|
|
10
|
+
not copied from any third-party asset set.
|
|
11
|
+
- **Scope:** this pack lives under `docs/` and is **not** shipped in the PyPI
|
|
12
|
+
wheel (which packages `src/mapwright/` only). mapwright ships no art; this is a
|
|
13
|
+
demo skin.
|
|
14
|
+
- **Layout:** `manifest.json` maps mapwright's neutral slots
|
|
15
|
+
(`mountain.young`, `tree.pine`, `city.castle`, …) to the PNG variants here.
|
|
16
|
+
See the *Atlas rendering & art packs* section of the top-level README for the
|
|
17
|
+
schema.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "atlas_pack",
|
|
3
|
+
"style": "antique-ink",
|
|
4
|
+
"colors": {
|
|
5
|
+
"parchment": "#ecdfbf",
|
|
6
|
+
"water": "#a9c2cc",
|
|
7
|
+
"coast": "#463c2c",
|
|
8
|
+
"label": "#2b2218"
|
|
9
|
+
},
|
|
10
|
+
"slots": {
|
|
11
|
+
"mountain.young": {
|
|
12
|
+
"files": [
|
|
13
|
+
"mountain_young_1.png",
|
|
14
|
+
"mountain_young_2.png"
|
|
15
|
+
],
|
|
16
|
+
"width": 2.0,
|
|
17
|
+
"anchor": "bottom"
|
|
18
|
+
},
|
|
19
|
+
"mountain.mid": {
|
|
20
|
+
"files": [
|
|
21
|
+
"mountain_mid_1.png"
|
|
22
|
+
],
|
|
23
|
+
"width": 2.0,
|
|
24
|
+
"anchor": "bottom"
|
|
25
|
+
},
|
|
26
|
+
"mountain.old": {
|
|
27
|
+
"files": [
|
|
28
|
+
"mountain_old_1.png",
|
|
29
|
+
"mountain_old_2.png"
|
|
30
|
+
],
|
|
31
|
+
"width": 2.0,
|
|
32
|
+
"anchor": "bottom"
|
|
33
|
+
},
|
|
34
|
+
"hill": {
|
|
35
|
+
"files": [
|
|
36
|
+
"hill_1.png",
|
|
37
|
+
"hill_2.png"
|
|
38
|
+
],
|
|
39
|
+
"width": 1.5,
|
|
40
|
+
"anchor": "bottom"
|
|
41
|
+
},
|
|
42
|
+
"tree.pine": {
|
|
43
|
+
"files": [
|
|
44
|
+
"tree_pine_1.png",
|
|
45
|
+
"tree_pine_2.png"
|
|
46
|
+
],
|
|
47
|
+
"width": 1.0,
|
|
48
|
+
"anchor": "bottom"
|
|
49
|
+
},
|
|
50
|
+
"tree.deciduous": {
|
|
51
|
+
"files": [
|
|
52
|
+
"tree_deciduous_1.png",
|
|
53
|
+
"tree_deciduous_2.png"
|
|
54
|
+
],
|
|
55
|
+
"width": 1.0,
|
|
56
|
+
"anchor": "bottom"
|
|
57
|
+
},
|
|
58
|
+
"tree.cactus": {
|
|
59
|
+
"files": [
|
|
60
|
+
"tree_cactus_1.png"
|
|
61
|
+
],
|
|
62
|
+
"width": 1.0,
|
|
63
|
+
"anchor": "bottom"
|
|
64
|
+
},
|
|
65
|
+
"dune": {
|
|
66
|
+
"files": [
|
|
67
|
+
"dune_1.png"
|
|
68
|
+
],
|
|
69
|
+
"width": 0.9,
|
|
70
|
+
"anchor": "bottom"
|
|
71
|
+
},
|
|
72
|
+
"city.castle": {
|
|
73
|
+
"files": [
|
|
74
|
+
"city_castle_1.png"
|
|
75
|
+
],
|
|
76
|
+
"width": 1.7,
|
|
77
|
+
"anchor": "bottom"
|
|
78
|
+
},
|
|
79
|
+
"city.large": {
|
|
80
|
+
"files": [
|
|
81
|
+
"city_large_1.png"
|
|
82
|
+
],
|
|
83
|
+
"width": 1.7,
|
|
84
|
+
"anchor": "bottom"
|
|
85
|
+
},
|
|
86
|
+
"city.town": {
|
|
87
|
+
"files": [
|
|
88
|
+
"city_town_1.png"
|
|
89
|
+
],
|
|
90
|
+
"width": 1.7,
|
|
91
|
+
"anchor": "bottom"
|
|
92
|
+
},
|
|
93
|
+
"city.village": {
|
|
94
|
+
"files": [
|
|
95
|
+
"city_village_1.png"
|
|
96
|
+
],
|
|
97
|
+
"width": 1.7,
|
|
98
|
+
"anchor": "bottom"
|
|
99
|
+
},
|
|
100
|
+
"decoration.compass": {
|
|
101
|
+
"files": [
|
|
102
|
+
"decoration_compass_1.png"
|
|
103
|
+
],
|
|
104
|
+
"width": 3.0,
|
|
105
|
+
"anchor": "center"
|
|
106
|
+
},
|
|
107
|
+
"decoration.ship": {
|
|
108
|
+
"files": [
|
|
109
|
+
"decoration_ship_1.png"
|
|
110
|
+
],
|
|
111
|
+
"width": 3.0,
|
|
112
|
+
"anchor": "center"
|
|
113
|
+
},
|
|
114
|
+
"decoration.creature": {
|
|
115
|
+
"files": [
|
|
116
|
+
"decoration_creature_1.png"
|
|
117
|
+
],
|
|
118
|
+
"width": 3.0,
|
|
119
|
+
"anchor": "center"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|