Worlds from the ground up.
Deterministic world generation in Rust.
Terrain, climate, and water, from a single seed.
Generate a continent, resolve its terrain and drainage into local areas, and save it as binary world data. Export PNG maps and JSON, or load the cells and water features through the Rust library. Run locally or in Docker.
Install · Quick start · What you get · Exports · Library · Docker and servers · Status · Development
Read the map legend or explore the architecture reference.
Build from source with stable Rust and a native C toolchain (compiler and linker):
git clone https://github.com/DiceMasterIO/arda.git
cd arda
cargo install --path crates/arda-cli --lockedThis installs the arda command. To build inside the checkout instead:
cargo build --release -p arda-cli --lockedThe binary is written to target/release/arda (arda.exe on Windows).
Use release builds for generation.
Start with the eight-area MICRO world:
# Generate the saved world data.
arda generate --seed 42 --micro --out worlds/w42
# Render an overview from that world.
arda export --world worlds/w42 --overview --out exports/w42
# Export one area at the default 8K resolution and as JSON.
arda export --world worlds/w42 --area 1,1 --out exports/w42
arda export --world worlds/w42 --area 1,1 --format json --out exports/w42Generation writes world.json and the native binary layers under
worlds/w42/. The exports are overview.png, area_01_01.png, and
area_01_01.json. Area coordinates are zero-based x,y pairs.
Generation needs a new or empty destination. Exporting reads the saved world; it does not rerun terrain or water generation.
For a single command that generates a new world and renders its overview:
arda preview --seed 42 --micro --quality 2k --out previews/w42This writes previews/w42/world/ and previews/w42/overview.png.
preview runs generation too, so use export for a world you already have.
Arda currently concentrates on the physical world: relief, climate, drainage, rivers, and lakes. It produces saved data as well as images.
| Layer | What it contains |
|---|---|
| Continent | Coarse relief shaped by tectonics, plus climate and drainage on a 1 km grid |
| Areas | 512 × 512 cells at 100 m spacing: 51.2 × 51.2 km per area, with terrain, rainfall, temperature, and water data |
| Water features | Shared river reaches and lakes with IDs, geometry, water surfaces, and annual flow information |
| Tactical blocks | Experimental 64 × 64 grids of five-foot tiles, sampled at selected land cells; this layer is unfinished |
The default requested extent is 500 × 1000 km. --micro selects a
102 × 204 km request with eight exported areas. Custom extents use
--size WIDTHxHEIGHT:
arda generate --seed 42 --size 500x1000 --out worlds/continent42Requested kilometre extents and the exported area grid are not identical: area counts currently use integer 51 km units, while each area spans 51.2 km. See operations for the exact modeled bounds and resource limits.
Seed + configuration
↓
Continent relief and climate
↓
Shared terrain evolution across area boundaries
↓
Connected drainage and annual water balance
↓
Saved areas, water features, and sampled blocks
↓
PNG maps · JSON exports · Rust queries
Terrain comes before water. Fine relief follows local regional height differences. Erosion evolves across internal area boundaries, so those boundaries do not become fixed terrain walls.
Lakes need a basin and a water supply. The water model combines physical depressions with rainfall, runoff, and evaporation. River and lake records are shared across areas, rather than reconstructed separately by each map export.
The saved world is the source for exports. PNG and JSON exports read persisted terrain and water geometry. Increasing image resolution changes the rendering, not the underlying terrain samples.
Generation is reproducible. A fixed seed, configuration, and generator revision determine the output. CI checks a shared golden world on Linux, macOS, and Windows. Keep the generator revision with a seed when you need to reproduce an older world; changes to generation can change its output.
arda generate automatically writes the native saved world. Its .bin
files carry terrain, climate, cells, and water records; sampled tactical
blocks use .tiles.zst archives. No separate --format bin export is
needed.
worlds/w42/
├── world.json # Manifest, seed, configuration, format version
├── continent/
│ ├── overview.bin # Coarse terrain, climate, and drainage
│ └── objects.bin
├── areas/<ax>_<ay>/
│ ├── cells.bin # Full saved area cell records
│ └── objects.bin # Local objects and shared water context
├── hydrology/ # Global .bin tables: lakes, reaches, basins, ...
└── blocks/<ax>_<ay>.tiles.zst # Compressed sampled tactical blocks
World::load opens this directory through the Rust API. Preserve the
directory structure when moving a world between a desktop, container,
or backend server.
| Output | Command options | Result |
|---|---|---|
| World overview | --overview |
overview.png, 8K long edge by default |
| Area map | --area 0,0 |
area_00_00.png, 8192 × 8192 by default |
| Small area preview | --area 0,0 --quality 512 |
area_00_00.png, 512 × 512 |
| High-resolution area | --area 0,0 --quality 32k |
area_00_00.png, 32768 × 32768 |
| Area data | --area 0,0 --format json |
area_00_00.json, versioned cell and object data |
| Sampled block | --block AX,AY,CX,CY --format png or json |
One saved experimental tactical block, if present |
Each row uses arda export --world WORLD_DIR ... --out EXPORT_DIR.
PNG and JSON are separate exports. --quality applies to area and overview
PNGs; it does not apply to JSON or tactical blocks.
Quality accepts any whole-pixel size from 512 through 32768, including
512, 1k, 2k, 4k, 8k, 16k, and 32k. A k is 1024 pixels.
The default is 8K. Areas are square; overviews preserve the exported
area grid's aspect ratio and use the selected quality for the long edge.
Detailed area maps still use the same 100 m terrain grid. Their additional pixels make channel geometry easier to inspect; they do not add finer terrain measurements. Overview river strokes are symbolic and should not be read as physical channel widths. The map legend explains the terrain colours and water presentation.
Area JSON includes selected terrain and water fields for every cell, plus water objects. Temperature and rainfall are saved in the world and available through the Rust API, but are not yet included in area JSON. The saved world stores binary layers for loading and querying; JSON provides an explicit interchange format. A full area JSON can be tens of megabytes, so applications should choose the areas and fields they need. Browser loading and network delivery are not implemented or benchmarked here.
Choose a resolution up to 32K
Use the same quality option for a saved world or a single area:
arda export --world worlds/w42 --overview --quality 32k --out exports/w42-32k
arda export --world worlds/w42 --area 1,1 --quality 16k --out exports/w42-16kBoth paths stream PNG output using rows or bands, instead of keeping the whole uncompressed image in memory. Larger exports still require more rendering time and output space. Completed images replace the previous file only after rendering succeeds.
For compatibility, --detail retains the older 4096 × 4096 area export
and its _detail.png filename. It cannot be combined with --quality.
The preview command also retains --px for pixels per area; choose
either --px or --quality.
Read an experimental tactical block
--block takes four coordinates: area X, area Y, cell X, cell Y.
Blocks are saved only at land cells whose local X and Y are multiples of
64, from 0 through 448. A coordinate such as 0,0,64,128 is a valid
request shape, but a block exists there only if that sampled cell is land.
The current tile vocabulary and adjacency rules are preliminary. These exports do not yet provide finished maps with detailed assets, movement rules, collision geometry, or NPCs.
The arda crate is the public entry point for generation, loading,
queries, and exports. Within a checkout, another workspace crate can use
arda = { path = "../arda" }.
use arda::{GenerateConfig, World};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = Path::new("worlds/library42");
arda::generate(42, GenerateConfig::MICRO, path)?;
let world = World::load(path)?;
let area = world.read_area(0, 0)?;
let cell = area.cell(100, 100)?;
println!("Elevation: {} mm", cell.height.raw());
Ok(())
}World::load reads the manifest without eagerly loading every area.
area() caches requested areas; read_area() returns an owned, uncached
read. generate_with_limits() accepts explicit resource limits and
rejects work that exceeds them, without changing the physical model to
fit.
Generate local API documentation with:
cargo doc --workspace --no-deps --openArda can generate and export worlds on a server using the same CLI or Rust API. The Docker image packages that CLI. Build it locally, then mount a writable world directory:
docker build -t arda-local .
docker run --rm -v /absolute/path/to/worlds:/worlds arda-local \
generate --seed 42 --micro --out /worlds/w42
docker run --rm -v /absolute/path/to/worlds:/worlds arda-local \
export --world /worlds/w42 --area 1,1 --format json --out /worlds/exports/w42The container runs as UID 10001; the mounted directory must be writable by
that user. Native .bin layers, block archives, and exported files remain
on the mounted volume after the container exits.
A backend can load the saved world through the Rust API or deliver the
exported files through its own HTTP service. Arda's built-in read-only
HTTP server (arda serve) is planned;
the current binary implements generate, preview, and export only.
The container does not currently start an HTTP listener.
Working, under active development. Terrain and hydrology generation, binary world storage and loading, PNG/JSON exports, Docker execution, the CLI, and the Rust library are implemented. The project is still developing its geography and higher level world content.
| Work still open | Current boundary |
|---|---|
| Terrain realism | Some worlds retain repetitive parallel drainage, angular shorelines, and large rectangular regional basins |
| Water simulation | A representative annual balance; no seasonal storage, groundwater, snowpack, or dynamic floods |
| Vegetation and human geography | Full vegetation, settlements, roads, buildings, naming, realms, and NPC generation remain deferred |
| Tactical maps | Sparse sampled blocks with a preliminary WFC tile set; detailed assets and gameplay geometry remain deferred |
| Serving and integration | No arda serve command or browser application; consumers use saved exports or the Rust API |
Generation is an offline batch. Valid size inputs can still exceed resource limits. Failures after generation begins can leave partial output for diagnosis; admission failures leave the destination untouched. There is no checkpoint resume; retry in a fresh directory. Incompatible saved-world format versions require regeneration.
See open items for the detailed status and operations for capacity and persistence behaviour.
The workspace separates the model, generation, rendering, public API, and CLI:
| Crate | Responsibility |
|---|---|
arda-core |
Coordinates, domain types, deterministic RNG, and storage formats |
arda-gen |
Continent, terrain, water, area, and block generation |
arda-render |
PNG rendering and JSON serialization |
arda |
Public generation, loading, query, and export API |
arda-cli |
The arda command |
Run the main local checks:
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-featuresCI also checks the golden world across three operating systems, the minimum supported Rust version, and dependency licenses/advisories. Generation tests do real work and can take substantially longer than ordinary unit tests.
Issues and pull requests are welcome. For generation or rendering bugs, include the seed, configuration, generator revision, exact command, and a map or data sample. Follow the coding standards and add a regression test for fixes. Golden fingerprints should change only when an intended generation change has been reviewed.
| Document | Use it for |
|---|---|
| Map legend | Reading terrain colours, hillshade, rivers, and lakes |
| Reference index | Navigating the implementation |
| Architecture | Crate boundaries and generation stages |
| Data models | Cells, water features, and saved formats |
| Operations | CLI behaviour, resource limits, and exports |
| Open items | Implemented work and remaining limitations |
| Testing | Determinism, physical checks, and verification scope |
Apache-2.0. See NOTICE for project attribution.