# How to Create Custom Tilesets for Unciv Maps: A Complete Guide to Visual Mods

> Learn to create custom tilesets for Unciv maps with this complete visual modding guide. Package images, define JSON, and register your mod to enhance your game's graphics.

- Repository: [Yair Morgenstern/Unciv](https://github.com/yairm210/Unciv)
- Tags: how-to-guide
- Published: 2026-06-18

---

**To create a custom tileset for Unciv, package your images in `Images/Tilesets/<Name>/`, define a JSON configuration in `jsons/Tilesets/<Name>.json`, and register the mod as a permanent visual mod in [`ModOptions.json`](https://github.com/yairm210/Unciv/blob/main/ModOptions.json) so the `TileSetCache` can load and render your graphics.**

Unciv treats tilesets as visual mods, allowing you to completely customize map appearance through custom graphics and configuration files. When the game initializes, the `TileSetCache` class reads your tileset's JSON configuration and lazily loads assets from your mod's dedicated folder. This guide walks through the complete process of creating custom tilesets for Unciv maps based on the actual source code implementation in the yairm210/Unciv repository.

## Understanding the Tileset Architecture

Before creating assets, you need to understand how Unciv processes tilesets internally. The rendering pipeline relies on several key classes working together to resolve images and apply visual rules.

### How TileSetCache Loads Your Assets

The `TileSetCache` class, located in [`core/src/com/unciv/models/tilesets/TileSetCache.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/models/tilesets/TileSetCache.kt), serves as the central registry for all tileset data. When the game starts, this cache reads the tileset's JSON configuration via [`TileSetConfig.kt`](https://github.com/yairm210/Unciv/blob/main/TileSetConfig.kt) and constructs a `TileSet` object containing set-specific options including fallback settings, scaling rules, and rule variants.

The cache expects to find graphic assets in the folder `Images/Tilesets/<TilesetName>/`. If the game requests an image that your tileset does not provide, the cache automatically falls back to the tileset specified in the `fallbackTileSet` field (defaulting to "FantasyHex") up to a configurable recursion depth.

### The Role of ImageGetter and TileSetStrings

Whenever a map tile needs a texture, the `ImageGetter` class ([`core/src/com/unciv/ui/images/ImageGetter.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/images/ImageGetter.kt)) queries the cache for the appropriate image. The `TileSetStrings` class ([`core/src/com/unciv/ui/components/tilegroups/TileSetStrings.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/components/tilegroups/TileSetStrings.kt)) wraps the current tileset name and handles fallback logic for UI components. This separation ensures that missing assets gracefully degrade to the fallback tileset without breaking the rendering pipeline.

## Setting Up Your Custom Tileset

Creating a functional tileset requires both graphic assets and a properly structured configuration file.

### Required Folder Structure

Your mod must follow a specific directory layout so `TileSetCache` can discover and load your assets:

```

MyMod/
├─ Images/
│  └─ Tilesets/
│     └─ MyCoolTileset/
│        ├─ Grassland.png
│        ├─ Forest.png
│        ├─ Edges/
│        │   └─ Cliff-Hills-Coast-Top.png
│        └─ Hexagon.png
├─ jsons/
│  └─ Tilesets/
│     └─ MyCoolTileset.json
└─ ModOptions.json

```

Place your PNG images in `Images/Tilesets/<TilesetName>/`. The optional `Edges/` subdirectory contains directional edge graphics for features like cliffs and coastlines.

### Creating the Tileset Configuration JSON

The `jsons/Tilesets/<TilesetName>.json` file defines your tileset's behavior. This configuration maps directly to the `TileSetConfig` data class in [`core/src/com/unciv/models/tilesets/TileSetConfig.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/models/tilesets/TileSetConfig.kt).

```json
{
  "useColorAsBaseTerrain": false,
  "useSummaryImages": true,
  "unexploredTileColor": {"r":0.2,"g":0.2,"b":0.2,"a":1},
  "fogOfWarColor": {"r":0,"g":0,"b":0,"a":1},
  "fallbackTileSet": "FantasyHex",
  "tileScale": 1.0,
  "tileScales": {
    "City center": 1.2,
    "Citadel": 1.5
  },
  "ruleVariants": {
    "Grassland+Jungle+Dyes+Trading post": [
      "Grassland",
      "JungleForGrasslandBack",
      "Dyes+Trading post",
      "JungleForGrasslandFront"
    ]
  }
}

```

Set `fallbackTileSet` to ensure missing graphics resolve to a base tileset. The `useColorAsBaseTerrain` option, when enabled, draws plain hexagons using the base terrain's RGB values instead of images.

### Rule Variants and Rendering Logic

**Rule variants** give you precise control over how the engine composites tile layers. Defined in the `ruleVariants` object, these mappings translate a tile signature string into an ordered list of image names. The [`TileLayerTerrain.kt`](https://github.com/yairm210/Unciv/blob/main/TileLayerTerrain.kt) class interprets these rules when resolving tile appearances through `ImageGetter`.

For example, a jungle with dyes and a trading post can render in a specific layer order: base terrain first, then back jungle layer, then improvements, then front jungle layer.

## Advanced Customization Options

Beyond basic image replacement, Unciv supports several advanced rendering features controlled through your JSON configuration.

### Base Terrain Colors and Summary Images

When `useColorAsBaseTerrain` is true, the engine uses `Hexagon.png` as a base and tints it according to the terrain's defined color. This reduces asset count but requires the `Hexagon.png` file in your tileset folder.

Setting `useSummaryImages` to true enables **summary images**, allowing a single graphic like "NaturalWonder" to replace multiple individual images. The [`TileLayer.kt`](https://github.com/yairm210/Unciv/blob/main/TileLayer.kt) class processes these summaries to simplify complex terrain rendering.

### Edge Graphics and Scaling

Place optional edge images in `Images/Tilesets/<TilesetName>/Edges/` to render directional transitions between terrain types. The [`TileLayerTerrain.kt`](https://github.com/yairm210/Unciv/blob/main/TileLayerTerrain.kt) loads these based on neighbor direction, allowing custom cliff faces or coastlines.

The `tileScale` field applies uniform scaling to all sprites, while `tileScales` allows per-terrain-type overrides. For example, the Minimal tileset uses this to enlarge city centers and citadels specifically.

## Enabling and Testing Your Tileset

Once your files are structured correctly, you must register the tileset with the game engine.

### Mod Registration and Options Menu

To make your tileset selectable, register your mod as a **permanent visual mod** in the Mod Manager. In your [`ModOptions.json`](https://github.com/yairm210/Unciv/blob/main/ModOptions.json), set the `tileset` field to your tileset name:

```json
{
  "tileset": "MyCoolTileset"
}

```

When enabled, the game parses `jsons/Tilesets/<TilesetName>.json`, merges it into `TileSetCache`, and exposes the tileset in the Options menu ([`core/src/com/unciv/ui/popups/options/DisplayTab.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/ui/popups/options/DisplayTab.kt)). Changing the selection triggers a UI reload, forcing the map to re-render with your custom graphics.

### Programmatic Loading (for Testing)

For automated testing or development scripts, you can load and activate tilesets programmatically:

```kotlin
// Load the mod (already placed in the mod folder)
UncivGame.loadMods(listOf("MyMod"))

// Switch to the new tileset
UncivGame.settings.tileSet = "MyCoolTileset"
UncivGame.settings.save()
UncivGame.reloadWorld()   // forces a map redraw with the new tileset

```

This approach bypasses the UI and is useful for verifying that your `ruleVariants` and image paths resolve correctly.

## Summary

- Unciv loads custom tilesets through `TileSetCache` in [`core/src/com/unciv/models/tilesets/TileSetCache.kt`](https://github.com/yairm210/Unciv/blob/main/core/src/com/unciv/models/tilesets/TileSetCache.kt), which reads JSON configurations and graphic assets from `Images/Tilesets/<Name>/`.
- The `ImageGetter` class resolves textures using fallback logic defined in your config's `fallbackTileSet` field.
- Create a `jsons/Tilesets/<Name>.json` file defining `ruleVariants`, scaling options, and rendering flags like `useColorAsBaseTerrain`.
- Register your tileset in [`ModOptions.json`](https://github.com/yairm210/Unciv/blob/main/ModOptions.json) as a permanent visual mod to make it selectable in the Options menu.
- Use `ruleVariants` to control the exact layering order of tile components, and place edge images in the `Edges/` subdirectory for directional terrain transitions.

## Frequently Asked Questions

### What image format should I use for Unciv tilesets?

Unciv expects PNG images for tileset graphics. Place these in your `Images/Tilesets/<TilesetName>/` directory. The `ImageGetter` class handles texture loading and supports transparency, so use PNG files with alpha channels for overlays and complex terrain features.

### How does the fallback tileset system work?

The `fallbackTileSet` field in your JSON configuration specifies which tileset to query when your custom tileset lacks a specific image. According to the source code in [`TileSetCache.kt`](https://github.com/yairm210/Unciv/blob/main/TileSetCache.kt), the engine recursively checks the fallback tileset up to a configurable depth, defaulting to "FantasyHex" if unspecified. This ensures your tileset displays correctly even if you haven't created art for every terrain type.

### Can I combine multiple mods with custom tilesets?

Only one tileset can be active at a time, selected via the Options menu in [`DisplayTab.kt`](https://github.com/yairm210/Unciv/blob/main/DisplayTab.kt). However, you can create a single mod that references assets from multiple sources or uses extensive `ruleVariants` to mix styles. The `TileSetCache` merges configurations from enabled permanent visual mods, but the last loaded tileset takes precedence.

### Where do I place edge graphics for cliffs and coastlines?

Place edge images in `Images/Tilesets/<TilesetName>/Edges/`. The [`TileLayerTerrain.kt`](https://github.com/yairm210/Unciv/blob/main/TileLayerTerrain.kt) class loads these based on directional detection between neighboring tiles. Name your edge files according to the terrain transitions they represent, such as `Cliff-Hills-Coast-Top.png`, and the engine will apply them automatically when rendering adjacent terrain types.