unity-explorer-mcp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnity Explorer MCP Scene Iteration
Unity Explorer MCP 场景迭代
Drive a running Decentraland Explorer build through its MCP automation server to build and test SDK7 scenes autonomously: edit the scene, watch it hot-reload, move the camera and player, take screenshots, and verify against what the code should produce.
The connected tools are self-describing — each carries its name, arguments, and output shape. Treat that as the authoritative tool catalog; the names used below (, , , , , , , , , , , , , , , , , , ) are the common ones.
mcp__explorer__*get_scene_stateget_scene_logsscreenshotteleportmove_towalklook_atset_camera_poseset_camera_modelist_scene_entitiesget_entity_detailsget_player_stateclick_entitysend_chattrigger_emotereload_sceneget_scene_content_statsget_scene_content_breakdownget_performance_statsDeeper reference, loaded only when the task reaches it:
- — before framing screenshots, free-camera sweeps, or navigating precise lines
reference/camera-and-movement.md - — before placing, downloading, converting, or exporting any 3D model
reference/assets.md - — before tuning emissives/bloom, UI overlays, skybox time, or judging thin geometry
reference/visuals.md - — before answering whether a scene is within its content budget, why it runs slow, or what to optimize (
reference/performance-debugging.md,get_scene_content_stats,get_scene_content_breakdown)get_performance_stats
通过其 MCP 自动化服务器驱动正在运行的 Decentraland Explorer 构建,以自主构建和测试 SDK7 场景:编辑场景、观察热重载、移动摄像机和玩家、截取屏幕,并对照代码应产生的结果进行验证。
已连接的 工具具备自描述能力——每个工具都携带自身的名称、参数和输出结构。将其视为权威工具目录;下文使用的名称(、、、、、、、、、、、、、、、、、、)是常见工具。
mcp__explorer__*get_scene_stateget_scene_logsscreenshotteleportmove_towalklook_atset_camera_poseset_camera_modelist_scene_entitiesget_entity_detailsget_player_stateclick_entitysend_chattrigger_emotereload_sceneget_scene_content_statsget_scene_content_breakdownget_performance_stats仅在任务进入相应环节时加载更深入的参考资料:
- ——在为截图取景、执行自由摄像机扫掠或沿精确路线导航之前
reference/camera-and-movement.md - ——在放置、下载、转换或导出任何 3D 模型之前
reference/assets.md - ——在调整自发光/bloom、UI 叠加层、天空盒时间或判断细薄几何体之前
reference/visuals.md - ——在回答场景是否处于内容预算内、运行缓慢的原因或应优化什么之前(
reference/performance-debugging.md、get_scene_content_stats、get_scene_content_breakdown)get_performance_stats
Gates
门控
Certain points in this skill are gates: you ask, call no tool after asking, and let the user answer. A gate opens only on their reply — never on your own judgment, never on their silence, never because a workaround is available to you. Running as a subagent, you cannot open a gate at all — there is no user to ask: stop and report the pending decision to your caller with your recommendation, rather than passing the gate on your own authority. Doing so violates the gate even when the workaround happens to work. The gates, in order: the skills-install gate and restart gate (below), the intent gate (pre-flight), the launch/kill gate (Setup step 1), and the bind gate (Setup step 2).
本 skill 中的某些时点是门控:提出问题后不得调用任何工具,并等待用户回答。只有用户回复才能开启门控——绝不能凭自己的判断、用户的沉默,或因为存在变通方案而开启。作为 subagent 运行时,你根本无法开启门控——因为没有用户可问:应停止操作,并将待定决策及建议报告给调用方,而不是擅自越过门控。即使变通方案可行,这样做仍违反门控规则。门控顺序如下:**skills-install gate(Skill 安装门控)**和 restart gate(重启门控)(见下文)、intent gate(意图门控)(预检)、launch/kill gate(启动/终止门控)(Setup 第 1 步)和 bind gate(绑定门控)(Setup 第 2 步)。
Load the SDK skills (before anything, either way)
加载 SDK skills(无论是否使用,均须先执行)
This skill only covers driving the Explorer; the SDK7 API knowledge (composite-first rule, component reference) lives in the other topic skills of the same package this skill ships from (entry point , plus , , etc.), and parts of the API (e.g. native ) are newer than training data. You need them whether or not the Explorer ends up in play, so do this before the pre-flight below.
decentraland/sdk-skillssdk-scenescreate-sceneadd-3d-modelsTriggerAreaLoad them: session skills first, then the filesystem — scene-local ( in the scene folder) and global (). This is done when you can name the topic skills available to you — not when you've noticed they exist. If they cannot be loaded — e.g. only itself was installed, not the whole package — skills-install gate: pull in the rest of the package's topic skills from that same source? Recommend it. On yes, ask at which level — scene-local or global — and run the matching command:
.claude/skills/~/.claude/skills/unity-explorer-mcpbash
npx skills add decentraland/sdk-skills --all # scene-local (run inside the scene folder)
npx skills add decentraland/sdk-skills --all -g # global (user-level, ~/.claude/skills)A fresh install lands on disk but does not bind — skills load at session start, and only the user can restart. Restart gate: restart now to pick the new skills up, or continue this session without them? Recommend restarting — until it happens the install buys nothing.
Declining either gate is fine — the scene can still be implemented, just less efficiently. Until the skills actually load, the stale memory rule under the iteration loop governs every SDK7 API you write.
本 skill 仅涵盖 Explorer 的驱动;SDK7 API 知识(composite-first 规则、组件参考)位于本 skill 所属 包中的其他主题 skill(入口为 ,以及 、 等),且部分 API(如原生 )比训练数据更新。无论最终是否使用 Explorer,你都需要这些 skill,因此必须在下面的预检之前加载它们。
decentraland/sdk-skillssdk-scenescreate-sceneadd-3d-modelsTriggerArea加载方式:先加载 session skills,再从文件系统加载——场景本地(场景文件夹中的 )和全局()。只有当你能说出可用的主题 skill 名称时,才算完成加载——不能仅因为发现它们存在。如果无法加载,例如只安装了 本身,而没有安装整个包,则进入 skills-install gate:是否从同一来源拉取该包的其他主题 skill?建议这样做。得到肯定答复后,询问安装级别——场景本地或全局——并运行对应命令:
.claude/skills/~/.claude/skills/unity-explorer-mcpbash
npx skills add decentraland/sdk-skills --all # scene-local (run inside the scene folder)
npx skills add decentraland/sdk-skills --all -g # global (user-level, ~/.claude/skills)新安装的内容会落盘,但不会绑定——skill 在 session 启动时加载,且只有用户可以重启。restart gate:现在重启以加载新 skill,还是不使用它们继续当前 session?建议重启——在重启发生前,这次安装不会带来任何作用。
拒绝任一门控都没有问题——仍可实现场景,只是效率较低。在 skill 实际加载之前,下面迭代循环中的 stale memory(陈旧记忆) 规则适用于你编写的每一个 SDK7 API。
Intent gate (pre-flight, do this first)
intent gate(预检,必须首先执行)
This skill fires on its own — the mere presence of an tool triggers it — so it is often loaded when the user never asked for it. Before probing for a server, launching the Explorer, or editing the scene, confirm they want to drive the scene through the Unity Explorer MCP server: "Do you want to build/test this scene against a running Decentraland Explorer via the Unity Explorer MCP server? This will launch/connect to the Explorer and iterate in-world."
mcp__explorer__*- YES — continue to Setup below.
- NO — run no setup, launch, or MCP step from this skill. Work on the scene without the Explorer (edit code, lean on the topic skills you just loaded), and let the user re-invoke this skill later if they change their mind.
本 skill 会自行触发——仅存在某个 工具就会触发,因此即使用户从未要求使用它,也常会被加载。在探测服务器、启动 Explorer 或编辑场景之前,确认用户是否希望通过 Unity Explorer MCP 服务器驱动场景:“Do you want to build/test this scene against a running Decentraland Explorer via the Unity Explorer MCP server? This will launch/connect to the Explorer and iterate in-world.”
mcp__explorer__*- YES——继续执行下方的 Setup。
- NO——不得执行本 skill 中的任何 setup、launch 或 MCP 步骤。在不使用 Explorer 的情况下处理场景(编辑代码、依赖刚加载的主题 skills),并告知用户改变主意后可以再次调用本 skill。
Setup (once per session)
Setup(每个 session 一次)
-
Probe for an already-running MCP server, then start the scene. Check through the harness first: iftools are available in the session, call
mcp__explorer__*— an answer means the server is up. Fall back to curl only if the tools are absent:get_scene_statebashcurl -s -m 2 http://127.0.0.1:8123/unity-explorer-mcp -X POST \ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}'Two launch paths produce the same server, and you cannot tell them apart from the probe:from the CLI, and the Creator Hub's scene Preview button with the MCP checkbox ticked (it passesnpm run start -- --mcpto the same preview process). Same endpoint, same tools, same behaviour — a Creator Hub launch is never the reason a connection fails, so recognise it as a normal setup rather than an anomaly to relaunch out of.--mcpServer found (tool answer orresult) — launch/kill gate: use the already-running Explorer, or start the scene from scratch with the MCP flag?serverInfo- Use it: launch nothing. If port 8000 isn't serving the target scene folder (, then check the PID's cwd), kill whatever holds it and run
lsof -nP -i :8000 -sTCP:LISTEN. Skip step 2 if the tools are already available.npm run start -- --no-client - From scratch: same gate, follow-up question, before touching anything — kill the previously-running scene server, or keep it and run a second stack alongside?
- Kill it: kill the port-8000 dev server, have the user close the running client (never kill an Editor process yourself), then continue below.
- Keep it: leave it and its Explorer untouched and start a second stack on its own ports — see "Running a second stack" in .
reference/setup.md
No server found — serve the scene and launch the Explorer in one command from the scene folder (keep it running in the background; if something else already holds port 8000, apply the same kill-or-keep question and port overrides as above):bashnpm install && npm run start -- --mcpAlternatively the user can launch from the Creator Hub: enable the "Enable MCP Server" checkbox in the scene's preview settings (only shown when the scene'sversion supports the@dcl/sdk-commandsflag), then hit Preview. Equivalent to the command above in every respect that matters here.--mcpThis serves the scene at, auto-launches the installed Decentraland client connected to it with the MCP server enabled (port 8123;http://127.0.0.1:8000picks another and implies--mcp-port <port>— adjust the 8123 URLs in steps 1 and 2 to match), and hot-reloads the scene whenever a source file changes. Useful extra flags:--mcp(dev-server port; the launched client follows it automatically),--port <port>(spawn parcel),--position x,y,--skip-auth-screen(force a new client instance),-n(allow concurrent Explorer instances),--multi-instance(serve only, launch nothing). Anything after a second standalone--no-clientis forwarded verbatim into the Explorer launch as extra parameters, e.g.--(npm consumes the firstnpm run start -- --mcp -- --windowed-mode --resolution 1280x720). If the command rejects--as an unknown option, the scene's--mcppredates the flag — update@dcl/sdk-commands, or launch a specific build by hand ("Launching a specific Explorer build manually" in@dcl/sdk). If the CLI prints "Please download & install the Decentraland Desktop Client" the dev server is fine but no client is installed — install one, or point the launch at a specific build the same way.reference/setup.mdA freshly launched Explorer needs the user to log in. The client opens on the auth screen unless a previous session's login is still cached (only skips it when a valid identity exists — a missing or expired login shows it anyway, and extra--skip-auth-screeninstances always ask). Tell the user to log in, then wait — step 3's polling only starts succeeding once they're through, and only then can you continue working on the scene through the MCP server.--multi-instance - Use it: launch nothing. If port 8000 isn't serving the target scene folder (
-
Register the MCP server, then confirm its tools are actually bound (default port 8123). Registration and binding are two different things — you need both.bash
claude mcp add --transport http --scope user explorer http://127.0.0.1:8123/unity-explorer-mcpErrors with "already exists in local config" if a previous session registered it — that's fine and expected; registration is persistent config, nothing to do.This command can hang with no output in non-terminal harnesses (observed in the Claude Code VS Code extension: >2 min, no result, no error). Run it with a short timeout —— and read a hang as probably already registered, not as a failure: registration persists across sessions, so a prior session'stimeout 15 claude mcp add ...still counts. Don't retry it; confirm the endpoint with the step 1 probe instead and move on to the bind gate.claude mcp addMANDATORY — bind gate: if you launched the Explorer yourself in this session, STOP here as soon as the readiness probe answers, and do NOT start the iteration loop over curl. Claude Code opens its MCP connections once, at session startup, and this server lives inside the Explorer process — so a session that started before the Explorer was up has already failed its one connection attempt, andtools will never appear on their own. Mid-session, only an explicitmcp__explorer__*reconnect re-binds them; alternatively, starting a fresh Claude session while the Explorer keeps running binds them automatically at that session's startup. Both are user actions: there is nothing you can run instead, so ask rather than trying to engineer around it./mcpOpen with the situation — "the Explorer is up, but this Claude session started before it, so the native MCP tools aren't bound" — then offer three paths, best first, with the fallback's costs stated before they can land in it:- Reconnect the server — fastest, and keeps this conversation. How, depends on the harness: the terminal CLI opens an interactive server menu on
explorer, with a reconnect entry to pick. The VS Code extension (and any embedded chat panel, e.g. the Creator Hub's) has no such menu — a bare/mcpthere only prints a status line plus usage, so the command to give the user is/mcp(or/mcp reconnect explorer), typed into the chat./mcp reconnect all - Start a fresh session / new conversation tab, leaving the Explorer running — the tools bind automatically at the new session's startup. In the VS Code extension and embedded panels this is just a new conversation tab, not restarting the app or the Explorer — say so, because users assume the expensive reading and decline. Make it the recommended path there whenever answers "MCP controls aren't available right now — the terminal is still starting up or is showing another view." — a known failure mode in that harness with no in-chat fix, and the new tab is the path verified to work.
/mcp reconnect - The curl fallback — one shell command per player action, permission prompts on each new call shape, more tokens, and no screenshot images you can inspect.
Useif your client has it, one option each; label the second "Restart session / new tab (Explorer stays up)" so it can't be misread as closing the Explorer. Otherwise put the same three in plain text and close with "Which do you prefer?".AskUserQuestionYou may only move past this step in one of these three states — no fourth reading exists, and a subagent can only ever be in the first:- Tools already present (the Explorer was running before this session started) — the gate doesn't apply; continue to step 3.
- The user rebound the tools — via reconnect, or by opening a fresh session/tab with the Explorer left up. Verify by calling a native
/mcptool, then continue to step 3. (A fresh session ends this conversation; the new one finds them bound and skips this gate.)mcp__explorer__* - The user has explicitly chosen the curl fallback in writing, this session, after being told its costs — only then read and drive the endpoint over HTTP. A working curl probe is not a decline, and neither is silence.
reference/curl-fallback.md
The probe in step 1 is the only curl call you make before this gate. Getting an answer out of it proves the Explorer is up — which is the trigger to ask, not permission to continue.Mention the prevention once, not every session: starting the Explorer before Claude Code — or simply leaving it running between sessions — skips this gate entirely.Not running in Claude Code?andclaude mcp addare Claude Code commands — for Cursor, Cline, or a custom SDK harness, the connection details and config shapes are in/mcp. The Claude Code VS Code extension and the Creator Hub's embedded chat are Claude Code: they take the commands above, with the harness differences noted in the bind gate.reference/setup.md - Reconnect the
-
Wait for the world to load: polluntil
get_scene_stateis false and the scene reportsloadingScreenOn.isReady: true
-
探测已经运行的 MCP 服务器,然后启动场景。 先通过 harness 检查:如果 session 中已有工具,调用
mcp__explorer__*——收到响应即表示服务器已启动。仅当工具不存在时,才回退到 curl:get_scene_statebashcurl -s -m 2 http://127.0.0.1:8123/unity-explorer-mcp -X POST \ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \ -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-06-18\",\"capabilities\":{},\"clientInfo\":{\"name\":\"probe\",\"version\":\"1\"}}}'两种启动路径会生成相同的服务器,而且通过探测无法区分二者:从 CLI 运行,以及从 Creator Hub 的场景 Preview 按钮启动并勾选 MCP(它会将npm run start -- --mcp传递给同一个 preview 进程)。二者使用相同 endpoint、相同工具和相同行为,因此 Creator Hub 启动并不是连接失败的原因;应将其视为正常 setup,而不是需要重新启动的异常。--mcp服务器已找到(工具响应或结果)——进入 launch/kill gate:使用已经运行的 Explorer,还是带 MCP 标志从头启动场景?serverInfo- 使用现有实例:不启动任何内容。如果端口 8000 未提供目标场景文件夹的服务(运行 ,然后检查 PID 的 cwd),则终止占用该端口的进程,并运行
lsof -nP -i :8000 -sTCP:LISTEN。如果工具已经可用,跳过第 2 步。npm run start -- --no-client - 从头启动:这是同一门控的后续问题——在触碰任何内容之前,是终止先前运行的场景服务器,还是保留它并并行运行第二套栈?
- 终止它:终止端口 8000 上的 dev server,让用户关闭正在运行的 client(绝不要自行终止 Editor 进程),然后继续执行下方步骤。
- 保留它:保持该服务及其 Explorer 不变,在独立端口上启动第二套栈——参见 中的“Running a second stack”。
reference/setup.md
未找到服务器——在场景文件夹中用一条命令提供场景服务并启动 Explorer(让它在后台持续运行;如果端口 8000 已被其他进程占用,则应用上述终止或保留问题以及端口覆盖设置):bashnpm install && npm run start -- --mcp或者,用户可以从 Creator Hub 启动:在场景的预览设置中启用 “Enable MCP Server” 复选框(仅当场景的版本支持@dcl/sdk-commands标志时才会显示),然后点击 Preview。在所有关键方面,它都等同于上面的命令。--mcp这会在提供场景服务,自动启动已安装且连接到该服务的 Decentraland client,并启用 MCP 服务器(端口 8123;http://127.0.0.1:8000可选择其他端口,并隐含启用--mcp-port <port>——相应调整第 1 步和第 2 步中的 8123 URL),且每当源文件发生变化时都会热重载场景。额外可用标志包括:--mcp(dev-server 端口;启动的 client 会自动跟随)、--port <port>(生成位置对应的 parcel)、--position x,y、--skip-auth-screen(强制启动新的 client 实例)、-n(允许并发 Explorer 实例)和--multi-instance(仅提供服务,不启动任何内容)。第二个独立的--no-client之后的所有内容都会逐字转发到 Explorer 启动命令中作为额外参数,例如--(npm 会消耗第一个npm run start -- --mcp -- --windowed-mode --resolution 1280x720)。如果命令提示--是未知选项,说明场景的--mcp版本早于该标志——请更新@dcl/sdk-commands,或手动启动特定构建(参见@dcl/sdk中的“Launching a specific Explorer build manually”)。如果 CLI 提示 “Please download & install the Decentraland Desktop Client”,则说明 dev server 正常,只是尚未安装 client——请安装 client,或按照相同方式让启动命令指向特定构建。reference/setup.md全新启动的 Explorer 需要用户登录。 除非仍缓存着上一 session 的登录状态,client 都会打开身份验证界面(仅在存在有效身份时才会跳过;缺失或过期的登录仍会显示,而且额外的--skip-auth-screen实例始终会要求登录)。告知用户登录,然后等待——只有用户通过验证后,第 3 步的轮询才会成功,此后才能继续通过 MCP 服务器处理场景。--multi-instance - 使用现有实例:不启动任何内容。如果端口 8000 未提供目标场景文件夹的服务(运行
-
注册 MCP 服务器,然后确认其工具实际已绑定(默认端口 8123)。注册与绑定是两件不同的事——两者缺一不可。bash
claude mcp add --transport http --scope user explorer http://127.0.0.1:8123/unity-explorer-mcp如果报错提示 “already exists in local config”,说明上一 session 已经注册过——这是正常且符合预期的情况;注册是持久化配置,无需处理。此命令在非终端 harness 中可能无输出并一直挂起(已观察到 Claude Code VS Code 扩展中超过 2 分钟,无结果也无错误)。使用短超时运行————并将其挂起视为“可能已经注册”,而不是失败:注册会跨 session 持久化,因此上一 session 的timeout 15 claude mcp add ...仍然有效。不要重试;改用第 1 步的探测确认 endpoint,然后进入 bind gate。claude mcp add必须执行——bind gate:如果是你在本 session 中启动了 Explorer,就绪探测一有响应便立即在此停止,切勿通过 curl 启动迭代循环。 Claude Code 只在 session 启动时建立一次 MCP 连接,而此 server 位于 Explorer 进程内部——因此,在 Explorer 启动之前就已开始的 session 已经用掉了唯一一次连接尝试,工具永远不会自行出现。在 session 中途,只有显式执行mcp__explorer__*重新连接才能重新绑定;另一种方法是,在 Explorer 保持运行时启动一个全新的 Claude session,这会在新 session 启动时自动完成绑定。这两种都是用户操作:没有你可以代为执行的命令,所以应询问用户,而不是尝试绕过。/mcp先说明情况——“Explorer 已启动,但这个 Claude session 在它之前就开始了,因此原生 MCP 工具尚未绑定”——然后提供三条路径,优先给出最佳选项,并在用户选择回退方案前说明其代价:- 重新连接 server——速度最快,并且可以保留当前对话。具体方式取决于 harness:终端 CLI 的
explorer会打开交互式服务器菜单,其中有可供选择的重新连接项。VS Code 扩展(以及任何嵌入式聊天面板,例如 Creator Hub)没有该菜单——在这些环境中,单独输入/mcp只会显示状态行和使用说明,因此应让用户在聊天中输入/mcp(或/mcp reconnect explorer)。/mcp reconnect all - 启动全新 session/新建对话标签页,让 Explorer 保持运行——工具会在新 session 启动时自动绑定。在 VS Code 扩展和嵌入式面板中,这只需新建一个对话标签页,无需重启应用或 Explorer——应明确说明这一点,因为用户通常会误以为需要执行耗时的读取和终止操作。当 回复 “MCP controls aren't available right now — the terminal is still starting up or is showing another view.” 时,应在这些 harness 中优先推荐此路径;这是已知且无法在聊天内修复的失败模式,而新建标签页是已经验证可行的方式。
/mcp reconnect - curl 回退方案——每个玩家动作需要一条 shell 命令,每次出现新的调用形式都会触发权限提示,消耗更多 token,而且无法检查返回的截图图像。
如果客户端提供,则每项提供一个选项;将第二项标记为 “Restart session / new tab (Explorer stays up)”,以免被误解为关闭 Explorer。否则,以纯文本给出相同的三项,并以 “Which do you prefer?” 收尾。AskUserQuestion只有在以下三种状态之一才能继续——不存在第四种解读,且 subagent 永远只能处于第一种:- 工具已经存在(Explorer 在本 session 启动前已经运行)——此门控不适用;继续执行第 3 步。
- 用户已重新绑定工具——通过 重新连接,或在 Explorer 保持运行时打开全新 session/标签页。调用原生
/mcp工具进行验证,然后继续执行第 3 步。(全新 session 会结束当前对话;新 session 会发现工具已经绑定,并跳过此门控。)mcp__explorer__* - 用户在本 session 中明确选择了 curl 回退方案——只有在告知其成本之后,才能读取 并通过 HTTP 驱动 endpoint。能够成功执行 curl 探测并不代表用户拒绝原生工具,沉默也不代表拒绝。
reference/curl-fallback.md
第 1 步中的探测是执行此门控前唯一一次 curl 调用。获得响应只能证明 Explorer 已经启动——这是询问用户的触发条件,而不是继续执行的许可。预防措施只需提及一次,不必每个 session 重复:在 Claude Code 之前启动 Explorer——或者干脆让 Explorer 在多个 session 之间保持运行——即可完全跳过此门控。不在 Claude Code 中运行?和claude mcp add是 Claude Code 命令;对于 Cursor、Cline 或自定义 SDK harness,连接详情和配置结构参见/mcp。Claude Code VS Code 扩展和 Creator Hub 的嵌入式聊天属于 Claude Code:它们支持上述命令,只需遵循 bind gate 中列出的 harness 差异。reference/setup.md - 重新连接
-
等待世界加载:轮询,直到
get_scene_state为 false,且场景报告loadingScreenOn。isReady: true
The iteration loop
迭代循环
Repeat until every requirement has proof: a screenshot or state read demonstrating it, captured from a retail camera mode (/, not the free camera), with healthy and no unexplained errors in the logs.
first_personthird_personget_scene_state- Edit the scene TypeScript in — read the owning topic skill before writing an API you can't recall exactly (see below). The dev server hot-reloads the running Explorer within a few seconds. If you need a deterministic reset instead, call
src/.reload_scene - Confirm the scene is healthy: — a
get_scene_stateofstateorJavaScriptErrormeans your code crashed the scene runtime.EcsError - Read the runtime output: with
get_scene_logsset to the last sequence number you saw. ScenesinceSeqoutput and exceptions land here.console.log - Look and verify: position the view (,
teleport,move_to,walk— for precise framing or free-camera sweeps readlook_at), thenreference/camera-and-movement.mdand inspect the image against what the scene code should produce.screenshot - Exercise behavior: into trigger areas,
walkon interactables,click_entityfor commands,send_chat, and re-screenshot to verify reactions.trigger_emote+list_scene_entitiesshow the scene's ECS state when visuals aren't enough.get_entity_details - Measure budget & performance (when the question is limits, frame rate, or what to optimize): for the whole-scene counts against their soft caps,
get_scene_content_statsto rank the heaviest source models (position the camera first — the visible columns are per point of view), andget_scene_content_breakdownto sample the real frame rate at a viewpoint. Don't prescribe from counts alone — correlate content with measured FPS. Full method and the materials-vs-shaderVariants interpretation are inget_performance_stats.reference/performance-debugging.md
Your SDK7 API memory is stale. The SDK ships components newer than training data — native + () among them — so failing to recall an API is no evidence it's missing, and neither is a version number you remember. When you can't recall an API exactly, or catch yourself hand-rolling a workaround (polling the player for a trigger volume, mutating to move the player), read the topic skill that owns it before writing the workaround: for triggers and pointer events, for forces on the player, for held keys, for the component reference and the index of the rest. Reach for the official docs only where no skill covers it, and say so when you do.
TriggerAreatriggerAreaEventsSystemTriggerArea.setBox(entity, ColliderLayer.CL_MAIN_PLAYER)Transformengine.PlayerEntityadd-interactivityplayer-physicsadvanced-inputsdk-scenesCross-examine every conclusion: confirm each visual claim with a state read (ECS values via , logs, position), and each state claim with pixels. One channel lies routinely — colliders exist that pixels don't show, entities render invisible while their state looks healthy, animations silently don't play. The reference files call out where cross-examination is mandatory.
get_entity_detailsget_player_stateMANDATORY — camera cleanup before finishing. NEVER leave the camera in mode when you stop working (end of task, handing back to the user, or pausing for their input): always restore it with as your last camera action, and confirm via → if anything in between could have failed.
freeset_camera_mode third_personget_player_statecamera.mode重复执行,直到每项需求都有证据:以面向用户的摄像机模式(/,而不是自由摄像机)采集一张截图或状态读取结果,同时 保持健康,且日志中不存在无法解释的错误。
first_personthird_personget_scene_state- 编辑 中的场景 TypeScript——编写无法准确回忆的 API 前,先阅读负责该 API 的主题 skill(见下文)。dev server 会在几秒内热重载正在运行的 Explorer。如果需要确定性的重置,则调用
src/。reload_scene - 确认场景健康:调用 ——
get_scene_state为state或JavaScriptError表示代码导致场景运行时崩溃。EcsError - 读取运行时输出:调用 ,并将
get_scene_logs设置为上次看到的序列号。场景的sinceSeq输出和异常会出现在这里。console.log - 观察并验证:调整视角(、
teleport、move_to、walk——精确取景或自由摄像机扫掠请参阅look_at),然后调用reference/camera-and-movement.md,根据场景代码应产生的结果检查图像。screenshot - 测试行为:使用 进入触发区域,对可交互对象调用
walk,使用click_entity发送命令,使用send_chat,然后重新截图以验证响应。当视觉信息不足时,使用trigger_emote和list_scene_entities查看场景的 ECS 状态。get_entity_details - 测量预算与性能(当问题涉及限制、帧率或应优化什么时):使用 获取整个场景的计数及其软限制,使用
get_scene_content_stats对最重的源模型进行排序(先定位摄像机——可见列取决于视点),并使用get_scene_content_breakdown在指定视点采样真实帧率。不要仅根据计数给出建议——应将内容与实测 FPS 关联分析。完整方法以及 materials 与 shaderVariants 的解释参见get_performance_stats。reference/performance-debugging.md
你的 SDK7 API 记忆是陈旧的。 SDK 随包提供的组件可能比训练数据更新——原生 + ()就是其中之一——因此想不起某个 API 并不代表它不存在,你记得的版本号也不是证据。当你无法准确回想某个 API,或发现自己正在绕道手写替代方案(轮询玩家 来实现触发体、修改 来移动玩家)时,先阅读负责该 API 的主题 skill,再编写替代方案:触发器和 pointer event 使用 ,玩家受力使用 ,长按按键使用 ,组件参考及其他索引使用 。只有在没有 skill 覆盖某项内容时才查阅官方文档,并明确说明这一点。
TriggerAreatriggerAreaEventsSystemTriggerArea.setBox(entity, ColliderLayer.CL_MAIN_PLAYER)Transformengine.PlayerEntityadd-interactivityplayer-physicsadvanced-inputsdk-scenes交叉验证每个结论: 每个视觉声明都用状态读取来确认(通过 检查 ECS 值、查看日志以及 中的位置),每个状态声明都用像素来确认。某一通道经常会说谎——碰撞体存在但像素中看不到,实体渲染为不可见但其状态看起来正常,动画悄无声息地没有播放。参考文件会指出哪些地方必须进行交叉验证。
get_entity_detailsget_player_state必须执行——结束前清理摄像机。 停止工作时(任务结束、交还用户或等待用户输入),绝不要把摄像机留在 模式:始终将 作为最后一个摄像机操作;如果中间有任何操作可能失败,则通过 → 确认。
freeset_camera_mode third_personget_player_statecamera.modeScreenshot frequency & cost
截图频率与成本
Every screenshot returned by the MCP tool lands in your context as an image (~1.2k tokens at 1280×720, scaling with pixel count). Occasional captures through the tool are fine; frequent or burst captures must go through the bundled script instead, which saves frames to disk (zero context cost) and prints only the caption:
screenshotCall it by absolute path — your cwd is the scene folder, not this skill's. below is the base directory reported when this skill loads ( when installed scene-local, when global):
<skill-dir>.claude/skills/unity-explorer-mcp/~/.claude/skills/unity-explorer-mcp/bash
<skill-dir>/scripts/screenshot.sh -o /tmp/shot.jpg # single frame to a file
<skill-dir>/scripts/screenshot.sh -n 10 -i 0.5 # burst: 10 frames every 0.5s (time-based behavior: tweens, animations)
<skill-dir>/scripts/screenshot.sh -w 640 # cheap sanity-check resolution (~4x fewer tokens when you Read it)
<skill-dir>/scripts/screenshot.sh --world-only --png # UI-less lossless frameFrames default to , deliberately outside the scene folder: anything left in the project gets uploaded on deploy and counts against the per-parcel MB limits. Keep / targets out of the scene too — or add the directory to if the user wants the frames kept beside their scene.
$TMPDIR/mcp-shots-d-o.dclignoreRequires curl + python3; pass when not on 8123. only the frames you actually need to inspect — capture many, look at few. For before/after comparisons, capture both to disk and read just those two. Use 640 for quick checks and 1280 only for final verification. Captures are serialized server-side (concurrent requests are rejected), so keep burst intervals ≥ 0.2s.
-p <port>ReadmaxWidth通过 MCP 工具返回的每张截图都会以图像形式进入上下文(1280×720 时约 1.2k tokens,成本随像素数增加)。偶尔通过工具捕获没有问题;频繁或连续捕获必须改用随附脚本,它会将帧保存到磁盘(上下文成本为零),并且只打印 caption:
screenshot按绝对路径调用它——当前工作目录是场景文件夹,而不是本 skill 的目录。下文的 是本 skill 加载时报告的基目录(安装在场景本地时为 ,安装在全局时为 ):
<skill-dir>.claude/skills/unity-explorer-mcp/~/.claude/skills/unity-explorer-mcp/bash
<skill-dir>/scripts/screenshot.sh -o /tmp/shot.jpg # single frame to a file
<skill-dir>/scripts/screenshot.sh -n 10 -i 0.5 # burst: 10 frames every 0.5s (time-based behavior: tweens, animations)
<skill-dir>/scripts/screenshot.sh -w 640 # cheap sanity-check resolution (~4x fewer tokens when you Read it)
<skill-dir>/scripts/screenshot.sh --world-only --png # UI-less lossless frame帧默认保存到 ,刻意放在场景文件夹之外:项目中遗留的任何内容都会在部署时上传,并计入每个 parcel 的 MB 限制。将 / 目标放在场景之外——或者,如果用户希望把帧保存在场景旁边,将该目录加入 。
$TMPDIR/mcp-shots-d-o.dclignore此功能需要 curl + python3;端口不是 8123 时,传入 。只 实际需要检查的帧——可以捕获许多帧,但只查看少数帧。对于前后对比,将两张图都捕获到磁盘,并且只读取这两张。快速检查使用 640,最终验证使用 1280。捕获操作在服务端串行执行(并发请求会被拒绝),因此连续捕获的间隔应 ≥ 0.2s。
-p <port>ReadmaxWidthScene health & recovery
场景健康与恢复
- Sequence-poll logs () instead of re-reading the whole buffer; errors survive in the buffer even if they scrolled by.
sinceSeq - changes (parcels, spawn points) are not hot-reloaded — restart the
scene.jsonprocess, thennpm run start.reload_scene - After or
teleport, always re-checkreload_scenebefore interacting; readiness can lag a few seconds.get_scene_state - One parcel is 16×16 m; parcel spans world positions
(x, y).(16x..16x+16, 16y..16y+16)spawns at parcel 0,0.--position 0,0 - If the connection drops, the client probably crashed or was closed — relaunch it the same way it was started (, or the manual launch line in
npm run start -- --mcp); the MCP endpoint URL stays the same.reference/setup.md - Missing tools: tools absent in-session is the bind gate — go back to Setup step 2, ask the user to reconnect the server (
mcp__explorer__*menu in the terminal CLI,/mcpin the VS Code extension) or open a fresh session/conversation tab with the Explorer left running, and end your turn there. The HTTP fallback is in/mcp reconnect explorer, to be opened only after they have been warned of its costs and explicitly chosen it.reference/curl-fallback.md - After a hot reload the player can end up off-parcel (e.g. parcel );
0,-1then reports a null scene andget_scene_statefails with "no scene at the current parcel". Checkreload_scene→get_player_state,parcelback inside, and the scene loads again.move_to - One file write per change. Each save triggers a rebuild, so a multi-part edit split across saves breaks the scene in between — mildly, when usage and import land in separate saves (a transient ), or terminally: two saves seconds apart can make the Explorer load a mid-write bundle →
SceneError: X is not definedat scene start → the scene drops out andSyntaxError: Invalid or unexpected tokenreportsget_scene_statewhile you're standing on the parcel. From that state nothing recovers in-session:scene: nullerrors ("no scene at the current parcel"),reload_scenehangs, the minimap RELOAD SCENE button no-ops, and moving off-parcel and back does not bring it back — only exiting/re-entering play mode (editor) or relaunching the standalone build. So batch multi-part changes into ONE write, write new modules before wiring them in, and after any save landing seconds after a previous one verify/reloadstill shows a scene before saving again.get_scene_state - The tool silently no-ops in local-scene-development mode:
teleportteleports are disallowed there (chat shows "Teleport is not allowed in local scene development mode") but the tool still answers "Arrived at (x,y)". Use/gotofor repositioning in local-scene sessions.move_to - The Explorer under test may be the Unity Editor in play mode, not a standalone Decentraland.app — check before considering a relaunch. Never kill the editor process; recovery from a wedged client is then a user action (exit/re-enter play mode).
ps aux | grep -i unity
- 按序列号轮询日志(),不要重复读取整个缓冲区;即使错误已经滚出屏幕,它们仍会保留在缓冲区中。
sinceSeq - 的变化(parcel、生成点)不会被热重载——重启
scene.json进程,然后调用npm run start。reload_scene - 调用 或
teleport后,务必再次检查reload_scene,然后再进行交互;就绪状态可能延迟几秒。get_scene_state - 一个 parcel 为 16×16 m;parcel 覆盖世界坐标
(x, y)。(16x..16x+16, 16y..16y+16)会在 parcel 0,0 生成。--position 0,0 - 如果连接中断,client 很可能已经崩溃或被关闭——按照原先的启动方式重新启动(,或使用
npm run start -- --mcp中的手动启动命令);MCP endpoint URL 保持不变。reference/setup.md - 缺少工具:session 中不存在 工具意味着遇到了 bind gate——返回 Setup 第 2 步,询问用户是否重新连接 server(终端 CLI 使用
mcp__explorer__*菜单,VS Code 扩展使用/mcp),或让 Explorer 保持运行并打开全新 session/对话标签页,然后结束当前轮次。HTTP 回退方案位于/mcp reconnect explorer中,只有在警告用户其成本且用户明确选择后才能打开。reference/curl-fallback.md - 热重载后,玩家可能落到 parcel 之外(例如 parcel );此时
0,-1会报告 null 场景,并且get_scene_state失败并提示 “no scene at the current parcel”。检查reload_scene→get_player_state,使用parcel移回 parcel 内,场景便会重新加载。move_to - 每次变更只写入一个文件。 每次保存都会触发重建,因此将一次变更拆分成多次保存会在中间破坏场景——轻则 和
usage分开保存时暂时出现import,重则相隔数秒的两次保存可能让 Explorer 加载到写入中途的 bundle → 场景启动时出现SceneError: X is not defined→ 场景掉线,而SyntaxError: Invalid or unexpected token在玩家仍站在 parcel 上时会报告get_scene_state。从该状态出发,session 内无法恢复:scene: null会报错(“no scene at the current parcel”),reload_scene会挂起,小地图上的 RELOAD SCENE 按钮不起作用,移动到 parcel 外再返回也无法使其恢复——只有退出并重新进入 play mode(editor)或重启 standalone build 才能恢复。因此,应将多部分更改合并为一次写入,先编写新 module,再将它们连接起来;任何一次保存若与前一次相隔数秒,都应先验证/reload仍显示场景,然后再进行下一次保存。get_scene_state - 工具在本地场景开发模式下会静默失效:此时禁止
teleport传送(聊天会显示 “Teleport is not allowed in local scene development mode”),但工具仍会回复 “Arrived at (x,y)”。本地场景 session 应使用/goto重新定位。move_to - 被测试的 Explorer 可能是处于 play mode 的 Unity Editor,而不是独立的 Decentraland.app——考虑重新启动之前,先运行 。绝不要终止 Editor 进程;如果 client 已卡死,恢复操作必须由用户完成(退出并重新进入 play mode)。
ps aux | grep -i unity
Interaction testing
交互测试
- presses a pointer button on a scene entity (get ids from
click_entity). The target needs alist_scene_entitiescomponent and a collider; the aim is validated by a real camera-origin raycast, so occluders returnPointerEvents+hit:false(reposition and retry) and the entity'sblockedBy*(default 10 m) applies — get close first.maxDistancemeans the target moved between press and release (e.g. a door starting to swing) and the release was delivered with the press-frame hit. For GLTF entities whose collider sits away from the pivot, pass an explicitupRayMissed: trueaim point. The player must be standing on the scene's parcel — off-parcel clicks fail with "no running current scene".x/y/z - moves relative to the camera and requires an explicit direction: pass
walkfor forward (directionY: 1strafes); omitting both errors with "directionX and directionY must not both be zero".directionX - Collider checks beat pixels for physics (cross-examine): straight at the target,
look_atforward, then comparewalkpositions to prove passage or blockage.get_player_state - Trigger areas fire immediately after
onTriggerEnterif the player is already standing inside one — reposition the player outside all triggers before testing enter/exit sequencing (and treat post-reload trigger logs as stale state, not gameplay).reload_scene
- 会在场景实体上按下 pointer button(从
click_entity获取 id)。目标必须具有list_scene_entitiescomponent 和 collider;瞄准会通过从摄像机原点发起的真实 raycast 进行验证,因此遮挡物会返回PointerEvents和hit:false(重新定位后重试),并且实体的blockedBy*(默认 10 m)也会生效——应先靠近目标。maxDistance表示目标在按下和释放之间发生了移动(例如一扇开始摆动的门),并且释放操作使用的是按下帧命中的目标。对于 collider 位于 pivot 之外的 GLTF 实体,请传入显式的upRayMissed: true瞄准点。玩家必须站在场景的 parcel 上——在 parcel 外点击会失败并提示 “no running current scene”。x/y/z - 会相对于摄像机移动,并且要求提供明确方向:向前传递
walk(directionY: 1用于横向移动);如果两者都省略,则会报错 “directionX and directionY must not both be zero”。directionX - 对 physics 而言,collider 检查比像素更可靠(交叉验证):使用 正对目标,使用
look_at向前移动,然后比较walk中的位置,以证明能否通过或被阻挡。get_player_state - 如果 后玩家已经站在触发区域内,
reload_scene会立即触发——测试进入/退出顺序前,将玩家重新定位到所有触发区域之外(并将重载后的触发日志视为陈旧状态,而不是游戏行为)。onTriggerEnter
When a capability is missing
缺少某项能力时
If the loop is blocked because no connected MCP tool can do what you need (e.g. pressing a specific key, reading a value no tool exposes), stop and hand it to the user: name the concrete action you're blocked on and why the existing tools can't cover it, and let them decide how to extend the setup. The MCP server and Explorer live outside this scene's repo — extending them is the user's call, not something to work around from here.
如果迭代循环因已连接的 MCP 工具无法完成所需操作而受阻(例如无法按下特定按键,或无法读取工具未暴露的值),应停止操作并将其交给用户:明确说明被阻断的具体操作,以及现有工具为何无法覆盖。不要绕过限制;MCP server 和 Explorer 位于此场景的 repo 之外,扩展它们由用户决定。