building-construction
π―Skillfrom taozhuo/game-dev-skills
building-construction skill from taozhuo/game-dev-skills
Installation
npx skills add https://github.com/taozhuo/game-dev-skills --skill building-constructionSkill Details
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
- ALWAYS load materials BEFORE creating parts
- ALWAYS use
createPart()function, never raw Part creation - NEVER use
SurfaceType.Studs- causes Z-fighting - ALWAYS set surfaces to
Smooth- MaterialVariant handles appearance - 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
- Mountains - Far outside map edge (50+ studs beyond)
- Forest - Dense trees inside map edge
- Invisible Wall - At exact map boundary
- 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)?
More from this repository10
audio-system skill from taozhuo/game-dev-skills
game-systems skill from taozhuo/game-dev-skills
animation-system skill from taozhuo/game-dev-skills
vfx-effects skill from taozhuo/game-dev-skills
optimization skill from taozhuo/game-dev-skills
ui-ux skill from taozhuo/game-dev-skills
data-persistence skill from taozhuo/game-dev-skills
procedural-generation skill from taozhuo/game-dev-skills
vehicle-physics skill from taozhuo/game-dev-skills
gemini-image-prompting skill from taozhuo/game-dev-skills