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
WorkerThreadPoolor a backgroundThreadto keep the UI responsive. - NEVER query
FastNoiseLiteevery frame β Sampling noise per frame (especially in_process) is a massive waste. Generate your map into anImageorArrayonce and sample from memory [NoiseSampling]. - NEVER use
randi()for reproducible seeds β Always store and reuse a specificseedwithin 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_iterationssafety 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 aTileMapPatternand useset_pattern()orset_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:
- Seed & RNG β MANDATORY proc_gen_seed_history.gd: one
RandomNumberGeneratorper level/chunk; persistseed+statefor shareable runs. - Async chunks β MANDATORY multi_threaded_chunk_gen.gd:
WorkerThreadPool.add_taskβ compute data off-thread βcall_deferred("_finalize_chunk")for SceneTree/node work. - Validate β bake nav β after tiles/meshes land on the main thread, rebake
NavigationRegion(see godot-navigation-pathfinding).
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
passDo 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 |
| Structured rooms + hallways | BSP | MANDATORY bsp_tree_rooms.gd |
| Organic caves / smooth terrain | Cellular Automata (4/5) | MANDATORY cellular_automata_dungeon.gd |
| Heightmaps, biomes, infinite terrain | FastNoiseLite β Image | MANDATORY fast_noise_noise2d_master.gd |
| Trees, rocks, spawns (no clumping) | Poisson Disk | MANDATORY poisson_disk_sampling_2d.gd |
| Tile adjacency / city blocks | Wave Function Collapse | MANDATORY wave_function_collapse_lite.gd (lite) or wfc_level_generator.gd (full rules) |
| Room graph before geometry | AStar graph layout | MANDATORY proc_gen_graph_layout.gd |
| 3D voxel / smooth terrain mesh | Marching Cubes base | MANDATORY proc_gen_marching_cubes_base.gd |
| Infinite chunked 3D terrain | ArrayMesh + LOD chunks | MANDATORY mesh_gen_infinite_terrain.gd |
| Plants / branching structures | L-System | MANDATORY l_system_tree_gen.gd |
| Contour / metaball maps (2D) | Marching Squares | MANDATORY 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.
Available Scripts
Core (always start here)
- proc_gen_seed_history.gd β MANDATORY seeded
RandomNumberGeneratorwith push/pop state history - multi_threaded_chunk_gen.gd β MANDATORY WorkerThreadPool β
call_deferredchunk finalize pattern
2D layout & placement
- drunknard_walk_path.gd β MANDATORY for tunnels/paths (pass local RNG, never global
randi()) - bsp_tree_rooms.gd β MANDATORY for structured floor plans
- cellular_automata_dungeon.gd β MANDATORY for organic caves
- poisson_disk_sampling_2d.gd β MANDATORY for blue-noise prop/enemy placement
- wave_function_collapse_lite.gd β MANDATORY lite WFC with entropy +
max_iterations - wfc_level_generator.gd β full WFC with tile-library adjacency rules
- proc_gen_graph_layout.gd β graph-before-geometry via AStar2D/3D
Noise & 3D
- fast_noise_noise2d_master.gd β MANDATORY FastNoiseLite β Image heightmaps
- mesh_gen_infinite_terrain.gd β runtime ArrayMesh terrain with LOD potential
- proc_gen_marching_cubes_base.gd β 3D mesh from voxel data
- marching_squares_metaballs.gd β 2D contour extraction
- 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.
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 β seed, frequency, noise type, and
get_image()/get_noise_2d()for heightmaps and biome masks. - Random number generation β why per-generator
RandomNumberGeneratorseeds beat globalrandi()for shareable runs. - RandomNumberGenerator β
seed/stateAPIs for deterministic sequences and undoable RNG history. - Using multiple threads β offload chunk/WFC work without freezing the main loop.
- Thread-safe APIs β which Godot APIs workers may call; SceneTree/node creation stays on the main thread.
- WorkerThreadPool β
add_task+call_deferredfinalize pattern for async chunk generation. - Using ArrayMesh β commit vertex/normal/index arrays for marching-cubes and infinite terrain meshes.
- Using SurfaceTool β incremental vertex building and normal generation for runtime planes.
- Using TileMaps β TileMapLayer/pattern batch writes after BSP, CA, WFC, or drunkard-walk grids.
- Using GridMaps β modular 3D cell placement backend for dungeon/terrain generators.
- Navigation introduction (3D) β rebake NavigationRegion meshes after procedural geometry lands.
- AStar2D β room/hallway graph validation before spawning tiles or meshes.
Related Skills
Prerequisites
- godot-project-foundations β scenes, resources, and import basics before generators emit TileMaps, GridMaps, or ArrayMeshes.
- godot-gdscript-mastery β typed arrays,
call_deferred, and WorkerThreadPool task patterns used across every generator script. - godot-resource-data-patterns β Resource-backed tile libraries, adjacency rules, and seed configs instead of hard-coded magic tables.
Complements
- godot-tilemap-mastery β
set_pattern/ terrain connect batching so large CA/WFC grids do not callset_cellper tile. - godot-3d-world-building β GridMap/MeshLibrary/CSG placement backends that consume room graphs and heightmaps.
- godot-navigation-pathfinding β runtime navmesh bake after rooms, caves, or terrain chunks finish.
- godot-performance-optimization β budgets for mesh commits, collision trimeshes, and MultiMesh prop scattering after generation.
- godot-save-load-systems β persist seed + player deltas instead of serializing every generated chunk.
- godot-scene-management β threaded load/unload of chunk scenes that wrap generated data.
- godot-monte-carlo-balancer β sample spawn density, loot tables, and room difficulty against seed distributions before shipping.
Downstream / consumers
- godot-genre-roguelike β run-based dungeon crawlers that consume BSP/WFC/drunkard generators and seeded RNG.
- godot-genre-sandbox β voxel/chunk worlds and cellular-automata sandboxes built on infinite terrain and CA scripts.
- godot-genre-open-world β chunk streaming and floating-origin layers that wrap multi-threaded chunk gen.
Master
- godot-master β library router and mirrored module entry for cross-skill discovery.