UO Renaissance base (land) tiles
Ultima Online draws terrain from land tiles: 44 px diamonds, each tagged with a terrain type. Most types have several texture variants plus edge transitions toward neighbouring types. This is the set of base terrain types found on the Renaissance-era (2000) Britannia, Felucca/Trammel and T2A Lost Lands maps, mapped onto our 1×1 ground-tile sprites (32 px diamond, see decision #34).
Each type is baked as 8 interchangeable variants in one sprite sheet (decision #43): the client picks one per map cell, and any variant joins any other without a seam, so large areas show no tile grid and no obvious repetition. Transitions between types are a follow-up. Transitions will probably be blended in the terrain shader rather than baked as sprites, because the client terrain is a real 3D mesh (decision #19).
| UO terrain | Where in UO | Sprite | Group | Status |
|---|---|---|---|---|
| grass | meadows everywhere | ground_grass | vegetation | done (earlier) |
| forest | forest floor under trees (grass + leaf litter) | ground_forest | vegetation | done |
| jungle | T2A jungle, Lost Lands | ground_jungle | vegetation | done |
| swamp | Fens, Lost Lands bogs | ground_swamp | vegetation | done |
| dirt | roads, paths, bare soil | ground_dirt | soil | done (earlier) |
| furrows | ploughed farm fields | ground_furrows | soil | done |
| sand | deserts, beaches | ground_sand | soil | done |
| snow | Dagger Isle, mountain peaks | ground_snow | soil | done |
| rock / mountain | mountain slopes, mining spots | ground_rock | mineral | done |
| cave | cave and dungeon dirt floor | ground_cave | mineral | done |
| lava | Fire dungeon, Lost Lands volcano | ground_lava | mineral | done |
| water | seas, lakes, rivers (animated in UO) | ground_water | mineral | done |
| cobblestones | city streets | ground_cobblestones | paved | done |
| flagstone | dungeon and keep stone floors | ground_flagstone | paved | done |
| wooden floor | some dungeon/interior land floors | floor_wood | paved | done (raised floor item) |
| void | black cave/void filler (NoDraw) | — | — | engine only, no sprite |
Per-tile checklist
Each tile follows the ground-tile rules in asset-pipeline.md:
1×1, an open surface sheet at Z >= 0 (no slab, nothing under the edge),
padding = 0, variants = 8, chunky details that survive 32 px (1 texel ≈
0.045 units), Principled BSDF only. Seamless across variants: a shared,
periodic edge band + a zero-mean per-variant interior (rules and helpers in the
"variants" section of tools/blender/models/ground_kit.py, reference
ground_grass.py).
For every tile:
- model script
tools/blender/models/ground_<type>.py(built onground_kit.pywhere it fits) - reads as its UO terrain at 32 px: colour palette, roughness, relief
- seamless: no edge-only features; heights periodic over the tile
- material maps: roughness/metallic/specular set; emissive only where real (lava)
- baked with
uo-baker bake-all --only ground_<type> --preview, validation passes -
uo-baker tile-check assets/sprites/ground_<type> --mosaic 8passes, andmosaic.png(8×8 random mix, albedo | lit) shows no border lines, no lattice and no variant that stands out (tile-check --allchecks every tile) -
preview.pngchecked: normals mostly blue on top, lit composite reads well
Type-specific notes:
- forest: darker grass than
ground_grass, brown leaf litter, a few twigs. - jungle: saturated dark green, large leaves/ferns low to the ground, damp soil.
- swamp: dark olive mud, glossy (low roughness) water puddles, reed tufts.
- furrows: parallel ploughed ridges along one tile axis, period divides the tile.
- sand: warm pale sand, wind ripples, small shells/pebbles.
- snow: bright blue-white, soft drifts, slight sparkle (low roughness spots).
- rock: grey-brown broken rock, cracks, chunky boulders flush with the surface.
- cave: dark brown-grey packed earth, pebbles, darker than
ground_dirt. - lava: dark basalt crust plates with glowing orange-yellow cracks (emissive).
- water: deep blue-teal, gentle periodic ripples, low roughness, slight specular.
- cobblestones: rounded grey stones in rows with dark grout, grout lines on the tile edges split half/half so neighbours join.
- flagstone: large irregular-looking flat slabs (grey-tan) with grout, same seam rule as cobblestones.

Crops of 8×8 random-variant mosaics (albedo | lit). Left column: grass, dirt, forest, jungle, swamp, furrows, sand; right: snow, rock, cave, lava, water, cobblestones, flagstone.
Swamp and forest are edge-matched (stochastic Wang tiles, decision #46): every map edge gets a random type and each cell uses the variant whose four edges match, so features cross tile edges. Swamp: an edge is wet with p = 0.15; a wet edge carries a water neck crossing it and the tile's channels join its wet edges at a pond, so water forms meandering chains over several tiles and about half of the tiles (all-dry edges) have no water at all (64 variants). Forest: two leaf-row layouts per edge (p = 0.5) with leaves cut at the edge line, and leaf drifts spread evenly over the tile (16 variants).
edge_max_z in the manifest sets how high the compared edge surface may be:
furrows 0.2 (tall ridges), cobblestones/flagstone 0.012 (only the grout joint,
stones are meant to differ). Rock and lava plates stand above the default 0.04,
so their check covers the cracks/channels at the edge; the plates themselves
match exactly on the edge line by construction.
Known follow-ups
- Rare features (sand footprints, a sunken cobble, the cave bone) live in one fixed variant, so they appear on ~1 tile in 8 at the same spot. Weighted variant picking in the client would make them rarer.
- Jungle keeps a very faint lattice in lit views (leaves cannot cover the last ~0.015 of the edge without crossing it); flagstone shows straight grout lines on tile edges, inherent to laid slabs.
morph_voronoi(rock, lava) and the variance-preserving blend (cave, water) are duplicated in two scripts each; move them intoground_kit.pywhen a third user appears.The client terrain shader still uses 5 procedural terrain ids.Done (decision #45):uo_proto::map::Terrainhas all 14 types and the terrain shader draws these tiles with a hashed variant per tile (crates/uo-client/src/terrain_tiles.rs, Terrain tiles in rendering.md).- Transitions between types are still the generic dithered border; UO-style per-pair transition rules (which type overlaps which) are not modelled.
- The water sheet uses only the water tile's colour and keeps procedural ripple normals: under the hard toon specular the baked ripples read as rows of streaks.