mcpField
C
creator-hub-mcp

creator-hub-mcp

github.com/decentraland创意与媒体4163 次安装今天更新
代码仓库

关于 creator-hub-mcp

creator-hub-mcp 是面向 Creator Hub 场景编辑的技能说明,指导 Agent 通过 MCP 操作编辑器中的实时场景,并遵循安全的场景修改流程。它还涵盖资源、智能物件目录和文件处理规则。

主要功能

  1. 01通过 MCP 编辑实时场景
  2. 02优先查找并放置智能物件
  3. 03处理提示词附件与本地资源
  4. 04遵循可撤销的场景修改流程

适用场景

  1. 01在 Creator Hub 中添加或修改场景实体
  2. 02将用户提供的模型或图片用于场景
  3. 03判断何时连接 MCP 或编辑文件

MCP 相关

Creator Hub 在应用内运行 MCP 服务,提供读取和修改打开场景的工具;内置 AI 助手及外部 MCP 客户端均可使用。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/decentraland/sdk-skills --skill creator-hub-mcp

安装后在 Claude Code 中输入/creator-hub-mcp确认已加载。

附带文件reference/connect.md

详细介绍

Creator Hub MCP — 实时场景编辑

Creator Hub 在应用内运行 MCP 服务(localhost、可流式传输的 HTTP、Bearer 令牌)。其工具可读取和修改编辑器中打开的场景:更改会应用到实时引擎,立即显示在视口中,自动保存到 assets/scene/main.composite,并且每项更改都会成为用户可撤销的常规步骤。同一服务也为 Creator Hub 内置的 AI 助手提供支持,并可开放给任何支持 MCP 的外部工具。

你可能处于以下两种运行方式之一:

你所处的位置……工具如何连接到你
在 Creator Hub 的 AI 助手中(Settings > AI > Enable AI Assistant;自 Creator Hub 0.50.0 起默认启用——不再是实验性功能)已预先接好。应用会启动你的 claude / codex / cursor-agent / gemini CLI,并将服务注册为 creator-hub,把这些技能链接到场景中,并注入与此技能相同的规则。四种提供方均无需进行任何设置。
在其他工具中(Claude Code 终端或 VS Code 扩展、Cursor、Codex、Claude Desktop,……)连接到正在运行的 Creator Hub——请参阅 reference/connect.md。用户从 Settings > AI > Expose AI assistant MCP server 复制 JSON 片段。此处不会为你接入技能——请参阅技能的来源。

在 Claude Code 中,工具显示为 mcp__creator-hub__<tool>;在 Creator Hub 的助手和其他客户端中,它们以原始名称显示(scene_state、create_entity,……)。已连接的工具会自我描述——请以实时目录为准,而非下表。

用户附加到提示词的文件

在 Creator Hub 的助手中,用户可以在一轮对话中附加文件(creator-hub 3395b643):输入框左侧的Attach files回形针按钮会打开多选器;文件可以拖到输入框上(覆盖层提示:Drop files to attach);也可以从剪贴板粘贴图像。附件会显示为可移除的标签;每条提示词最多 8 个。这对你意味着:

  • 从磁盘选择或拖入的文件会以真实的绝对路径传入——不会复制文件、进行 Base64 往返转换,也没有大小限制。请直接读取文件;不要让用户重新粘贴文件内容,或将文件移入项目。粘贴的(剪贴板)图像没有路径,因此应用会将其写入临时文件,并将该路径传给你。
  • **接受任何文件类型。**应用只会根据文件类型为标签图标分类:image(png、jpg、jpeg、gif、webp、bmp、svg、avif)、model(glb、gltf)、audio(mp3、wav、ogg、m4a、flac),其他文件均为 file。
  • **这是交接参考图像或 GLB 的自然方式。**拖入的 .glb 是用户想放入场景的模型:它仍在项目外部,因此在通过 GltfContainer 引用之前,请先将其复制到 assets/Models/ 下(边界框和碰撞体审查请参阅 add-3d-models)。参考图像通常用于说明 UI 或材质的艺术方向,而不是要导入的文件。
  • 提示词可能只有附件而完全没有文字——附件本身就是请求。请询问用户要如何处理,不要自行猜测。
用户从 Local Assets 面板提及的资源

第二种不同的通道(creator-hub d25eff1b8):在检查器的 Local Assets 面板中双击资源(树状视图或卡片),会将其作为标签附加到下一条提示词中,紧挨着实体选择项。多项资源和当前选择可以一并附加到一条提示词;发送后或聊天关闭时,提及内容会清除。该资源在本轮中以 [Editor context] 的形式传入,因此:

  • 被提及的文件会以项目相对路径的形式传入,且已存在于场景中——直接引用,不要复制或重新导入。
  • 被提及的内置化身动画会以名称而非路径的形式传入:它没有对应文件。使用 triggerEmote({ predefinedEmote: '<name>' }) 播放(参见 avatar-animations)。寻找对应的 .glb 文件正是此通道旨在避免的错误做法。
  • 标签只是指针,不是指令。即便带有标签,“这个”仍需要一个动词——如果请求含糊不清,请先询问。

规则 — 更改场景图时应使用 MCP;文件只是后备方案

**Creator Hub MCP 可用时,绝不要手动写入 assets/scene/main.composite、main.crdt 或 scene.json。**原因如下,均已在 Creator Hub 源码中验证:

  • 这些文件由编辑器管理。每次自动保存时(任何编辑器事务后约 100 ms),编辑器都会根据内存中的引擎状态完整重新生成 main.composite,且不会重新读取磁盘上的文件。对已打开场景进行的手动编辑会悄无声息地丢失;不会报错。
  • 这些工具会处理文件工作流中需要手动完成的记录工作:inspector::Nodes 注册、core-schema::Name、inspector::TransformConfig、entity-names.ts、实体 ID 分配,以及非核心组件上的 jsonSchema。
  • 用户可以撤销每次更改(Ctrl+Z / 助手的撤销 AI 更改按钮)。文件编辑无法撤销。

决策顺序——选择第一个符合条件的条目:

  1. 工具存在且能正常响应(get_selection 或 get_scene_settings 能返回结果——使用路由到编辑器的工具进行探测,而非 scene_state;即使场景已打开,外部客户端调用 scene_state 也会返回 No scene is open.;参见“注意事项”)→ 所有实体、组件和设置更改都使用这些工具。仅将磁盘上的 composite 作为只读交叉检查。
  2. 工具存在但无法正常工作(No editor window is open.、连接被拒绝、401)→ Creator Hub 已关闭、已重启(URL 和令牌会在每次启动时轮换),或没有打开场景。说明这一点,并请用户在 Creator Hub 中打开场景(或重新复制连接代码片段)。不要悄悄退回到直接编辑文件。
  3. 工具不存在,但用户有 Creator Hub → 告知用户 MCP 是安全的做法,并引导他们查看 reference/connect.md。只有用户拒绝时,才手动编辑文件;且必须先在 Creator Hub 中关闭场景(此时应全面遵循 composites 技能的编辑模式规则)。如果场景已打开或可能处于打开状态,请列出三个选项——关闭场景、连接 MCP,或明确接受在代码中构建静态实体(这些实体在编辑器中不可见)——并等待用户答复;先完成不依赖这些选项的工作。绝不要自行选择代码后备方案,即便是在非交互会话中也不行:在 2026-10-23 的一次会话中,系统没有询问用户,而是在 src/ 中构建了整个房间,结果遭到创作者拒绝。权威规则:sdk-scenes → Agent Behavioral Guidelines,第 5 项。
  4. 不涉及 Creator Hub(仅 CLI 的项目、CI)→ 适用 composites 技能的文件工作流。

仍可直接在文件中编辑的内容:src/**(场景代码;保存后会自动触发重新构建)、assets/Scripts/*.tsx(脚本组件——写入文件后再调用 attach_script),以及你添加到 assets/Models/、assets/Images/ 等目录下的资源文件。 静态几何应由编辑器管理,而不是放在 src/ 中。 墙壁、地板、家具和道具——无论是基础几何体还是 GLB——都应通过这些工具放入场景(create_entity + set_component MeshRenderer / GltfContainer,或 place_smart_item),绝不能在场景代码中调用 engine.addEntity()。用代码构建的房间会在预览中渲染,但在 Hub 的视口和实体树中不可见,也无法选中,创作者的第一个问题就是“我的办公室在哪?”(2026-10-08:需要重做,大约要调用 60 次 set_component)。这是 sdk-scenes 的组合优先规则,通过 MCP 实施。没有 MCP 但场景已打开时也一样:停下来询问(梯级第 3 行)——只有创作者明确选择时,才可以接受用代码构建静态几何体(2026-10-23:一次会话未经询问,就用代码构建了房间、一把椅子和约 60 个道具;创作者说:“未经警告,绝 NEVER 这样做。”)。

保存并不能证明运行中的 bundle 包含了你的改动。 预览的开发服务器(sdk-commands start)会监视 src/**,并在每次保存时重写 bin/index.js(位于 @dcl/sdk-commands 的 logic/bundle.ts)。开发服务器运行时,手动执行 sdk-commands build 也会写入同一个文件,两者会发生竞争;如果恰好在编辑过程中保存,就会打包一半写好的代码(出现 SyntaxError,场景卸载)——unity-explorer-mcp 中的每次改动只写入一次规则同样适用。如果你改动的内容没有显示在游戏世界中,调试场景之前先在 bin/index.js 中用 grep 搜索编辑内容中的字符串字面量;如果找不到,就触碰该文件,并等待下一条 Bundle saved。(2026-10 会话:一个 Agent 声称改动已完成,但过时的 bundle 中根本没有该改动;创作者发现了这一点。)

规则 — 手动构建任何标准对象前,先搜索目录

创建实体并使用 create_entity + set_component 手动组装其组件前,始终先执行 search_catalog,检查目录中是否已有该对象的 Smart Item。尤其适用于:

  • 灯具 — 目录的 lights 类别中有 Spotlight 和 Point Light Smart Item,内含真实 GLB 模型、预配置的 LightSource 组件,以及内置的 Turn On / Turn Off / Toggle 操作。手动创建 LightSource 实体会缺少可视模型、检查器集成和操作连线。
  • 交互式家具 — 门、椅子、平台、箱子、按钮、拉杆等。较新的脚本型物品:Floor Pressure Button(buttons,任何人站在上面时都会按下,默认在玩家之间共享)、Button Pedestal(buttons)、Lab Vault Door / Lab Capsule Door(doors)、Lab Stair Platform(platforms,活塞)、Water Plane / Water Cylinder(materials,玩家进入时产生水花)。
  • 媒体 — 屏幕、图像显示器、NFT 画框。
  • 触发器 — 触发区域、点击触发器。utils 类别中恰好只有一个名为 "Trigger Area"(e9fa0eab-44de-4efe-af77-a71171a1a73f)的条目,这是一个脚本型物品:用户可以放置并调整其大小的不可见方框或球体,带有一个控件,可将描述进入/离开时应发生什么的提示词填入 AI 助手的编辑框。旧的同名非脚本物品(1ab2733f-1782-4521-9eda-6aa8ad684277)和过渡标签 "Trigger Area (Script)" 均已在 creator-hub e43441b5 中移除;不要搜索它们。

place_smart_item 会处理手动调用 set_component 时遗漏的所有样板工作:

  • 下载物品的 GLB 文件,并将 asset-packs::Placeholder 解析为磁盘上的真实路径(例如 assets/asset-packs/spotlight/spotlight.glb)。
  • 设置 asset-packs::Script、asset-packs::Actions 和 inspector::Config 组件,让物品在 Creator Hub UI 中能够正常工作,并支持配置操作和触发器。
  • 自动将实体注册到 inspector::Nodes。

仅在目录中没有符合需求的物品时才手动构建。

如果用户已有媒体文件,请告诉他们将文件从 Local Assets 选项卡拖到视口中。 自 creator-hub 062ed0a2 起,这是最快的方式,并且生成的是指向用户文件的目录物品,而不是裸组件 — 实体会带有与手动放置物品相同的组件集和 basic-view inspector::Config:

拖入的文件生成的物品会重新指向的内容
.png / .jpg / .jpegImage(37460a1e-affc-4f87-b725-118cc11d86fc)Material PBR 纹理的 src;平面还会被抬高 +0.5 m,使其立在地面上,而不是半埋在地里
.mp3 / .ogg / .wavAmbient Sound - Forest Birds(5c8b4646-6ec0-41a0-8e9b-415a58728a9e)AudioSource.audioClipUrl
.mp4Video Screen(0201653b-bd38-48af-b9ef-a902a7e8bc9c)VideoPlayer.src 以及 asset-packs::VideoScreen.defaultURL — 管理员消息总线会在运行时根据 defaultURL 重新设置 src,因此只设置 src 会被悄然还原

实体名称取自文件名(去掉扩展名),并会与现有名称去重;导入时会跳过模板自带的占位媒体文件。.glb / .gltf 仍会作为普通模型拖入。你可以通过工具复现此操作(对同一资产 ID 调用 place_smart_item,然后对上述字段调用 set_component),但拖放只需用户一个动作 — 用户在键盘前时,优先采用这种方式。

工具目录

名称是在 creator-hub 服务(packages/creator-hub/main/src/modules/scene-mcp.ts)上注册的名称。

分组工具功能
读取get_project_info获取 scene.json 元数据(名称、地块、基地区域、生成点)、SDK 版本和依赖项。用于第 0 步确定边界。
读取scene_state已创建实体列表:id、名称、类型、世界变换、组件列表、GLTF src、Smart-Item 标志。最多显示前 200 个实体。
读取entity_detail按 id 或 Name 查看某个实体上的所有组件值。在调用 set_component 前,使用它了解组件的确切结构。
读取get_selection获取编辑器中当前选中的实体。执行操作前,用它解析“这个”/“选中的那个”。Scene 根节点永远不会被报告(creator-hub d25eff1b8):如果只选中了根节点,结果会为空,与未选中任何内容时完全相同。因此,结果为空并不表示用户取消了所有选择,而且“这个”仍可能指整个场景。Player 和 Camera 会正常报告。
读取get_scene_metrics获取实时预算(三角形、实体、物理体、材质、纹理)与场景限制的对比,以及超出边界的实体。
读取editor_screenshot编辑器视口截图(无需预览)。
修改create_entity创建新实体,可选指定 name 和 parent id。返回实体 id。
修改remove_entity删除实体及其子实体。
修改set_parent重新设置父级(保留世界位置)。parent: 0 表示场景根节点。
修改set_component创建或更新组件。component 接受简写(Transform)或完整名称(core::GltfContainer);value 与复合数据存储的 JSON 相同。更新时,传入的键会合并。
修改remove_component按名称移除组件。
资源search_catalog按名称/类别/标签搜索 Creator Hub 资源包目录。虽然名称如此,它同时涵盖静态物品和 Smart Items。省略 query 可列出所有内容。类别包括 buildings(完整建筑,列在 structures 之后)和 materials(Water Plane/Water Cylinder 物品),以及 Avatar Animations 资源包(45 个 _emote.glb 动画片段 + 32 个内置表情名称)——仅文件资源,参见 place_smart_item。这些新增内容也离线收录于 add-3d-models → references/asset-pack-catalog.md 和 avatar-animations → references/animation-catalog.md。**名称、类别、标签和说明文字都是生成的元数据,并非预览:**搜索 "man" 时,search_catalog 会返回 Human(decorations,标签为 man, person, figure, humanoid…,说明文字为 "Human figure in mid-action"),但它的 GLB 实际上是用 3D 字母拼成的单词 HUMAN(packs/cyberpunk/assets/human/Word_Human.glb,creator-hub origin/main 2026-10-19;在 2026-10-12 的会话中被当作角色放置)。放置尚未看过的物品前,请查看其 thumbnail.png——下载后位于 assets/asset-packs/<pkg>/ 下,与 data.json 同目录;或在 creator-hub 仓库的 packages/asset-packs/packs/<pack>/assets/<item>/ 下查看——也可以使用 add-3d-models 中的 GLB 包围盒审计功能。
资源place_smart_item按 assetId 在世界 position 放置目录中的物品(默认为 8,0,8)。将物品文件下载到 assets/asset-packs/<pkg>/ 并生成实体——Smart Items 会自带行为。现在大多数物品都以 asset-packs::Script 代码的形式提供(没有 Triggers);请通过 Script 的参数进行配置,并通过可选的 ActionCallback 参数连接“When X”钩子。参见 script-components。不接受仅文件资源(Avatar Animations 资源包中没有可放置的实体):对于内置表情,错误信息会指出应使用的 triggerEmote({ predefinedEmote }) 调用;对于动画片段,请用户将卡片拖到视口中(会将文件添加到 assets/asset-packs/<pkg>/,但不创建实体),或按照 avatar-animations → references/animation-catalog.md 下载,然后通过代码中的 triggerSceneEmote 播放。
脚本attach_script添加指向文件的 asset-packs::Script 组件。先编写文件(放在 assets/Scripts/ 下),再调用此工具。priority 为可选项。
设置get_scene_settings / set_scene_settings读取/更改 scene.json 字段(名称、描述、类别、标签、年龄分级、生成点、天空盒、地形、layout.parcels、标志)。每个传入字段都会整体替换当前值——请先读取。绝不能向它传入 spawnPoints:它的输入采用 scene.json 格式,会未经转换地写入元数据组件,导致数据层失效或在 scene.json 中写入 "position": {}——请改用 set_component 在实体 0 上写入生成点,参见下方的数据层规则。此工具的输入模式中不包含 thumbnail(thumbnail 键会被静默丢弃)——请用 set_component 在实体 0 的 inspector::SceneMetadata-v* 上设置,或在编辑器的 Scene settings → Thumbnail 中设置;切勿将封面写入 assets/Images/autogenerated-thumbnail.png:参见注意事项。
预览launch_preview、preview_status、stop_preview在启用 MCP 服务的 Decentraland Explorer 中启动/轮询/停止场景。
预览explorer_<name>(动态)、explorer_call预览运行时,Explorer 的运行时工具(explorer_screenshot、explorer_walk、explorer_click_entity、explorer_get_scene_logs,等等)会实时注册;如果这些工具尚未出现,可使用 explorer_call(tool, arguments) 作为备用方式。
聊天ask_user等待 Creator Hub 聊天中显示的问题得到答复。仅在嵌入式助手中有意义。10 分钟无答复后超时,并按关闭处理(packages/creator-hub/main/src/modules/scene-mcp.ts 中的 ASK_TIMEOUT_MS = 10 * 60_000,已在 origin/main 2026-10-15 核实)。超时后,聊天中的提示词也会关闭("This question is no longer active."),之后收到的任何答复都会被丢弃——超时的 ask_user 永远无法事后答复(creator-hub dc9d076be)。如果创作者可能已离开,切勿让工作轮次一直等待它;请改在最终消息中提出问题。

工作流

先阅读,再编写。 使用 get_project_info 获取场景边界(按 composites 技能的步骤 0 精确计算边界——这些工具不会阻止你将实体放在场景之外,而 get_scene_metrics 的安全保障并没有看起来那么可靠——请参阅下文 Bevy 渲染器的注意事项)。使用 scene_state 查看现有内容,避免名称重复。用户请求涉及其所选内容时,使用 get_selection。

添加模型。

  • 目录项 → 使用 search_catalog,然后使用 place_smart_item。文件会自动放入 assets/asset-packs/<pkg>/。
  • 建筑结构(房间、走廊、门道,以及任何 avatar 可以走过或进入的空间)→ 放置前,先按第三人称摄像机的需求确定空间包络尺寸;真实比例的尺寸在场景中会显得局促。相关尺寸见 add-3d-models → “RULE: Scale interiors up for the third-person camera”。
  • 用户已有的模型或你制作的模型 → 将 GLB 放在 assets/Models/ 下(Blender 制作和包围盒检查请参阅 add-3d-models 技能),然后调用 create_entity(带上 name),调用 set_component 设置 Transform({position:{x,y,z}, rotation:{x,y,z,w}, scale:{x,y,z}}),再调用 set_component 设置 core::GltfContainer({src, visibleMeshesCollisionMask, invisibleMeshesCollisionMask}——add-3d-models 中的遮罩规则以及动画/碰撞体检查仍然适用;GLB 包含动画片段时,添加 core::Animator)。
  • 灯光 → 使用类别为 lights 的 search_catalog 查找 Spotlight 和 Point Light Smart Item,然后使用 place_smart_item。这些项目包含灯光模型、LightSource 和切换操作。只有在需要不可见光源或非标准参数时,才手动创建单独的 LightSource 实体——完整的 LightSource API 和 Smart Item 规则请参阅 lighting-environment。
  • 为它添加行为 → 如果有合适的 Smart Item,就使用它(先调用 search_catalog);否则,在 assets/Scripts/ 下编写脚本并调用 attach_script(规则见 script-components),或者在 src/ 代码中按名称引用实体(engine.getEntityOrNullByName)。

组件结构。 set_component 会根据实际架构验证组件。首次写入某种组件前,对已有该组件的任意实体调用 entity_detail,或查阅 composites 格式目录中的对应条目。对于 asset-packs::Script,参数按位置放在 layout 中(见 script-components);优先使用 attach_script,让编辑器生成布局。

写入后。 只要数据层仍在运行,写入后读取就是安全的——服务器会在变更操作返回前等待自动保存完成,因此后续调用 scene_state 获取的是最新状态。进程一旦终止(见下一条规则),这种做法就不再安全;所以应检查磁盘上的数据,而不是工具返回的结果。添加几何体后,检查 get_scene_metrics。editor_screenshot 可在不启动预览的情况下显示结果;需要运行中的场景时,使用 launch_preview + explorer_*(行走、点击、日志、FPS)。unity-explorer-mcp 技能中的迭代循环、摄像机取景和性能参考同样适用于 explorer_* 工具——跳过该技能的 Setup 部分(无需 claude mcp add,也无需 bind gate),因为这些工具由 creator-hub 服务提供。完成后,将摄像机留在场景预期的零售模式下(通常为第三人称,除非场景要求第一人称);如果启动预览只是为了检查,则调用 stop_preview。 如果你无法查看运行时状态,只需说明一次,并标明你无法看到的内容。 从外部客户端看不到 explorer_* 工具,而 unity-explorer-mcp 服务拒绝连接只表示 Explorer 未运行(该技能的 Setup 会启动它)。主动提出帮忙完成设置;在收到截图或创建者确认视觉结果之前,都应报告为未经验证(“屏幕平面现在应该位于边框内——我还没有看到”),绝不能说已经完成。两次针对同一场景的会话(2026-10)中,每个视觉缺陷——屏幕悬浮在显示器前方、门与门框发生穿插、墙面 z-fighting、材质呈白色——都先由所有者发现,因为修复只根据代码就被报告为已完成。

绝不要通过代码固定编辑器实体的位置。 如果场景代码在每次加载时写入编辑器拥有的实体的 Transform,以此“纠正”其位置,就会悄无声息地覆盖创建者随后在 Hub 中进行的所有移动:他们把一个托盘拖到传送带上,但托盘却总是在空中偏移 2 m 后重新出现(所有者报告的症状;原因可在场景自身代码中找到,2026-10-11)。代码可以读取编辑器实体的 Transform;如果需要自行放置实体,就创建一个专属实体。

嵌套实体上的变换是相对于父级的。 Hub 将实体嵌套到组下时,该实体报告的 Transform.position 是相对于该组的位置,而非相对于场景的位置,因此,在用位置进行距离检查或将物体放置在其旁边之前,必须解析完整的父级链(在 assets/scene/main.composite 中发现,2026-10-11——该场景中之所以没有问题,只是因为这些组位于原点)。

错误处理。 撤销由用户操作——告诉他们应撤销什么,或者使用 remove_entity / set_component 恢复之前的值。绝不要通过编辑 main.composite 来“修复”错误。

规则 — 确认一批更改已写入磁盘;数据层可能会悄无声息地崩溃

负责承载编辑器引擎并写入 assets/scene/main.composite 的组件是 @dcl/inspector data layer;在 Bevy 渲染器下,它运行于单独的子进程中——应用会将其记录为 [UtilityProcess] Running "sdk-commands start --port <n> --no-browser --no-client --data-layer"(在 main/src/modules/bevy-realm.ts 中组装;端口是临时分配的,可执行文件位于场景自身的 node_modules/@dcl/sdk-commands)。在 Babylon 渲染器下,同一数据层则运行于 inspector iframe 内。无论哪种情况,Electron 主进程都不会写入 composite,只会读取它。

数据层崩溃后,Electron 应用中的 MCP 服务仍会运行,并且会继续对每次调用作出响应,仿佛一切正常。工具结果中不会有任何提示表明场景已不再变化。

因此,每批修改后都应检查文件,而不是工具: assets/scene/main.composite 的修改时间必须更新(使用 ls -l / stat 检查)。一批修改前后 mtime 没有变化,意味着这些编辑只存在于一个已经消失的进程中。

stat -f '%m %N' "assets/scene/main.composite"   # macOS; coreutils: stat -c '%Y %n'
(Get-Item "assets\scene\main.composite").LastWriteTime   # Windows (PowerShell)

数据层崩溃时的已观察症状(2026-10-08 会话;mtime 未更新时请检查以下症状):

  • set_component、create_entity、place_smart_item 等工具仍会返回成功。
  • scene_state / entity_detail 仍会返回崩溃前的值——回读结果“确认”了你的写入,实际上确认的却是旧快照。
  • editor_screenshot 返回空白图像。
  • get_scene_metrics 返回的值全为零,且 entitiesOutOfBoundaries 为空——但不要把这当作判断依据——在 Bevy 渲染器下,这些字段本来就会被硬编码为零(参见 Gotchas)。mtime 检查才是可靠的判断方法。 恢复操作由用户负责,内存中的编辑会丢失。 没有工具可以重启数据层。停止写入,查看 Creator Hub 主日志(macOS:~/Library/Logs/creator-hub/main.log;Windows:%APPDATA%\creator-hub\logs\main.log),查找 Exiting "sdk-commands start … --data-layer" … exit code=1 这一行——运行 grep -n "exit code=1\|reading 'deserialize'" main.log,不要只粗略浏览:2026-10-08 的会话中,崩溃日志行位于 241 KB 的 grep 结果中,却只读取了开头的 2 KB——告知创作者在 Creator Hub 中关闭并重新打开场景,然后重新应用崩溃后所做的每一项修改——与磁盘上的组合文件进行比较,找出内容从哪里开始不一致。离开编辑器页面也会终止该场景的预览服务(Hub 的 EditorPage 中的 handleBack → killPreview),因此重新打开后,创作者需要再次按下 Play——或者你再次调用 launch_preview——然后才能期待世界中出现任何新内容。

为什么 set_scene_settings + spawnPoints 会杀死数据层或清空位置——请阅读源代码(creator-hub origin/main d25eff1b,2026-10-19;@dcl/ecs main)。 工具的输入架构采用 scene.json 的形式接收 position——x: number | [min, max](main/src/modules/scene-mcp.ts)——而检查器的处理程序会将补丁原样合并到根实体的 inspector::SceneMetadata-v* 组件中({ ...current, ...patch },packages/inspector/src/lib/rpc/scene/server.ts)。该组件的 position.x/y/z 是 Schemas.OneOf({ single, range }),要求采用 { $case: 'single', value: 8 } 或 { $case: 'range', value: [a, b] } 的形式(lib/sdk/components/SceneMetadata.ts)。两种形式之间没有任何转换,因此普通数字会被放进 OneOf 槽位,而 CRDT 序列化器看不到 $case。Hub 自带的检查器运行的是 @dcl/ecs 7.29.0(根目录的 package.json),其 OneOf 序列化器会为没有 $case 的值写入一个空 case(js-sdk-toolchain 0dce4d2d,#1570,随 7.28.0+ 发布)。接下来会发生什么,取决于场景自身 node_modules/@dcl/inspector 中的数据层:如果 @dcl/ecs 低于 7.28.0,其 OneOf 反序列化器无法读取这个空 case(specs[specKeys[0 - 1]] 为 undefined),数据层就会崩溃——这就是 tooling-entrypoint.js 中的 TypeError: Cannot read properties of undefined (reading 'deserialize')(Object.deserialize → updateFromCrdt → receiveMessages)。2026-10-08 使用点值出生点时曾两次出现该错误:Hub 的写入方与场景较旧的读取方存在版本不匹配。使用匹配的 @dcl/ecs 时,写入会保留,但读取结果为 {},数据层的 scene.json 写入器(data-layer/host/utils/component.ts)会输出 "position": {}——2026-10 的 Creator Hub 0.51.0 中曾两次出现这种情况,尽管 get_scene_settings 仍显示格式正确的值。点值和范围值都会受影响;早期版本的本技能中对仅范围值受影响的猜测是错误的。

因此:请用 set_component 在实体 0 上以组件自身的格式写入出生点——使用与 Gotchas 中缩略图相同的路径;从 entity_detail(0) 获取带版本号的组件名称,并只传入 spawnPoints 键:

{"spawnPoints": [{"name": "spawn", "default": true,
  "position": {"x": {"$case": "single", "value": 8}, "y": {"$case": "single", "value": 0}, "z": {"$case": "single", "value": 8}},
  "cameraTarget": {"x": 8, "y": 1, "z": 12}}]}

范围轴的格式为 {"$case": "range", "value": [4, 12]}。然后读取 scene.json(会在下一次自动保存时更新),并检查每个 spawnPoints[].position 中都保存了数字。如果结果是 {},请在 Hub 中关闭场景并手动修复 scene.json:下次打开时,数据层会从 scene.json 重新载入 SceneMetadata(overrideWithSceneJson,data-layer/host/composite-provider.ts),因此手动编辑会生效,并据此刷新组合文件中的副本——场景关闭时编辑的其他场景设置也同样如此。这种格式不匹配是 Hub 的一个 bug;如果当前运行版本仍存在此问题,请通过 report-sdk-issue 进行报告。

预览生命周期——stop_preview 不会关闭 Explorer

stop_preview 按设计不会关闭 Explorer,也没有任何工具可以做到这一点。 已在 main/src/modules/explorer-gateway.ts 中验证:它会关闭 MCP 客户端/传输层,并对 sdk-commands start --explorer-alpha --hub … --mcp --mcp-port <n> 子进程执行 treeKill(日志显示为 [UtilityProcess] Killing process "…"),然后返回 {ok: true}。Explorer 应用不在该进程树中——sdk-commands 通过 open decentraland://… 启动它,将操作交给操作系统后自身退出——Creator Hub 中也没有任何东西会终止它。

preview_status 也不会检测到这一点:running 是根据网关对象是否存在以及同一个 sdk-commands 句柄上的 child.alive() 计算的,而不是通过探测 Explorer 或其端口得出的。因此,“没有正在运行的预览”说的是开发服务器,而不是应用。

接下来启动为何会失败——先说已验证的部分:每次 launch_preview 都会获取一个新的临时 MCP 端口([Gateway] launching preview … with MCP on :53880),并将其作为 --mcp-port 传入;而桌面版 Explorer 只能运行一个实例,因此第二次启动的深层链接会交给已经打开的窗口。推测(并非从 Explorer 源码中直接读取)是,已打开的窗口会继续在旧端口上运行 MCP,且不会绑定新端口。无论实际情况如何,重试约 45 秒后,Hub 都会返回:

预览已启动,但其 MCP 服务始终未响应。Explorer 可能仍在启动,或者此构建不支持 MCP。(TypeError: fetch failed)

并且请注意,这条失败路径也会终止刚启动的开发服务器,使 Explorer 孤立在已关闭的 realm 上。观察记录:2026-10-08,连续启动两次复现了该问题。(相关说明:preview_status 可能会轮询已启动但尚未就绪的 Explorer,最长达 90 秒,因此长时间卡住并不代表崩溃。)

在 launch_preview / preview_status 上出现 Tool call interrupted: the session ended…,是创建者停止了这一轮,而不是预览失败。 这两个工具都会阻塞很久(启动过程会重试 Explorer 的 MCP 约 45 秒,状态轮询最长达 90 秒);在嵌入式助手中,聊天的停止控件会在此期间终止 CLI 子进程(aiStop → killTree,main/src/modules/ai.ts),工具调用随后会报告已中断。2026-10-08 的一次会话中,四次此类中断都分别发生在创建者发送下一条消息时,而 Agent 启动的预览始终在运行。下结论前,先用 pgrep 检查 Explorer 并读取日志——不要像那次会话一样,在项目笔记中写入“launch_preview 会结束会话”。

规则——调用 launch_preview 前,同时检查工具和操作系统:

pgrep -fl '[M]acOS/Explorer'    # the Explorer app itself
pgrep -fl '[d]cl_watchdog'      # its watchdog, from /Applications/Decentraland.app

在这些模式中保留方括号。pgrep -f / pkill -f 会匹配每个进程的完整命令行,而许多 Agent 的 shell 工具会以 bash -c "<command>" 的形式运行命令,因此普通模式也会匹配包装 shell:检查会报告一个实际上并不存在的 Explorer 正在运行,而 pkill 会杀掉运行该命令的 shell。[d]cl_watchdog 仍能匹配真实进程,但不会匹配命令文本本身。

反过来的情况也会发生:创建者关闭 Explorer 窗口后,preview_status 仍会报告 running: true。 sdk-commands 子进程仍在运行,因此句柄仍会报告运行中;与此同时,每次 explorer_* 调用都会失败并返回 fetch failed(观察记录:2026-10-12)。因此,一连串 fetch failed 结果表示“应用已关闭”,而不是“场景有问题”——使用 pgrep -fl '[M]acOS/Explorer' 确认,然后依次调用 stop_preview 和一次 launch_preview 以恢复。两个方向的规则都一样:要确认“Explorer 是否正在运行”,只有 pgrep 能给出可靠答案。

preview_status 显示“未运行”,并不能证明 Explorer 已关闭。如果任一进程仍在运行,而你需要干净的预览,请关闭残留实例,确认它已退出,然后只调用一次 launch_preview:

pkill -f '[d]cl_watchdog'; pkill -f '[D]ecentraland.app/Contents/MacOS/Explorer'
for i in $(seq 1 30); do pgrep -f '[M]acOS/Explorer' >/dev/null || break; sleep 1; done   # wait up to 30 s

在 Windows 上,Explorer 进程名为 Decentraland.exe,看门狗进程名为 dcl_watchdog.exe。在 PowerShell 中运行以下命令(按进程名匹配,因此检查不会匹配运行该命令的 shell):

Get-Process Decentraland, dcl_watchdog -ErrorAction SilentlyContinue        # is either alive?
Stop-Process -Name dcl_watchdog -Force -ErrorAction SilentlyContinue        # watchdog first: it reacts to a non-zero Explorer exit
Stop-Process -Name Decentraland -Force -ErrorAction SilentlyContinue
Wait-Process -Name Decentraland -Timeout 30 -ErrorAction SilentlyContinue   # confirm it exited

该 Explorer 窗口属于创作者,不是测试环境。 你通过 explorer_* 工具执行的所有操作——explorer_move_to、explorer_reload_scene、相机模式更改,以及触发热重载的任何资源文件变动——都会影响创作者正在体验的会话。接管控制前,请检查 explorer_get_player_state 和近期的 explorer_get_scene_logs,确认是否有活动;进行外观检查时,优先使用 explorer_set_camera_pose 而不是 explorer_move_to,并恢复你发现的相机模式。完整规则见 unity-explorer-mcp 技能中的迭代循环(观察于 2026-10-10)。

之后两次尝试都首次连接成功。优先复用健康运行的预览(热重载 + explorer_reload_scene),而不是重启——仅在预览过时或 MCP 始终无响应时才结束进程。如果该 Explorer 窗口属于用户,结束进程前请先征求同意。

重新烘焙的 GLB 在运行中的预览里可能仍显示旧内容。 这不是开发服务器导致的:@dcl/sdk-commands 7.30.1 会在每次内容请求时重新遍历项目,以 no-cache 提供当前字节,根据 mtime 为每个文件的 id 设置版本,并运行一个 Hub 永远不会禁用的 chokidar 监视器——因此,陈旧内容来自下游的 Explorer 自身资源缓存。观察于 2026-10-08:在 launch_preview 之后添加或重命名的 GLB 在游戏内不可见,直到执行 explorer_reload_scene(一个案例)或完整重启预览(另一个案例);而在原路径下覆盖同名 GLB 后,显示的网格仍是旧的。src/ 热重载不受影响。实用规则:重新烘焙模型后,使用新的文件名导出,并更新 GltfContainer.src 指向该文件——这是已确认能可靠重新加载的方式;否则,请执行 explorer_reload_scene,如果旧网格仍存在,则重启预览。(症状:刚导出的网格缺失或明显过时,而 explorer_get_scene_logs 中没有加载错误。另请检查 .dclignore——被忽略的路径根本不会被提供。)

技能的来源

这些技能如何到达 Agent,取决于你使用上述两种设置中的哪一种。

在 Creator Hub 的 AI 助手中,由应用安装这些技能——绝不要手动复制。 安装程序位于 packages/creator-hub/main/src/modules/skills.ts:

  • 它会将 decentraland/sdk-skills 的 main 下载到每位用户的缓存中(以上游提交 SHA 和应用版本为键,采用原子方式替换,并可在离线状态下运行)。
  • 它会将该缓存符号链接到打开的场景中,路径为 .claude/skills 和 .agents/skills。应用创建的链接会添加到 .gitignore。如果用户已有真实的 skills 目录,应用会逐个链接其中的技能,并跳过用户已有的名称。

在这种设置下,不要将技能目录复制到场景中,也不要让用户这样做:手动放置的副本会遮蔽受管理的符号链接,之后便会悄然过时;更新由应用负责。

在外部客户端(Claude Code CLI 或 VS Code 扩展、Cursor、Codex、Claude Desktop 等)中,技能由用户自行安装。 MCP 代码片段只能连接工具,不会一并安装技能。有两种情况:

  • 如果 Creator Hub 当前打开了该场景,场景文件夹中已经存在应用管理的 .claude/skills / .agents/skills 符号链接,因此在该文件夹中启动的 Claude Code 会话会自动加载这些技能。不要重复添加。

  • 否则(工作目录不同、Creator Hub 未打开该场景,或客户端从其他位置读取技能),请从场景文件夹或用户的技能根目录按常规方式安装:

    npx skills add decentraland/sdk-skills --all
    

    重新运行同一命令即可更新;npx skills update 只会刷新已存在的技能,无法获取新添加的技能。请参阅代码库的 README,了解各技能的安装方式。

应用链接的技能集合中包含拒绝名单上的技能。 因此,在已链接到 Hub 的文件夹中启动 Claude Code 会话时,没有 deploy-scene / deploy-worlds(一次 2026-10 会话通过网络搜索查找 Worlds 部署命令,并手动编写了 worldConfiguration)。应为用户安装这些技能,而不是装进符号链接文件夹——运行 npx skills add decentraland/sdk-skills --skill deploy-worlds -g(用户级)——或者走捷径:将 worldConfiguration.name 添加到 scene.json,然后运行 npx @dcl/sdk-commands deploy --target-content https://worlds-content-server.decentraland.org;缩略图、两组名称/描述/缩略图以及错误表均位于 deploy-worlds 中。

Creator Hub Agent 内会刻意将四项技能列入拒绝名单: create-scene、deploy-scene、deploy-worlds、migrate-sdk6-to-sdk7。Creator Hub 通过自己的界面负责搭建和发布,并且仅支持 SDK7。安装程序通过两种方式处理这些技能:

  • 对于包含辅助文件的拒绝名单技能(create-scene、migrate-sdk6-to-sdk7),安装时不包含其 SKILL.md——其他技能仍可通过相对路径访问其 references/,但该技能本身绝不会被触发。
  • 对于目录中只有 SKILL.md 的拒绝名单技能(deploy-scene、deploy-worlds),则会完全跳过。

如果用户在 Creator Hub 中要求搭建项目或发布,请引导他们使用应用自身的流程,而不要尝试加载或重建这些技能。通过外部客户端手动运行 npx skills add 安装时不会应用拒绝名单:这四项技能在外部客户端中均可用。

注意事项

  • Creator Hub 每次启动都会更换 URL 和令牌。 昨天还可用的配置今天会报 ECONNREFUSED 或 401;解决方法是从 Settings 重新复制代码片段,而不是反复重试。

  • 一次只能打开一个项目。 服务针对单个编辑器窗口中打开的场景运行。用户位于场景列表时,变更工具会返回 No editor window is open.。

  • 从外部客户端调用磁盘读取工具和 launch_preview 时会返回 No scene is open.,即使场景明明已打开: 只有在内嵌助手开始一轮对话时(从 main/src/modules/ai.ts 调用 setSceneMcpProject),项目目录才会绑定到 get_project_info / scene_state / entity_detail / launch_preview(从初始版本 creator-hub 217e2f9f、PR #1499 到 origin/main d25eff1b,2026-10-20,行为始终如此)。所有经由编辑器路由的操作(get_selection、get_scene_metrics、get_scene_settings、所有变更操作、place_smart_item)都不受影响。因此,从外部客户端验证访问时,请用 get_selection / get_scene_settings,或执行一个无害的变更,再加上上文的复合文件 mtime 检查——不要用磁盘读取工具验证;只读地从磁盘读取 scene.json 和 assets/scene/main.composite 以获取实体列表;通过工具进行变更;若要在世界中检查,请从 Hub 的 Play 按钮启动预览,勾选 Enable MCP Server,并按照 unity-explorer-mcp 操作(其 Setup 部分适用于此路径——explorer_* 工具不会出现,因为没有请求通过 creator-hub 服务到达)。

  • 读取工具的数据会比引擎晚一个自动保存周期(约 100 ms)。变更工具已经会等待;只有在用户拖动对象的同时你进行读取时才需要注意。

  • Scene RPC "<tool>" timed out (no renderer response) 是 Hub 的 5 秒编辑器 RPC 超时(renderer/src/modules/rpc/scene/client.ts 中的 REQUEST_TIMEOUT_MS),并非崩溃:检查器未能及时响应。2026-10-08 在 Bevy 编辑器处于 Play 状态时,create_entity 曾出现两次此情况;停止 Play 后两次都成功了。请让创作者在批量变更前停止 Play,然后重试——不要改为直接编辑文件。

  • scene_state 最多返回 200 个实体。 对于大型场景,可通过 entity_detail 按名称筛选,或从磁盘读取复合文件。

  • Creator Hub 内的技能拒绝列表。 应用会将 decentraland/sdk-skills 链接到场景中的 .claude/skills / .agents/skills,但会移除 create-scene、deploy-scene、deploy-worlds 和 migrate-sdk6-to-sdk7 的 SKILL.md:在应用中,这些操作分别由自己的流程负责,包括脚手架搭建、发布和 SDK6 迁移。其参考文件仍可供交叉链接解析。

  • Explorer 的 --mcp 预览复选框属于另一个服务。 Enable MCP Server 位于 Play Options 弹出菜单中(编辑器标题栏 Play 按钮上的下拉箭头),悬停在 Desktop Client 行时会打开其飞出菜单。它会启动带有独立 MCP 的 Explorer,端口为 8123(即 unity-explorer-mcp 技能),并且仅当项目使用 @dcl/sdk 7.25.0 或更高版本时才会显示——如果用户找不到此复选框,请先检查场景的 SDK 版本,再排查 Hub。此处介绍的 Creator Hub MCP 是编辑器的服务;在内嵌助手中,请使用它的 launch_preview,而不是该复选框。从外部客户端调用 launch_preview 会失败(见上文 No scene is open. 的注意事项),因此在这种情况下,复选框才是正确的入口。

  • 按一次 Ctrl+Z = 撤销你的一项操作,而不是一次组件写入。 自 creator-hub fdc384b5 起,一整批同步变更会作为一个撤销事务提交(旧版的 200 项操作批次上限曾导致大型变更被拆成多个条目,因此按一次 Ctrl+Z 后会留下孤立实体)。涉及多个实体的操作——例如放置复合 Smart Item,或带子级的脚本化物品——现在都只占一个条目;撤销添加操作也会从 Bevy 视口中移除该实体。仍然请按用户实际撤销时所用的单位描述你的变更。

  • 可以在编辑器中静音场景音频,但仅限 Bevy。 视口工具栏上有一个扬声器切换按钮(Mute scene audio / Unmute scene audio),会将每个 AudioSource / AudioStream 以音量 0 传给渲染器;重新加载后状态仍会保留。Babylon 渲染器下没有此按钮,因为它根本不会播放场景音频。因此,“我听不到你添加的声音”并不能证明组件有误——先检查渲染器和此切换按钮,并注意静音开启时,Bevy 视口不会按你设置的 volume 播放。

  • 在 Bevy 渲染器下,get_scene_metrics 不会返回有用的信息。 已在 packages/inspector/src/lib/renderer/bevy/BevyRenderer.ts 中验证:getSceneMetrics() 返回 {triangles: 0, bodies: 0, materials: 0, textures: 0},getEntitiesOutsideLayout() 返回 [],两者均为硬编码值("No renderer to introspect yet — report zeros")。限制仍然有效;entities 是从 Nodes 树而非渲染器得出的;但内容指标全为零且 entitiesOutOfBoundaries 为空,表示“Bevy”,而不是“场景为空”或“存在问题”——不要据此判断预算状态或实体是否越界。在 Babylon 下,这些数据是真实的:computeEntitiesOutsideLayout 会检查每个实体的包围网格是否位于布局内,因此能够检测到尺寸过大的几何体。无论使用哪个渲染器,如需可靠的预算数据,请运行 launch_preview,并使用 explorer_get_scene_content_stats。

  • [已修复] 使用 Bevy 发布时,过去会丢弃地块布局变更。 由于 Bevy 下的数据层运行在 sdk-commands realm 中,scene.json 写入不会经过 Hub 的存储 RPC,因此 Hub 会保留项目加载时的布局,而发布时会将该旧布局写回——在 Scene settings 中调整大小的场景,发布后会恢复为原始布局(通常是 1x1)。此问题已在 creator-hub ee43befd0(2026 年 10 月)中修复:检查器的 notify_scene_metadata 报告现在会携带 parcels 和 base。get_project_info 会从磁盘读取 scene.json,从未受此问题影响,因此它不是变通方法,也从未出现过此症状。此处仅作说明,以便识别旧版 Hub 构建中的发布异常。

  • 绝不要将自定义缩略图保存为 assets/Images/autogenerated-thumbnail.png。 Hub 每次自动生成缩略图时,都会将视口截图写入这个固定路径,覆盖其中已有的任何文件;发布开始时以及项目卡片刷新时都会触发(packages/creator-hub/preload/src/modules/workspace.ts 中的 getProjectThumbnailPath / saveThumbnail),所以在此处写入的封面会在上传前被替换。它只会在以下三种情况下重写 scene.json 的 display.navmapThumbnail(workspace.ts 中的 saveThumbnail):该字段未设置、指向的文件不存在,或者其值指向大小写不同的自动生成路径。大小写不一致的自定义封面不会被修改——macOS 和 Windows 都能解析,因此只有部署时才会失败。这就是覆盖操作没有任何提示的原因。请将自定义封面保存为其他名称(例如 assets/Images/cover.png),并将场景指向该文件。

  • 图像资源位于 assets/Images/,I 必须大写;部署时大小写会影响结果。 部署文件列表会保留磁盘上的大小写,Catalyst 会区分大小写地将 display.navmapThumbnail 与文件列表匹配。因此,如果 scene.json 写的是 assets/images/...,而磁盘上的文件夹是 assets/Images/,发布时就会出现 Scene thumbnail 'assets/images/autogenerated-thumbnail.png' must be a file included in the deployment。本地不会发现问题:macOS 和 Windows 对两种大小写都能正常解析,所以场景在上传前看起来一切正常。Hub 现在默认将自动生成的缩略图写入 assets/Images/——resolveImagesFolderName 会保留仅大小写不同的现有文件夹,因此已有 assets/images/ 的项目仍会使用小写——并会在下次保存缩略图时重写大小写不一致的自动生成 navmapThumbnail 条目(creator-hub 9d82aac07);但你手动写入的任何路径都必须与实际存在的文件夹大小写一致。设置路径前请用 ls assets 检查,且绝不要新建仅大小写不同的第二个文件夹。set_scene_settings 无法完成此操作(其输入架构中没有 thumbnail 键;MCP SDK 会在编辑器收到数据前移除未知键),但可以用 set_component:通过 entity_detail(0) 读取根实体的 scene-metadata 组件,然后执行 set_component(0, "inspector::SceneMetadata-v5", {thumbnail: "assets/Images/cover.png"})——键会像任何更新一样进行合并,scene.json 中的 display.navmapThumbnail 会在下次自动保存时同步更新(已实时验证;106 个地块和出生点均保留)。请使用读取结果中的确切版本名称,而不要硬编码 -v5:编辑器会绑定到携带数据的版本(resolveActiveSceneComponent),因此使用较旧固定版本 sdk-commands 的场景仍使用 -v4;写入错误版本只会添加一个无人读取的组件。编辑器中的 Scene settings → Thumbnail 字段提供了等效的 UI 操作方式。

  • 大型场景中的 entity_detail(0) 输出巨大——在包含 106 个地块的场景中有 3,335 行 / 79 KB,主要是 inspector::Nodes 和地块列表,大到足以导致工具结果溢出(2026-10-10 观察到)。请将输出重定向到文件,并用 grep 仅筛选所需组件。此外,由于 set_component 会合并顶层键,只写回你更改的键——绝不要将刚读取的整个组件写回。

  • 你生成的缩略图(Blender 渲染、图像工具、截图)必须符合发布规格,之后才能将场景指向它。 发布到 World 时,缩略图超过 1,048,576 bytes 会被拒绝——曾使用普通的 1920x1080 PNG 遇到错误 Invalid thumbnail: size 1185064 bytes exceeds maximum of 1048576 bytes (1MB)。此检查不在 creator-hub 中(仓库中没有任何内容与此错误消息或常量匹配);Worlds 内容服务器会在部署时强制执行,因此编辑器和本地构建都不会提前警告。其余检查由编辑器执行:文件格式为 .png / .jpg,且宽高比必须为 16:9,误差不超过 1 %;建议使用 1920x1080(packages/inspector/src/components/EntityInspector/SceneInspector/utils.ts 中的 getThumbnailWarnings / validateThumbnailFile;Hub 自己截取的图像会居中裁剪为 16:9,且宽度上限为 1920,见 packages/creator-hub/renderer/src/modules/image.ts)。

  • 因此:按 16:9(1920x1080,或文件较小的 1344x756)渲染,优先导出高质量 JPEG,而非 PNG——ffmpeg -i cover.png -q:v 2 cover.jpg 在 1344x756 下生成的文件约为 100 KB;只有 PNG 实际低于上限时才使用。将路径写入场景前,先检查字节大小(ls -l)和尺寸(sips -g pixelWidth -g pixelHeight),不要等发布失败后再检查。请使用不同名称保存,并按上文所述更新场景指向——绝不要使用 assets/Images/autogenerated-thumbnail.png。

  • 每张缩略图都必须适应正方形裁剪:将文字、徽标和主体放在中央正方形区域内。 有些平台只显示 1920x1080 图像的中央 1080x1080 区域,因此两侧各有 (1920 - 1080) / (2 * 1920) ≈ 0.219 的宽度会被裁掉(THUMBNAIL_SAFE_AREA_INSET)。1920 宽的图像中,对应 x 坐标 420–1500;1280 宽的图像中,对应 x 坐标 280–1000。无论你是截取、渲染还是合成图像,都适用此规则。将场景指向该图像前,请先裁剪成正方形并检查效果。不要只看完整画面来判断:在完整画面中从一边延伸到另一边的标题看起来可能没问题(Locksmith,2026-10)。

    OUT="${TMPDIR:-/tmp}/cover-square.png"
    # macOS
    H=$(sips -g pixelHeight cover.png | awk '/pixelHeight/{print $2}'); sips -c $H $H cover.png --out "$OUT"
    # ImageMagick (any OS)
    H=$(magick identify -format %h cover.png); magick cover.png -gravity center -crop ${H}x${H}+0+0 +repage "$OUT"
    

    然后 Read 这张方形图像。文本中的每个词都必须出现在图像中。

  • node / npx 不在 PATH 中,并不意味着无计可施。 Creator Hub 自带完整的 Node(v22,包含 npm 和 npx),并通过它运行每个 sdk-commands 子进程(main/src/modules/node-runtime.ts、scripts/download-node.js):macOS 路径为 /Applications/Decentraland Creator Hub.app/Contents/Resources/node-bin/bin/{node,npm,npx},Windows 路径为 Creator Hub 可执行文件旁边的 resources 文件夹中的 resources\node-bin\node.exe(以及 npm.cmd / npx.cmd),Linux 路径为 resources/node-bin/bin/。对于没有自带 Node 的创作者机器,可以使用绝对路径运行 npx tsc --noEmit、npx skills add decentraland/sdk-skills --all、gltf-transform 等命令。(开发版的 Hub 不包含捆绑的 Node,会使用开发者的 Node。)

  • asset-packs::Placeholder 的 src 需要解析后的文件路径,而不是模板变量。 目录中存储的路径使用 {assetPath}/model.glb 作为模板;通过 set_component 按原样设置该字符串,会生成不可见或损坏的操纵器,因为引擎无法解析该变量。place_smart_item 会自动解析路径(例如解析为 assets/asset-packs/spotlight/spotlight.glb)。如果必须手动设置 Placeholder,请使用 GLB 文件在磁盘上的真实路径。

评论

支持 Markdown