PR

procedural-generation

Implements deterministic generation algorithms using seeds for consistent, reproducible results.

Install

mkdir -p .claude/skills/procedural-generation && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/12007" && unzip -o skill.zip -d .claude/skills/procedural-generation && rm skill.zip

Installs to .claude/skills/procedural-generation

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Procedural generation patterns — Perlin/Simplex noise, BSP dungeon generation, random walk, loot tables with weighted random, wave function collapse basics, seed-based reproducibility.
184 charsno explicit “when” trigger
Advanced

Key capabilities

  • Generate terrain using Perlin noise
  • Generate dungeons using BSP
  • Generate caves using random walk
  • Generate loot using weighted tables
  • Ensure seed-based reproducibility for generation algorithms

How it works

This skill provides patterns for procedural content generation, such as using Perlin noise for height maps or BSP for dungeons. It emphasizes seed-based reproducibility by using `System.Random` and deriving sub-seeds.

Inputs & outputs

You give it
A seed and parameters for generation (e.g., width, height, scale for noise map)
You get back
Generated content like height maps, dungeon layouts, or shuffled lists, reproducible with the same seed

When to use procedural-generation

  • Generate random dungeon layouts
  • Create procedural terrain maps
  • Implement balanced, seeded loot tables

About this skill

Procedural Generation Patterns

Patterns for generating content at runtime: terrain with noise, dungeons with BSP, caves with random walk, loot with weighted tables, and tile layouts with wave function collapse. All patterns support seed-based reproducibility.

Seed-Based Reproducibility

Every generation algorithm should accept a seed. Given the same seed, the output is identical. This enables shareable worlds, bug reproduction, and daily challenge modes.

Critical rule: Use System.Random (not UnityEngine.Random) for deterministic generation. UnityEngine.Random is a global singleton; any other code calling it between your generation steps will change the sequence.

public class SeededRandom
{
    private System.Random _rng;
    public int Seed { get; }

    public SeededRandom(int seed)
    {
        Seed = seed;
        _rng = new System.Random(seed);
    }

    public int Next(int min, int max) => _rng.Next(min, max);
    public float NextFloat() => (float)_rng.NextDouble();
    public float Range(float min, float max) => min + (max - min) * NextFloat();
    public bool Chance(float probability) => NextFloat() < probability;

    /// <summary>Shuffle a list in place using Fisher-Yates.</summary>
    public void Shuffle<T>(IList<T> list)
    {
        for (int i = list.Count - 1; i > 0; i--)
        {
            int j = _rng.Next(0, i + 1);
            (list[i], list[j]) = (list[j], list[i]);
        }
    }
}

For world generation, derive sub-seeds from the master seed so different systems (terrain, dungeons, loot) do not interfere:

int masterSeed = 12345;
var terrainRng = new SeededRandom(masterSeed);
var dungeonRng = new SeededRandom(masterSeed + 1);
var lootRng = new SeededRandom(masterSeed + 2);

Noise-Based Terrain Generation

Use Perlin noise to generate height maps for terrain, biome maps, moisture maps, and other continuous fields.

Basic Height Map

using UnityEngine;

public static class NoiseGenerator
{
    /// <summary>
    /// Generate a 2D noise map. Values range from 0 to 1.
    /// </summary>
    public static float[,] GenerateNoiseMap(
        int width, int height, int seed,
        float scale, int octaves, float persistence, float lacunarity,
        Vector2 offset)
    {
        var map = new float[width, height];

        // Use seed to generate random octave offsets
        var rng = new System.Random(seed);
        var octaveOffsets = new Vector2[octaves];
        for (int i = 0; i < octaves; i++)
        {
            float ox = rng.Next(-100000, 100000) + offset.x;
            float oy = rng.Next(-100000, 100000) + offset.y;
            octaveOffsets[i] = new Vector2(ox, oy);
        }

        if (scale <= 0f) scale = 0.001f;

        float maxNoise = float.MinValue;
        float minNoise = float.MaxValue;

        float halfW = width / 2f;
        float halfH = height / 2f;

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                float amplitude = 1f;
                float frequency = 1f;
                float noiseHeight = 0f;

                for (int o = 0; o < octaves; o++)
                {
                    float sampleX = (x - halfW + octaveOffsets[o].x) / scale * frequency;
                    float sampleY = (y - halfH + octaveOffsets[o].y) / scale * frequency;

                    // Mathf.PerlinNoise returns 0-1; remap to -1 to 1
                    float perlin = Mathf.PerlinNoise(sampleX, sampleY) * 2f - 1f;
                    noiseHeight += perlin * amplitude;

                    amplitude *= persistence;  // Each octave contributes less
                    frequency *= lacunarity;    // Each octave has finer detail
                }

                map[x, y] = noiseHeight;

                if (noiseHeight > maxNoise) maxNoise = noiseHeight;
                if (noiseHeight < minNoise) minNoise = noiseHeight;
            }
        }

        // Normalize to 0-1
        for (int y = 0; y < height; y++)
            for (int x = 0; x < width; x++)
                map[x, y] = Mathf.InverseLerp(minNoise, maxNoise, map[x, y]);

        return map;
    }
}

Parameter guide:

ParameterEffectTypical Value
scaleZoom level (higher = smoother)20-100
octavesLayers of detail4-6
persistenceAmplitude decay per octave0.4-0.6
lacunarityFrequency increase per octave1.8-2.2

Applying Noise to a Tilemap

using UnityEngine;
using UnityEngine.Tilemaps;

public class TerrainGenerator : MonoBehaviour
{
    [SerializeField] private Tilemap tilemap;
    [SerializeField] private TileBase waterTile;
    [SerializeField] private TileBase sandTile;
    [SerializeField] private TileBase grassTile;
    [SerializeField] private TileBase stoneTile;
    [SerializeField] private TileBase snowTile;

    [Header("Generation Settings")]
    [SerializeField] private int width = 100;
    [SerializeField] private int height = 100;
    [SerializeField] private int seed = 42;
    [SerializeField] private float scale = 30f;
    [SerializeField] private int octaves = 4;
    [SerializeField] private float persistence = 0.5f;
    [SerializeField] private float lacunarity = 2f;

    [Header("Height Thresholds")]
    [SerializeField] private float waterLevel = 0.3f;
    [SerializeField] private float sandLevel = 0.4f;
    [SerializeField] private float grassLevel = 0.7f;
    [SerializeField] private float stoneLevel = 0.85f;

    public void Generate()
    {
        tilemap.ClearAllTiles();

        var noiseMap = NoiseGenerator.GenerateNoiseMap(
            width, height, seed, scale, octaves, persistence, lacunarity, Vector2.zero);

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                float value = noiseMap[x, y];
                TileBase tile = GetTileForHeight(value);
                tilemap.SetTile(new Vector3Int(x - width / 2, y - height / 2, 0), tile);
            }
        }
    }

    private TileBase GetTileForHeight(float height)
    {
        if (height < waterLevel) return waterTile;
        if (height < sandLevel) return sandTile;
        if (height < grassLevel) return grassTile;
        if (height < stoneLevel) return stoneTile;
        return snowTile;
    }
}

BSP Dungeon Generation

Binary Space Partition creates rectangular rooms connected by corridors. It produces clean, grid-aligned dungeons suitable for roguelikes and RPGs.

Algorithm Overview

  1. Start with a large rectangle (the entire dungeon area).
  2. Recursively split it in half (horizontally or vertically) until pieces reach minimum size.
  3. Place a room inside each leaf partition (with random padding).
  4. Connect sibling rooms with corridors.

Implementation

using System.Collections.Generic;
using UnityEngine;

public class BSPDungeon
{
    public class BSPNode
    {
        public RectInt Area;
        public BSPNode Left;
        public BSPNode Right;
        public RectInt? Room;

        public bool IsLeaf => Left == null && Right == null;
    }

    private int _minPartitionSize;
    private int _minRoomSize;
    private int _roomPadding;
    private SeededRandom _rng;

    private List<RectInt> _rooms = new();
    private HashSet<Vector2Int> _corridors = new();

    public IReadOnlyList<RectInt> Rooms => _rooms;
    public IReadOnlyCollection<Vector2Int> Corridors => _corridors;

    public BSPDungeon(int minPartitionSize = 10, int minRoomSize = 4, int roomPadding = 2)
    {
        _minPartitionSize = minPartitionSize;
        _minRoomSize = minRoomSize;
        _roomPadding = roomPadding;
    }

    public int[,] Generate(int width, int height, int seed)
    {
        _rng = new SeededRandom(seed);
        _rooms.Clear();
        _corridors.Clear();

        // 0 = wall, 1 = floor
        var grid = new int[width, height];

        // Build BSP tree
        var root = new BSPNode { Area = new RectInt(0, 0, width, height) };
        Split(root);

        // Place rooms in leaves
        PlaceRooms(root);

        // Connect rooms
        ConnectRooms(root);

        // Write rooms to grid
        foreach (var room in _rooms)
        {
            for (int x = room.x; x < room.x + room.width; x++)
                for (int y = room.y; y < room.y + room.height; y++)
                    grid[x, y] = 1;
        }

        // Write corridors to grid
        foreach (var pos in _corridors)
        {
            if (pos.x >= 0 && pos.x < width && pos.y >= 0 && pos.y < height)
                grid[pos.x, pos.y] = 1;
        }

        return grid;
    }

    private void Split(BSPNode node)
    {
        // Stop if too small to split
        if (node.Area.width < _minPartitionSize * 2 &&
            node.Area.height < _minPartitionSize * 2)
            return;

        // Choose split direction
        bool splitHorizontal;
        if (node.Area.width < _minPartitionSize * 2)
            splitHorizontal = true;
        else if (node.Area.height < _minPartitionSize * 2)
            splitHorizontal = false;
        else
            splitHorizontal = _rng.Chance(0.5f);

        if (splitHorizontal)
        {
            int splitY = _rng.Next(
                node.Area.y + _minPartitionSize,
                node.Area.y + node.Area.height - _minPartitionSize);

            node.Left = new BSPNode
            {
                Area = new RectInt(node.Area.x, node.Area.y,
                    node.Area.width, splitY - node.Area.y)
            };
            node.Right = new BSPNode
            {
                Area = new RectInt(node.Area.x, splitY,
                    node.Area.width, node.Area.y + node.Area.height - splitY)
            };
        }
        else
        {
            i

---

*Content truncated.*

When not to use it

  • When `System.Random` is not used for deterministic generation
  • When generation logic is not separated from rendering
  • When complex generation is not run in a coroutine or background thread

Limitations

  • Requires `System.Random` for deterministic generation
  • Generation logic should be separated from rendering
  • Complex generation may require coroutines or background threads

How it compares

This skill offers structured patterns for procedural generation with a focus on deterministic reproducibility, which allows for shareable worlds and bug reproduction, unlike ad-hoc random generation.

Compared to similar skills

procedural-generation side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
procedural-generation (this skill)04moNo flagsAdvanced
mlir-development16moReviewAdvanced
compiler-development16moNo flagsAdvanced
add-cuda-kernel13moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry