ghosteau commited on
Commit
73d1010
·
verified ·
1 Parent(s): e5b87cf

STEVE-1 v1: style-conditioned terrain VAE (ONNX + mappings + base_v1 fine-tuning checkpoint)

Browse files
README.md CHANGED
@@ -1,3 +1,108 @@
1
  ---
2
  license: mit
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: mit
3
+ tags:
4
+ - minecraft
5
+ - terrain-generation
6
+ - vae
7
+ - onnx
8
+ - voxel
9
+ - film
10
+ - transfer-learning
11
+ - games
12
+ datasets:
13
+ - ghosteau/minecraft-chunks
14
+ pipeline_tag: other
15
  ---
16
+
17
+ # STEVE-1 — Style-conditioned Terrain Encoder VAE
18
+
19
+ STEVE-1 generates full Minecraft chunks (16 x 384 x 16 voxels, bedrock to build limit) from **latent noise + a biome ID + a style ID** in a **single ONNX forward pass** — fast enough to run inside a live PaperMC server. It is also a **pretrained base for transfer learning**: anyone can fine-tune a new terrain *style* onto it from a folder of their own world's chunks, in minutes, training ~1.8% of the weights, without touching the base.
20
+
21
+ - **Training pipeline, plugin, and fine-tuning notebook:** [github.com/ghosteau/generative-terrain](https://github.com/ghosteau/generative-terrain)
22
+ - **Training data:** [ghosteau/minecraft-chunks](https://huggingface.co/datasets/ghosteau/minecraft-chunks) (2,040 chunks, ~200M voxels, 22 biomes)
23
+
24
+ ## Architecture
25
+
26
+ A conditional VAE built around one hard constraint: in-game inference must be a single fast graph call (no diffusion, no autoregression).
27
+
28
+ | Component | What it does |
29
+ |---|---|
30
+ | Spatial latent `z` `[8, 4, 16, 4]` | A coarse 3D latent grid instead of one broadcast vector, so terrain varies from place to place (hills, valleys, caves) |
31
+ | Heightmap stage | The decoder first predicts a per-column surface height, then feeds a signed-distance-to-surface channel to the voxel head — the model commits to a surface instead of hedging |
32
+ | 3-level 3D U-Net (~4.6M params) | Chunk-scale receptive field: at the bottleneck the chunk is 2 x 48 x 2, so horizontal context is global |
33
+ | FiLM style conditioning | Every U-Net block and the heightmap head is modulated (per-channel scale/shift) by a style embedding. Style 0 = vanilla; 8 slots reserved for custom styles. This is the fine-tuning mechanism |
34
+ | 27 block groups | The model predicts semantic groups (`STONE`, `GRASS`, `WATER`, ores, ...); the plugin expands them to concrete blocks with local context |
35
+
36
+ Conditioning uses **only what exists before terrain does** (position, biome, noise, style). It deliberately never sees neighbour blocks, light, or surface flags — the data-leakage mistake that sank earlier versions of this project.
37
+
38
+ Training: EMA weights (exported), mixed precision, warmup + cosine LR, KL annealing with free bits, biome-balanced sampling, and biome dropout so a reserved `UNKNOWN` biome row learns generic terrain (that is what makes fine-tuning work on custom worlds with unrecognised biomes).
39
+
40
+ ## Files
41
+
42
+ | File | Purpose |
43
+ |---|---|
44
+ | `terrain_vae_decoder.onnx` | The generator: `(z, biome_id, style_id) -> logits [1, 27, 16, 384, 16]` |
45
+ | `block_group_mapping.json` | Class id -> block group name |
46
+ | `biome_id_mapping.json` | Biome name -> id (includes `UNKNOWN`) |
47
+ | `style_mapping.json` | Style name -> id (`BASE` = 0) |
48
+ | `base_v1/` | The versioned base checkpoint for fine-tuning: PyTorch weights + a manifest with the exact architecture and mappings |
49
+
50
+ ## Use it in a Minecraft server
51
+
52
+ Drop `terrain_vae_decoder.onnx` and the three JSON mappings into `<server>/plugins/GenerativeTerrain/` (plugin jar from the [GitHub repo](https://github.com/ghosteau/generative-terrain)), then in game:
53
+
54
+ ```
55
+ /generateterrain base style, current chunk
56
+ /generateterrain style <name> a fine-tuned custom style
57
+ ```
58
+
59
+ ## Use it from Python
60
+
61
+ ```python
62
+ import numpy as np
63
+ import onnxruntime as ort
64
+ from huggingface_hub import hf_hub_download
65
+
66
+ sess = ort.InferenceSession(hf_hub_download("ghosteau/STEVE-1", "terrain_vae_decoder.onnx"))
67
+
68
+ logits = sess.run(["logits"], {
69
+ "z": np.random.randn(1, 8, 4, 16, 4).astype(np.float32), # the variety
70
+ "biome_id": np.array([15], dtype=np.int64), # PLAINS (see biome_id_mapping.json)
71
+ "style_id": np.zeros(1, dtype=np.int64), # 0 = BASE
72
+ })[0]
73
+
74
+ chunk = logits.argmax(1)[0] # [16, 384, 16] block-group ids, Y index 0 = world Y -64
75
+ ```
76
+
77
+ Sample a fresh `z` per chunk; scale it (`z * 0.8`) for tamer terrain, (`z * 1.2`) for wilder.
78
+
79
+ ## Fine-tune it on your own terrain
80
+
81
+ This is the headline feature. The `base_v1/` directory is a self-contained transfer-learning checkpoint: weights plus a manifest that the pipeline's `fine_tune()` uses to rebuild the exact architecture, so version mismatches are impossible.
82
+
83
+ 1. Export 50+ chunks of your world with the plugin: `/grabchunkarea 5`
84
+ 2. Clone the [GitHub repo](https://github.com/ghosteau/generative-terrain), open `ml/notebooks/FineTune.ipynb`
85
+ 3. Point it at `base_v1/`, your CSV folder, and a style name; run it
86
+
87
+ Fine-tuning trains the new style vector and the FiLM projections (~84k of 4.6M parameters) while everything else stays frozen — a unit test in the repo asserts the base weights come out bit-identical. The exported ONNX then carries both the vanilla style and yours, selectable per command. Up to 8 custom styles fit in one model.
88
+
89
+ ## Training results
90
+
91
+ Vertical block-distribution profile, real vs generated (the terrain-plausibility check — bedrock floor, deepslate/stone body, thin surface band, air above):
92
+
93
+ ![Real vs generated vertical profiles](assets/profiles.png)
94
+
95
+ Training curves (EMA-validated loss):
96
+
97
+ ![Training curves](assets/vae_curves.png)
98
+
99
+ ## Limitations
100
+
101
+ - **Chunks generate independently** — edges between adjacent generated chunks do not line up yet. Cross-chunk edge conditioning is the next planned lever.
102
+ - **Rare biomes are undertrained**: the dataset has 1-5 chunks of TAIGA, FLOWER_FOREST, and SWAMP; those styles lean on the balanced sampler and will look generic.
103
+ - Trees and vegetation are coarse (single log/leaf groups expanded with heuristics by the plugin).
104
+ - Ores are placed procedurally after generation (as vanilla does), not modelled.
105
+
106
+ ## License and attribution
107
+
108
+ MIT. Not affiliated with or endorsed by Mojang or Microsoft; "Minecraft" is a trademark of Mojang Synergies AB. The name STEVE is, of course, for Steve.
assets/profiles.png ADDED
assets/real_profile.png ADDED
assets/vae_curves.png ADDED
base_v1/manifest.json ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": 1,
3
+ "version": "v1",
4
+ "created": "2026-07-02T20:08:08",
5
+ "num_classes": 27,
6
+ "num_biomes": 23,
7
+ "arch": {
8
+ "base_channels": 32,
9
+ "biome_embed_dim": 16,
10
+ "latent_channels": 8,
11
+ "latent_grid": [
12
+ 4,
13
+ 16,
14
+ 4
15
+ ],
16
+ "style_dim": 64,
17
+ "max_custom_styles": 8
18
+ },
19
+ "geometry": {
20
+ "chunk_width": 16,
21
+ "chunk_height": 384,
22
+ "chunk_depth": 16,
23
+ "min_y": -64
24
+ },
25
+ "biome_mapping": {
26
+ "BADLANDS": 0,
27
+ "BAMBOO_JUNGLE": 1,
28
+ "BEACH": 2,
29
+ "BIRCH_FOREST": 3,
30
+ "COLD_OCEAN": 4,
31
+ "DARK_FOREST": 5,
32
+ "DESERT": 6,
33
+ "ERODED_BADLANDS": 7,
34
+ "FLOWER_FOREST": 8,
35
+ "FOREST": 9,
36
+ "JUNGLE": 10,
37
+ "LUKEWARM_OCEAN": 11,
38
+ "MANGROVE_SWAMP": 12,
39
+ "OCEAN": 13,
40
+ "OLD_GROWTH_BIRCH_FOREST": 14,
41
+ "PLAINS": 15,
42
+ "RIVER": 16,
43
+ "SAVANNA": 17,
44
+ "SPARSE_JUNGLE": 18,
45
+ "SUNFLOWER_PLAINS": 19,
46
+ "SWAMP": 20,
47
+ "TAIGA": 21,
48
+ "UNKNOWN": 22
49
+ },
50
+ "block_groups": {
51
+ "AIR": [
52
+ "AIR",
53
+ "CAVE_AIR",
54
+ "VOID_AIR"
55
+ ],
56
+ "STONE": [
57
+ "STONE",
58
+ "ANDESITE",
59
+ "DIORITE",
60
+ "GRANITE",
61
+ "TUFF"
62
+ ],
63
+ "DEEPSLATE": [
64
+ "DEEPSLATE"
65
+ ],
66
+ "DIRT": [
67
+ "DIRT",
68
+ "COARSE_DIRT",
69
+ "ROOTED_DIRT"
70
+ ],
71
+ "GRASS": [
72
+ "GRASS_BLOCK",
73
+ "PODZOL"
74
+ ],
75
+ "SAND": [
76
+ "SAND",
77
+ "RED_SAND"
78
+ ],
79
+ "GRAVEL": [
80
+ "GRAVEL"
81
+ ],
82
+ "CLAY": [
83
+ "CLAY"
84
+ ],
85
+ "WATER": [
86
+ "WATER"
87
+ ],
88
+ "LAVA": [
89
+ "LAVA"
90
+ ],
91
+ "BEDROCK": [
92
+ "BEDROCK"
93
+ ],
94
+ "COAL_ORE": [
95
+ "COAL_ORE",
96
+ "DEEPSLATE_COAL_ORE"
97
+ ],
98
+ "IRON_ORE": [
99
+ "IRON_ORE",
100
+ "DEEPSLATE_IRON_ORE"
101
+ ],
102
+ "COPPER_ORE": [
103
+ "COPPER_ORE",
104
+ "DEEPSLATE_COPPER_ORE"
105
+ ],
106
+ "GOLD_ORE": [
107
+ "GOLD_ORE",
108
+ "DEEPSLATE_GOLD_ORE"
109
+ ],
110
+ "REDSTONE_ORE": [
111
+ "REDSTONE_ORE",
112
+ "DEEPSLATE_REDSTONE_ORE"
113
+ ],
114
+ "LAPIS_ORE": [
115
+ "LAPIS_ORE",
116
+ "DEEPSLATE_LAPIS_ORE"
117
+ ],
118
+ "DIAMOND_ORE": [
119
+ "DIAMOND_ORE",
120
+ "DEEPSLATE_DIAMOND_ORE"
121
+ ],
122
+ "EMERALD_ORE": [
123
+ "EMERALD_ORE",
124
+ "DEEPSLATE_EMERALD_ORE"
125
+ ],
126
+ "OAK_WOOD": [
127
+ "OAK_LOG",
128
+ "OAK_LEAVES"
129
+ ],
130
+ "SPRUCE_WOOD": [
131
+ "SPRUCE_LOG",
132
+ "SPRUCE_LEAVES"
133
+ ],
134
+ "BIRCH_WOOD": [
135
+ "BIRCH_LOG",
136
+ "BIRCH_LEAVES"
137
+ ],
138
+ "JUNGLE_WOOD": [
139
+ "JUNGLE_LOG",
140
+ "JUNGLE_LEAVES"
141
+ ],
142
+ "ACACIA_WOOD": [
143
+ "ACACIA_LOG",
144
+ "ACACIA_LEAVES"
145
+ ],
146
+ "DARK_OAK_WOOD": [
147
+ "DARK_OAK_LOG",
148
+ "DARK_OAK_LEAVES"
149
+ ],
150
+ "VEGETATION": [
151
+ "SHORT_GRASS",
152
+ "TALL_GRASS",
153
+ "SEAGRASS",
154
+ "TALL_SEAGRASS",
155
+ "KELP",
156
+ "KELP_PLANT",
157
+ "LILY_PAD"
158
+ ],
159
+ "MISC": [
160
+ "GLOW_LICHEN",
161
+ "MOSS_BLOCK",
162
+ "MOSS_CARPET",
163
+ "SCULK",
164
+ "SCULK_VEIN",
165
+ "POINTED_DRIPSTONE"
166
+ ]
167
+ },
168
+ "dataset_chunks": 2040
169
+ }
base_v1/style_mapping.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "BASE": 0
3
+ }
base_v1/vae_base.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0228c462212366303bc74c1900c8a3f847691f860fa4d76f59ce03434879e3f7
3
+ size 18532484
biome_id_mapping.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "BADLANDS": 0,
3
+ "BAMBOO_JUNGLE": 1,
4
+ "BEACH": 2,
5
+ "BIRCH_FOREST": 3,
6
+ "COLD_OCEAN": 4,
7
+ "DARK_FOREST": 5,
8
+ "DESERT": 6,
9
+ "ERODED_BADLANDS": 7,
10
+ "FLOWER_FOREST": 8,
11
+ "FOREST": 9,
12
+ "JUNGLE": 10,
13
+ "LUKEWARM_OCEAN": 11,
14
+ "MANGROVE_SWAMP": 12,
15
+ "OCEAN": 13,
16
+ "OLD_GROWTH_BIRCH_FOREST": 14,
17
+ "PLAINS": 15,
18
+ "RIVER": 16,
19
+ "SAVANNA": 17,
20
+ "SPARSE_JUNGLE": 18,
21
+ "SUNFLOWER_PLAINS": 19,
22
+ "SWAMP": 20,
23
+ "TAIGA": 21,
24
+ "UNKNOWN": 22
25
+ }
block_group_mapping.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "0": "AIR",
3
+ "1": "STONE",
4
+ "2": "DEEPSLATE",
5
+ "3": "DIRT",
6
+ "4": "GRASS",
7
+ "5": "SAND",
8
+ "6": "GRAVEL",
9
+ "7": "CLAY",
10
+ "8": "WATER",
11
+ "9": "LAVA",
12
+ "10": "BEDROCK",
13
+ "11": "COAL_ORE",
14
+ "12": "IRON_ORE",
15
+ "13": "COPPER_ORE",
16
+ "14": "GOLD_ORE",
17
+ "15": "REDSTONE_ORE",
18
+ "16": "LAPIS_ORE",
19
+ "17": "DIAMOND_ORE",
20
+ "18": "EMERALD_ORE",
21
+ "19": "OAK_WOOD",
22
+ "20": "SPRUCE_WOOD",
23
+ "21": "BIRCH_WOOD",
24
+ "22": "JUNGLE_WOOD",
25
+ "23": "ACACIA_WOOD",
26
+ "24": "DARK_OAK_WOOD",
27
+ "25": "VEGETATION",
28
+ "26": "MISC"
29
+ }
style_mapping.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "BASE": 0
3
+ }
terrain_vae_decoder.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8311a665929d33ad3ebcf4c92b57ec1913f3ff123f037a791c3890215a794559
3
+ size 16751514