Skip to main content

Domain-neutral procedural fantasy map & world generation: Voronoi terrain, hydraulic erosion, biomes, rivers, Markov place-names, and shaded-relief SVG.

Project description

mapwright

⚠️ Early development (v0.1, alpha). The API is still moving and may change without notice between versions. Extracted from a working application; usable today, but pin a commit if you depend on it.

Domain-neutral procedural fantasy map & world generation — Voronoi terrain with hydraulic erosion, climate-driven biomes, rivers, Markov place-names, and shaded-relief SVG rendering. Pure Python, numpy-only, fully seed-deterministic.

mapwright produces neutral data (cells, biomes, rivers, polygons) and a self-contained SVG renderer. It has no opinion about your application's models — map its output onto your own tiles/entities however you like.

Install

pip install git+https://github.com/sligara7/mapwright.git
# or, for local development:
pip install -e ".[dev]"

Quickstart

from mapwright import SeededRNG, RegionalTerrainGenerator, RegionalSVGRenderer, Marker

# Same seed -> same world, every time.
terrain = RegionalTerrainGenerator(SeededRNG(7)).generate(width=60, height=40)

markers = [Marker(name="Eldmoor", x=30, y=18, kind="settlement_city")]
svg = RegionalSVGRenderer().render(terrain, markers)
open("world.svg", "w").write(svg)

Shape the world with WorldMapConfig — or describe it and let an LLM fill the config:

from mapwright import WorldMapConfig, RegionalTerrainGenerator, SeededRNG

desert = WorldMapConfig.preset("desert")          # ready-made worlds...
custom = WorldMapConfig(continents=7, sea_level=0.55, temperature=-0.8)  # ...or tune
world  = RegionalTerrainGenerator(SeededRNG(1)).generate(60, 40, config=desert)

# Every field is a bounded scalar with a clear meaning, so it doubles as a schema
# a host app (or an LLM) can populate. from_dict clamps junk to valid ranges:
WorldMapConfig.from_dict({"temperature": 5, "continents": -3})  # -> safe, clamped

Presets: continent, pangaea, archipelago, islands, highlands, desert, arctic, tropical.

Procedural place-names in several culture styles:

from mapwright import SeededRNG, NameGenerator

namer = NameGenerator(SeededRNG(7))
namer.settlement("nordic")    # -> 'Eirmundheim'
namer.settlement("elvish")    # -> 'Faelynnwood'
namer.region("dwarvish")      # -> 'The Korvald Reach'

What's inside

Component What it does
SeededRNG One seed drives everything; .derive(label) yields independent, reproducible sub-streams (unifies stdlib + numpy).
NameGenerator Order-k character Markov names over hand-authored culture namebases; reproducible across processes.
RegionalTerrainGenerator Voronoi cells (Lloyd-relaxed) → heightmap → Planchon–Darboux depression fill → flux + hydraulic/creep erosion → rivers → latitude/elevation climate → Whittaker biomes.
compute_cell_polygons Reconstructs convex Voronoi polygons (half-plane clipping) for vector rendering.
RegionalSVGRenderer Shaded-relief (hillshade) SVG: biome polygons, coastline, rivers, labelled markers.
DungeonGenerator BSP-partitioned rooms + minimum-spanning-tree corridors → rooms, corridor cells, and a walkable grid (with Dungeon.ascii()).

Everything is neutral: RegionalTerrainGenerator returns a TerrainResult of TerrainCells (each with a Biome), and you decide how a Biome maps to your world.

Determinism

Every generator draws from a SeededRNG. The same seed (and parameters) reproduces an identical world — terrain, names, rivers, and SVG — across runs and across processes (the Markov chains are built in sorted order, so output never depends on PYTHONHASHSEED).

API stability & contract

The public API is exactly the names exported in mapwright.__all__ — that's the contract. It's pinned by tests/test_api_contract.py (public surface, key signatures), so an accidental breaking change fails CI.

For the world parameters specifically, WorldMapConfig.json_schema() returns a JSON Schema (draft 2020-12) — the machine-readable contract a host app or LLM can validate/generate against, then feed through WorldMapConfig.from_dict() (which clamps to valid ranges). Schema and runtime clamping are generated from the same field spec, so they can't drift.

Versioning follows SemVer. While at 0.x the API may still change between minor versions; every change is recorded in CHANGELOG.md. Pin a tag or commit if you depend on it.

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest

Credits & license

MIT licensed (see LICENSE). Algorithms were implemented clean-room from the publicly described techniques of Azgaar's Fantasy-Map-Generator (MIT) and Martin O'Leary / Ryan L. Guy's FantasyMapGenerator (Zlib); see NOTICE for details. The bundled name lists are original.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mapwright-0.2.0.tar.gz (36.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mapwright-0.2.0-py3-none-any.whl (31.3 kB view details)

Uploaded Python 3

File details

Details for the file mapwright-0.2.0.tar.gz.

File metadata

  • Download URL: mapwright-0.2.0.tar.gz
  • Upload date:
  • Size: 36.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mapwright-0.2.0.tar.gz
Algorithm Hash digest
SHA256 fa2ddf4debfa84971cb8be65058e3381f964ee15aec563df57611d673741f932
MD5 333c73c391428999851cda6c64a38670
BLAKE2b-256 59583a24ba109b6e94b672883257608c45f09ee812b583b62c0b17a821365108

See more details on using hashes here.

Provenance

The following attestation bundles were made for mapwright-0.2.0.tar.gz:

Publisher: publish.yml on sligara7/mapwright

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mapwright-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: mapwright-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 31.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mapwright-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2c9fa17a47a76254968a9f0a62c8d4de6c06145f7fa2177f8ec0eec63b7b279b
MD5 597019421e7a52f78a35b4818d4972fc
BLAKE2b-256 ca020001141b7e4415ae3c1ce352d255e2870f4732a8752c12da77d4241ebe06

See more details on using hashes here.

Provenance

The following attestation bundles were made for mapwright-0.2.0-py3-none-any.whl:

Publisher: publish.yml on sligara7/mapwright

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page