--- name: unity-scene description: Manage Unity scenes --- > **Before calling any skill in this module:** if you are about to call a skill with parameters guessed from its name or description, STOP — read this file (or fetch its schema via `GET /skills/recommend?includeSchema=true`) first. If you already have the parameter definitions from recommend/schema, you may proceed straight to dryRun. ## Triggers - Opening or saving scenes - Loading additively - Switching active scene - Querying scene contents - 打开或保存场景、叠加加载、切换活动场景、查询场景内容 # Unity Scene Skills Control Unity scenes - the containers that hold all your GameObjects. ## Operating Mode - **Approval**:本模块 Mixed —— `scene_get_info` / `scene_get_hierarchy` / `scene_get_loaded` / `scene_find_objects` 标 `SkillMode.SemiAuto`,可直接执行;`scene_screenshot` / `scene_unload` / `scene_set_active` 未设 Mode 字段(默认 FullAuto),Approval 模式下需 grant。 - **Auto / Bypass**:FullAuto 直接执行。 - **含 NeverInSemi 高危 skill**:`scene_create` / `scene_load` / `scene_save`(标 `RiskLevel="high"`,因为切换/覆盖整个场景文件影响范围极大)。这些在 Approval/Auto 下返 `MODE_FORBIDDEN`,仅 Bypass 或 Allowlist 命中可调。 **DO NOT** (common hallucinations): - `scene_delete` / `scene_rename` do not exist → delete scene files via `asset_delete`, rename via `asset_move` - `scene_list` does not exist → use `scene_get_loaded` (loaded scenes) or `asset_find` with `t:Scene` (all scene assets) - `scene_find_objects` is a simple name/tag/component filter; for regex/layer/path search use `gameobject_find` (SkillMode.SemiAuto, 只读,任何模式可直接调用) **Routing**: - For detailed hierarchy tree → use `perception` module's `hierarchy_describe` - For scene statistics → use `perception` module's `scene_summarize` - For screenshot → `scene_screenshot` (this module) captures the **Game View** final composited image (all cameras + UI; in Play mode this is the live runtime frame); `camera_screenshot` (camera module, SkillMode.FullAuto) renders a single Game Camera off-screen ## Skills Overview | Skill | Description | |-------|-------------| | `scene_create` | Create a new scene | | `scene_load` | Load a scene | | `scene_save` | Save current scene | | `scene_get_info` | Get scene information | | `scene_get_hierarchy` | Get hierarchy tree | | `scene_screenshot` | Capture screenshot | | `scene_get_loaded` | Get all loaded scenes | | `scene_unload` | Unload an additive scene | | `scene_set_active` | Set active scene | | `scene_find_objects` | Search objects by name/tag/component | --- ## Skills ### scene_create Create a new scene. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `scenePath` | string | Yes | Path for new scene (e.g., "Assets/Scenes/MyScene.unity") | ### scene_load Load a scene. | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `scenePath` | string | Yes | - | Scene asset path | | `additive` | bool | No | false | Load additively (keep current scene) | ### scene_save Save the current scene. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `scenePath` | string | No | Save path (null = save current) | ### scene_get_info Get current scene information. No parameters. **Returns**: `{sceneName, scenePath, isDirty, rootObjectCount, rootObjects: [{name, entityId, instanceId, childCount}]}` — root entries carry `childCount`, so you can tell which roots are worth descending into before paying for a hierarchy call. ### scene_get_hierarchy Get the scene hierarchy tree, depth-limited. | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `maxDepth` | int | No | 3 | Maximum hierarchy depth to expand | **Returns**: `{sceneName, hierarchy: [node, ...]}` where each node is `{name, scene, entityId, instanceId, components: [type, ...], childCount, children}`. `scene` is the node's owning scene name. > **DontDestroyOnLoad**: in Play mode, roots of the `DontDestroyOnLoad` pseudo-scene are appended after the active-scene nodes, marked with `scene: "DontDestroyOnLoad"`. `scene_get_loaded` also lists it as `{name: "DontDestroyOnLoad", isPseudoScene: true}` when it has roots. These objects are found by `gameobject_find` like any other; the scene itself cannot be unloaded or activated. > **`childCount` vs `children` — how to tell a leaf from a truncation.** `childCount` is always the node's *real* number of children, independent of `maxDepth`; `children` is `null` once the depth limit is reached. So: > > | `childCount` | `children` | Meaning | > |---|---|---| > | `0` | `null` | Genuine leaf — nothing below it. | > | `> 0` | `null` | **Clipped by `maxDepth`** — there are children you have not been shown. | > | `> 0` | array | Fully expanded at this level. | > > Never read `children: null` as "empty". When you see `childCount > 0` with `children: null` and you need what is below it, re-call with a larger `maxDepth` — the default is only `3`, so deep hierarchies are truncated by default — or query that subtree directly (`gameobject_find`, `hierarchy_describe` in the `perception` module). ### scene_screenshot Capture a screenshot of the **Game View** — the final composited frame of all cameras + UI. In Play mode this is the live runtime image, **not** the Scene/editor view. For a single Game Camera's render use `camera_screenshot` instead. | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `filename` | string | No | "screenshot.png" | Bare filename only (no path separators); saved under `Assets/Screenshots/` | | `width` | int | No | 1920 | Image width | | `height` | int | No | 1080 | Image height | | `returnImage` | bool | No | false | Also return a PNG as base64 in the response (`imageBase64`), for clients without filesystem access | | `maxDimension` | int | No | 1280 | Only used when `returnImage=true`; downscales the returned image (not the saved file) so its longer edge is ≤ this value. Clamped to 256–4096 | **Returns**: `{success, path, width, height, isPlaying, note}`. `isPlaying` indicates whether the frame is a live runtime image (Play mode) or a static Edit-mode frame. Adds `{imageBase64, imageWidth, imageHeight, imageBytes}` when `returnImage=true`. If the base64 payload would exceed 8MB, the skill returns an error asking for a smaller `maxDimension` — the file at `path` is still saved. **Async**: `ScreenCapture.CaptureScreenshot` writes the PNG ~1 frame later. If reading `path` immediately fails, wait ~200ms and retry. `returnImage` does **not** read that file back — since it isn't written yet — it instead does a separate synchronous capture of the Game View's current backbuffer (`ScreenCapture.CaptureScreenshotAsTexture`), so the returned image may be a moment older than the file eventually written to `path`. **returnImage usage tip:** a local agent that can read files (e.g. Claude Code against a local Unity Editor) should generally omit `returnImage` and just read the PNG at `path` once it's written — it's cheaper on tokens. Use `returnImage=true` for remote/MCP clients that have no filesystem access to the Unity project. ### scene_get_loaded Get list of all currently loaded scenes. No parameters. **Returns**: `{success, scenes: [{name, path, isActive, isDirty}]}` ### scene_unload Unload a loaded scene (additive). | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `sceneName` | string | Yes | Scene name to unload | ### scene_set_active Set the active scene (for multi-scene editing). | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `sceneName` | string | Yes | Scene name to set active | ### scene_find_objects Search GameObjects by name pattern, tag, or component type. For advanced search (regex, layer, path) use gameobject_find. | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `namePattern` | string | No | - | Name substring to match (case-insensitive) | | `tag` | string | No | - | Filter by tag; a tag not defined in Tags & Layers is rejected | | `componentType` | string | No | - | Filter by component type name; an unknown type is rejected | | `limit` | int | No | 50 | Max results to return | **Returns**: `{success, count, objects: [{name, path, instanceId, active, tag}]}` --- ## Example Usage ```python import unity_skills # Create a new scene unity_skills.call_skill("scene_create", scenePath="Assets/Scenes/Level1.unity") # Load an existing scene unity_skills.call_skill("scene_load", scenePath="Assets/Scenes/MainMenu.unity") # Load scene additively (multi-scene) unity_skills.call_skill("scene_load", scenePath="Assets/Scenes/UI.unity", additive=True) # Get current scene info info = unity_skills.call_skill("scene_get_info") print(f"Scene: {info['name']}, Objects: {info['rootObjectCount']}") # Get full hierarchy (useful for understanding scene structure) hierarchy = unity_skills.call_skill("scene_get_hierarchy", maxDepth=5) # Save scene unity_skills.call_skill("scene_save") # Take screenshot unity_skills.call_skill("scene_screenshot", filename="preview.png", width=1920, height=1080) ``` ## Best Practices 1. Always save before loading a new scene 2. Use additive loading for UI overlays 3. Keep scene hierarchy organized with empty parent objects 4. Use `scene_get_info` to verify scene state 5. Screenshots are saved under `Assets/Screenshots/` (filename is a bare name; any path separators are stripped) ## Exact Signatures Exact names, parameters, defaults, and returns are defined by `GET /skills/schema` or `unity_skills.get_skill_schema()`, not by this file. ## Common Errors Full transport-level codes (COMPILING/RATE_LIMIT etc.) → ../../references/protocol-error-codes.md | Error | Trigger | Fix | |---|---|---| | `TARGET_NOT_FOUND` | The requested scene is not found or not currently loaded (e.g., `Scene not found`, `Scene is not loaded`). | Verify the scene path with `asset_find` or list loaded scenes with `scene_get_loaded`, then retry. | | `MISSING_PARAM` | A required parameter is missing, such as `scenePath` for `scene_create`, or the current scene has no save path. | Provide `scenePath` or save the scene once before the operation. | | `SEMANTIC_INVALID` | An invalid tag or component type was passed to `scene_find_objects`. | Use a valid tag or component type name, and consider `gameobject_find` for more complex filters. | | `SKILL_ERROR` | A state constraint blocked the operation, such as attempting to unload the only loaded scene. | Adjust the request to a valid editor state (e.g., keep at least one scene loaded). |