references/algorithm-recipes.md
# Procedural Algorithm Recipes (load on demand)
> **MANDATORY** when implementing drunkard walk, BSP, noise biomes, WFC lite, or loot tables beyond the Golden Path scripts. All heavy work off-thread; SceneTree commits on main thread only.
## Drunkard's walk (organic caves)
```gdscript
func generate_dungeon(width: int, height: int, fill_percent: float = 0.4) -> Array:
var grid: Array = []
for y in height:
grid.append(Array().duplicate(width)) # 1 = wall
var x := width / 2
var y := height / 2
var floor_tiles := 0
var target := int(width * height * fill_percent)
var rng := RandomNumberGenerator.new()
while floor_tiles < target:
if grid[y][x] == 1:
grid[y][x] = 0
floor_tiles += 1
match rng.randi() % 4:
0: x = clampi(x + 1, 0, width - 1)
1: x = clampi(x - 1, 0, width - 1)
2: y = clampi(y + 1, 0, height - 1)
3: y = clampi(y - 1, 0, height - 1)
return grid
```
See [drunknard_walk_path.gd](../scripts/drunknard_walk_path.gd).
## Perlin / FastNoiseLite biomes
```gdscript
var noise := FastNoiseLite.new()
noise.seed = run_seed
noise.frequency = 0.05
# Prefer noise.get_image() once — never sample per frame in _process
```
See [fast_noise_noise2d_master.gd](../scripts/fast_noise_noise2d_master.gd).
## BSP room split
Full `BSPRoom.split()` recursion — [bsp_tree_rooms.gd](../scripts/bsp_tree_rooms.gd). Validate `min_size` before split to avoid degenerate leaves.
## Random loot tables
```gdscript
func roll_rarity(rng: RandomNumberGenerator) -> String:
var roll := rng.randf()
if roll < 0.6: return "common"
if roll < 0.85: return "uncommon"
if roll < 0.95: return "rare"
return "legendary"
```
Pair with [godot-resource-data-patterns](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-resource-data-patterns/SKILL.md) for `ItemData` resources.
## WFC lite loop
Always cap iterations — impossible adjacency rules can spin forever. See [wave_function_collapse_lite.gd](../scripts/wave_function_collapse_lite.gd).
## Expert: graph-before-geometry
Build room graph with `AStar2D` first — validate reachability before spawning tiles. [proc_gen_graph_layout.gd](../scripts/proc_gen_graph_layout.gd).
## Expert: marching cubes / ArrayMesh
Vertices/normals in worker thread → `add_surface_from_arrays` on main thread → `create_trimesh_collision()` only for active chunk. [proc_gen_marching_cubes_base.gd](../scripts/proc_gen_marching_cubes_base.gd).
## Serialization contract
Persist **seed** + player deltas — not full chunk arrays unless required. [proc_gen_seed_history.gd](../scripts/proc_gen_seed_history.gd).
## Godot 4.7
Path3D snap-to-colliders for spline roads/rivers on terrain colliders.
references/migration-notes.md
# Migration notes: godot-procedural-generation
Incremental upgrade for topics this skill covers. Apply **one hop**, stabilize/test, then next. Never skip hops.
If the project is **< 4.0**, follow [godot-version-migration](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-version-migration/SKILL.md) era bridges (legacy → 3→4) until 4.0, then these hops. Official 3→4: [Upgrading from Godot 3 to Godot 4](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.html).
## 4.0 → 4.1
Official: [Upgrading to Godot 4.1](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.1.html)
- `PathFollow2D.lookahead` removed — update 2D spline followers on generated paths.
- `MeshInstance3D.create_multiple_convex_collisions` optional `settings` — retune runtime mesh collider baking.
## 4.1 → 4.2
Official: [Upgrading to Godot 4.2](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.2.html)
- **Mesh format** upgrade — use Project → Tools → Upgrade Mesh Surfaces on generated/imported meshes.
## 4.2 → 4.3
Official: [Upgrading to Godot 4.3](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.3.html)
- **TileMap layers → `TileMapLayer` nodes** — migrate tile-based chunk/world generators before relying on layer APIs.
- `Skeleton3D.add_bone` returns `int32`; pose update signal rename.
- **Reverse Z** depth — update custom terrain/splat shaders comparing depth.
## 4.3 → 4.4
Official: [Upgrading to Godot 4.4](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.4.html)
- CSG uses Manifold — **non-manifold** meshes unsupported; bake proc meshes to `MeshInstance3D` instead of CSG booleans.
- `FileAccess.store_*` methods return `bool` success — handle chunk save failures.
## 4.4 → 4.5
Official: [Upgrading to Godot 4.5](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.5.html)
- `TileMapLayer.get_coords_for_body_rid` less precise with physics chunking — set `physics_quadrant_size = 1` for tile-collision debug of generated worlds.
- GLTF/BLEND/FBX naming version for non-joint nodes in skeletons — set Import dock Naming Version for instanced props.
## 4.5 → 4.6
Official: [Upgrading to Godot 4.6](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.6.html)
- Retune Environment glow/fog if the genre leans on bloom-heavy looks (biome fog, cave lighting).
- `MeshInstance3D.skeleton` default empty; SpringBone enums moved to `SkeletonModifier3D`.
## 4.6 → 4.7
Official: [Upgrading to Godot 4.7](https://docs.godotengine.org/en/stable/tutorials/migrating/upgrading_to_godot_4.7.html)
- Confirm project stretch mode and `AudioStreamPlayer.area_mask` after opening in 4.7.
- **Path3D snap-to-colliders** for spline-based road/river generation on terrain colliders.
- Jolt: `WorldBoundaryShape3D.plane.d` sign convention flipped — negate infinite floor/ceiling used in heightfield bounds.
scripts/bsp_tree_rooms.gd
# bsp_tree_rooms.gd
# Binary Space Partitioning for structured floor plans
extends Node
class RoomNode:
var x: int; var y: int; var w: int; var h: int
var left: RoomNode; var right: RoomNode
func split():
# Logic to split vertically or horizontally
# until min_room_size is reached.
pass
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html
# - https://docs.godotengine.org/en/stable/classes/class_astar2d.html
# - https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md — structured floor plans for run-based dungeons
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md — place rooms then batch hallway floors
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/cellular_automata_dungeon.gd
# cellular_automata_dungeon.gd
# Smooth cave generation using Cellular Automata (4/5 rule)
extends Node
@export var width := 60
@export var height := 40
@export var fill_percent := 45
var map: Array = []
var rng := RandomNumberGenerator.new()
func generate_caves(seed: int = 0) -> Array:
rng.seed = seed
_random_fill()
for i in range(5):
_smooth_map()
return map
func _smooth_map() -> void:
var new_map = map.duplicate(true)
for x in range(1, width - 1):
for y in range(1, height - 1):
var neighbors := _get_neighbor_count(x, y)
if neighbors > 4:
new_map[x][y] = 1 # Wall
elif neighbors < 4:
new_map[x][y] = 0 # Floor
map = new_map
func _get_neighbor_count(grid_x: int, grid_y: int) -> int:
var count := 0
for x in range(grid_x - 1, grid_x + 2):
for y in range(grid_y - 1, grid_y + 2):
if x != grid_x or y != grid_y:
count += map[x][y]
return count
func _random_fill() -> void:
map.clear()
for x in range(width):
map.append([])
for y in range(height):
map[x].append(1 if rng.randi() % 100 < fill_percent else 0)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html
# - https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html
# - https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md — paint CA walls/floors with terrain autotile
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-sandbox/SKILL.md — cellular automata sandboxes reuse the same grid rules
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/drunknard_walk_path.gd
# drunknard_walk_path.gd
# Simple path generation for dungeons or rivers
extends Node
var rng := RandomNumberGenerator.new()
func generate_path(start: Vector2i, steps: int, seed: int = 0) -> Array[Vector2i]:
rng.seed = seed
var current := start
var path: Array[Vector2i] = [start]
var directions := [Vector2i.UP, Vector2i.DOWN, Vector2i.LEFT, Vector2i.RIGHT]
for i in range(steps):
var dir := directions[rng.randi() % directions.size()]
current += dir
if not path.has(current):
path.append(current)
return path
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html
# - https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html
# - https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md — carve walk cells into floors/rivers
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md — lightweight tunnel layouts for early floors
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/dungeon_generator.gd
# skills/procedural-generation/scripts/dungeon_generator.gd
extends Node2D
## Dungeon Generator Expert Pattern
## BSP-based room placement with FastNoiseLite for terrain variation.
class_name DungeonGenerator
@export var room_count := 10
@export var min_room_size := Vector2i(5, 5)
@export var max_room_size := Vector2i(12, 12)
@export var map_size := Vector2i(100, 100)
var noise := FastNoiseLite.new()
var rooms: Array[Rect2i] = []
func _ready() -> void:
noise.seed = randi()
noise.frequency = 0.05
func generate() -> Array[Rect2i]:
rooms.clear()
# BSP rectangle subdivision
var initial_rect := Rect2i(Vector2i.ZERO, map_size)
var partitions := [initial_rect]
# Split into smaller partitions
while partitions.size() < room_count:
var partition: Rect2i = partitions.pick_random()
partitions.erase(partition)
var split_rects := _split_rect(partition)
if split_rects.size() == 2:
partitions.append_array(split_rects)
else:
partitions.append(partition) # Couldn't split, keep it
# Create rooms inside partitions
for partition in partitions:
var room := _create_room_in_partition(partition)
if room.has_area():
rooms.append(room)
return rooms
func _split_rect(rect: Rect2i) -> Array[Rect2i]:
# Can't split if too small
if rect.size.x < min_room_size.x * 2 or rect.size.y < min_room_size.y * 2:
return []
var split_horizontal := randf() > 0.5
if split_horizontal:
var split_y := randi_range(rect.position.y + min_room_size.y, rect.end.y - min_room_size.y)
return [
Rect2i(rect.position, Vector2i(rect.size.x, split_y - rect.position.y)),
Rect2i(Vector2i(rect.position.x, split_y), Vector2i(rect.size.x, rect.end.y - split_y))
]
else:
var split_x := randi_range(rect.position.x + min_room_size.x, rect.end.x - min_room_size.x)
return [
Rect2i(rect.position, Vector2i(split_x - rect.position.x, rect.size.y)),
Rect2i(Vector2i(split_x, rect.position.y), Vector2i(rect.end.x - split_x, rect.size.y))
]
func _create_room_in_partition(partition: Rect2i) -> Rect2i:
var room_w := randi_range(min_room_size.x, min(max_room_size.x, partition.size.x - 2))
var room_h := randi_range(min_room_size.y, min(max_room_size.y, partition.size.y - 2))
var room_x := partition.position.x + randi_range(1, partition.size.x - room_w - 1)
var room_y := partition.position.y + randi_range(1, partition.size.y - room_h - 1)
return Rect2i(room_x, room_y, room_w, room_h)
func get_noise_value_at(pos: Vector2i) -> float:
return noise.get_noise_2d(float(pos.x), float(pos.y))
## EXPERT USAGE:
## var gen := DungeonGenerator.new()
## gen.room_count = 15
## add_child(gen)
## var rooms := gen.generate()
##
## # Use rooms to place tiles
## for room in rooms:
## for x in range(room.position.x, room.end.x):
## for y in range(room.position.y, room.end.y):
## tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i.ZERO)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_fastnoiselite.html
# - https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html
# - https://docs.godotengine.org/en/stable/classes/class_astar2d.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md — place BSP rooms then batch hallways
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md — room_count / size exports feed run floors
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-3d-world-building/SKILL.md — same partitions can drive GridMap cells
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/fast_noise_noise2d_master.gd
# fast_noise_noise2d_master.gd
# Advanced usage of FastNoiseLite for terrain and heightmaps
extends Node
# EXPERT NOTE: Noise generation is expensive. Generate noise maps
# into a typed Array or Image rather than querying 'get_noise_2d' per tile.
var noise := FastNoiseLite.new()
var rng := RandomNumberGenerator.new()
func configure(seed: int, frequency: float = 0.01) -> void:
rng.seed = seed
noise.seed = seed
noise.frequency = frequency
noise.noise_type = FastNoiseLite.TYPE_PERLIN
func generate_heightmap(width: int, height: int) -> Image:
return noise.get_image(width, height)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_fastnoiselite.html
# - https://docs.godotengine.org/en/stable/classes/class_noise.html
# - https://docs.godotengine.org/en/stable/classes/class_image.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md — sample height/biome Image into TileMapLayer cells
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-3d-world-building/SKILL.md — drive GridMap / terrain meshes from noise maps
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/l_system_tree_gen.gd
# l_system_tree_gen.gd
# Procedural tree/plant growth using L-Systems
extends Node3D
# Turtle graphics approach to plant generation.
func draw_lsystem(axiom: String, rules: Dictionary, iterations: int):
var current = axiom
for i in range(iterations):
var next = ""
for char in current:
next += rules.get(char, char)
current = next
# Then iterate characters to draw lines/branches
return current
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/surfacetool.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/using_multimesh.html
# - https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-3d-materials/SKILL.md — bark/leaf materials on generated branch meshes
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — MultiMesh forests instead of per-tree nodes
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/marching_squares_metaballs.gd
# marching_squares_metaballs.gd
# Smooth contour generation (Marching Squares algorithm)
extends Node
# EXPERT NOTE: Use Marching Squares for organic-looking terrains,
# liquid simulations, or influence maps.
func get_contour_index(tl: float, tr: float, br: float, bl: float, threshold: float) -> int:
var index = 0
if tl >= threshold: index |= 8
if tr >= threshold: index |= 4
if br >= threshold: index |= 2
if bl >= threshold: index |= 1
return index
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/surfacetool.html
# - https://docs.godotengine.org/en/stable/classes/class_fastnoiselite.html
# - https://docs.godotengine.org/en/stable/tutorials/2d/2d_meshes.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-shaders-basics/SKILL.md — contour influence as canvas_item mask inputs
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-2d-physics/SKILL.md — rebuild CollisionPolygon2D from contour edges
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/mesh_gen_infinite_terrain.gd
# mesh_gen_infinite_terrain.gd
# Dynamic Mesh generation for 3D terrain [ArrayMesh]
extends MeshInstance3D
# EXPERT NOTE: For infinite 3D terrain, generating a custom ArrayMesh
# is better than tiling StaticBody3D planes.
func generate_plane(width: int, depth: int):
var am = ArrayMesh.new()
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
# Generate vertices with noise height
for z in range(depth):
for x in range(width):
var y = 0 # noise.get_noise_2d(x, z)
st.add_vertex(Vector3(x, y, z))
# Generate indices...
st.generate_normals()
am = st.commit()
mesh = am
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/arraymesh.html
# - https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/surfacetool.html
# - https://docs.godotengine.org/en/stable/classes/class_fastnoiselite.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-3d-world-building/SKILL.md — LOD / visibility ranges around generated chunks
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-physics-3d/SKILL.md — trimesh/convex collision after mesh commit
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/multi_threaded_chunk_gen.gd
# multi_threaded_chunk_gen.gd
# Offloading heavy proc-gen tasks to WorkerThreadPool
extends Node
signal chunk_ready(chunk_pos: Vector2i, height_data: PackedFloat32Array)
@export var world_seed: int = 0
@export var chunk_size: int = 16
var _noise := FastNoiseLite.new()
func _ready() -> void:
_noise.seed = world_seed
_noise.frequency = 0.05
_noise.noise_type = FastNoiseLite.TYPE_PERLIN
func request_chunk(chunk_pos: Vector2i) -> void:
WorkerThreadPool.add_task(_generate_chunk_task.bind(chunk_pos))
func _generate_chunk_task(pos: Vector2i) -> void:
var data := _calc_data(pos)
call_deferred("_finalize_chunk", pos, data)
func _calc_data(pos: Vector2i) -> PackedFloat32Array:
var data := PackedFloat32Array()
data.resize(chunk_size * chunk_size)
for y in chunk_size:
for x in chunk_size:
var wx := pos.x * chunk_size + x
var wy := pos.y * chunk_size + y
data[y * chunk_size + x] = _noise.get_noise_2d(float(wx), float(wy))
return data
func _finalize_chunk(pos: Vector2i, data: PackedFloat32Array) -> void:
chunk_ready.emit(pos, data)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_workerthreadpool.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/thread_safe_apis.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-open-world/SKILL.md — chunk request radii around the player
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-scene-management/SKILL.md — main-thread scene attach after deferred finalize
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/poisson_disk_sampling_2d.gd
# poisson_disk_sampling_2d.gd
# Blue-noise distribution for non-overlapping object placement
extends Node
# EXPERT NOTE: Poisson Disk Sampling is superior to random placement
# for trees, rocks, and spawns because it guarantees a minimum
# distance between objects, preventing 'clumping'.
var rng := RandomNumberGenerator.new()
func generate_points(width: float, height: float, radius: float, k: int = 30, seed: int = 0) -> Array[Vector2]:
rng.seed = seed
var points: Array[Vector2] = []
var spawn_points: Array[Vector2] = []
spawn_points.append(Vector2(width / 2, height / 2))
while spawn_points.size() > 0:
var spawn_index := rng.randi() % spawn_points.size()
var spawn_centre := spawn_points[spawn_index]
var accepted := false
for i in range(k):
var angle := rng.randf() * PI * 2
var dir := Vector2(cos(angle), sin(angle))
var candidate := spawn_centre + dir * rng.randf_range(radius, 2 * radius)
if _is_valid(candidate, width, height, radius, points):
points.append(candidate)
spawn_points.append(candidate)
accepted = true
break
if not accepted:
spawn_points.remove_at(spawn_index)
return points
func _is_valid(p: Vector2, w: float, h: float, r: float, points: Array[Vector2]) -> bool:
if p.x < 0 or p.x > w or p.y < 0 or p.y > h:
return false
for other in points:
if p.distance_to(other) < r:
return false
return true
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html
# - https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html
# - https://docs.godotengine.org/en/stable/tutorials/performance/using_multimesh.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-monte-carlo-balancer/SKILL.md — tune min radius vs spawn density / difficulty
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — MultiMesh instance props at blue-noise points
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/proc_gen_graph_layout.gd
class_name ProcGenGraphLayout
extends Node
## Expert pattern for managing dungeon layouts using AStar data structures.
## Decouples logical connections (rooms/hallways) from physical geometry.
var layout_graph := AStar2D.new()
## Adds a room node to the layout.
func add_room(id: int, pos: Vector2) -> void:
layout_graph.add_point(id, pos)
## Connects two rooms with a hallway.
func connect_rooms(id_a: int, id_b: int, bidirectional: bool = true) -> void:
layout_graph.connect_points(id_a, id_b, bidirectional)
## Returns all rooms in the layout.
func get_all_rooms() -> PackedInt64Array:
return layout_graph.get_point_ids()
## Returns connections for a specific room (e.g. to determine where doors should be).
func get_room_connections(id: int) -> PackedInt64Array:
return layout_graph.get_point_connections(id)
## Returns the spatial distance between two connected rooms.
func get_hallway_length(id_a: int, id_b: int) -> float:
return layout_graph.get_point_position(id_a).distance_to(layout_graph.get_point_position(id_b))
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_astar2d.html
# - https://docs.godotengine.org/en/stable/classes/class_astar3d.html
# - https://docs.godotengine.org/en/stable/tutorials/navigation/navigation_introduction_3d.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-navigation-pathfinding/SKILL.md — validate reachability before geometry spawn
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md — room graph drives floor progression
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/proc_gen_marching_cubes_base.gd
class_name ProcGenMarchingCubesBase
extends MeshInstance3D
## Base class for 3D terrain generation using ArrayMesh.
## Provides the foundation for Marching Cubes or Voxel geometry.
func update_geometry(vertices: PackedVector3Array, normals: PackedVector3Array, indices: PackedInt32Array) -> void:
var surface_array = []
surface_array.resize(Mesh.ARRAY_MAX)
surface_array[Mesh.ARRAY_VERTEX] = vertices
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices
var arr_mesh = ArrayMesh.new()
# PRIMITIVE_TRIANGLES is the standard for 3D surfaces
arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
self.mesh = arr_mesh
# Optimization: Generate collision if needed
# create_trimesh_collision()
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/arraymesh.html
# - https://docs.godotengine.org/en/stable/classes/class_arraymesh.html
# - https://docs.godotengine.org/en/stable/tutorials/physics/collision_shapes_3d.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-physics-3d/SKILL.md — create_trimesh_collision only for active chunks
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-3d-world-building/SKILL.md — hand off voxel meshes into level streaming
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/proc_gen_seed_history.gd
class_name ProcGenSeedHistory
extends Node
## Expert Seed & State History Manager.
## Ensures deterministic procedural generation and allows "undo/redo" of random sequences.
var rng := RandomNumberGenerator.new()
var state_history: Array[int] = []
func _ready() -> void:
rng.randomize()
## Seeds the generator and clears history.
func initialize_seed(new_seed: int) -> void:
rng.seed = new_seed
state_history.clear()
## Records the current RNG state before a generation step.
func push_state() -> void:
state_history.append(rng.state)
## Restores the RNG to a previous state.
func pop_state() -> void:
if state_history.is_empty(): return
rng.state = state_history.pop_back()
## Returns the current seed string (useful for sharing).
func get_seed_string() -> String:
return str(rng.seed)
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html
# - https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html
# - https://docs.godotengine.org/en/stable/tutorials/io/background_loading.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-save-load-systems/SKILL.md — persist seed + RNG state with player deltas
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md — shareable run seeds and undoable roll steps
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/wave_function_collapse_lite.gd
# wave_function_collapse_lite.gd
# Procedural tile arrangement using WFC principles
extends Node
@export var grid_width: int = 10
@export var grid_height: int = 10
@export var max_iterations: int = 1000
var rng := RandomNumberGenerator.new()
var _possibilities: Array = [] # 2D: each cell holds Array of tile ids
var _collapsed: Array = [] # 2D: bool
var _iterations: int = 0
func initialize(seed: int, tile_ids: Array) -> void:
rng.seed = seed
_iterations = 0
_possibilities.clear()
_collapsed.clear()
for y in grid_height:
var row_p: Array = []
var row_c: Array = []
for x in grid_width:
row_p.append(tile_ids.duplicate())
row_c.append(false)
_possibilities.append(row_p)
_collapsed.append(row_c)
func iterate() -> bool:
if _iterations >= max_iterations:
return false
_iterations += 1
var pos := find_lowest_entropy()
if pos.x < 0:
return false
if not collapse(pos.x, pos.y):
return false
propagate(pos.x, pos.y)
return true
func find_lowest_entropy() -> Vector2i:
var best := Vector2i(-1, -1)
var best_count := 999999
for y in grid_height:
for x in grid_width:
if _collapsed[y][x]:
continue
var count: int = _possibilities[y][x].size()
if count < best_count:
best_count = count
best = Vector2i(x, y)
return best
func collapse(x: int, y: int) -> bool:
var opts: Array = _possibilities[y][x]
if opts.is_empty():
return false
var chosen = opts[rng.randi() % opts.size()]
_possibilities[y][x] = [chosen]
_collapsed[y][x] = true
return true
func propagate(x: int, y: int) -> void:
var chosen = _possibilities[y][x][0]
var neighbors := [
Vector2i(x + 1, y), Vector2i(x - 1, y),
Vector2i(x, y + 1), Vector2i(x, y - 1),
]
for n in neighbors:
if n.x < 0 or n.x >= grid_width or n.y < 0 or n.y >= grid_height:
continue
if _collapsed[n.y][n.x]:
continue
var opts: Array = _possibilities[n.y][n.x]
opts.erase(chosen)
if opts.is_empty():
opts.append(chosen)
func get_collapsed_grid() -> Array:
var grid: Array = []
for y in grid_height:
var row: Array = []
for x in grid_width:
if _collapsed[y][x] and not _possibilities[y][x].is_empty():
row.append(_possibilities[y][x][0])
else:
row.append(null)
grid.append(row)
return grid
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html
# - https://docs.godotengine.org/en/stable/classes/class_tilemappattern.html
# - https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-resource-data-patterns/SKILL.md — adjacency rule Resources per tile
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md — commit collapsed cells via set_pattern
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
scripts/wfc_level_generator.gd
# skills/procedural-generation/code/wfc_level_generator.gd
extends Node
## Wave Function Collapse (WFC) Expert Pattern
## Generates rule-based tile maps with zero constraint violations.
@export var grid_size: Vector2i = Vector2i(10, 10)
@export var tile_library: Array[Resource] # Contains TileData with adjacency rules
var _grid: Array = [] # 2D array of 'Cell' objects
class Cell:
var possibilities: Array = [] # List of TileData
var collapsed: bool = false
var selected_tile: Resource = null
func _ready() -> void:
# 1. WFC Initialization
_init_grid()
_collapse_next()
func _init_grid() -> void:
for x in grid_size.x:
_grid.append([])
for y in grid_size.y:
var cell = Cell.new()
cell.possibilities = tile_library.duplicate()
_grid[x].append(cell)
func _collapse_next() -> void:
# 2. Entropy Selection
# Expert logic: Select the cell with the FEWEST possibilities
# to collapse next (Min-Entropy Heuristic).
var cell = _find_lowest_entropy()
if not cell:
print("Level Generation Complete")
return
cell.selected_tile = cell.possibilities.pick_random()
cell.collapsed = true
cell.possibilities = [cell.selected_tile]
# 3. Constraint Propagation
# Update neighbors based on the newly selected tile's rules.
_propagate_constraints()
# Recursively collapse until finished
_collapse_next()
func _find_lowest_entropy() -> Cell:
# Basic min-entropy search...
return null
func _propagate_constraints() -> void:
# Placeholder for the AC-3 or similar arc-consistency algorithm
pass
## EXPERT NOTE:
## Use 'Poisson Disk Sampling': For object distribution (trees/rocks),
## use Poisson Disk instead of pure Random to ensure a minimum
## distance between items, preventing unrealistic 'clumping'.
## For 'procedural-generation', use 'WorkerThreadPool' to run
## generation in the background, allowing for 'Infinite World'
## loading without frame-stutters.
## NEVER use 'randi()' for map seeds; use a unique 'RandomNumberGenerator'
## instance per level to ensure the same seed ALWAYS produces the same map.
# =============================================================================
# GDSkills research links (agents) — does not affect runtime
# Official docs:
# - https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html
# - https://docs.godotengine.org/en/stable/classes/class_workerthreadpool.html
# - https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html
# Related skills:
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-resource-data-patterns/SKILL.md — tile_library adjacency Resources
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md — constraint-safe room tiles for seeded runs
# - https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md — keep WFC off the main thread
# Parent skill: https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-procedural-generation/SKILL.md
# =============================================================================
SKILL.md
---
name: godot-procedural-generation
description: "Expert blueprint for procedural content generation (dungeons, terrain, loot, levels) using FastNoiseLite, random walks, BSP trees, Wave Function Collapse, and seeded randomization. Use when creating roguelikes, sandbox games, or dynamic content. Keywords procedural, generation, FastNoiseLite, Perlin noise, BSP, drunkard walk, Wave Function Collapse, seeding."
---
# Procedural Generation
Seeded algorithms, noise functions, and constraint propagation define replayable content generation. **Do not paste inline algorithm tutorials** — load the MANDATORY scripts below.
## NEVER Do in Procedural Generation
- **NEVER generate chunks on the Main Thread** — Proc-gen is CPU intensive and causes frame-rate spikes. Use `WorkerThreadPool` or a background `Thread` to keep the UI responsive.
- **NEVER query `FastNoiseLite` every frame** — Sampling noise per frame (especially in `_process`) is a massive waste. Generate your map into an `Image` or `Array` once and sample from memory [NoiseSampling].
- **NEVER use `randi()` for reproducible seeds** — Always store and reuse a specific `seed` within your random number generator (`RandomNumberGenerator.new()`) to ensure consistent world generation.
- **NEVER use pure randomness for object placement** — Pure random (white noise) causes clumping and overlapping. Use **Poisson Disk Sampling** or **Jittered Grids** for natural-looking distributions.
- **NEVER forget to bound your loops** — Procedural loops (like WFC or Cellular Automata) can easily enter infinite states if constraints are impossible. Always include a `max_iterations` safety break.
- **NEVER instantiate nodes directly from proc-gen threads** — You cannot touch the SceneTree from a worker thread. Generate the *data* in the thread, then notify the Main Thread to handle `add_child()`.
- **NEVER use complex WFC for simple layouts** — Wave Function Collapse is powerful but overkill for simple paths. Use **Drunkard's Walk** or **BSP** for lightweight structured layouts.
- **NEVER rely on `TileMap.set_cell()` for large-scale updates** — Updating 10,000 cells individually is slow. Prepare a `TileMapPattern` and use `set_pattern()` or `set_cells_terrain_connect()` for batch updates.
- **NEVER forget to bake Navigation at the end** — Procedurally generated worlds need their navmeshes rebaked at runtime or the AI will walk into walls.
- **NEVER ignore data serialization** — If you generate a world, you must be able to save the *seed* and any *player modifications*. Don't try to save the entire raw chunk state if avoidable.
---
## Golden Path (MANDATORY)
Every generator starts here — seed isolation, async data, main-thread commit:
1. **Seed & RNG** — **MANDATORY** [proc_gen_seed_history.gd](scripts/proc_gen_seed_history.gd): one `RandomNumberGenerator` per level/chunk; persist `seed` + `state` for shareable runs.
2. **Async chunks** — **MANDATORY** [multi_threaded_chunk_gen.gd](scripts/multi_threaded_chunk_gen.gd): `WorkerThreadPool.add_task` → compute data off-thread → `call_deferred("_finalize_chunk")` for SceneTree/node work.
3. **Validate → bake nav** — after tiles/meshes land on the main thread, rebake `NavigationRegion` (see [godot-navigation-pathfinding](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-navigation-pathfinding/SKILL.md)).
```gdscript
var rng := RandomNumberGenerator.new()
func begin_generation(run_seed: int) -> void:
rng.seed = run_seed
WorkerThreadPool.add_task(_build_data.bind(run_seed))
func _build_data(seed: int) -> Dictionary:
var local_rng := RandomNumberGenerator.new()
local_rng.seed = seed
var noise := FastNoiseLite.new()
noise.seed = seed
return {"heights": noise.get_image(64, 64)}
func _ready() -> void:
# Worker returns here — safe for nodes
pass
func _finalize_from_worker(data: Dictionary) -> void:
# add_child / set_pattern / create_trimesh_collision — main thread only
pass
```
> **Do NOT Load** the full `scripts/` folder. Open only the script that matches your algorithm row below.
## Algorithm Decision Tree
| Layout / content need | Algorithm | Script (MANDATORY when chosen) |
|-----------------------|-----------|--------------------------------|
| Winding tunnels, rivers, simple paths | Drunkard's Walk | **MANDATORY** [drunknard_walk_path.gd](scripts/drunknard_walk_path.gd) |
| Structured rooms + hallways | BSP | **MANDATORY** [bsp_tree_rooms.gd](scripts/bsp_tree_rooms.gd) |
| Organic caves / smooth terrain | Cellular Automata (4/5) | **MANDATORY** [cellular_automata_dungeon.gd](scripts/cellular_automata_dungeon.gd) |
| Heightmaps, biomes, infinite terrain | FastNoiseLite → Image | **MANDATORY** [fast_noise_noise2d_master.gd](scripts/fast_noise_noise2d_master.gd) |
| Trees, rocks, spawns (no clumping) | Poisson Disk | **MANDATORY** [poisson_disk_sampling_2d.gd](scripts/poisson_disk_sampling_2d.gd) |
| Tile adjacency / city blocks | Wave Function Collapse | **MANDATORY** [wave_function_collapse_lite.gd](scripts/wave_function_collapse_lite.gd) (lite) or [wfc_level_generator.gd](scripts/wfc_level_generator.gd) (full rules) |
| Room graph before geometry | AStar graph layout | **MANDATORY** [proc_gen_graph_layout.gd](scripts/proc_gen_graph_layout.gd) |
| 3D voxel / smooth terrain mesh | Marching Cubes base | **MANDATORY** [proc_gen_marching_cubes_base.gd](scripts/proc_gen_marching_cubes_base.gd) |
| Infinite chunked 3D terrain | ArrayMesh + LOD chunks | **MANDATORY** [mesh_gen_infinite_terrain.gd](scripts/mesh_gen_infinite_terrain.gd) |
| Plants / branching structures | L-System | **MANDATORY** [l_system_tree_gen.gd](scripts/l_system_tree_gen.gd) |
| Contour / metaball maps (2D) | Marching Squares | **MANDATORY** [marching_squares_metaballs.gd](scripts/marching_squares_metaballs.gd) |
**Routing hints:** Simple path → drunkard; rectangular rooms → BSP; constraint tiles → WFC lite; open-world chunks → noise + `multi_threaded_chunk_gen.gd`. For roguelike run orchestration, hand off to [godot-genre-roguelike](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md).
## Available Scripts
### Core (always start here)
- [proc_gen_seed_history.gd](scripts/proc_gen_seed_history.gd) — **MANDATORY** seeded `RandomNumberGenerator` with push/pop state history
- [multi_threaded_chunk_gen.gd](scripts/multi_threaded_chunk_gen.gd) — **MANDATORY** WorkerThreadPool → `call_deferred` chunk finalize pattern
### 2D layout & placement
- [drunknard_walk_path.gd](scripts/drunknard_walk_path.gd) — **MANDATORY** for tunnels/paths (pass local RNG, never global `randi()`)
- [bsp_tree_rooms.gd](scripts/bsp_tree_rooms.gd) — **MANDATORY** for structured floor plans
- [cellular_automata_dungeon.gd](scripts/cellular_automata_dungeon.gd) — **MANDATORY** for organic caves
- [poisson_disk_sampling_2d.gd](scripts/poisson_disk_sampling_2d.gd) — **MANDATORY** for blue-noise prop/enemy placement
- [wave_function_collapse_lite.gd](scripts/wave_function_collapse_lite.gd) — **MANDATORY** lite WFC with entropy + `max_iterations`
- [wfc_level_generator.gd](scripts/wfc_level_generator.gd) — full WFC with tile-library adjacency rules
- [proc_gen_graph_layout.gd](scripts/proc_gen_graph_layout.gd) — graph-before-geometry via AStar2D/3D
### Noise & 3D
- [fast_noise_noise2d_master.gd](scripts/fast_noise_noise2d_master.gd) — **MANDATORY** FastNoiseLite → Image heightmaps
- [mesh_gen_infinite_terrain.gd](scripts/mesh_gen_infinite_terrain.gd) — runtime ArrayMesh terrain with LOD potential
- [proc_gen_marching_cubes_base.gd](scripts/proc_gen_marching_cubes_base.gd) — 3D mesh from voxel data
- [marching_squares_metaballs.gd](scripts/marching_squares_metaballs.gd) — 2D contour extraction
- [l_system_tree_gen.gd](scripts/l_system_tree_gen.gd) — procedural plant/tree grammar
## Expert Procedural Patterns
### 1. 3D Terrain via ArrayMesh (Marching Cubes)
For voxel-like or smooth organic terrain, use `ArrayMesh` to generate geometry from code.
- **Logic**: Calculate vertices, normals, and indices in a worker thread.
- **Commit**: Use `add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)` to create the mesh.
- **Performance**: Use `create_trimesh_collision()` only for the current chunk to keep physics updates fast.
### 2. Graph-Based Dungeon Logic
Don't generate your dungeon geometry first. Build a logical graph using `AStar2D`.
- **Vertices**: Represent "Rooms".
- **Edges**: Represent "Hallways" or "Doors".
- **Benefit**: You can easily run validation (is every room reachable?) before spawning a single mesh.
## Deep dive (load on demand)
Drunkard walk, noise biomes, BSP, loot tables, WFC loops — [references/algorithm-recipes.md](references/algorithm-recipes.md).
## Reference
> Progressive disclosure: open Official Documentation links only when researching a specific API; load Related Skills when routing to a peer domain — do not preload the whole lattice.
### Official Documentation
- [FastNoiseLite](https://docs.godotengine.org/en/stable/classes/class_fastnoiselite.html) — seed, frequency, noise type, and `get_image()`/`get_noise_2d()` for heightmaps and biome masks.
- [Random number generation](https://docs.godotengine.org/en/stable/tutorials/math/random_number_generation.html) — why per-generator `RandomNumberGenerator` seeds beat global `randi()` for shareable runs.
- [RandomNumberGenerator](https://docs.godotengine.org/en/stable/classes/class_randomnumbergenerator.html) — `seed`/`state` APIs for deterministic sequences and undoable RNG history.
- [Using multiple threads](https://docs.godotengine.org/en/stable/tutorials/performance/using_multiple_threads.html) — offload chunk/WFC work without freezing the main loop.
- [Thread-safe APIs](https://docs.godotengine.org/en/stable/tutorials/performance/thread_safe_apis.html) — which Godot APIs workers may call; SceneTree/node creation stays on the main thread.
- [WorkerThreadPool](https://docs.godotengine.org/en/stable/classes/class_workerthreadpool.html) — `add_task` + `call_deferred` finalize pattern for async chunk generation.
- [Using ArrayMesh](https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/arraymesh.html) — commit vertex/normal/index arrays for marching-cubes and infinite terrain meshes.
- [Using SurfaceTool](https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/surfacetool.html) — incremental vertex building and normal generation for runtime planes.
- [Using TileMaps](https://docs.godotengine.org/en/stable/tutorials/2d/using_tilemaps.html) — TileMapLayer/pattern batch writes after BSP, CA, WFC, or drunkard-walk grids.
- [Using GridMaps](https://docs.godotengine.org/en/stable/tutorials/3d/using_gridmaps.html) — modular 3D cell placement backend for dungeon/terrain generators.
- [Navigation introduction (3D)](https://docs.godotengine.org/en/stable/tutorials/navigation/navigation_introduction_3d.html) — rebake NavigationRegion meshes after procedural geometry lands.
- [AStar2D](https://docs.godotengine.org/en/stable/classes/class_astar2d.html) — room/hallway graph validation before spawning tiles or meshes.
### Related Skills
#### Prerequisites
- [godot-project-foundations](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-project-foundations/SKILL.md) — scenes, resources, and import basics before generators emit TileMaps, GridMaps, or ArrayMeshes.
- [godot-gdscript-mastery](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-gdscript-mastery/SKILL.md) — typed arrays, `call_deferred`, and WorkerThreadPool task patterns used across every generator script.
- [godot-resource-data-patterns](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-resource-data-patterns/SKILL.md) — Resource-backed tile libraries, adjacency rules, and seed configs instead of hard-coded magic tables.
#### Complements
- [godot-tilemap-mastery](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-tilemap-mastery/SKILL.md) — `set_pattern` / terrain connect batching so large CA/WFC grids do not call `set_cell` per tile.
- [godot-3d-world-building](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-3d-world-building/SKILL.md) — GridMap/MeshLibrary/CSG placement backends that consume room graphs and heightmaps.
- [godot-navigation-pathfinding](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-navigation-pathfinding/SKILL.md) — runtime navmesh bake after rooms, caves, or terrain chunks finish.
- [godot-performance-optimization](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-performance-optimization/SKILL.md) — budgets for mesh commits, collision trimeshes, and MultiMesh prop scattering after generation.
- [godot-save-load-systems](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-save-load-systems/SKILL.md) — persist seed + player deltas instead of serializing every generated chunk.
- [godot-scene-management](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-scene-management/SKILL.md) — threaded load/unload of chunk scenes that wrap generated data.
- [godot-monte-carlo-balancer](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-monte-carlo-balancer/SKILL.md) — sample spawn density, loot tables, and room difficulty against seed distributions before shipping.
#### Downstream / consumers
- [godot-genre-roguelike](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-roguelike/SKILL.md) — run-based dungeon crawlers that consume BSP/WFC/drunkard generators and seeded RNG.
- [godot-genre-sandbox](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-sandbox/SKILL.md) — voxel/chunk worlds and cellular-automata sandboxes built on infinite terrain and CA scripts.
- [godot-genre-open-world](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-genre-open-world/SKILL.md) — chunk streaming and floating-origin layers that wrap multi-threaded chunk gen.
#### Master
- [godot-master](https://github.com/thedivergentai/gd-agentic-skills/blob/main/skills/godot-master/SKILL.md) — library router and mirrored module entry for cross-skill discovery.