🎯

building-construction

🎯Skill

from taozhuo/game-dev-skills

VibeIndex|
What it does

building-construction skill from taozhuo/game-dev-skills

building-construction

Installation

Install skill:
npx skills add https://github.com/taozhuo/game-dev-skills --skill building-construction
1
Last UpdatedJan 29, 2026

Skill Details

SKILL.md

Provides patterns for building detailed structures programmatically using Parts and CSG. Use when creating buildings, towers, vehicles, or any brick-by-brick constructions in code.

Overview

# Building & Construction Patterns

---

MANDATORY: Stud Material Initialization

> CRITICAL: This code block MUST be included at the START of every building script. No exceptions. Always load stud materials BEFORE creating any parts.

```lua

--------------------------------------------------------------------------------

-- MANDATORY INITIALIZATION - COPY THIS BLOCK FIRST

--------------------------------------------------------------------------------

local Workspace = game:GetService("Workspace")

local AssetService = game:GetService("AssetService")

local MaterialService = game:GetService("MaterialService")

-- Stud material configuration

local STUD_ASSET_ID = 13719188279 -- 2022 Stud MaterialVariant

local studMaterialName = ""

local studBaseMaterial = Enum.Material.Plastic

-- Load stud materials (MUST run before creating parts)

local function loadStudMaterials()

-- Check if already loaded in MaterialService

for _, item in ipairs(MaterialService:GetChildren()) do

if item:IsA("MaterialVariant") then

studMaterialName = item.Name

studBaseMaterial = item.BaseMaterial

print("[Studs] Found existing: " .. studMaterialName)

return true

end

end

-- Load via AssetService

local success, err = pcall(function()

local asset = AssetService:LoadAssetAsync(STUD_ASSET_ID)

if asset then

local matVariant = asset:FindFirstChildWhichIsA("MaterialVariant", true)

if matVariant then

matVariant.Parent = MaterialService

studMaterialName = matVariant.Name

studBaseMaterial = matVariant.BaseMaterial

print("[Studs] Loaded: " .. studMaterialName .. " (BaseMaterial: " .. tostring(studBaseMaterial) .. ")")

end

asset:Destroy()

end

end)

if not success then

warn("[Studs] FAILED to load: " .. tostring(err))

return false

end

return studMaterialName ~= ""

end

-- EXECUTE IMMEDIATELY

local studsLoaded = loadStudMaterials()

if not studsLoaded then

warn("[Studs] Running without stud materials - parts will be smooth plastic")

end

--------------------------------------------------------------------------------

-- STANDARD PART CREATION FUNCTION (Uses loaded stud materials)

--------------------------------------------------------------------------------

local function createPart(size, cframe, color, name, parent)

local part = Instance.new("Part")

part.Size = size

part.CFrame = cframe

part.Anchored = true

part.BrickColor = color

-- Apply stud material (if loaded)

if studMaterialName ~= "" then

part.Material = studBaseMaterial

part.MaterialVariant = studMaterialName

else

part.Material = Enum.Material.Plastic

end

-- NEVER use legacy studs (causes Z-fighting)

part.TopSurface = Enum.SurfaceType.Smooth

part.BottomSurface = Enum.SurfaceType.Smooth

part.Name = name or "Part"

part.Parent = parent

return part

end

--------------------------------------------------------------------------------

-- YOUR CODE STARTS HERE (use createPart function above)

--------------------------------------------------------------------------------

```

Why This Is Mandatory

| Issue | Legacy SurfaceType.Studs | MaterialVariant (This Pattern) |

|-------|-------------------------|-------------------------------|

| Z-Fighting | YES - 3D geometry overlaps | NO - flat PBR texture |

| Performance | Worse - extra geometry | Better - texture only |

| Future-proof | NO - deprecated 2018 | YES - modern standard |

| Visual Quality | Inconsistent | High quality PBR |

Critical Rules

  1. ALWAYS load materials BEFORE creating parts
  2. ALWAYS use createPart() function, never raw Part creation
  3. NEVER use SurfaceType.Studs - causes Z-fighting
  4. ALWAYS set surfaces to Smooth - MaterialVariant handles appearance
  5. part.Material MUST match studBaseMaterial - or variant won't apply

---

Quick Reference Links

Official Documentation:

  • [Parts Overview](https://create.roblox.com/docs/parts)
  • [MaterialVariant API](https://create.roblox.com/docs/reference/engine/classes/MaterialVariant)
  • [MaterialService API](https://create.roblox.com/docs/reference/engine/classes/MaterialService)
  • [AssetService API](https://create.roblox.com/docs/reference/engine/classes/AssetService)
  • [Part API](https://create.roblox.com/docs/reference/engine/classes/Part)
  • [CFrame API](https://create.roblox.com/docs/reference/engine/datatypes/CFrame)

Community Resources:

  • Asset ID 13719188279 - 2022 Stud MaterialVariant (RECOMMENDED)
  • Asset ID 18987102498 - Full 2008-2024 Studs pack
  • [Resurface Plugin](https://create.roblox.com/store/asset/5765511674) - For existing builds

---

Performance Optimization (Community Consensus)

Part Count Guidelines

  • Optimal: Under 5,000 parts in render distance
  • Per Building: 100-600 parts (no interior)
  • Warning: 9,000+ parts = noticeable fps drops

Critical Rules

  • ALWAYS anchor static parts - moving parts = lag
  • Disable CanCollide + CanTouch on decorative parts
  • Avoid Unions - bad topology, breaks instancing
  • Reuse designs - vary with scale/color/rotation instead of unique parts
  • Enable Streaming in Workspace for large maps

MeshPart Settings (If Using Meshes)

| RenderFidelity | Use For |

|----------------|---------|

| Performance | Decorative, distant objects |

| Automatic | Interactive items |

| Precise | Major landmarks only |

| CollisionFidelity | Use For |

|-------------------|---------|

| Box | Walkthrough objects, tiny items |

| Hull | Trees, varied shapes |

| Default | Terrain, complex structures |

---

Layer System (Avoid Z-Fighting)

> IMPORTANT: Never place parts with surfaces at exactly the same Y position. Use a layer system.

```lua

-- Define layer heights (build from bottom up)

local LAYERS = {

GROUND = 0, -- Base ground level

PLATFORM = 2, -- Platforms ON TOP of ground (not overlapping)

SPAWN = 4, -- Spawn platforms above main platforms

DECORATION = 5, -- Decorations on platforms

}

-- Ground: 2 thick centered at Y=0, top surface at Y=1

local GROUND_TOP = LAYERS.GROUND + 1

-- Platforms sit ON TOP of ground (bottom at Y=1, not Y=0)

createPart(Vector3.new(80, 3, 80), CFrame.new(0, GROUND_TOP + 1.5, 0), color, "Platform", parent)

```

---

Natural Map Borders (Community Best Practice)

> DO NOT use plain walls. Use mountains + forest + invisible collision.

```lua

--------------------------------------------------------------------------------

-- NATURAL BORDER PATTERN

--------------------------------------------------------------------------------

local borderFolder = Instance.new("Folder")

borderFolder.Name = "MapBorder"

borderFolder.Parent = workspace

-- Low-poly mountain

local function createMountain(position, baseSize, height, color)

local mountain = Instance.new("Model")

mountain.Name = "Mountain"

-- Base (wide)

createPart(Vector3.new(baseSize, height * 0.4, baseSize),

CFrame.new(position + Vector3.new(0, height * 0.2, 0)),

color, "Base", mountain)

-- Middle (narrower)

createPart(Vector3.new(baseSize 0.7, height 0.35, baseSize * 0.7),

CFrame.new(position + Vector3.new(0, height * 0.55, 0)),

color, "Mid", mountain)

-- Peak with snow cap

createPart(Vector3.new(baseSize 0.35, height 0.3, baseSize * 0.35),

CFrame.new(position + Vector3.new(0, height * 0.85, 0)),

BrickColor.new("Institutional white"), "Peak", mountain)

mountain.Parent = borderFolder

return mountain

end

-- Dense forest cluster

local function createForestCluster(centerX, centerZ, groundY, radius, density)

for i = 1, density do

local angle = math.random() math.pi 2

local dist = math.random() * radius

local x = centerX + math.cos(angle) * dist

local z = centerZ + math.sin(angle) * dist

local height = math.random(6, 14)

createTree(Vector3.new(x, groundY, z), height, borderFolder)

end

end

-- Invisible collision wall

local function createInvisibleWall(size, cframe)

local wall = Instance.new("Part")

wall.Size = size

wall.CFrame = cframe

wall.Anchored = true

wall.Transparency = 1

wall.CanCollide = true

wall.Name = "InvisibleBarrier"

wall.Parent = borderFolder

return wall

end

-- Add atmosphere fog

local atmosphere = Instance.new("Atmosphere")

atmosphere.Density = 0.3

atmosphere.Haze = 1

atmosphere.Parent = game:GetService("Lighting")

```

Border Placement Pattern

  1. Mountains - Far outside map edge (50+ studs beyond)
  2. Forest - Dense trees inside map edge
  3. Invisible Wall - At exact map boundary
  4. Atmosphere - Fog to obscure distant edges

---

Building Patterns

Simple Tree

```lua

local function createTree(position, height, parent)

local tree = Instance.new("Model")

tree.Name = "Tree"

-- Trunk

createPart(Vector3.new(2, height, 2),

CFrame.new(position + Vector3.new(0, height / 2, 0)),

BrickColor.new("Reddish brown"), "Trunk", tree)

-- Leaves (stacked, tapering)

local leafSizes = {8, 6, 4}

for i, size in ipairs(leafSizes) do

createPart(Vector3.new(size, 3, size),

CFrame.new(position + Vector3.new(0, height + i * 3 - 1, 0)),

BrickColor.new("Bright green"), "Leaves" .. i, tree)

end

tree.Parent = parent

return tree

end

```

Castle Components

```lua

-- Foundation (widest, ground level)

createPart(Vector3.new(40, 2, 40), CFrame.new(0, 1, 0), BrickColor.new("Dark stone grey"), "Foundation", castle)

-- Walls

createPart(Vector3.new(wallLength, wallHeight, wallThickness), wallCFrame, BrickColor.new("Medium stone grey"), "Wall", castle)

-- Crenellations (on top of walls)

for i = -n, n do

createPart(Vector3.new(1.5, 2, 1.5), CFrame.new(i * spacing, wallTop + 1, wallZ), BrickColor.new("Medium stone grey"), "Crenel", castle)

end

-- Corner towers (taller than walls)

createPart(Vector3.new(towerSize, towerHeight, towerSize), cornerCFrame, BrickColor.new("Medium stone grey"), "Tower", castle)

-- Tower roofs (stacked, tapering)

for i, size in ipairs({4, 3, 2}) do

createPart(Vector3.new(size, 1, size), CFrame.new(roofX, roofY + i - 1, roofZ), BrickColor.new("Bright red"), "Roof" .. i, castle)

end

```

Dragon/Creature (Static Decoration)

```lua

-- For STATIC decorations: keep all parts Anchored

-- DO NOT use WeldConstraint for static models

local function createDragon(position, color, scale, parent)

local dragon = Instance.new("Model")

dragon.Name = "Dragon"

local s = scale or 1

-- Body (main mass)

createPart(Vector3.new(6s, 4s, 10*s), CFrame.new(position), color, "Body", dragon)

-- Head

createPart(Vector3.new(3s, 3s, 4s), CFrame.new(position + Vector3.new(0, 1s, -6*s)), color, "Head", dragon)

-- Snout

createPart(Vector3.new(2s, 1.5s, 2s), CFrame.new(position + Vector3.new(0, 0.5s, -8.5*s)), color, "Snout", dragon)

-- Neck

createPart(Vector3.new(2s, 3s, 2s), CFrame.new(position + Vector3.new(0, 2s, -4s)) CFrame.Angles(math.rad(-30), 0, 0), color, "Neck", dragon)

-- Tail segments

local tailPos = position + Vector3.new(0, 0, 5*s)

for i = 1, 4 do

local tailSize = (5 - i) * s

createPart(Vector3.new(tailSize, tailSize, 3s), CFrame.new(tailPos + Vector3.new(0, 0, i 3*s)), color, "Tail" .. i, dragon)

end

-- Wings

for side = -1, 1, 2 do

createPart(Vector3.new(8s, 0.5s, 6*s),

CFrame.new(position + Vector3.new(side 6s, 2s, 0)) CFrame.Angles(0, 0, math.rad(side * 20)),

color, (side == 1 and "RWing" or "LWing"), dragon)

end

-- Legs

for _, offset in ipairs({{-2, -3}, {2, -3}, {-2, 3}, {2, 3}}) do

createPart(Vector3.new(1.5s, 3s, 1.5*s),

CFrame.new(position + Vector3.new(offset[1]s, -2s, offset[2]*s)),

color, "Leg", dragon)

end

dragon.Parent = parent

return dragon

end

```

---

Model Organization

```

Workspace/

MapName/

Terrain/ -- Ground, borders, natural features

MainGround

MapBorder/

Mountains/

Trees/

InvisibleWalls/

HubArea/ -- Spawn, shops, etc

ObbyCourse/ -- Stages

WinnerArea/ -- Victory zone

```

Rules

  • Use Folders for organization (not Models)
  • Use Models only for geometric objects that move together
  • Set PrimaryPart only for physics-joined models
  • Anchor all static parts

---

Color Palette (Classic Style)

| Color | BrickColor Name | Use For |

|-------|-----------------|---------|

| Grey | "Medium stone grey" | Neutral, backgrounds, stone |

| Dark Grey | "Dark stone grey" | Shadows, metal, dark accents |

| Brown | "Reddish brown" | Wood, doors, trunks |

| Green | "Bright green" | Grass, leaves, nature |

| Red | "Bright red" | Lava, danger, accents |

| Blue | "Bright blue" | Water, ice, sky elements |

| Yellow | "Bright yellow" | Gold, highlights, rewards |

| White | "Institutional white" | Snow, clean surfaces |

---

Checklist Before Building

  • [ ] Stud materials loaded at script start?
  • [ ] Using createPart() function (not raw Instance.new)?
  • [ ] All surfaces set to Smooth?
  • [ ] Layer system defined to avoid Z-fighting?
  • [ ] All static parts anchored?
  • [ ] Map border uses mountains + forest (not plain walls)?
  • [ ] Part count reasonable (<5000 in view)?