Skip to content

About

TypeScript reimplementation of watabou's Medieval Fantasy City Generator

Resources

Stars

8 stars

Watchers

0 watching

Forks

Repository files navigation

SettleMaker

Generate settlement maps. Bring your own world.

Version 4 uses one physical planner for every village and city, with shared rendering, resident accounting and GeoJSON in local metres. The legacy APIs are retired. See the 4.0.0 release notes and migration guide.

SettleMaker is a procedural map engine for Node.js and browsers. Give it a settlement's population, roads, terrain and seed; get an SVG map, local GeoJSON and a model you can inspect. The physical planner combines dispersed village plots and dense city blocks with shared landscape, rendering, resident accounting and GeoJSON in metres. All public generation uses this planner. See the migration guide for the retired API.

The bundled artwork depicts medieval settlements. Portable skins can replace buildings, vegetation, field textures and material colours for your own setting, without forking the engine. Copperline includes industrial, steampunk and modern examples. The city generator builds on watabou's TownGeneratorOS.

Ashford: a generated temperate village with individual homes, roads and fields Thornwall: a generated walled city using the current city artwork

Ashford, population 300, and Thornwall, population 10,000. Both are real generateSettlement outputs, seed 2. Click an image for the full SVG. Explore the gallery and exact inputs.

Install and generate a map

npm install settlemaker

The package uses ES modules and includes TypeScript declarations. Save this as generate.mjs and run node generate.mjs:

import { writeFile } from 'node:fs/promises';
import { generateSettlement } from 'settlemaker';

const burg = {
  name: 'Ashford',
  population: 300,
  biome: 'temperate',
  port: false,
  citadel: false,
  walls: false,
  plaza: true,
  temple: true,
  shanty: false,
  capital: false,
  roadBearings: [
    { bearing_deg: 18, kind: 'main', route_id: 'north-road' },
    { bearing_deg: 142, kind: 'town', route_id: 'south-road' },
    { bearing_deg: 267, kind: 'local', route_id: 'west-road' },
  ],
};

const result = generateSettlement(burg, { seed: 2 });
await writeFile('ashford.svg', result.svg);
await writeFile('ashford.geojson', JSON.stringify(result.geojson, null, 2));
console.log(result.kind); // 'planned'
console.log(result.model.development.preset); // 'village'

For a city of any size, set engine: 'city' on the burg. Set engine: 'village' to keep a large settlement rural. Omitting it retains automatic selection at 1,000 people. walls, citadel, plaza and temple describe requested features; their treatment depends on the planner and available geometry. Use generateSettlement as your normal entry point. planSettlement is an equivalent explicit planning entry point.

CommonJS callers can use await import('settlemaker') inside an async function. In a browser app, import from settlemaker through your bundler, or serve the standalone ESM file node_modules/settlemaker/dist/settlemaker.browser.js yourself. The engine needs no rendering service or runtime artwork downloads.

Node, browser and TypeScript setup

What the engine produces

Output What you can use it for
svg A complete vector map with embedded artwork; display, save or rasterize it.
geojson Buildings, streets, water and shared physical features in local metres, with version and scale metadata. These are not longitude/latitude coordinates.
model A SettlementModel with physical geometry, development settings and resident accounting.
model.degradedFlags Requested features that generation could not place.
model.waterContextResult Diagnostics when using the measured-water contract.

With engine: 'auto' (the default), population 1–1,000 selects the village planner; larger populations select the city planner. Explicit selection removes that boundary. Both layouts return the same physical model and GeoJSON contract in local metres. Use development for explicit density and resident allocation settings.

Layouts and SVGs are repeatable for the same inputs, seed, rendering options and package version. Physical GeoJSON has no changing timestamp. Save the input, seed, package version and any skin alongside output you want to reproduce.

API and input reference · GeoJSON, scale and identity

Biomes, roads and water

The default artwork covers temperate, desert, tundra, tropical and coastal settlements. These select different buildings, vegetation and landscape rules; changing a biome can change the generated layout. A coastal artwork choice alone does not supply a shoreline: provide water geometry or oceanBearing.

Qasra: desert village with native buildings and field textures Snowmere: tundra village with snowy roofs and natural ground Reedbank: tropical village beside a supplied river

Supply every real road approach independently, using clockwise bearings from north. through: true describes a continuing route; it does not create an opposite exit. Use route IDs to retain provenance through shared streets and city gates.

Water can come from filled polygons, village river centrelines, or a generated coast from oceanBearing. Both physical layouts support measured waterContext and polygon/river input in local metres. port requests infrastructure, rather than controlling whether water is visible.

Road and water inputs · Measured-water contract

Shared themes and independent population

Using burg from the first example:

const largeVillage = generateSettlement(
  { ...burg, population: 2000, engine: 'village', biome: 'desert' },
  { seed: 2, theme: 'blueprint' },
);
const smallCity = generateSettlement(
  { ...burg, population: 800, engine: 'city', biome: 'desert' },
  { seed: 2, theme: 'blueprint' },
);

Both planners use the same regional ground, water and material colours. Omit theme for natural biome colours, or choose night, blueprint, parchment, classic, bw, ink, ancient, colour or simple. default is an alias for parchment. Themes recolour the artwork without changing settlement geometry; biomes can change both artwork and planning. Skins replace artwork for your setting.

Make it your own

A skin is a JSON document loaded with createSkin. It can replace exact SVG slots, set material tokens and define named biomes that inherit existing terrain behaviour. Partial skins inherit any artwork they omit.

Using burg from the first example:

import { createSkin } from 'settlemaker';

const skin = createSkin({
  version: 1,
  id: 'moon-glass',
  name: 'Moon Glass',
  tokens: { '--sm-stone': '#badcea' },
  biomes: {
    lunar: {
      base: 'tundra',
      village: { ground: '#68748c' },
      city: { paper: '#68748c' },
    },
  },
});

const moonVillage = generateSettlement(
  { ...burg, biome: 'lunar' },
  { seed: 2, skin },
);
await writeFile('moon-village.svg', moonVillage.svg);

For artwork replacement, SKIN_SLOTS supplies the supported IDs, view boxes, anchors and placement constraints. Skin format 1 exposes 693 runtime slots. The downloadable default artwork contains 852 drawings; catalogue drawings and runtime slots serve different purposes.

Copperline industrial artwork applied to the village engine Copperline steampunk artwork applied to the city engine

Copperline covers all runtime slots and supplies industrial, steampunk and modern presets. Skins change presentation and select an existing biome base; they do not add new planning algorithms, occupancy rules or GeoJSON categories. Some roads, walls and bridges are generated geometry rather than replaceable SVG slots. Read the authoring guide for the supported controls and limits.

Create a skin · JSON schema · Copperline · Artwork catalogue

Choose your integration

Task Guide
Generate and save maps in Node or a browser app Getting started
Understand every input and rendering option Library API
Join features, place output on a map or crop tiles GeoJSON and coordinates
Embed the separately hosted renderer in an iframe URL adapter contract
Render an existing city scene Scene and rendering contract
Draw a complete alternative setting Skin authoring
Build, test or regenerate documentation Development

The npm library runs in your application. The website at settlemaker.com is a separate application with its own deployment cycle. Publishing an npm release does not update that site. The URL codec does not transport skins or fetch arbitrary skin files.

License and attribution

The engine is GPL-3.0-only. See LICENSE and NOTICE for the terms, upstream attribution and dependency notices.

The six default artwork collections are distributed under CC BY 4.0 with a rendered-output exception, described in symbols/LICENSE. Their credits ship with the package. Copperline is GPL-3.0-only and is outside that artwork exception. Keep each collection's terms with redistributed artwork.

About

TypeScript reimplementation of watabou's Medieval Fantasy City Generator

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages