Releases: CDS-SP/minecraft-citygen
Release list
CityGen 0.4.1 (Windows)
CityGen 0.4.1 Release Notes
Released on August 20, 2026.
This is a patch release for the extracted-asset ground offset refactor. Building
placement already read the authored ground_offset; this release extends that
same offset path to roads and fill props so every marker-authored asset seats
from extracted metadata instead of assuming a hard-coded flush origin.
Highlights
- Roads and trees now seat from extracted asset metadata. The city
constructor no longer treats them as implicitly flush assets with a baked-in
0Y offset. - Road/fill schematics now persist their authored ground offset. The
extraction stage writes the asset ground seat into the SpongeOffsetfield,
and the loader preserves it through rotation and composition.
What Changed
Unified offset plumbing
pipeline/01_roads_extract.pynow writes each extracted road or fill asset's
ground offset into the schematicOffsetfield.engine/schematic_reader.pynow reads the SpongeOffsetfield, and
engine/road_schematic.pyattaches that value to loaded tiles as
ground_offset.engine/schematic_transform.pynow preservesground_offsetwhen rotating a
tile, so randomized fill-prop rotation does not lose the authored seat.
City construction
pipeline/04_city_construct.pynow seats the road grid from the shared road
offset returned by the road schematic builder.- Fill props are now seated from each tile's extracted
ground_offsetinstead
of from a hard-coded flush assumption. pipeline/03_grid_construct.pynow preserves the road-grid offset when
exporting the combined grid schematic.
Upgrade notes
- Re-extract road assets before rebuilding outputs. Existing road and fill
schematics exported before 0.4.1 do not carry the new offset metadata, so
they will still read as zero-offset assets until regenerated. - After re-extraction, re-run the grid and city construction stages to pick up
the corrected seating.
Verification
python -m compileall src/engine/schematic_reader.py src/engine/schematic_transform.py src/engine/road_schematic.py src/pipeline/01_roads_extract.py src/pipeline/03_grid_construct.py src/pipeline/04_city_construct.pypython src/pipeline/03_grid_construct.py --seed 1 --fine 8 --out .codex/grid_offset_smoke.schempython src/pipeline/04_city_construct.py --seed 1 --fine 8 --out .codex/city_offset_smoke.schem
CityGen 0.4.0 (Windows)
CityGen 0.4.0 Release Notes
Released on August 21, 2026.
This release fills the empty space in a generated city. The gaps between roads and
buildings are now populated with fill props — self-contained one-cell assets
that carry their own ground — and the bundled world ships three of them as trees.
Along the way, road extraction was unified with the building marker convention, so
there is no longer any road-specific detection logic.
Highlights
- Empty lot cells are filled with a randomly chosen, randomly rotated fill
prop. The bundled world ships three trees (spruce, birch, oak), so open ground
reads as landscaped space instead of a flat plate. - Road extraction now shares the building marker convention. Road tiles and
fill props are authored exactly like a type-1 build (wool boundary +
gold/diamond/emerald markers + a name sign) and run through the same extraction. - The top-down simulation preview places matching tree tiles in the same
cells with the same seed, so the preview lines up with the built city.
What Changed
Fill props (empty-space filling)
- A new asset class — fill props — is authored in the road region alongside
the road tiles (15_fill_1x1_A,16_fill_1x1_B,17_fill_1x1_C). Each is a
self-contained 9x9 (one fine cell) asset that carries its own ground. pipeline/04_city_construct.pydrops a random, randomly rotated prop into every
fully-empty non-road lot cell, seated on the lot ground plane. Cells occupied by
a building are skipped, and prop cells are excluded from the flat ground fill so
nothing pokes up through a prop's own ground.pipeline/01_roads_simulation.pydraws top-down tile PNGs for the props, and
pipeline/04_city_simulation.pyscatters them into the preview with the same
seed used by the build.
Shared marker extraction
engine/marker_extract.pyis a new module holding the wool-boundary +
gold/diamond/emerald cuboid extraction. Both02_builds_extractand
01_roads_extractnow call into it.- The old road detector (top-down surface components,
yellow_wool/white_wool
edge trimming, per-column Y-extent) is removed. Author road tiles the same way
you author a type-1 build.
Ground fill
- The default empty-lot ground fill block changed from
minecraft:smooth_stone
tominecraft:smooth_stone_slab[type=bottom]. The origin anchor column keeps a
solid block.
Fixes
- Tall road and fill assets are no longer clipped to the
ROAD_BOXY span: the
marker cuboid (gold→diamond) is captured in full, regardless of the box height. - Fill props seat flush with the lot surface instead of hovering one block above
it, and the flat ground fill no longer leaks a block into a prop's cell.
Upgrade notes
- Custom road worlds must be re-authored. Road extraction no longer keys off
yellow_wool/white_woolsurface markers. Each road tile now needs a wool
boundary, a gold/diamond marker pair (opposite corners), a single emerald at
ground level, and a name sign — the same convention as buildings. The bundled
default world has already been updated. - Regenerate roads, then the city, to pick up the new fill props and slab ground:
re-run the road extraction, grid, and city stages.
Verification
python -m pytestpython packaging/build_windows_release.py --clean- Generate a city and confirm the empty lots are filled with randomly rotated
trees seated flush with the ground, and that the top-down preview matches.
CityGen 0.3.5 (Windows)
CityGen 0.3.5 Release Notes
Released on August 20, 2026.
This release overhauls the extraction region selector. Its world preview is
now a true top-down surface map, rendered block-by-block at full resolution and
kept fast the way dedicated map tools do it.
Highlights
- The region-selector preview is a real top-down surface map — the topmost block
of each column — instead of the old thin altitude slice that painted most of
the world flat green. - It now renders one pixel per block (full resolution), yet stays fast by
reading each chunk's precomputed surface heightmap rather than scanning columns.
What Changed
Region selector
render_topdown_previewnow derives each column's surface from the chunk's
WORLD_SURFACEheightmap — a single array read per chunk replaces the previous
per-column vertical scan, and the result no longer depends on the selection's
Y bounds.- Ungenerated columns render as a neutral background instead of fake grass fill.
- Colours come from each column's highest non-air block, using the corrected
0.3.0 palette (green foliage, blue water).
Performance
- The world reader reads each
.mcaregion file once and caches its bytes, so
all chunks in a region share a single read instead of re-opening the file. - Per-chunk colour mapping is vectorized with NumPy (build a palette-to-RGB
lookup once per section, gather all 256 columns at once). - Worlds larger than the full-resolution cap are point-sampled from the same
heightmaps so the image stays bounded.
UI
- Removed the drop shadows from the region-selector dialog buttons ("Use
Selection" / "Cancel"). The extraction "Pick" button keeps its shadow.
New internals
World.surface_heightmap(cx, cz)— decodes a chunk'sWORLD_SURFACEheightmap
to per-column surface heights.World.top_solid_block(x, z)— highest non-air block in a column (used as a
fallback and for verification).
Upgrade notes
- No configuration or output changes to generated schematics or renders. Only the
region-selector preview is affected.
Verification
python -m pytestpython packaging/build_windows_release.py --clean- Open the Extraction tab, click Pick, and confirm the preview shows a
block-by-block top-down surface map.
CityGen 0.3.0 (Windows)
CityGen 0.3.0 Release Notes
Released on August 20, 2026.
This release follows the Tkinter-to-Qt migration with a structural cleanup of the
Qt GUI layer, a reduction of surrounding tooling debt, and a renderer palette fix.
Unlike 0.2.x, this release does change generated output: biome-tinted blocks
(leaves, grass, vines, water) now render in colour instead of gray, and the
WorldEdit auto-copy step has been removed.
Highlights
- The 1,100-line
gui/qt_app.pywas split into focused modules, and the Qt image
viewer gained a public overlay API so dialogs no longer reach into its internals. - The renderer palette now honours Minecraft's biome tinting, so leaves and grass
are green and water is blue instead of gray. clear_cache.pymoved intotools/and now also clears build, packaging, and
test caches.- Dead code left over from the Tkinter era was removed, and the WorldEdit
auto-copy step was retired.
What Changed
GUI structure
- Split
gui/qt_app.pyintotheme,workers,widgets,region_dialog,
tabs, andapp. - Flattened the Qt image-viewer factory into module-level classes with a direct
PySide6import, and gaveQtImageViewera public overlay API
(image_rect,set_overlay_rect,clear_overlay) so the region-selector
dialog no longer touches private members. - Replaced string-matched error handling with typed
SeedError/ConfigError,
and the hand-rolled argument loop withargparse(adds--helpand a real
--no-custom-themeflag). - Centralized the brand palette and the label-to-value selector mapping, made the
button-icon helper idempotent, and switched to the staticQFontDatabaseAPI. - Added headless GUI unit tests covering argument parsing, style configuration,
and widget value round-trips.
Renderer
- The palette generator (
tools/update_render_colors.py) now reads each model
face'stintindexand multiplies grayscale colormap masks by a representative
biome tint (plains foliage/grass, default water; birch and spruce use their
fixed constants). - Tinting is gated on the source texture actually being grayscale and on an
explicit allow-list, so pre-coloured blocks (cherry and azalea leaves) are left
untouched. src/engine/color_render.csvwas regenerated from the 26.2 client jar.
Tooling and cleanup
- Removed the WorldEdit auto-copy step and the
MC_CITY_WORLDEDIT_SCHEMoverride.
The final city schematic is still written toartifacts/city/production/as a
WorldEdit-ready.schem. - Moved
clear_cache.pyintotools/and expanded it to also clearbuild/,
dist/,*.egg-info/,.pytest_cache/, and the startup error log. - Deduplicated
numbaacross thespeed/builddependency extras.
Fixes
- Replaced the deprecated
QFontDatabase()instance call with the static form. - Corrected stale "Tkinter" references in entry-point docstrings and comments.
Upgrade notes
- Renders will look different: foliage and water now show their in-game colours.
Regenerate any previews or city renders to pick up the new palette. - The WorldEdit auto-copy is gone. If you relied on
MC_CITY_WORLDEDIT_SCHEM,
copy the schematic fromartifacts/city/production/yourself instead. clear_cache.pynow lives attools/clear_cache.py; update any scripts that
invoked it.- Local tooling that imported
gui.qt_appshould import from the new modules
(gui.app,gui.tabs,gui.widgets, ...). - The
--custom-qt-themeflag was removed (the theme is on by default); use
--no-custom-themeto opt out.
Verification
python -m pytestpython packaging/build_windows_release.py --clean- Launch the built executable and confirm the GUI opens and renders show green
foliage.
CityGen 0.2.1 (Windows)
CityGen 0.2.1 Release Notes
Released on August 20, 2026.
This is a hot-fix release for the Windows installer build. There are no changes
to application code or generated output — it exists solely to make the packaged
0.2.0 executable start.
The problem
The 0.2.0 Windows build failed immediately on launch with:
_tkinter.TclError: invalid command name "::msgcat::mcmset"
ttkbootstrap initializes localization at startup, which requires Tcl's
msgcat package (version 1.6+, for the ::msgcat::mcmset command). That
package was not bundled, so the interpreter had no such command.
The cause
The PyInstaller Tcl/Tk hook only collected the tcl8.6/ and tk8.6/ script
directories. The Tcl 8.x "module" packages — msgcat, http, tcltest, and
friends — ship as .tm files under a separate tcl8/ directory that sits
beside tcl8.6/, not inside it, so msgcat was never included.
The fix
The hook now also bundles the tcl8/ module tree to the bundle root, where Tcl
looks for it (the module path is resolved relative to the interpreter library,
i.e. [file dirname $tcl_library]/tcl8). package require msgcat now succeeds
and the application starts normally.
Upgrade notes
- No configuration or output changes.
- Rebuild the Windows installer to pick up the fix.
Verification
python -m pytestpython packaging/build_windows_release.py --clean- Launch the built executable and confirm the GUI opens.
CityGen 0.2.0 (Windows)
CityGen 0.2.0 Release Notes
Released on August 20, 2026.
This is an internal refactor and maintenance release. It focuses on structure,
readability, consistency, and cross-platform support. There are no intended
changes to the generated output — the city constructor was verified to produce
byte-identical results (decoded) against the previous implementation.
Highlights
- The large GUI widgets module was split into focused submodules, and the two
image viewers now share a common pan/zoom base instead of duplicating it. - The city constructor was decomposed into named stages and given readable
identifiers. - Path handling, imports, type-annotation imports, and the logger contract were
made consistent across the codebase. - The per-user data directory is now platform-aware instead of Windows-only.
What Changed
GUI
- Split
gui/widgets.pyintoviewers,region_dialog,controls,tooltip,
progress,panels,config_frame, and a sharedpan_zoommodule. - Extracted a shared pan/zoom mixin, removing duplicated zoom, pan, and
scroll-region logic across the two viewers. - Replaced the mutable theme module globals with a single theme object.
Pipeline and engine
- Decomposed
city_construct.run()into named helper stages. - Renamed terse identifiers, including the
Tiledimension fields
(W/H/Ltowidth/height/length). - Promoted
World._load_chunkto a publicload_chunkmethod. - Collapsed redundant production-schematic path aliases.
- Documented the environment-override and module-reload invariant.
Consistency
- Standardized path construction on
pathlib(public constants remain strings). - Applied
from __future__ import annotationsuniformly. - Replaced initial-only aliased imports with explicit names.
- Unified the logger call contract to a single string argument.
Compatibility
- Made the per-user data directory follow macOS and Linux conventions instead of
assuming Windows. - Added upper version bounds to declared dependencies.
Fixes
- Narrowed overly broad exception handlers that could hide real failures, while
keeping the intended top-level and worker error boundaries. - Corrected stale file references and machine-specific absolute links in
docs/TECHNICAL.md.
Upgrade notes
- No configuration or output changes are expected.
- Any local tooling that imported the internal
gui.widgetsmodule should import
from the new focused modules instead, and the GUI theme palette is now read
fromgui.common.theme.
Verification
python -m pytestpython packaging/build_windows_release.py --clean
CityGen 0.1.0 (Windows)
CityGen 0.1.0 Release Notes
Released on August 19, 2026.
Highlights
- The project now uses a
src/package layout, which makes packaging and installs cleaner. - CityGen can now be installed and launched with command entry points instead of relying on repo-local execution only.
- Common Minecraft save folders and WorldEdit schematic folders are detected automatically.
- Windows release packaging now has a defined installer flow built around PyInstaller and Inno Setup.
- The isometric renderer now works even when
numbais not installed, while still using CPUnumbaacceleration when available.
What Changed
Packaging and runtime
- Added project metadata and dependencies in
pyproject.toml. - Added
citygenandcitygen-doctorcommand entry points. - Moved application code under
src/. - Added runtime path handling for source, installed, and frozen builds.
- Added a first-run environment doctor for dependency and path checks.
Minecraft path handling
- Replaced machine-specific defaults with discovery for common Minecraft launcher save locations.
- Added WorldEdit schematic-folder discovery with a repo-local fallback.
- Improved extraction failures when the configured world path is missing.
Windows distribution
- Added a Windows installer build script.
- Added PyInstaller hooks for Tcl/Tk so the GUI can start reliably in frozen builds.
- Standardized release output under
dist/release/. - Set
CityGen-setup.exeas the primary release artifact.
Documentation
- Reorganized screenshots and technical docs under
docs/. - Added release process documentation and changelog support.
- Kept
README.mdat repo root and moved the engineering reference todocs/TECHNICAL.md.
Tests
- Added regression coverage for path discovery.
- Added regression coverage for the isometric renderer fallback path.
- Added test bootstrapping for the new
src/layout.
User-visible fixes
- Fixed missing runtime dependency declarations in packaging metadata.
- Replaced Windows-only folder-opening logic with a cross-platform helper.
- Fixed frozen-app startup issues caused by missing
tkinterpackaging.
Upgrade notes
- Direct imports now resolve from
src/, so any local tooling that assumed top-levelconfig/,engine/,gui, orpipelinepaths should be updated. - Technical documentation now lives at
docs/TECHNICAL.md. - Demo images now live under
docs/.
Verification
python -m pytestpython src/config/doctor.py