Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when implementing procedural generation — noise-based terrain, BSP dungeons, cellular automata caves, wave function collapse, and seeded randomness in Godot 4.3+
.claude/skills/jame581-procedural-generation/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -6% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 33% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 47% | 0% |
All examples target Godot 4.3+ with no deprecated APIs. GDScript is shown first, then C#.
> Related skills: 2d-essentials for TileMapLayer usage, 3d-essentials for 3D terrain meshes, math-essentials for vectors and transforms, godot-optimization for chunk loading and performance.
Always use seeds for reproducible generation. This enables shareable seeds, replay, and deterministic testing.
gdscript# RandomNumberGenerator — per-instance, seedable var rng := RandomNumberGenerator.new() func generate_level(level_seed: int) -> void: rng.seed = level_seed var width: int = rng.randi_range(20, 40) var height: int = rng.randi_range(15, 30) var enemy_count: int = rng.randi_range(3, 8) var treasure_chance: float = rng.randf_range(0.05, 0.15) # AVOID: Global randf()/randi() — not reproducible across calls # USE: rng.randf(), rng.randi(), rng.randf_range(), rng.randi_range()
csharpprivate RandomNumberGenerator _rng = new(); public void GenerateLevel(ulong levelSeed) { _rng.Seed = levelSeed; int width = _rng.RandiRange(20, 40); int height = _rng.RandiRange(15, 30); int enemyCount = _rng.RandiRange(3, 8); float treasureChance = _rng.RandfRange(0.05f, 0.15f); }
> Tip: Generate a seed from a string for shareable level codes: var seed: int = "MyLevel".hash()
FastNoiseLite for height maps, biome distribution, 2D terrain. Key params: noise_type (Perlin / Simplex / Cellular / Value), frequency (lower = larger features), seed. For terrain, sample noise at each tile coord, threshold the value to pick a tile.
> See references/noise-generation.md for the basic noise-map recipe, noise-type reference table, and 2D terrain + TileMapLayer walkthrough.
Binary Space Partitioning recursively splits a rectangle into smaller rectangles, carves a room inside each leaf, connects siblings with corridors. Produces grid-aligned room-based dungeons (think roguelike).
> See references/bsp-dungeons.md for the full recursive partition + room placement + corridor connection algorithm in GDScript + C#.
Fill a grid with random walls/floors at ~45% density, then iterate "a cell becomes a wall if ≥ 5 of 8 neighbors are walls" 4-5 times. The result is organic cave shapes — no straight corridors.
> See references/cellular-automata.md for the full GDScript + C# implementation with TileMapLayer integration.
WFC is a constraint solver: given a tile set with adjacency rules, pick the lowest-entropy cell, collapse it to a valid tile, propagate constraints, repeat. Produces tile-rule-respecting output but is non-trivial to implement.
> See references/wave-function-collapse.md for concept overview and a simplified GDScript + C# implementation.
| Symptom | Cause | Fix | |---------|-------|-----| | Same level every time | Not seeding the RNG | Set rng.seed before generation | | Different results on different platforms | Using global randf() / randi() | Use a dedicated RandomNumberGenerator instance | | Noise looks blocky | Frequency too high | Lower frequency (try 0.01–0.05) | | Caves are all wall or all floor | fill_chance too extreme or too few iterations | Use fill_chance 0.40–0.50 and 4–6 iterations | | BSP rooms overlap | Split position too close to edge | Ensure min_room_size buffer in split calculation | | WFC contradiction (no valid tile) | Adjacency rules too restrictive | Add more allowed neighbors or implement backtracking | | Generation takes too long | Processing entire map in one frame | Use await get_tree().process_frame to spread across frames, or use a thread |
RandomNumberGenerator, never global randf()/randi()FastNoiseLite frequency and octaves are tuned for the game's tile/world scale| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 21,279 | 13,710 | -36% | 1 | 1 | 0% | 4,217 | 3,965 | -6% | 0 | 0 | — |
case-02 | pass→pass | 8,833 | 5,945 | -33% | 1 | 1 | 0% | 1,591 | 2,335 | +47% | 0 | 0 | — |
case-03 | pass→pass | 7,844 | 6,084 | -22% | 1 | 1 | 0% | 1,353 | 2,363 | +75% | 0 | 0 | — |
case-04 | fail→pass | 17,571 | 16,438 | -6% | 1 | 1 | 0% | 3,121 | 4,151 | +33% | 0 | 0 | — |
case-05 | pass→pass | 12,695 | 9,837 | -23% | 1 | 1 | 0% | 2,182 | 2,963 | +36% | 0 | 0 | — |
case-06 | pass→pass | 11,399 | 8,356 | -27% | 1 | 1 | 0% | 1,990 | 2,702 | +36% | 0 | 0 | — |
case-07 | fail→pass | 18,096 | 17,827 | -1% | 1 | 1 | 0% | 3,684 | 4,531 | +23% | 0 | 0 | — |
case-08 | pass→pass | 18,896 | 18,210 | -4% | 1 | 1 | 0% | 3,484 | 4,623 | +33% | 0 | 0 | — |
case-09 | pass→pass | 20,010 | 17,245 | -14% | 1 | 1 | 0% | 3,610 | 4,509 | +25% | 0 | 0 | — |
case-10 | pass→pass | 23,740 | 22,801 | -4% | 1 | 1 | 0% | 4,378 | 5,755 | +31% | 0 | 0 | — |
case-11 | pass→pass | 13,703 | 9,589 | -30% | 1 | 1 | 0% | 2,186 | 2,763 | +26% | 0 | 0 | — |
case-12 | pass→pass | 18,219 | 18,752 | +3% | 1 | 1 | 0% | 2,555 | 4,153 | +63% | 0 | 0 | — |
case-13 | pass→pass | 16,292 | 13,976 | -14% | 1 | 1 | 0% | 2,813 | 3,672 | +31% | 0 | 0 | — |
case-14 | pass→pass | 12,427 | 11,654 | -6% | 1 | 1 | 0% | 1,921 | 3,192 | +66% | 0 | 0 | — |
case-15 | fail→pass | 14,749 | 10,095 | -32% | 1 | 1 | 0% | 2,586 | 3,109 | +20% | 0 | 0 | — |
case-16 | pass→pass | 16,953 | 14,370 | -15% | 1 | 1 | 0% | 2,540 | 3,534 | +39% | 0 | 0 | — |
case-17 | pass→pass | 14,763 | 8,538 | -42% | 1 | 1 | 0% | 2,369 | 2,734 | +15% | 0 | 0 | — |
case-18 | pass→pass | 12,048 | 10,275 | -15% | 1 | 1 | 0% | 2,248 | 3,191 | +42% | 0 | 0 | — |
case-19 | pass→pass | 16,720 | 16,441 | -2% | 1 | 1 | 0% | 2,922 | 4,325 | +48% | 0 | 0 | — |
case-20 | pass→pass | 14,932 | 10,498 | -30% | 1 | 1 | 0% | 2,897 | 3,148 | +9% | 0 | 0 | — |
case-21 | pass→pass | 12,123 | 10,758 | -11% | 1 | 1 | 0% | 1,912 | 2,880 | +51% | 0 | 0 | — |
case-22 | pass→pass | 20,330 | 14,984 | -26% | 1 | 1 | 0% | 3,885 | 4,113 | +6% | 0 | 0 | — |
case-23 | pass→pass | 22,277 | 15,276 | -31% | 1 | 1 | 0% | 4,381 | 4,262 | -3% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +17 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.