Skip to content

Feature/multi-view screenshot#840

Merged
Scriptwonder merged 4 commits intoCoplayDev:betafrom
Scriptwonder:feature/contact-sheet-screenshots
Feb 28, 2026
Merged

Feature/multi-view screenshot#840
Scriptwonder merged 4 commits intoCoplayDev:betafrom
Scriptwonder:feature/contact-sheet-screenshots

Conversation

@Scriptwonder
Copy link
Collaborator

@Scriptwonder Scriptwonder commented Feb 28, 2026

Description

Provide a multi-view screenshot feature that lets you save multiple screenshots in a contact sheet-like layout.

Type of Change

Save your change type

  • New feature (non-breaking change that adds functionality)
  • Documentation update

Changes Made

  1. Screenshot enhancement
  2. CLI update
  3. Update docs

Testing/Screenshots/Recordings

image image

Documentation Updates

  • I have added/removed/modified tools or resources
  • If yes, I have updated all documentation files using:
    • The LLM prompt at tools/UPDATE_DOCS_PROMPT.md (recommended)
    • Manual updates following the guide at tools/UPDATE_DOCS.md

Related Issues

Additional Notes

Summary by Sourcery

Add configurable multi-angle screenshot contact sheets and extend screenshot tooling and docs to support the new orbit batch mode.

New Features:

  • Introduce an orbit batch screenshot mode that captures a configurable azimuth-by-elevation grid around a target and returns a labeled contact-sheet image.
  • Add CLI and tool parameters for orbit-based batch screenshots, including orbit angles, elevations, distance, FOV, and output directory selection.

Enhancements:

  • Change surround batch screenshots to return a single labeled contact-sheet composite instead of multiple separate images, and surface the composite path and metadata in CLI output.
  • Support saving positioned single screenshots from inline base64 data to a chosen output directory while preserving existing file-based screenshot flows.
  • Improve the raw CLI command to accept JSON parameters split across multiple arguments for better Windows compatibility.

Build:

  • Bump the MCP for Unity package version to 9.4.8-beta.8 to reflect the new screenshot capabilities.

Documentation:

  • Update skill and CLI documentation to describe screenshot parameters, positioned and batch capture modes, and the new orbit contact-sheet workflow.

Summary by CodeRabbit

  • New Features

    • Added Batch Orbit mode for configurable multi-angle grid captures; surround batch now returns a single labeled contact-sheet.
    • Added in-memory camera render and contact-sheet composition capabilities.
    • Added output_dir and related CLI options for flexible screenshot output.
  • Documentation

    • Updated screenshot save path to Assets/Screenshots/.
    • Expanded CLI guides, examples, and a new Screenshot Parameters reference (includes orbit options and filename flag).

actions-user and others added 3 commits February 27, 2026 18:40
…499094106

chore: update Unity package to beta version 9.4.8-beta.8
- Batch surround/orbit modes now return a single composite contact sheet image
- Added orbit mode with configurable azimuth, elevations, distance, FOV
- Contact sheet tiles are labeled with compass directions (front, back_left, etc.)
- CLI saves contact sheet PNGs to Assets/Screenshots/ by default
- ScreenshotUtility: RenderCameraToTexture, ComposeContactSheet with 5x7 pixel font
- Server manage_scene.py: orbit params forwarding
- CLI raw command: nargs fix for Windows argument splitting
- Updated docs: CLI_USAGE, CLI_EXAMPLE, SKILL.md, tools-reference
Copilot AI review requested due to automatic review settings February 28, 2026 03:03
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 28, 2026

Reviewer's Guide

Adds a configurable multi-view screenshot workflow that captures orbit/surround batches as a labeled contact-sheet image, wires it through the Unity bridge, CLI, and tool metadata, and updates docs and examples accordingly.

Sequence diagram for CLI orbit batch screenshot contact sheet workflow

sequenceDiagram
    actor Dev
    participant CLI as unity_mcp_CLI
    participant Tool as manage_scene_tool
    participant Server as Unity_MCP_server
    participant Editor as ManageScene
    participant Util as ScreenshotUtility

    Dev->>CLI: scene screenshot --batch orbit --look-at Player --orbit-angles 8
    CLI->>Tool: manage_scene(action=screenshot, batch=orbit, orbit_angles, orbit_elevations, ...)
    Tool->>Server: run_command manage_scene params
    Server->>Editor: CaptureScreenshot(SceneCommand cmd)
    Editor->>Editor: CaptureOrbitBatch(cmd)

    loop elevations x azimuth_angles
        Editor->>Util: RenderCameraToTexture(tempCam, maxResolution)
        Util-->>Editor: Texture2D tile
    end

    Editor->>Util: ComposeContactSheet(tiles, tileLabels)
    Util-->>Editor: base64, width, height

    Editor-->>Server: SuccessResponse{imageBase64, imageWidth, imageHeight, shots, screenshotsFolder}
    Server-->>CLI: JSON result

    CLI->>CLI: unwrap result, extract imageBase64, screenshotsFolder
    CLI->>CLI: decode base64 and write PNG to output_dir
    CLI-->>Dev: print_success Contact_sheet_saved_to_path
Loading

Updated class diagram for SceneCommand, ManageScene, and ScreenshotUtility

classDiagram
    class SceneCommand {
        +string camera
        +bool includeImage
        +int maxResolution
        +string batch
        +JToken lookAt
        +Vector3 viewPosition
        +Vector3 viewRotation
        +int orbitAngles
        +float[] orbitElevations
        +float orbitDistance
        +float orbitFov
        +JToken sceneViewTarget
        +bool includeComponents
        +bool includeTransform
    }

    class ManageScene {
        +SceneCommand ToSceneCommand(JObject p)
        +object CaptureScreenshot(SceneCommand cmd)
        +object CaptureSurroundBatch(SceneCommand cmd)
        +object CaptureOrbitBatch(SceneCommand cmd)
        +float[] ParseFloatArray(JToken token)
        +string GetDirectionLabel(float azimuthDeg)
    }

    class ScreenshotUtility {
        +string RenderCameraToBase64(Camera camera,int maxResolution)
        +Texture2D RenderCameraToTexture(Camera camera,int maxResolution)
        +(string base64,int width,int height) ComposeContactSheet(List_Texture2D_tiles,List_string_labels,int padding)
        +Texture2D DownscaleTexture(Texture2D source,int maxEdge)
        +void DrawText(Texture2D tex,string text,int startX,int startY,int charHeight,Color color)
        +ulong GetGlyph(char c)
        +void DestroyTexture(Texture2D tex)
    }

    ManageScene --> SceneCommand : uses
    ManageScene --> ScreenshotUtility : calls
    ScreenshotUtility --> Texture2D : produces
    ScreenshotUtility --> Camera : renders_from
Loading

File-Level Changes

Change Details Files
Extend SceneCommand and manage_scene tool to support configurable orbit batch parameters for screenshots.
  • Add orbit-related fields (angles, elevations, distance, FOV) to the SceneCommand payload and parsing, including a helper to parse float arrays from JSON.
  • Update manage_scene tool signature and parameter coercion to accept orbit_* options for screenshot actions and validate/normalize them.
  • Document orbit batch semantics in the tool description string so AI clients understand how to use the new parameters.
MCPForUnity/Editor/Tools/ManageScene.cs
Server/src/services/tools/manage_scene.py
Change surround batch to output a contact-sheet composite image instead of separate images, and add a new orbit batch implementation that generates a labeled azimuth×elevation grid contact sheet.
  • Refactor surround capture to render each angle to a Texture2D tile, collect simple shot metadata, and compose a single contact-sheet PNG with ScreenshotUtility.ComposeContactSheet.
  • Introduce CaptureOrbitBatch which computes camera positions from orbit parameters (center/radius, azimuth steps, elevation rings), uses direction labels (via GetDirectionLabel), and returns a composite contact sheet plus metadata.
  • Ensure batch mode selection supports both 'surround' and new 'orbit' values and returns descriptive error messages for unknown modes.
MCPForUnity/Editor/Tools/ManageScene.cs
Add reusable rendering and contact-sheet composition helpers including text labeling on tiles.
  • Add RenderCameraToTexture helper that renders a Camera to a Texture2D with optional downscaling and proper RenderTexture state restoration.
  • Add ComposeContactSheet to arrange tiles in a padded grid, draw label banners and simple bitmap text per tile, encode to PNG base64, and clean up textures.
  • Implement a minimal bitmap font (GetGlyph/DrawText) to render labels directly into the composite texture without external font dependencies.
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
Enhance CLI screenshot command to drive orbit/surround batches, save composite images to disk, and support new parameters/output control.
  • Extend CLI options with orbit_* and output-dir flags and marshal them into the manage_scene command payload (including JSON parsing for orbit-elevations).
  • Normalize the Unity response schema, detect batch runs, decode the composite base64 image, and save a single contact-sheet PNG to the chosen directory with informative status output.
  • Improve single positioned screenshot behavior by saving inline base64 images to disk when Unity does not save a file directly, and keep existing simple-path behavior when it does.
Server/src/cli/commands/scene.py
Improve raw CLI command argument handling to be robust to Windows argument splitting.
  • Change raw command params to accept a varargs tuple, re-join them into a single JSON string, and parse that instead of a single positional argument.
  • Update error handling to emit clearer JSON parse failures when the joined params are invalid.
Server/src/cli/main.py
Update docs and skill references to describe multi-view screenshot capabilities, parameters, and CLI usage.
  • Expand SKILL.md and CLI docs with detailed screenshot parameter tables, examples for single, surround, and orbit captures, and clarify that batch modes return a single contact-sheet image.
  • Add CLI examples for the new orbit mode and output-dir usage, and update naming (filename vs name) and default screenshot folder (Assets/Screenshots/).
  • Update tools-reference docs to describe surround/orbit as contact-sheet producers, add orbit examples, and adjust screenshot path descriptions.
unity-mcp-skill/SKILL.md
docs/guides/CLI_USAGE.md
docs/guides/CLI_EXAMPLE.md
.claude/skills/unity-mcp-skill/references/tools-reference.md
unity-mcp-skill/references/tools-reference.md
Bump Unity MCP package version to reflect the new feature.
  • Increment package.json version from 9.4.8-beta.7 to 9.4.8-beta.8.
MCPForUnity/package.json

Possibly linked issues

  • #Take screenshots during play mode: PR significantly extends screenshot tooling for LLM visual inspection, fulfilling the requested screenshot capability for debugging.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

📝 Walkthrough

Walkthrough

Adds orbit-based batch screenshot capture and contact-sheet composition across editor, runtime, CLI, and docs; introduces in-memory camera rendering and composition helpers, CLI/Service parameter plumbing for orbit options, and updates documentation and package versioning.

Changes

Cohort / File(s) Summary
Documentation
docs/guides/CLI_EXAMPLE.md, docs/guides/CLI_USAGE.md, unity-mcp-skill/SKILL.md, unity-mcp-skill/references/tools-reference.md, .claude/skills/unity-mcp-skill/references/tools-reference.md
Added orbit batch examples and Screenshot Parameters docs; changed default screenshot save path to Assets/Screenshots/; clarified batch surround as a 6-tile contact sheet and added orbit contact-sheet docs.
Editor: Scene Capture
MCPForUnity/Editor/Tools/ManageScene.cs
Added orbit batch support (orbitAngles, orbitElevations, orbitDistance, orbitFov), parsing helpers, GetDirectionLabel, CaptureOrbitBatch flow, and changed batch outputs to return a single composite contact-sheet with per-tile metadata.
Runtime: Screenshot Utilities
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
New APIs: RenderCameraToTexture(Camera, maxResolution) and ComposeContactSheet(tiles, labels, padding). Added bitmap-font text rendering helpers (GetGlyph, DrawText) and in-memory texture composition returning base64 PNG and dimensions.
Server CLI & Service
Server/src/cli/commands/scene.py, Server/src/cli/main.py, Server/src/services/tools/manage_scene.py
Wired orbit CLI flags (orbit_angles, orbit_elevations, orbit_distance, orbit_fov, output_dir), improved batch response handling and saving of composite base64 images, changed raw_command to accept nargs for params, and mapped/validated new orbit params in manage_scene.
Package Metadata
MCPForUnity/package.json
Bumped package version from 9.4.8-beta.7 to 9.4.8-beta.8.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server
    participant Editor as UnityEditor
    participant Util as ScreenshotUtility

    Client->>Server: screenshot(batch="orbit", orbit_angles, orbit_elevations, ...)
    Server->>Editor: manage_scene(action="screenshot", batch="orbit", orbitAngles, orbitElevations, ...)
    Editor->>Editor: resolve target (look_at or bounds) and compute orbit grid
    loop for each elevation × azimuth
        Editor->>Util: RenderCameraToTexture(tempCamera, maxResolution)
        Util-->>Editor: Texture2D tile
        Editor->>Editor: generate tile label (GetDirectionLabel)
    end
    Editor->>Util: ComposeContactSheet(tiles[], labels[], padding)
    Util-->>Editor: base64 composite image + width/height
    Editor-->>Server: return composite image + metadata (center, radius, tiles)
    Server->>Server: save composite image to output_dir (timestamped)
    Server-->>Client: return saved path + metadata
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #818: Shares changes to screenshot capture and ScreenshotUtility helpers (surround/contact-sheet work); closely related codepaths and feature set.
  • PR #600: Overlaps in ManageScene and rendering helper refactors impacting capture flow and texture rendering.

Poem

🐰 I hopped round the scene with a camera in tow,
angles and elevations in tidy tableau,
tiles stitched together with labels so sweet,
a contact-sheet feast—orbital views to greet! 📸✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature/multi-view screenshot' clearly and concisely describes the main feature added by the PR—a multi-view screenshot capability.
Description check ✅ Passed The description covers all required template sections with sufficient detail: describes the feature, selects appropriate change types, lists specific changes, includes testing screenshots, confirms documentation updates, and provides comprehensive summary notes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • In ComposeContactSheet, you call tiles[idx].GetPixels32() but then ignore the result and repeatedly call GetPixel in the inner loops; switching to use the GetPixels32() buffer (or SetPixels32 by row) would significantly reduce per-pixel method call overhead for larger grids.
  • The screenshot CLI response handling now unwraps result/inner in several ways (status, success, nested data); it might be worth centralizing this into a small helper to avoid subtle discrepancies if the backend response shape evolves again.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ComposeContactSheet`, you call `tiles[idx].GetPixels32()` but then ignore the result and repeatedly call `GetPixel` in the inner loops; switching to use the `GetPixels32()` buffer (or `SetPixels32` by row) would significantly reduce per-pixel method call overhead for larger grids.
- The screenshot CLI response handling now unwraps `result`/`inner` in several ways (`status`, `success`, nested `data`); it might be worth centralizing this into a small helper to avoid subtle discrepancies if the backend response shape evolves again.

## Individual Comments

### Comment 1
<location path="Server/src/cli/commands/scene.py" line_range="348" />
<code_context>
-        count = len(data.get("screenshots", []))
-        print_success(f"Captured {count} batch screenshots")
+    # Unwrap the response: {"status":"success","result":{"success":true,"data":{...}}}
+    inner = result.get("result", result)  # fallback to result if no nesting
+    is_success = (result.get("status") == "success"
+                  or inner.get("success", False)
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard `inner.get(...)` with a type check to avoid attribute errors when `inner` is not a dict.

Because `inner` comes from `result.get("result", result)`, it may be non-dict values (e.g. string, list) depending on `run_command`’s error shape. In those cases `inner.get("success", False)` will raise `AttributeError` and hide the real error. A safer pattern is:

```python
inner = result.get("result", result)
if isinstance(inner, dict):
    is_success = (
        result.get("status") == "success"
        or inner.get("success", False)
        or result.get("success", False)
    )
    data = inner.get("data", inner)
else:
    is_success = result.get("status") == "success" or result.get("success", False)
    data = {}
```

This preserves current behavior for valid responses while avoiding secondary failures for unexpected shapes.
</issue_to_address>

### Comment 2
<location path="MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs" line_range="352" />
<code_context>
+                for (int i = 0; i < bgPixels.Length; i++) bgPixels[i] = bgColor;
+                sheet.SetPixels32(bgPixels);
+
+                for (int idx = 0; idx < count; idx++)
+                {
+                    int col = idx % cols;
</code_context>
<issue_to_address>
**suggestion (performance):** Avoid per-pixel `GetPixel` calls and use the already-fetched pixel buffer for better performance.

In `ComposeContactSheet`, you populate `tilePixels = tiles[idx].GetPixels32()` but then ignore it and call `GetPixel` inside the inner loops, which is much slower at scale.

Instead, index directly into `tilePixels` when composing the sheet, e.g.:

```csharp
Color32[] tilePixels = tiles[idx].GetPixels32();
for (int ty = 0; ty < tileH; ty++)
{
    int rowOffset = ty * tileW;
    for (int tx = 0; tx < tileW; tx++)
    {
        sheet.SetPixel(x + tx,
                       y + labelHeight + ty,
                       tilePixels[rowOffset + tx]);
    }
}
```

For more gain, you could build a row buffer and use `SetPixels32` per row to reduce call overhead on large grids.

Suggested implementation:

```csharp
                    // Draw tile pixels using pre-fetched pixel buffer for better performance
                    Color32[] tilePixels = tiles[idx].GetPixels32();
                    for (int ty = 0; ty < tileH; ty++)
                    {
                        int rowOffset = ty * tileW;
                        for (int tx = 0; tx < tileW; tx++)
                        {
                            sheet.SetPixel(
                                x + tx,
                                y + labelHeight + ty,
                                tilePixels[rowOffset + tx]
                            );
                        }
                    }

```

For even better performance on large sheets, you can further optimize by:
1. Allocating a `Color32[] rowBuffer = new Color32[tileW];`
2. Inside the `ty` loop, copy the corresponding slice from `tilePixels` into `rowBuffer` and call `sheet.SetPixels32(x, y + labelHeight + ty, tileW, 1, rowBuffer);`
This would reduce the overhead of many `SetPixel` calls but is not required to satisfy the current suggestion.
</issue_to_address>

### Comment 3
<location path="unity-mcp-skill/SKILL.md" line_range="85" />
<code_context>
+| `batch` | string | `"surround"` (6 fixed angles) or `"orbit"` (configurable grid) |
+| `look_at` | string | Target: GameObject name/path/ID, or `"x,y,z"` world position |
+| `view_position` | list | Camera position `[x,y,z]` for positioned screenshot |
+| `view_rotation` | list | Camera euler rotation `[x,y,z]` for positioned screenshot |
+| `orbit_angles` | int | Number of azimuth samples around the target (default 8) |
+| `orbit_elevations` | list | Vertical angles in degrees, e.g. `[0, 30, -15]` (default `[0]`) |
</code_context>
<issue_to_address>
**suggestion (typo):** Capitalize “Euler” when referring to Euler angles in the description.

Since “Euler” is a proper noun here, please capitalize it in the description, e.g., “Camera Euler rotation `[x,y,z]` for positioned screenshot.”

```suggestion
| `view_rotation` | list | Camera Euler rotation `[x,y,z] for positioned screenshot |
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

count = len(data.get("screenshots", []))
print_success(f"Captured {count} batch screenshots")
# Unwrap the response: {"status":"success","result":{"success":true,"data":{...}}}
inner = result.get("result", result) # fallback to result if no nesting
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Guard inner.get(...) with a type check to avoid attribute errors when inner is not a dict.

Because inner comes from result.get("result", result), it may be non-dict values (e.g. string, list) depending on run_command’s error shape. In those cases inner.get("success", False) will raise AttributeError and hide the real error. A safer pattern is:

inner = result.get("result", result)
if isinstance(inner, dict):
    is_success = (
        result.get("status") == "success"
        or inner.get("success", False)
        or result.get("success", False)
    )
    data = inner.get("data", inner)
else:
    is_success = result.get("status") == "success" or result.get("success", False)
    data = {}

This preserves current behavior for valid responses while avoiding secondary failures for unexpected shapes.

| `batch` | string | `"surround"` (6 fixed angles) or `"orbit"` (configurable grid) |
| `look_at` | string | Target: GameObject name/path/ID, or `"x,y,z"` world position |
| `view_position` | list | Camera position `[x,y,z]` for positioned screenshot |
| `view_rotation` | list | Camera euler rotation `[x,y,z]` for positioned screenshot |
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (typo): Capitalize “Euler” when referring to Euler angles in the description.

Since “Euler” is a proper noun here, please capitalize it in the description, e.g., “Camera Euler rotation [x,y,z] for positioned screenshot.”

Suggested change
| `view_rotation` | list | Camera euler rotation `[x,y,z]` for positioned screenshot |
| `view_rotation` | list | Camera Euler rotation `[x,y,z] for positioned screenshot |

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
docs/guides/CLI_EXAMPLE.md (2)

89-89: Consider clarifying "contact sheet" terminology.

The term "contact sheet" is used to describe the batch output format. While this is a well-known photography term, users unfamiliar with it might benefit from a brief explanation (e.g., "a grid layout of multiple screenshots") or a reference to the PR images that show the feature visually.

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

In `@docs/guides/CLI_EXAMPLE.md` at line 89, Update the CLI docs line for the
`--batch, -b` flag to clarify "contact sheet" by adding a brief parenthetical
definition (e.g., "contact sheet (a grid layout of multiple screenshots)")
and/or a short reference to the PR images that demonstrate the output; adjust
the text around the existing tokens `--batch, -b`, `surround`, `orbit`, and
`contact sheet` so the meaning is immediately clear to readers unfamiliar with
photography jargon.

93-96: Consider noting parameter scope.

The orbit-specific parameters (--orbit-angles, --orbit-elevations, --orbit-distance, --orbit-fov) only apply when using --batch orbit mode. Adding a note like "Used with --batch orbit" in the descriptions would help users understand parameter interactions.

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

In `@docs/guides/CLI_EXAMPLE.md` around lines 93 - 96, The descriptions for the
orbit-specific CLI flags (`--orbit-angles`, `--orbit-elevations`,
`--orbit-distance`, `--orbit-fov`) should explicitly state they only apply when
using `--batch orbit`; update each flag's description in CLI_EXAMPLE.md to
append a short note like "Used with `--batch orbit`" so users understand the
parameter scope and avoid confusion when using other batch modes.
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs (1)

360-368: Consider using SetPixels32 for better performance.

The nested SetPixel loops for copying tile pixels are O(width × height) per tile with per-pixel method call overhead. For large contact sheets with many tiles, this could be slow.

♻️ Potential optimization using block copy
-                    // Draw tile pixels
-                    Color32[] tilePixels = tiles[idx].GetPixels32();
-                    for (int ty = 0; ty < tileH; ty++)
-                    {
-                        for (int tx = 0; tx < tileW; tx++)
-                        {
-                            sheet.SetPixel(x + tx, y + labelHeight + ty, tiles[idx].GetPixel(tx, ty));
-                        }
-                    }
+                    // Draw tile pixels using block copy for each row
+                    Color32[] tilePixels = tiles[idx].GetPixels32();
+                    for (int ty = 0; ty < tileH; ty++)
+                    {
+                        int srcStart = ty * tileW;
+                        int dstStart = (y + labelHeight + ty) * sheetW + x;
+                        for (int tx = 0; tx < tileW; tx++)
+                        {
+                            bgPixels[dstStart + tx] = tilePixels[srcStart + tx];
+                        }
+                    }

This would require restructuring to use bgPixels throughout and call SetPixels32 once at the end.

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

In `@MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs` around lines 360 - 368, The
current nested per-pixel SetPixel loop in ScreenshotUtility (using
sheet.SetPixel and tiles[idx].GetPixel) is slow; replace it by using the
existing tiles[idx].GetPixels32() (tilePixels) and copy those Color32 blocks
into the sheet's bgPixels buffer at the computed (x, y + labelHeight) offset
(using Array.Copy or Buffer.BlockCopy with the per-row stride) and then call
sheet.SetPixels32(bgPixels) once (or use
Texture2D.SetPixels32(x,y,width,height,tilePixels) if you prefer per-tile block
calls) to update the texture; update references to tilePixels, tileW, tileH,
sheet, bgPixels, and labelHeight and remove the per-pixel SetPixel loops.
Server/src/services/tools/manage_scene.py (1)

210-219: Consider adding range validation for orbit_distance and orbit_fov.

The current implementation validates that these are numeric but doesn't check for invalid ranges. For example:

  • Negative orbit_distance is likely invalid
  • orbit_fov outside typical bounds (e.g., 1-179 degrees) could cause rendering issues

If Unity already handles these edge cases gracefully, this is fine as-is. Otherwise, consider adding bounds checks similar to the max_resolution validation at lines 169-170.

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

In `@Server/src/services/tools/manage_scene.py` around lines 210 - 219, Add
explicit range validation for orbit_distance and orbit_fov after converting them
to floats in the block handling orbit parameters: ensure orbit_distance is >= 0
(or a sensible positive minimum) and ensure orbit_fov is within a safe degree
range (e.g., 1 <= orbit_fov <= 179). Update the same branches that currently set
params["orbitDistance"] and params["orbitFov"] (and their error returns) to
return {"success": False, "message": "..."} with clear messages when values are
out of range, mirroring the style used for max_resolution validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@MCPForUnity/Editor/Tools/ManageScene.cs`:
- Around line 58-72: ParseFloatArray currently calls arr[i].ToObject<float>()
which can throw for malformed elements; wrap the per-element conversion in a
try-catch inside the for loop in ParseFloatArray and on failure throw a
descriptive exception (e.g., JsonException) that includes the array index and
the offending token value and preserves the original exception as inner; keep
the single-value path using ParamCoercion.CoerceFloatNullable unchanged.

In `@Server/src/services/tools/manage_scene.py`:
- Around line 202-209: Remove the redundant json re-import and instead use the
existing json module to parse orbit_elevations when it's a str, and after
parsing validate that orbit_elevations is a list containing only numeric types
(int or float); if parsing fails or the value is not a list of numbers return
the same error object, otherwise set params["orbitElevations"] =
orbit_elevations. Ensure you reference the orbit_elevations variable and
params["orbitElevations"] in your changes and perform the type check after
json.loads succeeds.

---

Nitpick comments:
In `@docs/guides/CLI_EXAMPLE.md`:
- Line 89: Update the CLI docs line for the `--batch, -b` flag to clarify
"contact sheet" by adding a brief parenthetical definition (e.g., "contact sheet
(a grid layout of multiple screenshots)") and/or a short reference to the PR
images that demonstrate the output; adjust the text around the existing tokens
`--batch, -b`, `surround`, `orbit`, and `contact sheet` so the meaning is
immediately clear to readers unfamiliar with photography jargon.
- Around line 93-96: The descriptions for the orbit-specific CLI flags
(`--orbit-angles`, `--orbit-elevations`, `--orbit-distance`, `--orbit-fov`)
should explicitly state they only apply when using `--batch orbit`; update each
flag's description in CLI_EXAMPLE.md to append a short note like "Used with
`--batch orbit`" so users understand the parameter scope and avoid confusion
when using other batch modes.

In `@MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs`:
- Around line 360-368: The current nested per-pixel SetPixel loop in
ScreenshotUtility (using sheet.SetPixel and tiles[idx].GetPixel) is slow;
replace it by using the existing tiles[idx].GetPixels32() (tilePixels) and copy
those Color32 blocks into the sheet's bgPixels buffer at the computed (x, y +
labelHeight) offset (using Array.Copy or Buffer.BlockCopy with the per-row
stride) and then call sheet.SetPixels32(bgPixels) once (or use
Texture2D.SetPixels32(x,y,width,height,tilePixels) if you prefer per-tile block
calls) to update the texture; update references to tilePixels, tileW, tileH,
sheet, bgPixels, and labelHeight and remove the per-pixel SetPixel loops.

In `@Server/src/services/tools/manage_scene.py`:
- Around line 210-219: Add explicit range validation for orbit_distance and
orbit_fov after converting them to floats in the block handling orbit
parameters: ensure orbit_distance is >= 0 (or a sensible positive minimum) and
ensure orbit_fov is within a safe degree range (e.g., 1 <= orbit_fov <= 179).
Update the same branches that currently set params["orbitDistance"] and
params["orbitFov"] (and their error returns) to return {"success": False,
"message": "..."} with clear messages when values are out of range, mirroring
the style used for max_resolution validation.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08b8eac and 706176e.

📒 Files selected for processing (11)
  • .claude/skills/unity-mcp-skill/references/tools-reference.md
  • MCPForUnity/Editor/Tools/ManageScene.cs
  • MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
  • MCPForUnity/package.json
  • Server/src/cli/commands/scene.py
  • Server/src/cli/main.py
  • Server/src/services/tools/manage_scene.py
  • docs/guides/CLI_EXAMPLE.md
  • docs/guides/CLI_USAGE.md
  • unity-mcp-skill/SKILL.md
  • unity-mcp-skill/references/tools-reference.md

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a multi-view (contact sheet) screenshot capability to manage_scene, exposing both fixed-angle surround and configurable orbit batch modes across Unity, server tool wrapper, CLI, and docs.

Changes:

  • Implement contact-sheet composition for batch="surround" and new batch="orbit" screenshot mode (Unity).
  • Extend server tool + CLI to pass orbit parameters and save returned composite images to disk.
  • Update skill/docs/tool references and CLI guides to document new screenshot behavior and options.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
MCPForUnity/Editor/Tools/ManageScene.cs Adds orbit batch mode and changes batch outputs to a single composite contact sheet + metadata.
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs Adds camera-to-texture rendering and contact-sheet compositor utilities.
Server/src/services/tools/manage_scene.py Exposes orbit params (angles/elevations/distance/fov) to Unity via tool wrapper.
Server/src/cli/commands/scene.py Adds CLI flags for orbit + output dir; saves composite base64 images to disk for batch/positioned captures.
Server/src/cli/main.py Improves raw command JSON arg handling by joining split args (Windows-friendly).
docs/guides/CLI_USAGE.md Documents new screenshot usage, including batch contact sheets and orbit parameters.
docs/guides/CLI_EXAMPLE.md Updates example commands for new screenshot flags and batch modes.
unity-mcp-skill/SKILL.md Documents screenshot parameters and introduces batch contact-sheet guidance.
unity-mcp-skill/references/tools-reference.md Updates tool reference for contact-sheet batch behavior and adds orbit batch example.
.claude/skills/unity-mcp-skill/references/tools-reference.md Mirrors tool reference updates for Claude skill bundle.
MCPForUnity/package.json Bumps package version to 9.4.8-beta.8.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +292 to +296

RenderTexture.active = rt;
var tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
tex.Apply();
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

RenderCameraToTexture allocates a Texture2D inside the try block but never destroys it if ReadPixels/Apply (or DownscaleTexture) throws. This can leak textures in editor sessions. Consider mirroring RenderCameraToBase64’s pattern: keep references outside the try and DestroyTexture(...) in a finally when the method exits via exception.

Copilot uses AI. Check for mistakes.
Comment on lines +360 to +364
// Draw tile pixels
Color32[] tilePixels = tiles[idx].GetPixels32();
for (int ty = 0; ty < tileH; ty++)
{
for (int tx = 0; tx < tileW; tx++)
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

ComposeContactSheet is doing per-pixel GetPixel/SetPixel work inside nested loops; this will be extremely slow for orbit grids (potentially 100+ tiles) and can freeze the editor. Also tilePixels is currently computed but unused. Prefer bulk operations (e.g., SetPixels32 into a preallocated sheet buffer, Graphics.CopyTexture, or blitting via a RenderTexture) and remove/replace the unused tilePixels allocation.

Copilot uses AI. Check for mistakes.
| `view_position` | list | Camera position `[x,y,z]` for positioned screenshot |
| `view_rotation` | list | Camera euler rotation `[x,y,z]` for positioned screenshot |
| `orbit_angles` | int | Number of azimuth samples around the target (default 8) |
| `orbit_elevations` | list | Vertical angles in degrees, e.g. `[0, 30, -15]` (default `[0]`) |
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The docs claim orbit_elevations defaults to [0], but the Unity implementation defaults to [0, 30, -15] when not provided. Please update the documented default to match actual behavior (or adjust the code default if [0] is intended).

Suggested change
| `orbit_elevations` | list | Vertical angles in degrees, e.g. `[0, 30, -15]` (default `[0]`) |
| `orbit_elevations` | list | Vertical angles in degrees, e.g. `[0, 30, -15]` (default `[0, 30, -15]`) |

Copilot uses AI. Check for mistakes.
batch="orbit", # str - "orbit" for configurable angle grid
look_at="Player", # str|int|list[float] - target to orbit around
orbit_angles=8, # int, default 8 - number of azimuth steps
orbit_elevations=[0, 30], # list[float], default [0] - vertical angles in degrees
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The tools reference says orbit_elevations has default [0], but ManageScene.CaptureOrbitBatch uses [0, 30, -15] when orbitElevations is omitted. Update this default to avoid confusing callers.

Suggested change
orbit_elevations=[0, 30], # list[float], default [0] - vertical angles in degrees
orbit_elevations=[0, 30], # list[float], default [0, 30, -15] - vertical angles in degrees

Copilot uses AI. Check for mistakes.
/// <summary>
/// Captures screenshots from a configurable orbit around a target for visual QA.
/// Supports custom azimuth count, elevation angles, distance, and FOV.
/// Returns all images as inline base64 PNGs (no files saved to disk).
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The XML doc for CaptureOrbitBatch says it “Returns all images as inline base64 PNGs”, but the implementation returns a single composite contact-sheet image (imageBase64) plus shot metadata. Update the comment to match the actual response shape so tool consumers aren’t misled.

Suggested change
/// Returns all images as inline base64 PNGs (no files saved to disk).
/// Returns a single composite contact-sheet image as an inline base64 PNG (imageBase64)
/// plus per-shot metadata; no files are saved to disk.

Copilot uses AI. Check for mistakes.
Comment on lines +331 to +332
if orbit_angles:
params["orbitAngles"] = orbit_angles
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

These truthiness checks will ignore explicit values like 0 (e.g., --orbit-angles 0) and silently fall back to defaults, which is confusing. Use is not None and validate ranges (e.g., orbit_angles >= 1) so invalid values produce a clear error instead of being dropped.

Copilot uses AI. Check for mistakes.
Comment on lines +340 to +342
if orbit_distance:
params["orbitDistance"] = orbit_distance
if orbit_fov:
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

orbit_distance/orbit_fov are parsed as floats by click, but these if orbit_distance: / if orbit_fov: checks will drop legitimate falsy values (0.0) instead of validating and erroring. Prefer is not None and reject non-positive distances / out-of-range FOV early so CLI behavior matches the help text.

Suggested change
if orbit_distance:
params["orbitDistance"] = orbit_distance
if orbit_fov:
if orbit_distance is not None:
if orbit_distance <= 0:
print_error(f"Invalid orbit-distance {orbit_distance}: must be positive.")
sys.exit(1)
params["orbitDistance"] = orbit_distance
if orbit_fov is not None:
# Require a sensible vertical field-of-view in degrees.
if orbit_fov <= 0 or orbit_fov >= 180:
print_error(
f"Invalid orbit-fov {orbit_fov}: must be between 0 and 180 degrees (exclusive)."
)
sys.exit(1)

Copilot uses AI. Check for mistakes.
batch="orbit", # str - "orbit" for configurable angle grid
look_at="Player", # str|int|list[float] - target to orbit around
orbit_angles=8, # int, default 8 - number of azimuth steps
orbit_elevations=[0, 30], # list[float], default [0] - vertical angles in degrees
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

The tools reference says orbit_elevations has default [0], but ManageScene.CaptureOrbitBatch uses [0, 30, -15] when orbitElevations is omitted. Update this default to avoid confusing callers.

Suggested change
orbit_elevations=[0, 30], # list[float], default [0] - vertical angles in degrees
orbit_elevations=[0, 30], # list[float], default [0, 30, -15] - vertical angles in degrees

Copilot uses AI. Check for mistakes.
"Elevation angles in degrees for batch='orbit' (default [0, 30, -15]). "
"E.g., [0, 30, 60] for ground-level, mid, and high views."] | None = None,
orbit_distance: Annotated[float | str,
"Camera distance from target for batch='orbit' (default auto from bounds)."] | None = None,
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

manage_scene’s orbit_distance docstring says the default is “auto from bounds”, but on the Unity side if look_at is provided as a raw position (not a GameObject with renderers), the radius defaults to 5 when orbit_distance is omitted. Consider clarifying the docstring to describe this behavior (auto-fit when bounds are available, otherwise a fixed fallback).

Suggested change
"Camera distance from target for batch='orbit' (default auto from bounds)."] | None = None,
"Camera distance from target for batch='orbit'. Default auto-fits from renderer bounds when available; "
"if only a raw position is provided (no bounds), a fixed fallback distance (5 units) is used."] | None = None,

Copilot uses AI. Check for mistakes.
Comment on lines +198 to +202
# orbit batch params
coerced_orbit_angles = coerce_int(orbit_angles, default=None)
if coerced_orbit_angles is not None:
params["orbitAngles"] = coerced_orbit_angles
if orbit_elevations is not None:
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

Orbit parameters were added here, but there are existing integration/unit tests for manage_scene screenshot param forwarding in Server/tests/integration/test_manage_scene_screenshot_params.py. Adding similar tests for orbit_angles/orbit_elevations/orbit_distance/orbit_fov (including the JSON-string parsing path) would help prevent regressions.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
unity-mcp-skill/references/tools-reference.md (1)

139-150: Minor clarification: example uses custom elevations, not the default.

Line 145 shows orbit_elevations=[0, 30] which is a valid custom value, while the inline comment notes the default is [0, 30, -15]. This is correct as written (demonstrating customization), but consider either using the default value in the example or adding a brief note that this overrides the default.

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

In `@unity-mcp-skill/references/tools-reference.md` around lines 139 - 150, The
example for manage_scene shows orbit_elevations=[0, 30] but the inline comment
mentions the default [0, 30, -15]; update the snippet to make intent clear by
either reverting orbit_elevations to the default (orbit_elevations=[0, 30, -15])
or keep the custom [0, 30] and add a short clarifying comment after
orbit_elevations such as "overrides default [0, 30, -15]" so readers know this
example demonstrates customization; refer to manage_scene and the
orbit_elevations parameter when making the change.
MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs (1)

331-332: Assumes all tiles have uniform dimensions.

The method reads tileW and tileH from tiles[0] only. If callers pass tiles with varying dimensions, the contact sheet will be corrupted. This is likely fine since RenderCameraToTexture produces consistent sizes, but consider adding a validation or documenting this precondition.

📝 Optional: Add precondition check
 int tileW = tiles[0].width;
 int tileH = tiles[0].height;
 int count = tiles.Count;
+
+#if UNITY_ASSERTIONS
+for (int i = 1; i < count; i++)
+{
+    UnityEngine.Assertions.Assert.AreEqual(tileW, tiles[i].width, $"Tile {i} width mismatch");
+    UnityEngine.Assertions.Assert.AreEqual(tileH, tiles[i].height, $"Tile {i} height mismatch");
+}
+#endif
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs` around lines 331 - 332, The
code assumes uniform tile dimensions by reading tileW/tileH from tiles[0]; add a
validation in the same method (the contact-sheet builder that uses tiles[] and
tileW/tileH) to verify every Texture2D in tiles has the same width and height as
tiles[0] (or explicitly document the precondition that callers of
RenderCameraToTexture must produce uniform sizes); if a mismatch is found,
either throw an ArgumentException (or log an error and abort/return) with a
clear message referencing tiles and expected vs actual dimensions so corrupted
contact sheets are avoided.
MCPForUnity/Editor/Tools/ManageScene.cs (1)

105-109: Consider adopting ToolParams for parameter validation in future refactors.

As per coding guidelines, ToolParams with methods like GetInt(), RequireString() is preferred for C# Editor tools. The current code uses ParamCoercion which is consistent with the existing pattern in this file. This is noted as a future improvement opportunity rather than a blocking issue for this PR.

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

In `@MCPForUnity/Editor/Tools/ManageScene.cs` around lines 105 - 109, The current
parameter coercion in ManageScene.cs uses ParamCoercion and ParseFloatArray for
orbitAngles, orbitElevations, orbitDistance and orbitFov; refactor these usages
to use the Editor tooling's ToolParams API in a future change by replacing
ParamCoercion.CoerceIntNullable/CoerceFloatNullable and ParseFloatArray calls
with the appropriate ToolParams methods (e.g., GetInt(), GetFloat(),
RequireString(), or nullable variants) so validation and error messages are
consistent; target the code that constructs orbitAngles, orbitElevations,
orbitDistance and orbitFov and switch to reading from a ToolParams instance
instead of directly using ParamCoercion/ParseFloatArray.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@MCPForUnity/Editor/Tools/ManageScene.cs`:
- Around line 105-109: The current parameter coercion in ManageScene.cs uses
ParamCoercion and ParseFloatArray for orbitAngles, orbitElevations,
orbitDistance and orbitFov; refactor these usages to use the Editor tooling's
ToolParams API in a future change by replacing
ParamCoercion.CoerceIntNullable/CoerceFloatNullable and ParseFloatArray calls
with the appropriate ToolParams methods (e.g., GetInt(), GetFloat(),
RequireString(), or nullable variants) so validation and error messages are
consistent; target the code that constructs orbitAngles, orbitElevations,
orbitDistance and orbitFov and switch to reading from a ToolParams instance
instead of directly using ParamCoercion/ParseFloatArray.

In `@MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs`:
- Around line 331-332: The code assumes uniform tile dimensions by reading
tileW/tileH from tiles[0]; add a validation in the same method (the
contact-sheet builder that uses tiles[] and tileW/tileH) to verify every
Texture2D in tiles has the same width and height as tiles[0] (or explicitly
document the precondition that callers of RenderCameraToTexture must produce
uniform sizes); if a mismatch is found, either throw an ArgumentException (or
log an error and abort/return) with a clear message referencing tiles and
expected vs actual dimensions so corrupted contact sheets are avoided.

In `@unity-mcp-skill/references/tools-reference.md`:
- Around line 139-150: The example for manage_scene shows orbit_elevations=[0,
30] but the inline comment mentions the default [0, 30, -15]; update the snippet
to make intent clear by either reverting orbit_elevations to the default
(orbit_elevations=[0, 30, -15]) or keep the custom [0, 30] and add a short
clarifying comment after orbit_elevations such as "overrides default [0, 30,
-15]" so readers know this example demonstrates customization; refer to
manage_scene and the orbit_elevations parameter when making the change.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 706176e and 66e788a.

📒 Files selected for processing (7)
  • .claude/skills/unity-mcp-skill/references/tools-reference.md
  • MCPForUnity/Editor/Tools/ManageScene.cs
  • MCPForUnity/Runtime/Helpers/ScreenshotUtility.cs
  • Server/src/services/tools/manage_scene.py
  • docs/guides/CLI_USAGE.md
  • unity-mcp-skill/SKILL.md
  • unity-mcp-skill/references/tools-reference.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • .claude/skills/unity-mcp-skill/references/tools-reference.md
  • unity-mcp-skill/SKILL.md
  • docs/guides/CLI_USAGE.md

@Scriptwonder Scriptwonder merged commit 5733dbc into CoplayDev:beta Feb 28, 2026
2 checks passed
@Scriptwonder Scriptwonder deleted the feature/contact-sheet-screenshots branch February 28, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants