Claude Skill

roblox-building

Use when building geometry, maps, props, or generated assets with MCP or standalone Luau.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download tabooharmony-roblox-brain-skills_gameplay_roblox-building-6051c35.zip · 12 KB
Part of tabooharmony/roblox-brain — 29 skills

Install

skills CLI npx skills add https://github.com/TabooHarmony/roblox-brain/tree/main/skills/gameplay/roblox-building
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install tabooharmony-roblox-brain@llmmart
Git git clone https://github.com/TabooHarmony/roblox-brain.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole tabooharmony/roblox-brain collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Roblox Building

When to Load

Load for geometry, props, maps, and spatial onboarding via MCP or Luau.

Quick Reference

MCP Build Mode

  1. Inspect Studio, Workspace, and existing assets.
  2. Name the root, origin, dimensions, and assets.
  3. Build in phases; read back each batch.
  4. Verify the tree, view, and traversal.

Asset Choice

  • Search project assets and Toolbox before generating. Check type, creator, price, scripts, and fit.
  • Before paid or cross-owner insertion, disclose creator, ID, price, and rights. Inspect scripts and dependencies; remove unneeded code and test in scene. See roblox-security.
  • MCP: generate_procedural_model, generate_mesh, generate_material.
  • Studio Assistant previews models, restyles textures, and segments imported meshes. These aren't confirmed MCP tools; see full reference.
  • Check mesh bounds, collision, PBR, and quality levels.
  • Use permitted images; wait for jobs to finish.
  • EditableImage/EditableMesh have permission and memory limits.
  • Use native Parts/CSG when reuse or generation is unsuitable.

Player Scale

Player ~5 studs | Door 4w×7h | Ceiling 10-14 | Counter 3.5-4 | Seat 1.5 | Path 6+

Spatial Rules

  • Name dimensions; offset sub-parts from anchor CFrames, not guessed world coordinates.
  • Snap to 0.125/0.25/0.5 studs.
  • Build complex CSG near origin, then PivotTo the destination.
  • Set anchoring, collision, shadows, color, and material explicitly.

Acceptance

Prop: named model, pivot, scale, bounds, materials, collision, anchoring, no loose parts, asset provenance. Map: root/origin, zones, landmarks, spawns/return paths, path widths, traversal, and bounds checks excluding Baseplate/Terrain/SpawnLocation. Evidence: readback, a view when supported, and playtest results.

Anti-Patterns

Guessing coordinates | unanchored or duplicate parts | hardcoded world positions | silent CSG failure | oversized batches | claims without readback

Details: references/full.md covers maps, validation, and assets.

Files (roblox-brain)
  • references
    • full.md 26.5 KB
      # Building 3D in Roblox: Full Reference
      
      
      > **Code in this reference is illustrative. Adapt to your game and verify in Studio before production use.**
      
      Use this skill when creating physical geometry in Roblox Studio (via MCP or standalone scripts). Covers single objects, room-scale structures, and multi-zone maps.
      
      ## MCP Mode (if using MCP bridge)
      
      MCP code execution is stateless. Every call is a blank slate.
      
      1. **Variables don't persist** between calls.
      2. **Object references are lost** between calls.
      3. **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
      end
      ```
      
      **Ground 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
      end
      ```
      
      ## MCP Build Contract
      
      Use the shared `roblox-studio-mcp` session contract. Before changing a place:
      
      1. List/select the intended Studio and call `get_studio_state`.
      2. Confirm the target datamodel and inspect `Workspace`, existing map roots, coordinate conventions, scripts, and reusable assets.
      3. Declare a build root, origin, named dimensions, asset manifest, and acceptance gates.
      4. Apply one bounded phase at a time. Re-acquire references in every stateless `execute_luau` call.
      5. Read back the tree and properties before starting the next phase.
      6. Start play only when runtime behavior matters. Capture console, navigation, and visual evidence, then stop play.
      
      Keep a one-line mutation record per mutating step (target, pre-state, intended change, compensating action) and reconcile ambiguous tool timeouts by reading the target back before retrying; destructive tests must confirm actual store and endpoint destinations rather than trusting the place label. Full pattern: `roblox-studio-mcp`.
      
      If a capability is unavailable, switch to the offline Luau path and identify the missing evidence instead of claiming the build was verified.
      
      ## Asset-Aware Prop Workflow
      
      **Toolbox is a production asset source, not just a shortcut for prototypes.** Check existing project assets and Studio's Toolbox (Creator Store and your/group inventory) before generating a replacement for a common prop, mesh, material, sound, or UI asset. Roblox's [Toolbox guide](https://create.roblox.com/docs/projects/assets/toolbox) covers category search, creator/price filters, detail previews, and insertion; its [building curriculum](https://create.roblox.com/docs/tutorials/curriculums/core/building/apply-polished-assets) demonstrates reusing a Creator Store asset library to replace greybox scenery. Choose the least risky source that fits the game's scale, style, and gameplay:
      
      1. **Find candidates:** search the project first, then Toolbox/Creator Store or creator inventory by category and purpose; narrow by creator, asset type, price, and rating. Inspect the detail page's creator, previews, description, script count, and geometry complexity. Popularity and a verified creator are signals, not proof of safety or fit. If the available tool cannot show details, inspect the asset in Studio before accepting it.
      2. **Decide before insertion:** compare a plausible asset with building it. Use existing or Store assets when they fit without heavy rework; build a custom asset when the mechanic, style, permissions, or performance needs demand it. Record asset ID, creator/source, type, price, usage rights, and intended parent. For cross-owner or paid results, show these to the user and get explicit consent before insertion or purchase.
      3. **Inspect the inserted model:** read its entire hierarchy before play. Check Scripts/LocalScripts/ModuleScripts, package links, and nested assets; remove or disable code the game does not need. For needed code, inspect what it does, especially obfuscation, remote asset loads, and requests for sensitive capabilities. Roblox warns that [third-party models can contain backdoors](https://create.roblox.com/docs/scripting/security/third-party-vulnerabilities), and a [DevForum cleanup guide](https://devforum.roblox.com/t/clearing-your-game-of-malicious-scripts-plugins-and-backdoors/511830) shows why scanning script descendants and checking plugin provenance matter. Do not treat a scanner, rating, or sandbox as a clean bill of health; see `roblox-security` for code isolation.
      4. **Fit and test:** parent under the intended build root; verify pivot, size/player scale, collisions, anchoring, materials, textures, dependent asset permissions, and scripts after insertion. Compare with the project's visual language. Playtest traversal and the asset's behavior; a model that looks right in the thumbnail can break movement or load without its dependencies.
      5. **Procedural:** use `generate_procedural_model` for configurable primitive-part props, buildings, scenery, and image-guided blockouts. Pass meaningful `partNames` and user requirements as the prompt. The tool may auto-insert the result.
      6. **Mesh:** use `generate_mesh` for a custom textured prop. Bound the size and triangle budget; do not treat the returned mesh as accepted until inspected.
      7. **Material:** use `generate_material`, then apply and verify its returned base material and material-variant name on target parts.
      8. **Image:** use `store_image` for permitted local PNG/JPG references or `upload_image` for a permitted source accepted by the live schema. Never upload external content without permission.
      9. **Wait:** if a generation returns a job ID, call `wait_job_finished` with its `generationId` before dependent edits. Follow the live tool schema because some generation tools complete or insert automatically.
      10. **Place:** parent the result under the named build root, set pivot/transform, and read back class, descendants, bounds, materials, collision, anchoring, and asset provenance.
      11. **Fallback:** use native Parts, CSG, primitives, and coherent materials when reuse or generation is unavailable, slow, rejected, or visually unsuitable.
      
      Generated assets are candidates. Structural and visual review are still required.
      
      ### Studio Assistant generation (not the MCP tool list)
      
      Roblox's [Studio Assistant guide](https://create.roblox.com/docs/assistant/guide) and [feature announcement](https://devforum.roblox.com/t/introducing-new-texture-generation-tools-segment-any-mesh-and-image-previews/4890084) describe these editor workflows. Use them when an agent can operate Studio's Assistant UI or guide a person through it; check the live tool list before assuming an MCP client can call them.
      
      - **Restyle existing meshes:** select one or more meshes and use the ribbon button, right-click **Generate > Texture**, or Assistant's `/generate_texture`. Iterate on the generated texture, then export it to a texturing program for further editing if needed. Check the mesh and appearance afterward rather than assuming generation preserved every detail.
      - **Segment imported meshes:** select the `MeshPart` itself, then use `/segment_mesh` in Assistant. Name up to five parts; suggested names for familiar objects can improve results. Run the command again on a part if you need finer division. This is an early-preview feature; the guide says it replaces the original mesh in Workspace, so inspect the new hierarchy, materials, collisions, and behavior before proceeding.
      - **Preview before generating:** for text-prompt `/generate_mesh` or `/generate_procedural_model`, review the suggested part names and choose from four generated image previews before creating the final model. A supplied hint image guides the model but currently skips that four-preview step. This is an Assistant UI flow, not a promise that MCP `generate_mesh` exposes preview selection.
      
      ## Mesh-Backed Geometry
      
      `MeshPart` is a `BasePart` with a custom mesh. Treat the visible mesh, its appearance, and its collision shape as separate review surfaces:
      
      - read back `MeshId`/`MeshContent`, `MeshSize`, transform, bounds, `Anchored`, `CanCollide`, `CanTouch`, `CanQuery`, and `CollisionFidelity`;
      - inspect a child `SurfaceAppearance` and its `ColorMap`, normal, metalness, roughness, and emissive maps when present; PBR appearance depends on device and graphics quality, so preview representative quality levels;
      - do not imply that a runtime script can repair `MeshId` or most PBR maps. Resolve authoring/import issues before placement, then verify after insertion;
      - record source and intended use for each non-original mesh. A repeated asset key may indicate reuse, but static equality is not proof of license or quality.
      
      Use native Parts or CSG for simple collision and blockout geometry. Use a separate low-cost collision model when the visible mesh is large, detailed, or non-interactive. Let measured playtests and profiling, not class counts, decide performance changes.
      
      ## EditableImage and EditableMesh (runtime pixel/vertex editing)
      
      `EditableImage` and `EditableMesh` are runtime-editable image and mesh objects (not `Instance`s, so `Instance.new` does not work). Create them through `AssetService`:
      
      ```luau
      local AssetService = game:GetService("AssetService")
      
      -- from scratch (synchronous)
      local image = AssetService:CreateEditableImage({ Size = Vector2.new(256, 256) })
      
      -- from an owned asset (async, may throw on permission/network failure)
      local loaded = AssetService:CreateEditableImageAsync(Content.fromUri(assetUri))
      ```
      
      Hard constraints (official):
      
      - Creation APIs can return `nil` when the device is out of `Editable*` memory budget. Always nil-check before use; `:Destroy()` finished objects to free budget.
      - In published experiences the creator must be 13+, ID-verified, and have the "Allow Mesh / Image APIs" toggle on (Game Settings → Security). Loading assets works only for assets the experience owner (or group) owns.
      - `Editable*` objects do not replicate. Each client/server boundary needs its own creation; replicating edits means sending your own data (and you are then responsible for moderation of user-generated content, so prefer seed/slider parameters over free-form pixel replication).
      - `EditableImage` size is fixed at creation. `EditableMesh` created from an asset is fixed-size by default (cheaper; positions/attributes editable, topology not). Non-fixed meshes: 60,000 vertex / 20,000 triangle limit.
      
      Rendering to UI: wrap with `Content.fromObject(image)` and assign to `ImageLabel.ImageContent` (or `MeshPart.TextureContent` / `MeshPart.MeshContent`). Practitioner tip: set `ResampleMode` to `Pixelated` for crisp low-resolution renders.
      
      Pixel work uses the `buffer` library, 4 bytes per pixel RGBA, row-major:
      
      ```luau
      local w, h = image.Size.X, image.Size.Y
      local px = buffer.create(w * h * 4)
      for y = 0, h - 1 do
          for x = 0, w - 1 do
              local i = (y * w + x) * 4
              buffer.writeu8(px, i, r) buffer.writeu8(px, i + 1, g)
              buffer.writeu8(px, i + 2, b) buffer.writeu8(px, i + 3, 255)
          end
      end
      image:WritePixelsBuffer(Vector2.zero, image.Size, px)
      ```
      
      Practitioner guidance (devforum, unverified by us):
      
      - Pack a pixel as one `u32` write where possible instead of four `u8` writes; batch per-row and write once per frame. A one-`EditableImage`-update-per-frame limit has been reported, so profile before assuming per-frame writes are free.
      - Expensive per-pixel loops (raycast renderers, fractals) benefit from Parallel Luau: compute row buffers inside Actors, then `task.synchronize` before `WritePixelsBuffer` (it is not callable in parallel).
      - For painting on meshes: `EditableMesh:RaycastLocal` gives the hit UV, then draw at that coordinate on the paired `EditableImage` (`DrawImageTransformed` for cropping/rotation, `DrawCircle`/`DrawRectangle`/`DrawLine` for shapes).
      - `EditableMesh` IDs (vertex/face/UV/normal) are stable but unordered with holes; iterate `GetVertices()`/`GetFaces()` results, never `1..count`. Use batch APIs (`BatchSetValues`) over per-element calls for bulk edits; re-derive collision via `AssetService:CreateMeshPartAsync` at the end of a conceptual edit, not per-op.
      
      ## Player 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
      
      ## Build Process
      
      ### Objects (single Model)
      
      1. **Assess**: Do you know the components, scale, and style? If not, ask.
      2. **Plan**: Declare dimensions as named variables. Choose an anchor part.
      3. **Build**: Generate parts with relative positioning. Split across calls if >20 parts.
      4. **Verify**: Run validation (check Anchored, below-floor, default colors).
      
      ### Maps (multi-zone)
      
      1. **Layout**: Define total size, zone breakdown, gameplay type. If any is vague, ask.
      2. **Ground**: Floor planes, boundaries, Origin anchor, folder hierarchy.
      3. **Zone shells**: Floor sections, walls, dividers per zone.
      4. **Landmarks**: Orientation structures (towers, fountains, trees).
      5. **Fill**: Props, furniture, vegetation per zone.
      6. **Environment**: Lighting, Atmosphere, 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,
      }
      ```
      
      ### 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
      ```
      
      ### Grid 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.
      
      ## CSG (Union / Subtract)
      
      ### The 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
      ```
      
      ### Safe CSG Wrapper
      
      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()
      end
      ```
      
      ### CSG Rules
      
      - 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 supports Part, PartOperation, and MeshPart. Terrain is NOT supported.
      - Set `CollisionFidelity = Enum.CollisionFidelity.Box` on decorative unions for performance.
      
      ## Terrain Import Workflow
      
      Roblox's built-in terrain sculpting is fine for small worlds but tedious for large open-world landscapes (tutorial guide: Large-Scale Roblox Terrain). The proven external pipeline: generate a landscape in a desktop terrain tool, import as an OBJ mesh, then convert to voxel terrain so it streams with the engine.
      
      1. Generate: Quadspinner Gaea (free tier, 1k map resolution) with a Primitive → Displace → Erosion node graph. Add a Mesher node at the end, export as `.tor` then OBJ.
      2. Optimize (optional): import OBJ into Blender, apply a Decimate modifier down to ~50-200k faces if the mesh is too heavy to import (note: too few triangles = holes after voxel conversion).
      3. Import into Studio: use the OBJ Importer plugin (converts vertex data to wedges/parts) in a blank place; this bypasses Roblox's OBJ polygon limit.
      4. Convert to terrain: run a part-to-voxel conversion script over the imported parts. Heightmap import is faster and supports higher resolutions, but the selective material-painting step below only works on the mesh path.
      
      **Material painting:** with the mesh path you can paint materials automatically by slope and altitude (e.g. rock on steep slopes, grass on flats), then the voxel conversion preserves the painted result. For imported heightmaps, paint via a color map that adheres to Roblox's colormap material set instead.
      
      Gaea is resource-hungry (8-16 GB RAM recommended; Studio uses a lot during import). Lower-end hardware can still manage the 1k free-tier resolution.
      
      > Heightmaps cannot represent overhangs or caves; use the mesh path for those.
      
      ## 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)
      ```
      
      ### WedgePart Orientation
      
      The zero-height edge (tip) points toward +Z by default.
      
      | Desired tip direction | Rotation |
      |---|---|
      | Up (+Y) | `CFrame.Angles(-math.pi/2, 0, 0)` |
      | Down (-Y) | `CFrame.Angles(math.pi/2, 0, 0)` |
      | Forward (+Z) | none |
      | Backward (-Z) | `CFrame.Angles(math.pi, 0, 0)` |
      
      ### Neon Material
      
      Neon glows visually but does NOT cast light on surroundings. Add a PointLight/SpotLight as a child for actual illumination.
      
      ### Default Part Properties
      
      Always set explicitly:
      - `Anchored = true` (defaults to false!)
      - `CanCollide = true` (false for small decorative clutter)
      - `CastShadow = true` (false for invisible triggers)
      
      ## 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.
      
      ## 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
      
              -- For MeshPart, read back MeshId/MeshContent. If the asset manifest
              -- expects PBR, inspect child SurfaceAppearance maps in Studio or
              -- plugin tooling; ordinary runtime scripts may not access most maps.
          end
      end
      print(string.format("Parts: %d | Errors: %d | Warnings: %d", parts, errors, warnings))
      ```
      
      If any errors: fix and re-verify. Warnings are advisory.
      
      ## 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)
      ```
      
      ## Acceptance Gates
      
      Before calling a prop complete, verify:
      
      - exactly one named model under the intended build root
      - pivot and bounding box are sensible at player scale
      - every structural part has deliberate anchoring, collision, material, and color
      - no loose or duplicate parts remain
      - generated or inserted assets have recorded provenance and were read back after placement
      
      Before calling a map phase complete, verify:
      
      - the map root and `Origin` are present
      - zone floors and landmarks are inside the intended bounds
      - each named spawn has a navigable return path, is not inside collision or facing a wall, and, when the design declares a fixed session population, spawn count matches it
      - main paths are reachable and wide enough
      - geometry is connected to the ground or a parent structure
      - bounds calculations exclude `Baseplate`, `Terrain`, and default `SpawnLocation` unless intentionally included
      
      ## Player-Facing Route Acceptance
      
      Treat a map as a player path, not only a geometry tree:
      
      1. Draw the main route as nodes and edges: spawn, first action, decision points, checkpoints, goals, returns, and exits.
      2. From every spawn, verify that the next landmark or affordance is visible, the camera is not inside geometry, and the player is not facing a wall or hazard.
      3. Give each critical action a readable world cue and feedback. Route prompts and input to their owning skills rather than encoding progress in decoration alone.
      4. Check the return path and recovery from falls, death, wrong turns, and interrupted traversal.
      5. Playtest from the player camera at representative movement speeds. A top-down editor view cannot prove wayfinding or spatial onboarding.
      
      Use runtime observation or a small funnel to judge onboarding success. Static route structure can reveal what to test, not whether players understand it.
      
      For world interactions, prefer `ProximityPrompt` when cross-device button or hold semantics fit. Use `ClickDetector` for simple click interactions and `Touched` only when physical contact is the mechanic. `BillboardGui`, `SurfaceGui`, and `Highlight` provide cues, not authority. Validate outcomes on the server from current distance, state, cooldown, and ownership.
      
      ## Large-Place Readback
      
      For a large root, do not use an unbounded "dump everything" readback as the only check. Partition the inspection by build root or zone and collect:
      
      - instance and descendant counts, plus bounds and pivot for each scope;
      - class counts for structural and effect-heavy classes such as `MeshPart`, `UnionOperation`, `SurfaceAppearance`, `Attachment`, and `ParticleEmitter`;
      - anchoring, collision, and query-state exceptions;
      - repeated mesh, texture, and image references that may deserve deduplication review;
      - the smallest representative set of paths needed to investigate each exception.
      
      Use the report to choose the next bounded inspection or playtest. Static counts are triage signals, not proof of quality, usability, memory use, or frame rate. Confirm performance concerns with Scene Analysis, the Developer Console, MicroProfiler, and representative devices.
      
      ## Evidence Recipes
      
      - **Structural:** return counts, classes, paths, bounds, pivots, materials, anchoring errors, collision errors, and asset IDs from an edit-time inspection.
      - **Visual:** use `screen_capture` with a deliberate camera position when supported. If capture fails or hangs, report that and retain structural evidence rather than inventing visual conclusions.
      - **Runtime:** start play, navigate to the spawn and a representative landmark, exercise the relevant interaction, collect console output, and stop play. A clean console is evidence of no observed errors, not proof of all behavior.
      - **Recovery:** if a phase fails, preserve the last verified phase, remove only the disposable failed output, and retry with a smaller batch or native fallback.
      
      ## Community ecosystem (leads, not sources)
      
      ### Interaction prompts: ProximityPrompt and ProximityPromptService
      
      `ProximityPrompt` (parent to a `BasePart`, `Attachment`, or `Model`) renders a built-in interaction prompt (key hint + label) and fires `Triggered` when the player interacts; no GUI code needed. Default `RequiresLineOfSight = true` and `MaxActivationDistance = 10`. `HoldDuration` makes the player hold the key; `GamepadKeyCode`/`Style` control presentation. `ObjectText`/`ActionText` are the sub-label and main label. `KeyboardKeyCode`/`ClickablePrompt` customize input.
      
      `ProximityPromptService` is the manager: `Enabled` toggles all prompts, `MaxPromptsVisible` (default 16) caps simultaneous prompts, `MaxIndicatorsVisible` (default 16, clamped 0-64) caps opt-in distance indicators. Events: `PromptShown`/`PromptHidden` (client-side visibility), `PromptTriggered(prompt, player)` fires on completed interaction (key press, or after `HoldDuration` hold), `PromptTriggerEnded`, `PromptButtonHoldBegan`/`PromptButtonHoldEnded` (hold-progress UI), plus `IndicatorShown`/`IndicatorHidden` for custom indicator UI (indicators only appear when a prompt sets `MaxIndicatorDistance > 0`). Listen globally on the service to avoid per-prompt wiring:
      
      ```luau
      local PPS = game:GetService("ProximityPromptService")
      PPS.PromptTriggered:Connect(function(prompt, player)
          handleInteraction(prompt, player) -- one connection for every prompt in the game
      end)
      ```
      
      Server scripts can also create and configure prompts programmatically; `TriggerEnded` on the prompt itself pairs with `Triggered` for release-to-cancel mechanics.
      
      - [Large-Scale Roblox Terrain: the ultimate guide](https://devforum.roblox.com/t/large-scale-roblox-terrain-the-ultimate-guide/405672) (84k views): still the terrain-at-scale reference.
      - [Realistic oceans via mesh deformation](https://devforum.roblox.com/t/realistic-oceans-using-mesh-deformation/1159345); [greedy meshing explainer](https://devforum.roblox.com/t/consume-everything-how-greedy-meshing-works/452717).
      - [Free texture sites](https://devforum.roblox.com/t/free-texture-sites/70131) (174k views); [City Loader plugin](https://devforum.roblox.com/t/city-loader-plugin-templates-for-real-life-buildingscities-in-studio/696886).
      
  • SKILL.md 2.9 KB
    ---
    name: roblox-building
    description: "Use when building geometry, maps, props, or generated assets with MCP or standalone Luau."
    last_reviewed: 2026-08-31
    sources:
      - original
      - https://devforum.roblox.com/t/large-scale-roblox-terrain-the-ultimate-guide/405672
      - https://devforum.roblox.com/t/a-complete-guide-to-editableimages/3858566
      - https://create.roblox.com/docs/reference/engine/classes/EditableImage
      - https://raw.githubusercontent.com/Roblox/creator-docs/main/content/en-us/studio/mcp.md
      - https://create.roblox.com/docs/production/game-design/core-loops
      - https://create.roblox.com/docs/production/game-design/onboarding
      - https://create.roblox.com/docs/production/game-design/onboarding-techniques
      - https://create.roblox.com/docs/projects/assets/toolbox
      - https://create.roblox.com/docs/scripting/security/third-party-vulnerabilities
      - https://create.roblox.com/docs/assistant/guide
    ---
    
    # Roblox Building
    
    ## When to Load
    
    Load for geometry, props, maps, and spatial onboarding via MCP or Luau.
    
    ## Quick Reference
    
    ### MCP Build Mode
    1. Inspect Studio, Workspace, and existing assets.
    2. Name the root, origin, dimensions, and assets.
    3. Build in phases; read back each batch.
    4. Verify the tree, view, and traversal.
    
    ### Asset Choice
    - Search project assets and Toolbox before generating. Check type, creator, price, scripts, and fit.
    - Before paid or cross-owner insertion, disclose creator, ID, price, and rights. Inspect scripts and dependencies; remove unneeded code and test in scene. See `roblox-security`.
    - MCP: `generate_procedural_model`, `generate_mesh`, `generate_material`.
    - Studio Assistant previews models, restyles textures, and segments imported meshes. These aren't confirmed MCP tools; see full reference.
    - Check mesh bounds, collision, PBR, and quality levels.
    - Use permitted images; wait for jobs to finish.
    - `EditableImage`/`EditableMesh` have permission and memory limits.
    - Use native Parts/CSG when reuse or generation is unsuitable.
    
    ### Player Scale
    Player ~5 studs | Door 4w×7h | Ceiling 10-14 | Counter 3.5-4 | Seat 1.5 | Path 6+
    
    ### Spatial Rules
    - Name dimensions; offset sub-parts from anchor CFrames, not guessed world coordinates.
    - Snap to 0.125/0.25/0.5 studs.
    - Build complex CSG near origin, then `PivotTo` the destination.
    - Set anchoring, collision, shadows, color, and material explicitly.
    
    ### Acceptance
    **Prop:** named model, pivot, scale, bounds, materials, collision, anchoring, no loose parts, asset provenance.
    **Map:** root/origin, zones, landmarks, spawns/return paths, path widths, traversal, and bounds checks excluding Baseplate/Terrain/SpawnLocation.
    **Evidence:** readback, a view when supported, and playtest results.
    
    ### Anti-Patterns
    Guessing coordinates | unanchored or duplicate parts | hardcoded world positions | silent CSG failure | oversized batches | claims without readback
    
    **Details:** `references/full.md` covers maps, validation, and assets.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related