Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/skills/unity-mcp-skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ uri="file:///full/path/to/file.cs"
| **Editor** | `manage_editor`, `execute_menu_item`, `read_console` | Editor control |
| **Testing** | `run_tests`, `get_test_job` | Unity Test Framework |
| **Batch** | `batch_execute` | Parallel/bulk operations |
| **ProBuilder** | `manage_probuilder` | 3D modeling, mesh editing, complex geometry. **When `com.unity.probuilder` is installed, prefer ProBuilder shapes over primitive GameObjects** for editable geometry, multi-material faces, or complex shapes. Supports 13 shape types, face/edge/vertex editing, smoothing, and per-face materials. See [ProBuilder Guide](references/probuilder-guide.md). |
| **UI** | `manage_ui`, `batch_execute` with `manage_gameobject` + `manage_components` | **UI Toolkit**: Use `manage_ui` to create UXML/USS files, attach UIDocument, inspect visual trees. **uGUI (Canvas)**: Use `batch_execute` for Canvas, Panel, Button, Text, Slider, Toggle, Input Field. **Read `mcpforunity://project/info` first** to detect uGUI/TMP/Input System/UI Toolkit availability. (see [UI workflows](references/workflows.md#ui-creation-workflows)) |

## Common Workflows
Expand Down
116 changes: 116 additions & 0 deletions .claude/skills/unity-mcp-skill/references/tools-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Complete reference for all MCP tools. Each tool includes parameters, types, and
- [UI Tools](#ui-tools)
- [Editor Control Tools](#editor-control-tools)
- [Testing Tools](#testing-tools)
- [ProBuilder Tools](#probuilder-tools)

---

Expand Down Expand Up @@ -789,3 +790,118 @@ execute_custom_tool(
```

Discover available custom tools via `mcpforunity://custom-tools` resource.

---

## ProBuilder Tools

### manage_probuilder

Unified tool for ProBuilder mesh operations. Requires `com.unity.probuilder` package. When available, **prefer ProBuilder over primitive GameObjects** for editable geometry, multi-material faces, or complex shapes.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `action` | string | Yes | Action to perform (see categories below) |
| `target` | string | Sometimes | Target GameObject name/path/id |
| `search_method` | string | No | How to find target: `by_id`, `by_name`, `by_path`, `by_tag`, `by_layer` |
| `properties` | dict | No | Action-specific parameters |

**Actions by category:**

**Shape Creation:**
- `create_shape` — Create ProBuilder primitive (shape_type, size, position, rotation, name). 12 types: Cube, Cylinder, Sphere, Plane, Cone, Torus, Pipe, Arch, Stair, CurvedStair, Door, Prism
- `create_poly_shape` — Create from 2D polygon footprint (points, extrudeHeight, flipNormals)

**Mesh Editing:**
- `extrude_faces` — Extrude faces (faceIndices, distance, method: FaceNormal/VertexNormal/IndividualFaces)
- `extrude_edges` — Extrude edges (edgeIndices or edges [{a,b},...], distance, asGroup)
- `bevel_edges` — Bevel edges (edgeIndices or edges [{a,b},...], amount 0-1)
- `subdivide` — Subdivide faces via ConnectElements (faceIndices optional)
- `delete_faces` — Delete faces (faceIndices)
- `bridge_edges` — Bridge two open edges (edgeA, edgeB as {a,b} pairs, allowNonManifold)
- `connect_elements` — Connect edges/faces (edgeIndices or faceIndices)
- `detach_faces` — Detach faces to new object (faceIndices, deleteSourceFaces)
- `flip_normals` — Flip face normals (faceIndices)
- `merge_faces` — Merge faces into one (faceIndices)
- `combine_meshes` — Combine ProBuilder objects (targets list)
- `merge_objects` — Merge objects with auto-convert (targets, name)
- `duplicate_and_flip` — Create double-sided geometry (faceIndices)
- `create_polygon` — Connect existing vertices into a new face (vertexIndices, unordered)

**Vertex Operations:**
- `merge_vertices` — Collapse vertices to single point (vertexIndices, collapseToFirst)
- `weld_vertices` — Weld vertices within proximity radius (vertexIndices, radius)
- `split_vertices` — Split shared vertices (vertexIndices)
- `move_vertices` — Translate vertices (vertexIndices, offset [x,y,z])
- `insert_vertex` — Insert vertex on edge or face (edge {a,b} or faceIndex + point [x,y,z])
- `append_vertices_to_edge` — Insert evenly-spaced points on edges (edgeIndices or edges, count)

**Selection:**
- `select_faces` — Select faces by criteria (direction + tolerance, growFrom + growAngle)

**UV & Materials:**
- `set_face_material` — Assign material to faces (faceIndices, materialPath)
- `set_face_color` — Set vertex color on faces (faceIndices, color [r,g,b,a])
- `set_face_uvs` — Set UV params (faceIndices, scale, offset, rotation, flipU, flipV)

**Query:**
- `get_mesh_info` — Get mesh details with `include` parameter:
- `"summary"` (default): counts, bounds, materials
- `"faces"`: + face normals, centers, and direction labels (capped at 100)
- `"edges"`: + edge vertex pairs with world positions (capped at 200, deduplicated)
- `"all"`: everything
- `ping` — Check if ProBuilder is available

**Smoothing:**
- `set_smoothing` — Set smoothing group on faces (faceIndices, smoothingGroup: 0=hard, 1+=smooth)
- `auto_smooth` — Auto-assign smoothing groups by angle (angleThreshold: default 30)

**Mesh Utilities:**
- `center_pivot` — Move pivot to mesh bounds center
- `freeze_transform` — Bake transform into vertices, reset transform
- `validate_mesh` — Check mesh health (read-only diagnostics)
- `repair_mesh` — Auto-fix degenerate triangles

**Not Yet Working (known bugs):**
- `set_pivot` — Vertex positions don't persist through mesh rebuild. Use `center_pivot` or Transform positioning instead.
- `convert_to_probuilder` — MeshImporter throws internally. Create shapes natively instead.
Comment on lines +849 to +869
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

The action catalog is incomplete for experimental actions.

convert_to_probuilder and set_pivot are still exposed actions, but they are omitted from the Query/Mesh Utilities lists and only mentioned later as known-bug cases. Since Line 806 tells readers to choose an action from the categories below, this makes the reference self-contradictory.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/skills/unity-mcp-skill/references/tools-reference.md around lines
849 - 869, The catalog lists experimental actions (convert_to_probuilder,
set_pivot) as exposed but omits them from the Query and Mesh Utilities sections,
creating a contradiction; update the reference so the action lists and the
"choose an action" guidance match by either (A) adding convert_to_probuilder to
the Query or Mesh Utilities lists and set_pivot to Mesh Utilities with a clear
"(experimental / known-bug: see Not Yet Working)" tag, or (B) remove these
actions from the exposed action surface and only keep them in the "Not Yet
Working" section—also update the line that instructs readers to choose an action
from the categories to mention that experimental/buggy actions are listed with
that tag if you choose option A.


**Examples:**

```python
# Check availability
manage_probuilder(action="ping")

# Create a cube
manage_probuilder(action="create_shape", properties={"shape_type": "Cube", "name": "MyCube"})

# Get face info with directions
manage_probuilder(action="get_mesh_info", target="MyCube", properties={"include": "faces"})

# Extrude the top face (find it via direction="top" in get_mesh_info results)
manage_probuilder(action="extrude_faces", target="MyCube",
properties={"faceIndices": [2], "distance": 1.5})

# Select all upward-facing faces
manage_probuilder(action="select_faces", target="MyCube",
properties={"direction": "up", "tolerance": 0.7})

# Create double-sided geometry (for room interiors)
manage_probuilder(action="duplicate_and_flip", target="Room",
properties={"faceIndices": [0, 1, 2, 3, 4, 5]})

# Weld nearby vertices
manage_probuilder(action="weld_vertices", target="MyCube",
properties={"vertexIndices": [0, 1, 2, 3], "radius": 0.1})

# Auto-smooth
manage_probuilder(action="auto_smooth", target="MyCube", properties={"angleThreshold": 30})

# Cleanup workflow
manage_probuilder(action="center_pivot", target="MyCube")
manage_probuilder(action="validate_mesh", target="MyCube")
```

See also: [ProBuilder Workflow Guide](probuilder-guide.md) for detailed patterns and complex object examples.
83 changes: 83 additions & 0 deletions .claude/skills/unity-mcp-skill/references/workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Common workflows and patterns for effective Unity-MCP usage.
- [Testing Workflows](#testing-workflows)
- [Debugging Workflows](#debugging-workflows)
- [UI Creation Workflows](#ui-creation-workflows)
- [ProBuilder Workflows](#probuilder-workflows)
- [Batch Operations](#batch-operations)

---
Expand Down Expand Up @@ -1425,6 +1426,88 @@ Both systems are active simultaneously. For UI, prefer `InputSystemUIInputModule

---

## ProBuilder Workflows

When `com.unity.probuilder` is installed, prefer ProBuilder shapes over primitive GameObjects for any geometry that needs editing, multi-material faces, or non-trivial shapes. Check availability first with `manage_probuilder(action="ping")`.

See [ProBuilder Workflow Guide](probuilder-guide.md) for full reference with complex object examples.

### ProBuilder vs Primitives Decision

| Need | Use Primitives | Use ProBuilder |
|------|---------------|----------------|
| Simple placeholder cube | `manage_gameobject(action="create", primitive_type="Cube")` | - |
| Editable geometry | - | `manage_probuilder(action="create_shape", ...)` |
| Per-face materials | - | `set_face_material` |
| Custom shapes (L-rooms, arches) | - | `create_poly_shape` or `create_shape` |
| Mesh editing (extrude, bevel) | - | Face/edge/vertex operations |
| Batch environment building | Either | ProBuilder + `batch_execute` |

### Basic ProBuilder Scene Build

```python
# 1. Check ProBuilder availability
manage_probuilder(action="ping")

# 2. Create shapes (use batch for multiple)
batch_execute(commands=[
{"tool": "manage_probuilder", "params": {
"action": "create_shape",
"properties": {"shape_type": "Cube", "name": "Floor", "width": 20, "height": 0.2, "depth": 20}
}},
{"tool": "manage_probuilder", "params": {
"action": "create_shape",
"properties": {"shape_type": "Cube", "name": "Wall1", "width": 20, "height": 3, "depth": 0.3,
"position": [0, 1.5, 10]}
}},
{"tool": "manage_probuilder", "params": {
"action": "create_shape",
"properties": {"shape_type": "Cylinder", "name": "Pillar1", "radius": 0.4, "height": 3,
"position": [5, 1.5, 5]}
}},
])

# 3. Edit geometry (always get_mesh_info first!)
info = manage_probuilder(action="get_mesh_info", target="Wall1",
properties={"include": "faces"})
# Find direction="front" face, subdivide it, delete center for a window

# 4. Apply materials per face
manage_probuilder(action="set_face_material", target="Floor",
properties={"faceIndices": [0], "materialPath": "Assets/Materials/Stone.mat"})

# 5. Smooth organic shapes
manage_probuilder(action="auto_smooth", target="Pillar1",
properties={"angleThreshold": 45})

# 6. Screenshot to verify
manage_scene(action="screenshot", include_image=True, max_resolution=512)
```

### Edit-Verify Loop Pattern

Face indices change after every edit. Always re-query:

```python
# WRONG: Assume face indices are stable
manage_probuilder(action="subdivide", target="Obj", properties={"faceIndices": [2]})
manage_probuilder(action="delete_faces", target="Obj", properties={"faceIndices": [5]}) # Index may be wrong!

# RIGHT: Re-query after each edit
manage_probuilder(action="subdivide", target="Obj", properties={"faceIndices": [2]})
info = manage_probuilder(action="get_mesh_info", target="Obj", properties={"include": "faces"})
# Find the correct face by direction/center, then delete
manage_probuilder(action="delete_faces", target="Obj", properties={"faceIndices": [correct_index]})
```

### Known Limitations

- **`set_pivot`**: Broken -- vertex positions don't persist through mesh rebuild. Use `center_pivot` or Transform positioning.
- **`convert_to_probuilder`**: Broken -- MeshImporter throws. Create shapes natively with `create_shape`/`create_poly_shape`.
- **`subdivide`**: Uses `ConnectElements.Connect` (not traditional quad subdivision). Connects face midpoints.

---

## Batch Operations

### Mass Property Update
Expand Down
2 changes: 1 addition & 1 deletion MCPForUnity/Editor/Tools/GameObjects/GameObjectModify.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal static object Handle(JObject @params, JToken targetToken, string search

bool modified = false;

string name = @params["name"]?.ToString();
string name = @params["name"]?.ToString() ?? @params["new_name"]?.ToString() ?? @params["newName"]?.ToString();
if (!string.IsNullOrEmpty(name) && targetGo.name != name)
{
// Check if we're renaming the root object of an open prefab stage
Expand Down
45 changes: 39 additions & 6 deletions MCPForUnity/Editor/Tools/ManageScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,8 @@ private static object CaptureSurroundBatch(SceneCommand cmd)
if (r != null && r.gameObject.activeInHierarchy) targetBounds.Encapsulate(r.bounds);
}
center = targetBounds.center;
radius = targetBounds.extents.magnitude * 1.8f;
radius = Mathf.Max(radius, 3f);
radius = targetBounds.extents.magnitude * 2.5f;
radius = Mathf.Max(radius, 5f);
}
}
else
Expand All @@ -632,8 +632,8 @@ private static object CaptureSurroundBatch(SceneCommand cmd)
return new ErrorResponse("No renderers found in the scene. Cannot determine scene bounds for batch capture.");

center = bounds.center;
radius = bounds.extents.magnitude * 1.8f;
radius = Mathf.Max(radius, 3f);
radius = bounds.extents.magnitude * 2.5f;
radius = Mathf.Max(radius, 5f);
}

// Define 6 viewpoints: front, back, left, right, top, bird's-eye (45° elevated front-right)
Expand All @@ -655,6 +655,10 @@ private static object CaptureSurroundBatch(SceneCommand cmd)
tempCam.farClipPlane = radius * 4f;
tempCam.clearFlags = CameraClearFlags.Skybox;

// Force material refresh once before capture loop
EditorApplication.QueuePlayerLoopUpdate();
SceneView.RepaintAll();

var tiles = new List<Texture2D>();
var tileLabels = new List<string>();
var shotMeta = new List<object>();
Expand Down Expand Up @@ -773,6 +777,10 @@ private static object CaptureOrbitBatch(SceneCommand cmd)
tempCam.farClipPlane = radius * 4f;
tempCam.clearFlags = CameraClearFlags.Skybox;

// Force material refresh once before capture loop
EditorApplication.QueuePlayerLoopUpdate();
SceneView.RepaintAll();

var tiles = new List<Texture2D>();
var tileLabels = new List<string>();
var shotMeta = new List<object>();
Expand Down Expand Up @@ -851,7 +859,7 @@ private static object CaptureOrbitBatch(SceneCommand cmd)

/// <summary>
/// Captures a single screenshot from a temporary camera placed at view_position and aimed at look_at.
/// Returns inline base64 PNG (no file saved to disk).
/// Returns inline base64 PNG and also saves the image to Assets/Screenshots/.
/// </summary>
private static object CapturePositionedScreenshot(SceneCommand cmd)
{
Expand Down Expand Up @@ -912,20 +920,45 @@ private static object CapturePositionedScreenshot(SceneCommand cmd)

var (b64, w, h) = ScreenshotUtility.RenderCameraToBase64(tempCam, maxRes);

// Save to disk
string screenshotsFolder = Path.Combine(Application.dataPath, "Screenshots");
Directory.CreateDirectory(screenshotsFolder);
string fileName = !string.IsNullOrEmpty(cmd.fileName)
? (cmd.fileName.EndsWith(".png", System.StringComparison.OrdinalIgnoreCase) ? cmd.fileName : cmd.fileName + ".png")
: $"screenshot-{DateTime.Now:yyyyMMdd-HHmmss}.png";
string fullPath = Path.Combine(screenshotsFolder, fileName);
// Ensure unique filename
if (File.Exists(fullPath))
{
string baseName = Path.GetFileNameWithoutExtension(fullPath);
string ext = Path.GetExtension(fullPath);
int counter = 1;
while (File.Exists(fullPath))
{
fullPath = Path.Combine(screenshotsFolder, $"{baseName}_{counter}{ext}");
counter++;
}
}
byte[] pngBytes = System.Convert.FromBase64String(b64);
File.WriteAllBytes(fullPath, pngBytes);

string assetsRelativePath = "Assets/Screenshots/" + Path.GetFileName(fullPath);
AssetDatabase.ImportAsset(assetsRelativePath, ImportAssetOptions.ForceSynchronousImport);

var data = new Dictionary<string, object>
{
{ "imageBase64", b64 },
{ "imageWidth", w },
{ "imageHeight", h },
{ "viewPosition", new[] { camPos.x, camPos.y, camPos.z } },
{ "screenshotsFolder", screenshotsFolder },
{ "path", assetsRelativePath },
};
if (targetPos.HasValue)
data["lookAt"] = new[] { targetPos.Value.x, targetPos.Value.y, targetPos.Value.z };

return new SuccessResponse(
$"Positioned screenshot captured (max {maxRes}px).",
$"Positioned screenshot captured (max {maxRes}px) and saved to '{assetsRelativePath}'.",
data
);
}
Expand Down
8 changes: 8 additions & 0 deletions MCPForUnity/Editor/Tools/ProBuilder.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading