settlemaker 3.0.0 → 3.0.1

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 (55) hide show
  1. package/README.md +162 -277
  2. package/dist/output/geojson-builder.d.ts +1 -1
  3. package/dist/output/geojson-builder.js +1 -1
  4. package/dist/settlemaker.browser.js +1 -1
  5. package/docs/README.md +54 -0
  6. package/docs/api.md +175 -0
  7. package/docs/artwork-integration.md +104 -0
  8. package/docs/current-symbol-library.md +62 -42
  9. package/docs/development.md +102 -0
  10. package/docs/examples/gallery/coastal-city.png +0 -0
  11. package/docs/examples/gallery/coastal-city.svg +4253 -0
  12. package/docs/examples/gallery/coastal-village.png +0 -0
  13. package/docs/examples/gallery/coastal-village.svg +1211 -0
  14. package/docs/examples/gallery/copperline-city.png +0 -0
  15. package/docs/examples/gallery/copperline-city.svg +1139 -0
  16. package/docs/examples/gallery/copperline-village.png +0 -0
  17. package/docs/examples/gallery/copperline-village.svg +2382 -0
  18. package/docs/examples/gallery/desert-city.png +0 -0
  19. package/docs/examples/gallery/desert-city.svg +3509 -0
  20. package/docs/examples/gallery/desert-village.png +0 -0
  21. package/docs/examples/gallery/desert-village.svg +455 -0
  22. package/docs/examples/gallery/fixtures.json +449 -0
  23. package/docs/examples/gallery/temperate-city-night.png +0 -0
  24. package/docs/examples/gallery/temperate-city-night.svg +3511 -0
  25. package/docs/examples/gallery/temperate-city.png +0 -0
  26. package/docs/examples/gallery/temperate-city.svg +3511 -0
  27. package/docs/examples/gallery/temperate-village.png +0 -0
  28. package/docs/examples/gallery/temperate-village.svg +3227 -0
  29. package/docs/examples/gallery/tropical-city.png +0 -0
  30. package/docs/examples/gallery/tropical-city.svg +3508 -0
  31. package/docs/examples/gallery/tropical-village.png +0 -0
  32. package/docs/examples/gallery/tropical-village.svg +3761 -0
  33. package/docs/examples/gallery/tundra-city.png +0 -0
  34. package/docs/examples/gallery/tundra-city.svg +3509 -0
  35. package/docs/examples/gallery/tundra-village.png +0 -0
  36. package/docs/examples/gallery/tundra-village.svg +1549 -0
  37. package/docs/fmg-embed-zoom.md +54 -0
  38. package/docs/gallery.md +139 -0
  39. package/docs/geojson.md +188 -0
  40. package/docs/getting-started.md +157 -0
  41. package/docs/landscape-character-review.md +55 -0
  42. package/docs/releases/3.0.1.md +18 -0
  43. package/docs/scene-schema.md +160 -0
  44. package/docs/schema-v3.md +38 -0
  45. package/docs/skins.md +52 -0
  46. package/docs/test-urls.md +39 -0
  47. package/docs/url-api.md +252 -0
  48. package/docs/water-context-v1.md +384 -0
  49. package/package.json +15 -8
  50. package/scripts/check-docs.mjs +106 -0
  51. package/scripts/generate-copperline.mjs +255 -0
  52. package/scripts/generate-examples.mjs +54 -0
  53. package/scripts/render-copperline.mjs +36 -0
  54. package/src/output/geojson-builder.ts +1 -1
  55. package/symbols/copperline/README.md +10 -3
@@ -0,0 +1,54 @@
1
+ # Embedding and zoom
2
+
3
+ This is guidance for an application hosting the [URL renderer](url-api.md), not
4
+ an API for controlling a cross-origin iframe after loading it. The npm package
5
+ generates SVG; the host page supplies layout, zoom, downloads and diagnostics.
6
+
7
+ ## Responsive preview
8
+
9
+ Put the map in a viewport-sized container and scale the SVG with CSS using its
10
+ `viewBox`. City and village roots need not have identical size attributes. Size
11
+ the displayed element explicitly rather than assuming that generated width and
12
+ height attributes alone implement a responsive layout.
13
+
14
+ ```css
15
+ html, body, #map { margin: 0; width: 100%; height: 100%; }
16
+ #map svg { display: block; width: 100%; height: 100%; }
17
+ ```
18
+
19
+ Keep the full view box as the initial fit if the preview is intended to show the
20
+ entire settlement and its surrounding terrain. Cropping the frame is a host
21
+ presentation decision; it changes what is visible, not the generated settlement.
22
+ There is no `fit=cover` URL parameter in the current library parser.
23
+
24
+ ## Host-owned navigation
25
+
26
+ A parent page can pan a larger iframe inside an overflow-hidden container. If it
27
+ uses layout resizing for zoom, the renderer should remain responsive to viewport
28
+ changes without regenerating the settlement. Regeneration on each resize can
29
+ block interaction and does not belong in zoom handling.
30
+
31
+ A host using its own SVG DOM can implement local pan/zoom directly. A cross-origin
32
+ iframe does not expose that DOM to its parent. This contract defines no
33
+ `postMessage` zoom, result, or automatic water-resurvey messages. Specific zoom
34
+ limits and input gestures are application choices, not engine guarantees.
35
+
36
+ ## Diagnostics remain visible
37
+
38
+ A renderer must show parse/generation errors and measured-water warnings within
39
+ the page. Some embedded previews disable pointer events, so explanations must be
40
+ readable without hovering or clicking. Do not replace a failed measured-water map
41
+ with a plain dry map. Include required survey coverage when an error supplies it.
42
+
43
+ Map navigation and diagnostics need deliberate layout: a warning should remain
44
+ readable at the initial fit rather than being reduced to an unreadable part of a
45
+ zoomed map. The older expectation of an SVG-only page does not override the
46
+ measured-water diagnostic requirements.
47
+
48
+ ## Multiple maps and tiles
49
+
50
+ Use separate image/iframe documents for independent maps. Inline SVGs can share
51
+ conflicting IDs even with different city `clipId` options. See the
52
+ [SVG embedding rules](scene-schema.md#embedding-svg) and
53
+ [local tile helpers](geojson.md#tiling). Preserve `data-bg="paper"` and village
54
+ scale metadata when post-processing output for those helpers.
@@ -0,0 +1,139 @@
1
+ # Gallery
2
+
3
+ These maps were generated with SettleMaker 3.0.1 through the public
4
+ `generateSettlement` API. PNG previews and full SVGs come from the same output.
5
+ The gallery covers all five built-in artwork biomes in both engines, plus Copperline.
6
+
7
+ [Exact inputs and seeds](examples/gallery/fixtures.json) · [Regenerate the gallery](development.md#documentation-checks)
8
+
9
+ Hosted preview links carry the saved inputs; the website's deployed generator may
10
+ differ from this package version. Skins are loaded by the library API, so the
11
+ Copperline examples link to their SVGs rather than an unsupported skin URL.
12
+
13
+ ## Ashford — temperate village
14
+
15
+ Roads, individual homes, a green and cultivated fields.
16
+
17
+ Population **300** · seed **2** · engine **village**
18
+
19
+ [![Ashford — temperate village](examples/gallery/temperate-village.png)](examples/gallery/temperate-village.svg)
20
+
21
+ [Full SVG](examples/gallery/temperate-village.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZDLasMwEEX_5a5VSNzSBO3a3yghTKJJLCpLQhrXtCb_3nEeDg10pyvuORrNiC_YpcGuL0fYETkVgT1QqGyw90KOw5wHCqHOKQf6IVgpvQbhLge-pdpSlO-7h7Ka7p6SyL0zFR-PqvsYsbuErWMdYrk2-PTRwaIjHzH1e-Gtn26iztc-TQKczCP40sykpOGBrHr8j2xeVzMZ0l5H_YMOXOVKbgwidfpRvNX2kIrTZk65DyQ-RdjnxUKX6dO5Mi2FCwnri6jM6mpOvw)
22
+
23
+ ## Thornwall — walled city
24
+
25
+ Native city buildings, denser central wards, greener outskirts and defensive walls.
26
+
27
+ Population **10000** · seed **2** · engine **settlement**
28
+
29
+ [![Thornwall — walled city](examples/gallery/temperate-city.png)](examples/gallery/temperate-city.svg)
30
+
31
+ [Full SVG](examples/gallery/temperate-city.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZDBasMwEET_Zc4qNKakRcd-Q24hmE28jUVkSUjrmNbk37tqa5cGqpNGzJsd7Ywr7MbgOOYz7IwUs8C-kS9scHJCHXtYyaPKibwvi0iePmgRwkPyvKjSU5D33xRKmrOm5EjdK1N24axh-xnHb9F2rA02LwYXFzpYDOQCqn8Ubl19CVquf6gBuJl78KlZSYnTHVn0-h_ZbJ9X0seTNv2DTlzkhzwYBBr0n9j1MYe6D_WmmEZP4mLQFo96dJsuftnqXjiTsE5FYda85vYJ)
32
+
33
+ ## Qasra — desert village
34
+
35
+ Desert buildings, sparse vegetation and irrigated field textures.
36
+
37
+ Population **300** · seed **2** · engine **village**
38
+
39
+ [![Qasra — desert village](examples/gallery/desert-village.png)](examples/gallery/desert-village.svg)
40
+
41
+ [Full SVG](examples/gallery/desert-village.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZDBasMwEET_Zc4KJE5oi479g55LMJtom4jKkpDWNa3xv3fdJg4N9KYR84bZGfEBuzE49OUEOyKnIrBvFCobHL2Q47DogUKoi8qBvghWSq9CuMuBr6qeKcrnLYeyJt1ySiL3zFR8PGnc64jDr2gda4nNk8G7jw4WHfmI2d8Lt37-idrvvJoDMJl7cNcspKThjqz6_I9sHh4XMqSjVv2DDlzlQu4NInV6KF6oFlJfTrkPJD5F2O16rVP69GNwXFnHnHQOZo1ppm8)
42
+
43
+ ## Qasr — desert city
44
+
45
+ Urban desert architecture, religious buildings and courtyards.
46
+
47
+ Population **10000** · seed **2** · engine **settlement**
48
+
49
+ [![Qasr — desert city](examples/gallery/desert-city.png)](examples/gallery/desert-city.svg)
50
+
51
+ [Full SVG](examples/gallery/desert-city.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZBRi8IwEIT_yz5HOIt4kkf_gc8iZTV7GtwmIdlatPS_u7279jjBPGXCfMNkeriBXRo4tvkMtocUs4D9Qi5k4OQFHTFYya3KDpnLJBLjAych1CSmSZULBrn_pWDSHJ51jui2hNmHs6btezj-iNqRVlhuDFx9cGChQR9g9LdCtR9fgra7LMYAGMwruKpmUmL3Qha9viOr9edMcjxp1X9oR0V-yYOBgI1-FHZYstpSTC2j-Bi0wIceXdLHb4ejQrrloHsQaU41PAE)
52
+
53
+ ## Snowmere — tundra village
54
+
55
+ Snowy dwellings and low tundra vegetation with natural ground instead of arable fields.
56
+
57
+ Population **300** · seed **2** · engine **village**
58
+
59
+ [![Snowmere — tundra village](examples/gallery/tundra-village.png)](examples/gallery/tundra-village.svg)
60
+
61
+ [Full SVG](examples/gallery/tundra-village.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZDRTgIxEEX_5T7XBFaDpo_8go_GkIGO0NBtm3bqRjb8u7OgSyTxrbe553SmIz5hlwbbVvawI3IqAvtBobLBzgs5DnMeKIQ6pxzoRLBSmgbhPgf-TfVAUb5uHspqunlKIrdmKj7uVfc2YnsNG8c6xPLF4Oijg0VPPmLqN-GNn26iznd4mAQ4m3vwqZtJScMdWfX4H9mtnmcypJ2O-gcduMoP-W4QqddF8RrT0HNhreaUWyDxKcI-Lhb6mz5dOtKiK6TvoTKrqTt_Aw)
62
+
63
+ ## Frosthold — tundra city
64
+
65
+ Northern roofs, fortifications and biome-specific ground.
66
+
67
+ Population **10000** · seed **2** · engine **settlement**
68
+
69
+ [![Frosthold — tundra city](examples/gallery/tundra-city.png)](examples/gallery/tundra-city.svg)
70
+
71
+ [Full SVG](examples/gallery/tundra-city.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZDRTsMwDEX_xc9BYhUClEce-AmEJm_x1gg3jhKHCqr9O-6gnTaJPOVEPjc3meAT_MbBrpUj-AmyFAV_QK7kYB8VAzF4Lc1wROa6QGb8xgWUhsy0UO0x6dclBbPl8MpFMLwQlpiOlvY2we4XtoGswubZwUdMATwMGBPM801pG-eTZO36uzkATu5WfOhWU2W8Matt_zO7x6fVZNlb1St1pKp_5ruDhIM9FF6LVO2Fg81myY1RoyRrcW_LvjPKeUxbCgXtSqhEFtadfgA)
72
+
73
+ ## Reedbank — tropical river village
74
+
75
+ A supplied river enables tropical paddy selection; fields follow real parcels.
76
+
77
+ Population **300** · seed **2** · engine **village**
78
+
79
+ [![Reedbank — tropical river village](examples/gallery/tropical-village.png)](examples/gallery/tropical-village.svg)
80
+
81
+ [Full SVG](examples/gallery/tropical-village.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZBBT8MwDIX_i8-d1A0YkCP3XbiiaXIbs1pLkyhxV6Dqf8fdRgeTuPlZ_p6fPcARzLKAqkt7MAPEkATMO7pMBdQsaMnNukfn8qyiwy8EI6lTIdRGRz8qN-jl8-qDUZ2uPimgfSFM7Pdq9zZAdRY7Sxpi-VTAgb0FAy2yh2m-E9rx1PGar1lMBjAWt-D9aiYl9Ddk1vI_crV-nEkXao36B-0py4XcFuCx1UPhlchW6A86GkPsHAoHD-auLPWbHE4zkkLkix0fKZ2vrclLIseeTvIDzOJhovRhz-WUTTu_GrqyZyvNBsx63I76Xd2smcdv)
82
+
83
+ ## Palmreach — tropical city
84
+
85
+ Tropical architecture and vegetation in the city engine.
86
+
87
+ Population **10000** · seed **2** · engine **settlement**
88
+
89
+ [![Palmreach — tropical city](examples/gallery/tropical-city.png)](examples/gallery/tropical-city.svg)
90
+
91
+ [Full SVG](examples/gallery/tropical-city.svg) · [Hosted preview](https://settlemaker.com/fmg?i=dZDRisIwEEX_ZZ4jaBGVPPoFvouUsZ21wWkSkqllt_Tfne5uu6xgnnLDnMPNDPAAuzFw7dIN7AAxJAH7gZzJQOUEa2KwkjqNPTLnOUTGL5yDUBuZ5pQb9PL5Z8GoHl5yClgfCZPzN7WdB7j-hLImrbA5GLg7X4OFFp2Hab4TKt304rVds5oEMJpXcFsspIT-hcx6fUcWu_1Ccqi06j-0pyy_5MWAx1Y_CifkNhFWjc7GEDtGccFri7UeXacL32OSQnSTcdS1EKmuGJ8)
92
+
93
+ ## Dunewick — coastal village
94
+
95
+ A generated coast from oceanBearing, with coastal buildings and vegetation.
96
+
97
+ Population **300** · seed **2** · engine **village**
98
+
99
+ [![Dunewick — coastal village](examples/gallery/coastal-village.png)](examples/gallery/coastal-village.svg)
100
+
101
+ [Full SVG](examples/gallery/coastal-village.svg) · [Hosted preview](https://settlemaker.com/fmg?i=XY_RbsIwDEX_xc9Bapn2sDyi_cU0ITfxICLEUepQbVX_fW6BIng8lu_x9QgXsK2BrpYD2BEyFwH7g7EnAy4IeoorDxhjv1KO-IdgpVQFoXOOdKf-iEl-Hx7Manp4CqPfEZaQDqr7GqG7wt6Tlti2jYFTSB4sCA8J5kAV2od54hh72cwGmMxL8q19X5ORnV58ivqaaJNRjjB9G0h41r7wqcMhuJOuZs41ogROqmq0RBd42VluLjZ2hOlWHexHM-mvRCrfTv8)
102
+
103
+ ## Saltmouth — port city
104
+
105
+ Port infrastructure beside a generated coastline. This is a bearing-based coast, not a measured survey.
106
+
107
+ Population **12000** · seed **2** · engine **settlement**
108
+
109
+ [![Saltmouth — port city](examples/gallery/coastal-city.png)](examples/gallery/coastal-city.svg)
110
+
111
+ [Full SVG](examples/gallery/coastal-city.svg) · [Hosted preview](https://settlemaker.com/fmg?i=RY69DsIwDITfxXOGUCYy8godEYNpTRvJjaP8gGjVd8dFFMY7n7-7BR7gDgZuNQ3gFoiSCriSKhnofMGeGNwdOat-InPej5Fxxl0UmiLTrvKIobx-bx1GBf0xSbA_EyYfBqVdGmvN0dqrgYCTMqBFLpPUMoK2SKyMxUvQlZq0utTLJ9YJ5g1rYMR0k5paP28-YxpIXekIw7cH3MmuOoyoB9esbw)
112
+
113
+ ## Copperline — industrial village
114
+
115
+ The same village planner with a complete replacement skin and industrial artwork.
116
+
117
+ Population **250** · seed **2** · engine **village**
118
+
119
+ [![Copperline — industrial village](examples/gallery/copperline-village.png)](examples/gallery/copperline-village.svg)
120
+
121
+ [Full SVG](examples/gallery/copperline-village.svg) · [Skin JSON](examples/copperline.skin.json)
122
+
123
+ ## Brassworks — steampunk city
124
+
125
+ Copperline machinery and brass materials on the existing city layout and semantic feature types.
126
+
127
+ Population **2000** · seed **2** · engine **settlement**
128
+
129
+ [![Brassworks — steampunk city](examples/gallery/copperline-city.png)](examples/gallery/copperline-city.svg)
130
+
131
+ [Full SVG](examples/gallery/copperline-city.svg) · [Skin JSON](examples/copperline.skin.json)
132
+
133
+ ## One layout, another palette
134
+
135
+ Thornwall with the same inputs and seed, using `svg.palette: PALETTES.night`.
136
+ City palettes alter presentation; they do not replace all native material tokens.
137
+ Use a skin for complete artwork and material control.
138
+
139
+ [![Thornwall with the night palette](examples/gallery/temperate-city-night.png)](examples/gallery/temperate-city-night.svg)
@@ -0,0 +1,188 @@
1
+ # GeoJSON, coordinates and identity
2
+
3
+ Both planners return a `FeatureCollection` with a top-level `metadata` foreign
4
+ member. The current `metadata.schema_version` is **4**. Filter features by
5
+ `properties.layer`, then inspect the geometry type and the fields for that engine.
6
+ Do not assume that sharing a schema number makes the two planners interchangeable
7
+ at the individual property level.
8
+
9
+ The return type is the standard GeoJSON `FeatureCollection` type. It does not
10
+ expose every engine-specific foreign member statically. Applications reading
11
+ metadata from external files should validate it before use; the tables below
12
+ describe the generated data.
13
+
14
+ ## Coordinate frames
15
+
16
+ | Property | Village | City |
17
+ | --- | --- | --- |
18
+ | `metadata.coordinate_system` | `burg_local_y_down` | `local_origin_y_down` |
19
+ | `metadata.coordinate_units` | `metres` | `settlement_units` |
20
+ | Origin | Original burg position | Local output frame; may include the coastal translation |
21
+ | Axes | x east, y south | x right/east, y down/south |
22
+ | `scale.meters_per_unit` | 1 | Population-based estimate |
23
+ | `scale.source` | `village_metres` | `population_heuristic_v1` |
24
+ | `local_origin_shift` | `{dx: 0, dy: 0, source: 'none'}` | Actual translation and reason |
25
+
26
+ These are **local planar coordinates**, not WGS84 longitude and latitude. A GIS
27
+ or map library expecting geographic GeoJSON needs an explicit placement transform.
28
+ Do not feed them directly into a geographic map and expect correct placement.
29
+ The city scale is an estimate, not a physical survey. This is why measured
30
+ `waterContext` is currently restricted to the village planner.
31
+
32
+ `metadata.local_bounds` has `min_x`, `min_y`, `max_x`, `max_y`. For villages this is
33
+ the drawn tile frame in metres. Village SVG coordinates are translated and scaled
34
+ for display; the root's `data-px-per-metre` records that scale. In particular,
35
+ changing `village.pxPerMetre` does not change GeoJSON coordinates.
36
+
37
+ ## Shared metadata
38
+
39
+ | Key | Meaning |
40
+ | --- | --- |
41
+ | `schema_version` | Output structure version, currently 4. |
42
+ | `settlemaker_version` | Package/generator version. Record it with saved maps. |
43
+ | `settlement_generation_version` | City input hash or the village marker `'village'`; not a complete cache key. |
44
+ | `generated_at` | Generation timestamp; differs between otherwise identical runs. |
45
+ | `local_bounds` | Local output extent. |
46
+ | `scale` | `meters_per_unit`, `diameter_meters`, `diameter_local`, `source`. Diameter describes settlement scale, not necessarily the full surrounding frame. |
47
+ | `stable_ids` | Engine-specific ID hints; treat actual IDs as opaque strings. |
48
+ | `poi_density` | `'hamlet'` or `'town'` POI regime. This is not the village/city planner discriminator. |
49
+ | `degraded_flags` | Dropped city walls/citadel requests; empty for villages. |
50
+ | `local_origin_shift` | Output translation. Do not apply it again to already generated output. |
51
+
52
+ City outputs above population 1,000 also carry `building_capacity`:
53
+ `basis: 'ordinary-building-budget'`, `target`, `placed`, `shortfall`, `corePlaced`,
54
+ `outerPlaced`, and `status: 'met' | 'shortfall'`. `corePlaced + outerPlaced = placed`;
55
+ `shortfall = max(0, target - placed)`. These are ordinary-building counts, not a
56
+ certified housed population. The same object is available through
57
+ `Model.getBuildingCapacity()` and `Scene.buildingCapacity`.
58
+
59
+ Village metadata adds `contract_radius_m`, `green_relation`, optional `outline_m`
60
+ and `diagnostics`. The contract circle locates supplied approaches, while
61
+ `local_bounds` describes the drawn frame; they are different extents. Measured
62
+ water diagnostics are returned as `result.waterContextResult` and on the village
63
+ site. Do not assume there is an equivalent top-level GeoJSON field.
64
+
65
+ ## City features
66
+
67
+ | `layer` | Geometry | Selected properties |
68
+ | --- | --- | --- |
69
+ | `ward` | Polygon | `wardType` |
70
+ | `building` | Polygon | `building_id`, `wardType` |
71
+ | `street` | LineString | `street_id`, `streetType` (`artery`, `road`, `alley`, `park`), optional `width` |
72
+ | `green` | Polygon | `kind: 'garden'`, `wardType` |
73
+ | `water` | Polygon / MultiPolygon | Water geometry; inspect the emitted geometry type. |
74
+ | `wall` | LineString | `wallType` |
75
+ | `tower` | Point | `wallType` |
76
+ | `entrance` | Point | `entrance_id`, gate type, bearings and matched route information |
77
+ | `pier` | Polygon | `wardType` |
78
+ | `poi` | Point | `poi_id`, `kind`, `ward_type`, `building_id` |
79
+
80
+ City POIs may be attached to an ordinary building, or float at a placed well,
81
+ market, mill or pier. Those floating kinds use `building_id: null`; other adopted
82
+ POIs have a building ID. Ward labels describe attribution, not a guarantee that
83
+ the feature lies inside the corresponding ward polygon. The engine does not
84
+ supply narrative names for streets or POIs.
85
+
86
+ City bridge rendering information is available in `Scene.layers.bridges`;
87
+ there is no matching promise that city GeoJSON contains village-style `crossing`
88
+ features. Likewise, city park/field/vegetation rendering is richer than the
89
+ selected GeoJSON layers above; use the scene when reproducing city presentation.
90
+
91
+ ## Village features
92
+
93
+ | `layer` | Geometry | Selected properties |
94
+ | --- | --- | --- |
95
+ | `building` | Polygon | `building_id`, `lot_id`, `glyph`, `occupancy`, `bearing_deg` |
96
+ | `street` | LineString | `street_id`, `streetType`, widths, setback, optional route provenance and role |
97
+ | `green` | Point | `shape`, `variant`, `diameter_m`, `bearing_deg`, `relation`, optional `outline_m` |
98
+ | `field` | Polygon | `field_id`, `glyph`, `furrow_bearing_deg` |
99
+ | `water` | Polygon | `water_id`; interior rings preserve land islands when present |
100
+ | `crossing` | Point | `crossing_id`, `street_id`, `span_m`, `bearing_deg`, `narrow`, optional deck and centreline |
101
+ | `wall` | LineString | `wall_id`, `wallType: 'village_wall'`, `material` |
102
+ | `gate` | Point | `gate_id`, `route_ids` |
103
+ | `junction` | Point | `junction_id`, `street_ids` |
104
+ | `poi` | Point | `poi_id`, `kind`, `glyph`, `bearing_deg` |
105
+
106
+ Village POIs do not carry the city POI `building_id`/`ward_type` contract. A village
107
+ green is a Point plus shape data, whereas a city garden is a Polygon. Village
108
+ wall openings are `gate` features, not city `entrance` features. Consumers must
109
+ branch where these differences matter.
110
+
111
+ ### Village road cross-sections
112
+
113
+ | Property | Meaning in metres |
114
+ | --- | --- |
115
+ | `width_m` | Reserved road corridor. |
116
+ | `surface_width_m` | Painted travelled surface. |
117
+ | `setback_m` | Additional distance from corridor edge to parcel frontage. |
118
+ | `surface_clip_m` | Optional polygon limiting paint at a width transition. |
119
+
120
+ The frontage offset from the centreline is `width_m / 2 + setback_m`. A surface
121
+ width is not a parcel reservation. `route_role` can be `approach`, `street` or
122
+ `through`; `streetType` describes the drawn segment's class, which may differ
123
+ from the incoming route class. `route_ids` carries provenance on shared or
124
+ continuing streets. Optional `parent_street_id` records the model's parent lane.
125
+
126
+ Street LineStrings stay continuous for connectivity. To reproduce the map's
127
+ surfaces, clip road paint out of water and apply any `surface_clip_m`. Render
128
+ short bridge decks separately using crossing `deck_m` and `centreline_m` where
129
+ present and `narrow` is true. A continuous line through water alone is not a
130
+ bridge surface. Decks include dry abutments; do not use the Point feature as the
131
+ entire deck geometry.
132
+
133
+ ## IDs and persistence
134
+
135
+ Every street feature has its own `street_id`. A supplied route ID can appear on
136
+ multiple approach/continuation features; it identifies external provenance, not
137
+ a unique generated street. Village junctions name the participating street IDs.
138
+ City gate features echo matched input routes in `matched_route_id` and, where
139
+ present, `matched_route_ids`.
140
+
141
+ Do not parse prefixes to discover geometry or engine type. City IDs are allocated
142
+ with prefixes such as `b`, `s`, `p`, `g`; village IDs use their own content-derived
143
+ forms. IDs repeat for identical inputs within a generator version, but are not
144
+ promised stable across releases. Persist user annotations with the generating
145
+ configuration and have a migration strategy if you regenerate after an upgrade.
146
+
147
+ Skins retain semantic IDs and categories. A Copperline power-station drawing can
148
+ occupy a religious-building slot; it does not turn the GeoJSON kind into a new
149
+ industrial feature taxonomy. Store the requested skin and biome separately.
150
+
151
+ ## Tiling
152
+
153
+ The package crops an SVG into a local square tile pyramid. It does not assign
154
+ geographic web-map coordinates or rasterize PNG tiles for you. Starting with a
155
+ `result` and its original `burg`:
156
+
157
+ ```js
158
+ import {
159
+ parseSvgViewBox, declaredMetersPerUnit, computeTileInfo, cropSvgToTile,
160
+ } from 'settlemaker';
161
+
162
+ const viewBox = parseSvgViewBox(result.svg);
163
+ if (!viewBox) throw new Error('SVG has no usable viewBox');
164
+ const tileInfo = computeTileInfo(
165
+ viewBox,
166
+ burg.population,
167
+ declaredMetersPerUnit(result.svg),
168
+ );
169
+ const rootTileSvg = cropSvgToTile(result.svg, tileInfo, 0, 0, 0);
170
+ ```
171
+
172
+ `declaredMetersPerUnit` reads village SVG scale so the tile helper does not
173
+ substitute its population heuristic. City SVGs use the helper's scale estimate
174
+ when no explicit override is supplied. Preserve `data-bg="paper"` if you
175
+ post-process a generated SVG: the cropper uses that rectangle to extend the
176
+ background to the tile bounds.
177
+
178
+ Use `enumerateTiles(tileInfo.maxZoom)` or `totalTileCount` to plan the pyramid,
179
+ and a rasterizer such as your application's SVG image pipeline if you need PNGs.
180
+ Keep your host-map placement transform separate from this local z/x/y scheme.
181
+
182
+ ## Version handling
183
+
184
+ Check `metadata.schema_version === 4` for this contract, and tolerate optional
185
+ fields and unfamiliar layers that your application does not use. A future
186
+ breaking structure change needs a new schema version. Additive artwork or road
187
+ fields need not change that number. The old [schema-v3 note](schema-v3.md) is a
188
+ historical migration record, not the schema check for current output.
@@ -0,0 +1,157 @@
1
+ # Getting started
2
+
3
+ SettleMaker is an ES module library. The examples here use Node 24, the runtime
4
+ used to validate the 3.0.x npm release. A source checkout also includes an optional
5
+ Nix development shell; Nix is not required to install or use the npm package.
6
+
7
+ ## Node.js
8
+
9
+ ```sh
10
+ mkdir my-settlements
11
+ cd my-settlements
12
+ npm init -y
13
+ npm install settlemaker
14
+ ```
15
+
16
+ Save the following as `generate.mjs`. The `.mjs` extension enables ESM without
17
+ changing your project's package settings; alternatively use `.js` and set
18
+ `"type": "module"` in your package.json.
19
+
20
+ ```js
21
+ import { writeFile } from 'node:fs/promises';
22
+ import { generateSettlement } from 'settlemaker';
23
+
24
+ const burg = {
25
+ name: 'Thornwall', population: 5000, biome: 'temperate',
26
+ port: false, citadel: true, walls: true, plaza: true,
27
+ temple: true, shanty: false, capital: false,
28
+ roadBearings: [20, 145, 270],
29
+ };
30
+ const result = generateSettlement(burg, { seed: 42 });
31
+ await writeFile('thornwall.svg', result.svg);
32
+ await writeFile('thornwall.geojson', JSON.stringify(result.geojson, null, 2));
33
+ console.log(result.kind, result.degradedFlags);
34
+ ```
35
+
36
+ ```sh
37
+ node generate.mjs
38
+ ```
39
+
40
+ Open the SVG in a browser or vector editor. Generation is synchronous; it can take
41
+ noticeable time for large inputs. In an interactive app, run expensive generation
42
+ in a worker so it does not block the UI. There is no asynchronous generator or
43
+ cancellation API in this release.
44
+
45
+ For CommonJS, load the ESM package from an async function:
46
+
47
+ ```js
48
+ async function main() {
49
+ const { generateSettlement } = await import('settlemaker');
50
+ // Call generateSettlement with the complete burg object shown above.
51
+ console.log(typeof generateSettlement);
52
+ }
53
+ main().catch(console.error);
54
+ ```
55
+
56
+ ## TypeScript
57
+
58
+ Declarations are included, and `@types/geojson` is installed transitively.
59
+ For Node ESM projects, use `module: "NodeNext"` and `moduleResolution: "NodeNext"`,
60
+ with a modern target and the `DOM` library if you explicitly configure `lib`:
61
+ URL helpers use Web Platform types. Install `@types/node` in your own project
62
+ when your code imports Node built-ins.
63
+
64
+ ```ts
65
+ import { generateSettlement, type AzgaarBurgInput } from 'settlemaker';
66
+
67
+ const burg: AzgaarBurgInput = {
68
+ name: 'Ashford', population: 300,
69
+ port: false, citadel: false, walls: false, plaza: true,
70
+ temple: true, shanty: false, capital: false,
71
+ };
72
+ const result = generateSettlement(burg, { seed: 2 });
73
+ if (result.kind === 'village') {
74
+ console.log(result.model.buildings.length); // VillageModel
75
+ } else {
76
+ console.log(result.model.patches.length); // city Model
77
+ }
78
+ ```
79
+
80
+ `GenerationParams` is an interface, not a constructor. For the city pipeline use
81
+ `mapToGenerationParams(burg, seed)` before `new Model(params).generate()`.
82
+ See [lower-level rendering](scene-schema.md#render-an-existing-city-model).
83
+
84
+ ## Browser applications
85
+
86
+ With a bundler, use the same package import as Node:
87
+
88
+ ```js
89
+ import { generateSettlement } from 'settlemaker';
90
+ ```
91
+
92
+ For a page without a bundler, copy
93
+ `node_modules/settlemaker/dist/settlemaker.browser.js` into an asset directory
94
+ served by your application. This standalone ESM bundle includes the runtime
95
+ code and default artwork; it does not fetch SVG files during generation.
96
+
97
+ ```html
98
+ <!doctype html>
99
+ <html lang="en">
100
+ <meta charset="utf-8">
101
+ <title>My settlement</title>
102
+ <style>#map svg { display: block; width: 100%; height: auto; }</style>
103
+ <div id="map"></div>
104
+ <script type="module">
105
+ import { generateSettlement } from './assets/settlemaker.browser.js';
106
+ const result = generateSettlement({
107
+ name: 'Ashford', population: 300, biome: 'temperate',
108
+ port: false, citadel: false, walls: false, plaza: true,
109
+ temple: true, shanty: false, capital: false,
110
+ roadBearings: [18, 142, 267],
111
+ }, { seed: 2 });
112
+ document.querySelector('#map').innerHTML = result.svg;
113
+ </script>
114
+ </html>
115
+ ```
116
+
117
+ Serve the page over HTTP during development. Use a separate image document or
118
+ iframe for each map when displaying several maps: generated SVGs contain IDs
119
+ that can collide if multiple copies are inserted into the same DOM. See
120
+ [SVG embedding](scene-schema.md#embedding-svg).
121
+
122
+ ## Load a portable skin
123
+
124
+ In Node, resolve the example distributed inside the installed package:
125
+
126
+ ```js
127
+ import { readFile } from 'node:fs/promises';
128
+ import { createSkin, generateSettlement } from 'settlemaker';
129
+
130
+ const definitionUrl = import.meta.resolve('settlemaker/docs/examples/copperline.skin.json');
131
+ const definition = JSON.parse(await readFile(new URL(definitionUrl), 'utf8'));
132
+ const skin = createSkin(definition);
133
+ const result = generateSettlement({
134
+ name: 'Brassworks', population: 2000, biome: 'steampunk',
135
+ port: false, citadel: false, walls: false, plaza: true,
136
+ temple: true, shanty: false, capital: false,
137
+ roadBearings: [20, 145, 270],
138
+ }, { seed: 42, skin });
139
+ console.log(result.kind, result.svg.length);
140
+ ```
141
+
142
+ In a browser, host a skin JSON file with your application, fetch it, check the
143
+ response and pass its parsed JSON to `createSkin`. Create the runtime handle with
144
+ the same loaded module instance that performs generation. To transfer a skin to
145
+ a worker or save it, transfer the definition JSON and load it there; do not
146
+ serialize or move the runtime handle between independently loaded bundles.
147
+
148
+ ## Save and reproduce
149
+
150
+ Store the complete burg input, explicit seed, package version, rendering options
151
+ and skin definition/version. The same configuration reproduces the geometry and
152
+ SVG within a package version. Geometry and feature IDs may change on upgrades.
153
+ GeoJSON includes a creation timestamp, so complete JSON strings will differ even
154
+ when the geometry is identical. The city-only `geojson.generatedAt` option can
155
+ fix that timestamp; the village generator has no corresponding option.
156
+
157
+ [Full API](api.md) · [Output coordinates](geojson.md) · [Skin authoring](skins.md)
@@ -0,0 +1,55 @@
1
+ # Landscape character review
2
+
3
+ Historical review of the 2.7.0 artwork pass. Counts and validation below record
4
+ that review, not the current release. See the [current gallery](gallery.md) and
5
+ [artwork integration](artwork-integration.md) for maintained guidance.
6
+
7
+ Reviewed through the public `generateSettlement` API in `output/art-integration/`.
8
+ The river fixtures use coarse centrelines with default meandering enabled;
9
+ straight authored polygons and the straight-channel override are not used for
10
+ these natural rivers. The gallery links the previous release for visual comparison. Source changes are
11
+ in the city-glyphs worktree; this refinement has not been released.
12
+
13
+ ## Observed results
14
+
15
+ The gallery includes villages and 10,000-person cities in all five biomes,
16
+ 50,000- and 100,000-person temperate cities, a bridge village and a tropical
17
+ river village with rice paddies. All use seed 2 except the bridge fixture (3).
18
+
19
+ Roof coverage is building polygon area / residential ward area, grouped by
20
+ centre-to-edge character. It excludes parks, roads outside wards and farmland;
21
+ it is a visual-density diagnostic, not an occupancy or population claim.
22
+
23
+ | Population | Centre | Middle | Edge | Main parks | Rural house glyphs |
24
+ | --- | --- | --- | --- | --- | --- |
25
+ | 10000 | 71.7% | 61.5% | 43.6% | 3 | 264 |
26
+ | 50000 | 68.3% | 61.1% | 37.2% | 3 | 452 |
27
+ | 100000 | 68.9% | 57.7% | 37.7% | 3 | 1678 |
28
+
29
+ The 10,000-person capacity regression fixture retains its full 953-building
30
+ budget. City planning keeps a 10% local supply reserve before the final census
31
+ trim, with the existing minimum legible building size and capped core intact.
32
+ The metropolis still reports any capacity shortfall instead of inventing housing.
33
+ Gardens are actual parcel backgrounds, exported as additive green features.
34
+
35
+ Village enclosure support lines sit 3.5 metres outside measured roof and porch
36
+ bounds. Intersecting henge reservations enlarge only the affected part of that
37
+ boundary; detached henges do not replace the village perimeter. Roads retain
38
+ real openings and wet wall sections are omitted.
39
+
40
+ ## Validation
41
+
42
+ - Full regression report: 1,417 passed, zero failures, `success: true`.
43
+ - New behavioural coverage: species clustering, valid biome plant selections,
44
+ source-identical biome greens, softened crowns, desert versus paddy irrigation,
45
+ ocean-versus-river eligibility, measured wall clearance, city density gradient,
46
+ varied roofs, rural outskirts and garden GeoJSON correspondence.
47
+ - Existing geometry/access, household budgets, POI identities, collision, water,
48
+ determinism and SVG/GeoJSON tests remain active. Tests that assumed one park,
49
+ one housing style, or no nested SVG groups now check the new contracts.
50
+ - 372 saved landscape assets, 210 additional plant seeds, 42 snow comparisons,
51
+ 30 seamless tiles, clear farm entrances and live gallery controls passed.
52
+ - 60 green SVGs and 14 generated map SVGs parsed with unique IDs and resolved
53
+ internal references. Golden city renders were inspected and regenerated twice
54
+ to verify byte-for-byte determinism before updating their hashes.
55
+ - TypeScript build, script typecheck and browser bundle passed.
@@ -0,0 +1,18 @@
1
+ # 3.0.1 — current documentation and generated examples
2
+
3
+ The npm README and public documentation now describe the 3.0.x library and its
4
+ portable skin system. The README includes regenerated PNG/SVG examples from the
5
+ current public API, with release-pinned links that work on npm and GitHub.
6
+
7
+ New getting-started, API, GeoJSON, gallery and development guides replace the
8
+ outdated entry-point examples and fragmented contract guidance. The URL and city
9
+ scene guides document current options, coordinate/engine differences, rendering
10
+ limits and separate website deployment. Schema v3 is clearly historical.
11
+
12
+ The examples cover five default artwork biomes in both planners and Copperline.
13
+ Documentation checks run the README examples, typecheck snippets and check links,
14
+ anchors and gallery provenance. Public docs and gallery files ship in the package.
15
+
16
+ Generation algorithms and artwork are unchanged from 3.0.0. Exported generator
17
+ metadata reports 3.0.1; GeoJSON schema 4, Scene 2, URL payload 1, skin format 1 and
18
+ water context 1 remain unchanged.