roblox-building
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBuilding 3D in Roblox via MCP
通过MCP在Roblox中构建3D内容
Use this skill when the AI is creating physical geometry in Roblox Studio through an MCP connection (execute_luau / run_code). Covers single objects, room-scale structures, and multi-zone maps.
当AI通过MCP连接(execute_luau / run_code)在Roblox Studio中创建物理几何结构时,请使用本技能。涵盖单个对象、房间规模的结构以及多区域地图。
MCP Statelessness (CRITICAL)
MCP无状态性(至关重要)
MCP code execution is stateless. Every call is a blank slate.
- Variables don't persist between calls.
- Object references are lost between calls.
- Fix: Re-acquire references at the start of EVERY call.
luau
-- MUST be at the start of every MCP call
local model = workspace:FindFirstChild("MyBuild")
if not model then
model = Instance.new("Model")
model.Name = "MyBuild"
model.Parent = workspace
endGround Truth Rule: Never guess coordinates from chat history. If you need the position/size of a previously created part, READ it from workspace first:
luau
local existing = model:FindFirstChild("TableTop")
if existing then
print(existing.CFrame, existing.Size) -- read before calculating offsets
endMCP代码执行是无状态的。每次调用都是全新的环境。
- 变量不会在调用之间持久化
- 对象引用会在调用之间丢失
- 解决方法:在每次调用开始时重新获取引用。
luau
-- 必须放在每个MCP调用的开头
local model = workspace:FindFirstChild("MyBuild")
if not model then
model = Instance.new("Model")
model.Name = "MyBuild"
model.Parent = workspace
end基本原则:永远不要从聊天记录中猜测坐标。如果需要获取之前创建部件的位置/尺寸,请先从workspace中读取:
luau
local existing = model:FindFirstChild("TableTop")
if existing then
print(existing.CFrame, existing.Size) -- 计算偏移前先读取
endPlayer Scale Reference
玩家比例参考
- Player height: ~5 studs
- Doorway: 4 wide × 7 tall
- Ceiling height: 10-14 studs (rooms), 16+ (halls)
- Table/counter top: 3.5-4 studs from floor
- Seat height: ~1.5 studs from floor
- Paths: minimum 6 studs wide (10+ for main roads)
- Stair step: 1 stud rise, 1.5 stud run
- 玩家身高:约5 studs
- 门口:宽4 × 高7 studs
- 天花板高度:房间为10-14 studs,走廊为16+ studs
- 桌子/柜台高度:距离地面3.5-4 studs
- 座椅高度:距离地面约1.5 studs
- 路径:最小宽度6 studs(主路建议10+ studs)
- 楼梯台阶:高度1 stud,深度1.5 stud
Build Process
构建流程
Objects (single Model)
对象(单个Model)
- Assess — Do you know the components, scale, and style? If not, ask.
- Plan — Declare dimensions as named variables. Choose an anchor part.
- Build — Generate parts with relative positioning. Split across calls if >20 parts.
- Verify — Run validation (check Anchored, below-floor, default colors).
- 评估 — 你是否了解组件、比例和风格?如果不了解,请询问。
- 规划 — 将尺寸声明为命名变量。选择一个锚定部件。
- 构建 — 生成带有相对定位的部件。如果部件超过20个,拆分到多个调用中。
- 验证 — 运行验证(检查是否锚定、是否低于地面、是否使用默认颜色)。
Maps (multi-zone)
地图(多区域)
- Layout — Define total size, zone breakdown, gameplay type. If any is vague, ask.
- Ground — Floor planes, boundaries, Origin anchor, folder hierarchy.
- Zone shells — Floor sections, walls, dividers per zone.
- Landmarks — Orientation structures (towers, fountains, trees).
- Fill — Props, furniture, vegetation per zone.
- Environment — Lighting, Atmosphere, SpawnLocations.
- 布局 — 定义总尺寸、区域划分、游戏玩法类型。如果有任何模糊之处,请询问。
- 地面 — 地面平面、边界、原点锚点、文件夹层级。
- 区域框架 — 每个区域的地面部分、墙壁、分隔物。
- 地标 — 定位结构(塔楼、喷泉、树木)。
- 填充 — 每个区域的道具、家具、植被。
- 环境 — 光照、大气、SpawnLocations。
Spatial Patterns
空间模式
Geometric Manifest (named dimensions, no magic numbers)
几何定义(命名尺寸,无魔法数字)
luau
local Def = {
Width = 6.0,
Depth = 3.0,
Height = 2.8,
TopThickness = 0.2,
LegSize = 0.3,
LegInset = 0.1,
}luau
local Def = {
Width = 6.0,
Depth = 3.0,
Height = 2.8,
TopThickness = 0.2,
LegSize = 0.3,
LegInset = 0.1,
}Relative Positioning (anchor pattern)
相对定位(锚定模式)
All sub-parts position relative to an anchor part's CFrame. Never use hardcoded world coordinates.
luau
local top = Instance.new("Part")
top.Size = Vector3.new(Def.Width, Def.TopThickness, Def.Depth)
top.CFrame = CFrame.new(0, Def.Height - Def.TopThickness / 2, 0)
top.Anchored = true
top.Parent = model
-- Legs relative to top
local legH = Def.Height - Def.TopThickness
local leg = Instance.new("Part")
leg.Size = Vector3.new(Def.LegSize, legH, Def.LegSize)
local ox = Def.Width / 2 - Def.LegSize / 2 - Def.LegInset
local oz = Def.Depth / 2 - Def.LegSize / 2 - Def.LegInset
leg.CFrame = top.CFrame * CFrame.new(ox, -(Def.TopThickness / 2 + legH / 2), oz)
leg.Anchored = true
leg.Parent = model所有子部件的位置都相对于锚定部件的CFrame。永远不要使用硬编码的世界坐标。
luau
local top = Instance.new("Part")
top.Size = Vector3.new(Def.Width, Def.TopThickness, Def.Depth)
top.CFrame = CFrame.new(0, Def.Height - Def.TopThickness / 2, 0)
top.Anchored = true
top.Parent = model
-- 相对于桌面的桌腿
local legH = Def.Height - Def.TopThickness
local leg = Instance.new("Part")
leg.Size = Vector3.new(Def.LegSize, legH, Def.LegSize)
local ox = Def.Width / 2 - Def.LegSize / 2 - Def.LegInset
local oz = Def.Depth / 2 - Def.LegSize / 2 - Def.LegInset
leg.CFrame = top.CFrame * CFrame.new(ox, -(Def.TopThickness / 2 + legH / 2), oz)
leg.Anchored = true
leg.Parent = modelGrid Snapping
网格对齐
Snap dimensions to consistent increments (0.125, 0.25, or 0.5 studs). Avoid arbitrary decimals like 0.333 or 1.17 which compound into visible gaps.
将尺寸对齐到一致的增量(0.125、0.25或0.5 studs)。避免使用0.333或1.17这类任意小数,它们会导致可见的间隙。
CSG (Union / Subtract)
CSG(合并/减法)
The Epsilon Rule
微小偏移规则(Epsilon Rule)
Cutters MUST slightly overlap boundaries they cut through. Coplanar surfaces cause Z-fighting or leave microscopic skins.
luau
local EPSILON = 0.05
-- Hole through a 1-stud thick wall
local wall = Instance.new("Part")
wall.Size = Vector3.new(10, 10, 1)
local cutter = Instance.new("Part")
-- Add EPSILON*2 to the axis passing through the wall
cutter.Size = Vector3.new(2, 2, 1 + EPSILON * 2)
cutter.CFrame = wall.CFrame切割部件必须与要切割的边界轻微重叠。共面表面会导致Z轴冲突或留下微小的残留面。
luau
local EPSILON = 0.05
-- 在1 stud厚的墙上开孔
local wall = Instance.new("Part")
wall.Size = Vector3.new(10, 10, 1)
local cutter = Instance.new("Part")
-- 向穿过墙壁的轴添加EPSILON*2的尺寸
cutter.Size = Vector3.new(2, 2, 1 + EPSILON * 2)
cutter.CFrame = wall.CFrameSafe CSG Wrapper
安全CSG包装器
CSG operations are async and can fail. Always pcall, verify, and clean up.
luau
local success, result = pcall(function()
return basePart:SubtractAsync({cutterPart})
end)
if success and result and result:IsA("BasePart") then
result.CFrame = basePart.CFrame -- preserve exact transform
result.UsePartColor = true
result.Color = basePart.Color
result.Material = basePart.Material
result.Name = basePart.Name
result.Anchored = true
result.Parent = basePart.Parent
basePart:Destroy()
cutterPart:Destroy()
else
warn("CSG failed:", result)
cutterPart:Destroy()
endCSG操作是异步的,可能会失败。始终使用pcall、验证并清理。
luau
local success, result = pcall(function()
return basePart:SubtractAsync({cutterPart})
end)
if success and result and result:IsA("BasePart") then
result.CFrame = basePart.CFrame -- 保留精确变换
result.UsePartColor = true
result.Color = basePart.Color
result.Material = basePart.Material
result.Name = basePart.Name
result.Anchored = true
result.Parent = basePart.Parent
basePart:Destroy()
cutterPart:Destroy()
else
warn("CSG failed:", result)
cutterPart:Destroy()
endCSG Rules
CSG规则
- Keep CSG trees shallow. Don't subtract from a part that was already unioned multiple times.
- Perform complex CSG near origin (0,0,0), then PivotTo() the final model to its destination. Floating-point precision degrades far from origin.
- GeometryService only supports Part and PartOperation. NOT MeshPart or Terrain.
- Set on decorative unions for performance.
CollisionFidelity = Enum.CollisionFidelity.Box
- 保持CSG树结构浅。不要对已经多次合并的部件执行减法操作。
- 在原点(0,0,0)附近执行复杂的CSG操作,然后使用PivotTo()将最终模型移动到目标位置。远离原点时浮点精度会下降。
- GeometryService仅支持Part和PartOperation。不支持MeshPart或Terrain。
- 为装饰性合并部件设置以提升性能。
CollisionFidelity = Enum.CollisionFidelity.Box
Platform Quirks
平台特性
Cylinder Orientation
圆柱体方向
Cylinders extend along the X-axis by default. To stand one upright:
luau
local pillar = Instance.new("Part")
pillar.Shape = Enum.PartType.Cylinder
pillar.Size = Vector3.new(10, 2, 2) -- Length, Diameter, Diameter
pillar.CFrame = CFrame.new(0, 5, 0) * CFrame.Angles(0, 0, math.pi / 2)圆柱体默认沿X轴延伸。要使其直立:
luau
local pillar = Instance.new("Part")
pillar.Shape = Enum.PartType.Cylinder
pillar.Size = Vector3.new(10, 2, 2) -- 长度,直径,直径
pillar.CFrame = CFrame.new(0, 5, 0) * CFrame.Angles(0, 0, math.pi / 2)WedgePart Orientation
WedgePart方向
The zero-height edge (tip) points toward +Z by default.
| Desired tip direction | Rotation |
|---|---|
| Up (+Y) | |
| Down (-Y) | |
| Forward (+Z) | none |
| Backward (-Z) | |
零高度边缘(尖端)默认指向+Z方向。
| 期望尖端方向 | 旋转角度 |
|---|---|
| 向上(+Y) | |
| 向下(-Y) | |
| 向前(+Z) | 无 |
| 向后(-Z) | |
Neon Material
Neon材质
Neon glows visually but does NOT cast light on surroundings. Add a PointLight/SpotLight as a child for actual illumination.
Neon材质会发光,但不会对周围环境投射光线。需添加PointLight/SpotLight作为其子对象以实现实际照明。
Default Part Properties
默认部件属性
Always set explicitly:
- (defaults to false!)
Anchored = true - (false for small decorative clutter)
CanCollide = true - (false for invisible triggers)
CastShadow = true
始终显式设置:
- (默认值为false!)
Anchored = true - (小型装饰杂物可设为false)
CanCollide = true - (不可见触发器可设为false)
CastShadow = true
Anti-Patterns
反模式
- Guessing coordinates — Read from workspace, don't rely on chat memory.
- Unanchored parts — They fall. Always set Anchored = true.
- Hardcoded world positions — Use relative offsets from anchor CFrame.
- Block-only for organic shapes — Use CSG, Cylinders, Spheres, WedgeParts.
- Silent CSG failures — Always pcall and verify result is BasePart.
- Building everything in one call — Split by phase. 20-30 parts per call max.
- Floating geometry — All structures must connect to ground or parent structure.
- Default colors — Always set explicit Color and Material. Default gray = unfinished.
- 猜测坐标 — 从workspace读取,不要依赖聊天记忆。
- 未锚定部件 — 它们会掉落。始终设置Anchored = true。
- 硬编码世界位置 — 使用相对于锚定CFrame的偏移量。
- 仅用方块构建有机形状 — 使用CSG、圆柱体、球体、WedgePart。
- CSG失败无提示 — 始终使用pcall并验证结果是否为BasePart。
- 一次调用构建所有内容 — 按阶段拆分。每次调用最多20-30个部件。
- 悬空几何结构 — 所有结构必须连接到地面或父结构。
- 默认颜色 — 始终设置明确的Color和Material。默认灰色代表未完成。
Validation Script
验证脚本
Run after building to catch common issues:
luau
local TARGET = "MyBuild" -- change to your model/folder name
local root = workspace:FindFirstChild(TARGET)
if not root then print("[ERROR] " .. TARGET .. " not found"); return end
local errors, warnings, parts = 0, 0, 0
for _, desc in ipairs(root:GetDescendants()) do
if desc:IsA("BasePart") then
parts += 1
if not desc.Anchored then
print("[ERROR] " .. desc:GetFullName() .. " not Anchored")
errors += 1
end
if desc.Position.Y - desc.Size.Y / 2 < -0.5 then
print("[WARN] " .. desc.Name .. " below floor")
warnings += 1
end
if desc.Color == Color3.new(163/255, 162/255, 165/255) and desc.Material == Enum.Material.Plastic then
print("[WARN] " .. desc.Name .. " uses default color/material")
warnings += 1
end
end
end
print(string.format("Parts: %d | Errors: %d | Warnings: %d", parts, errors, warnings))If any errors: fix and re-verify. Warnings are advisory.
构建完成后运行以捕获常见问题:
luau
local TARGET = "MyBuild" -- 改为你的模型/文件夹名称
local root = workspace:FindFirstChild(TARGET)
if not root then print("[ERROR] " .. TARGET .. " not found"); return end
local errors, warnings, parts = 0, 0, 0
for _, desc in ipairs(root:GetDescendants()) do
if desc:IsA("BasePart") then
parts += 1
if not desc.Anchored then
print("[ERROR] " .. desc:GetFullName() .. " not Anchored")
errors += 1
end
if desc.Position.Y - desc.Size.Y / 2 < -0.5 then
print("[WARN] " .. desc.Name .. " below floor")
warnings += 1
end
if desc.Color == Color3.new(163/255, 162/255, 165/255) and desc.Material == Enum.Material.Plastic then
print("[WARN] " .. desc.Name .. " uses default color/material")
warnings += 1
end
end
end
print(string.format("Parts: %d | Errors: %d | Warnings: %d", parts, errors, warnings))如果有任何错误:修复后重新验证。警告为建议性内容。
Map Folder Structure
地图文件夹结构
workspace/
MapName/ (Folder)
Origin (invisible anchor at 0,0,0)
Terrain/ (ground planes)
Zone_Spawn/
Floor
Walls/
Props/
Zone_Arena/
Landmarks/
Lighting/ (PointLights, SpotLights)
Spawns/ (SpawnLocation instances)workspace/
MapName/ (Folder)
Origin (位于0,0,0的不可见锚点)
Terrain/ (地面平面)
Zone_Spawn/
Floor
Walls/
Props/
Zone_Arena/
Landmarks/
Lighting/ (PointLights, SpotLights)
Spawns/ (SpawnLocation实例)