Claude-skill-registry building-construction
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.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/building-construction" ~/.claude/skills/majiayu000-claude-skill-registry-building-construction && rm -rf "$T"
manifest:
skills/data/building-construction/SKILL.mdsource content
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.
-------------------------------------------------------------------------------- -- 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
function, never raw Part creationcreatePart() - NEVER use
- causes Z-fightingSurfaceType.Studs - ALWAYS set surfaces to
- MaterialVariant handles appearanceSmooth - part.Material MUST match studBaseMaterial - or variant won't apply
Quick Reference Links
Official Documentation:
Community Resources:
- Asset ID
- 2022 Stud MaterialVariant (RECOMMENDED)13719188279 - Asset ID
- Full 2008-2024 Studs pack18987102498 - Resurface Plugin - 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.
-- 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.
-------------------------------------------------------------------------------- -- 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
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
-- 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)
-- 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(6*s, 4*s, 10*s), CFrame.new(position), color, "Body", dragon) -- Head createPart(Vector3.new(3*s, 3*s, 4*s), CFrame.new(position + Vector3.new(0, 1*s, -6*s)), color, "Head", dragon) -- Snout createPart(Vector3.new(2*s, 1.5*s, 2*s), CFrame.new(position + Vector3.new(0, 0.5*s, -8.5*s)), color, "Snout", dragon) -- Neck createPart(Vector3.new(2*s, 3*s, 2*s), CFrame.new(position + Vector3.new(0, 2*s, -4*s)) * 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, 3*s), 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(8*s, 0.5*s, 6*s), CFrame.new(position + Vector3.new(side * 6*s, 2*s, 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.5*s, 3*s, 1.5*s), CFrame.new(position + Vector3.new(offset[1]*s, -2*s, 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
function (not raw Instance.new)?createPart() - 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)?