Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate game content procedurally — seeded deterministic RNG, value/Perlin/ Simplex noise for terrain and heightmaps, grid dungeon generation (rooms + corridors, BSP, random walk), and weighted loot/drop tables. Engine-neutral algorithms. Use when the user mentions procedural generation, perlin/simplex noise, random seed, dungeon generator, heightmap/terrain, or loot tables.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 158% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 62% | 0% |
| case-08 | ✓→✓ | = Same ✓ | 36% | 0% |
| case-09 | ✓→✓ | = Same ✓ | 44% | 0% |
Generate levels, terrain, and loot from compact rules and a seed. The throughline of good procgen is determinism: a single seed reproduces the same world, so bugs are repeatable and players can share seeds. This skill owns the core algorithms — noise, seeded RNG, dungeon layout, weighted tables; genres like roguelike and survival-crafting consume it.
you do not want to author by hand.
challenges, shareable worlds).
When not to use: for the engine's tile API to paint the result, use godot-tilemap or unity-tilemap-2d. For routing AI through the generated map, use game-ai. For carefully hand-paced levels, use level-design — procgen and authored design are complementary, not interchangeable.
everywhere. Never call the global/static random in generation code — it makes results irreproducible and order-dependent.
Discrete rooms/corridors → space partitioning or agent-based carving. Outcomes with rarities → weighted tables.
Generation fills int[][] or a dict; a separate pass draws it.
reachable? Is the spawn safe? Is there a path to the exit? Reject or repair layouts that fail; do not hand the player a broken map.
then sweep seeds to check the distribution, not just one lucky map.
pythonimport random rng = random.Random(seed) # a dedicated instance — NOT the global random.* room_count = rng.randint(5, 12) # same seed -> same sequence, every run # RIGHT: thread `rng` through every function that makes a choice. # WRONG: calling random.randint(...) (global state) — order-dependent, unseedable.
Engine equivalents: Godot var rng = RandomNumberGenerator.new(); rng.seed = s; Unity var rng = new System.Random(seed) (or UnityEngine.Random.InitState). Store the seed in the save file so a world can be regenerated.
python# Sum several octaves: each higher octave has higher frequency, lower amplitude. def fbm(noise, x, y, octaves=5, lacunarity=2.0, gain=0.5): total, amp, freq, norm = 0.0, 1.0, 1.0, 0.0 for _ in range(octaves): total += amp * noise(x * freq, y * freq) # noise() returns ~0..1 norm += amp # track total amplitude amp *= gain # each octave contributes less freq *= lacunarity # ...at a higher frequency return total / norm # normalize back into 0..1 # Redistribute to carve flat valleys / sharpen peaks: higher exp -> more lowland. elevation = pow(fbm(noise, nx, ny), 2.2)
Use a real noise library (FastNoiseLite, opensimplex, Unity.Mathematics.noise, or Mathf.PerlinNoise) — do not implement gradient noise yourself. Seed elevation and moisture with different seeds so a biome lookup over both fields isn't perfectly correlated. Full biome lookup and island shaping are in references/noise.md.
python# Roll proportional to weight: common drops far more often than legendary. def weighted_pick(rng, table): # table: list of (item, weight) total = sum(w for _, w in table) roll = rng.uniform(0, total) # a point on the cumulative line upto = 0.0 for item, w in table: upto += w if roll < upto: # first bucket the roll falls into return item return table[-1][0] # float-safety fallback loot = weighted_pick(rng, [("common", 70), ("rare", 25), ("legendary", 5)])
Weights need not sum to 100 — they are relative. To prevent bad streaks, use a "pity"/bag system (see references/dungeon-generation.md notes on distributions).
python# 1. Place non-overlapping rooms; 2. connect them; 3. carve into the grid. rooms = [] for _ in range(attempts): r = Rect(rng.randint(1, W-w-1), rng.randint(1, H-h-1), w, h) if not any(r.intersects(o.expand(1)) for o in rooms): # keep a 1-tile gap rooms.append(r) for a, b in zip(rooms, rooms[1:]): # connect each room to the next carve_l_corridor(grid, a.center, b.center, rng) # horizontal then vertical
The complete generator (BSP partitioning, L-corridors, reachability check, and random-walk caves) is in references/dungeon-generation.md.
breaks the moment call order changes. Always pass a seeded instance.
seed/offset produces biomes that line up in bands. Offset or reseed each field.
0..1; divide by the summed amplitude (and beware library output ranges — some return -1..1, some 0..1).
the spawn and discard/reconnect unreachable regions before play.
on a small grid. Cap attempts and accept fewer rooms.
input (time, physics, hash randomization) leaking into generation destroys reproducibility.
references/noise.md — octaves/lacunarity/gain, redistribution, islandshaping, two-axis biome lookup, blue-noise object scatter.
references/dungeon-generation.md — BSP, rooms+corridors, random-walk caves,cellular-automata smoothing, connectivity validation, distribution/pity tables.
godot-tilemap, unity-tilemap-2d — paint the generated grid into the engine.game-ai — pathfinding over the generated graph.level-design — pacing and hand-authored structure that procgen complements.roguelike, survival-crafting — genres that compose this skill.Other measured skills in the registry, with their headline benchmark lift.