@fps-games/editor 0.1.5-beta.5 → 0.1.7-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/dist/agent-bridge/capabilities/assets.d.ts +8 -0
  2. package/dist/agent-bridge/capabilities/assets.d.ts.map +1 -0
  3. package/dist/agent-bridge/capabilities/assets.js +226 -0
  4. package/dist/agent-bridge/capabilities/assets.js.map +1 -0
  5. package/dist/agent-bridge/capabilities/editor-state.d.ts +5 -0
  6. package/dist/agent-bridge/capabilities/editor-state.d.ts.map +1 -0
  7. package/dist/agent-bridge/capabilities/editor-state.js +72 -0
  8. package/dist/agent-bridge/capabilities/editor-state.js.map +1 -0
  9. package/dist/agent-bridge/capabilities/host-lifecycle.d.ts +4 -0
  10. package/dist/agent-bridge/capabilities/host-lifecycle.d.ts.map +1 -0
  11. package/dist/agent-bridge/capabilities/host-lifecycle.js +87 -0
  12. package/dist/agent-bridge/capabilities/host-lifecycle.js.map +1 -0
  13. package/dist/agent-bridge/capabilities/prefabs.d.ts +5 -0
  14. package/dist/agent-bridge/capabilities/prefabs.d.ts.map +1 -0
  15. package/dist/agent-bridge/capabilities/prefabs.js +735 -0
  16. package/dist/agent-bridge/capabilities/prefabs.js.map +1 -0
  17. package/dist/agent-bridge/capabilities/scene-objects.d.ts +9 -0
  18. package/dist/agent-bridge/capabilities/scene-objects.d.ts.map +1 -0
  19. package/dist/agent-bridge/capabilities/scene-objects.js +394 -0
  20. package/dist/agent-bridge/capabilities/scene-objects.js.map +1 -0
  21. package/dist/agent-bridge/capabilities/selection.d.ts +5 -0
  22. package/dist/agent-bridge/capabilities/selection.d.ts.map +1 -0
  23. package/dist/agent-bridge/capabilities/selection.js +57 -0
  24. package/dist/agent-bridge/capabilities/selection.js.map +1 -0
  25. package/dist/agent-bridge/capabilities/shadows.d.ts +5 -0
  26. package/dist/agent-bridge/capabilities/shadows.d.ts.map +1 -0
  27. package/dist/agent-bridge/capabilities/shadows.js +1876 -0
  28. package/dist/agent-bridge/capabilities/shadows.js.map +1 -0
  29. package/dist/agent-bridge/capabilities/transform.d.ts +5 -0
  30. package/dist/agent-bridge/capabilities/transform.d.ts.map +1 -0
  31. package/dist/agent-bridge/capabilities/transform.js +162 -0
  32. package/dist/agent-bridge/capabilities/transform.js.map +1 -0
  33. package/dist/agent-bridge/capabilities/ui-regions.d.ts +4 -0
  34. package/dist/agent-bridge/capabilities/ui-regions.d.ts.map +1 -0
  35. package/dist/agent-bridge/capabilities/ui-regions.js +168 -0
  36. package/dist/agent-bridge/capabilities/ui-regions.js.map +1 -0
  37. package/dist/agent-bridge/capabilities/viewport.d.ts +5 -0
  38. package/dist/agent-bridge/capabilities/viewport.d.ts.map +1 -0
  39. package/dist/agent-bridge/capabilities/viewport.js +407 -0
  40. package/dist/agent-bridge/capabilities/viewport.js.map +1 -0
  41. package/dist/agent-bridge/capability-sources.d.ts +6 -0
  42. package/dist/agent-bridge/capability-sources.d.ts.map +1 -0
  43. package/dist/agent-bridge/capability-sources.js +26 -0
  44. package/dist/agent-bridge/capability-sources.js.map +1 -0
  45. package/dist/agent-bridge/diagnostics.d.ts +12 -0
  46. package/dist/agent-bridge/diagnostics.d.ts.map +1 -0
  47. package/dist/agent-bridge/diagnostics.js +45 -0
  48. package/dist/agent-bridge/diagnostics.js.map +1 -0
  49. package/dist/agent-bridge/index.d.ts +5 -0
  50. package/dist/agent-bridge/index.d.ts.map +1 -0
  51. package/dist/agent-bridge/index.js +5 -0
  52. package/dist/agent-bridge/index.js.map +1 -0
  53. package/dist/agent-bridge/register.d.ts +4 -0
  54. package/dist/agent-bridge/register.d.ts.map +1 -0
  55. package/dist/agent-bridge/register.js +908 -0
  56. package/dist/agent-bridge/register.js.map +1 -0
  57. package/dist/agent-bridge/shared.d.ts +189 -0
  58. package/dist/agent-bridge/shared.d.ts.map +1 -0
  59. package/dist/agent-bridge/shared.js +39 -0
  60. package/dist/agent-bridge/shared.js.map +1 -0
  61. package/dist/agent-bridge/source-types.d.ts +90 -0
  62. package/dist/agent-bridge/source-types.d.ts.map +1 -0
  63. package/dist/agent-bridge/source-types.js +2 -0
  64. package/dist/agent-bridge/source-types.js.map +1 -0
  65. package/dist/build-info.json +17 -17
  66. package/dist/local-editor-agent-actions.d.ts +8 -1
  67. package/dist/local-editor-agent-actions.d.ts.map +1 -1
  68. package/dist/local-editor-agent-actions.js +171 -12
  69. package/dist/local-editor-agent-actions.js.map +1 -1
  70. package/dist/local-editor-agent-bridge-transport.d.ts +95 -0
  71. package/dist/local-editor-agent-bridge-transport.d.ts.map +1 -0
  72. package/dist/local-editor-agent-bridge-transport.js +340 -0
  73. package/dist/local-editor-agent-bridge-transport.js.map +1 -0
  74. package/dist/local-editor-agent-bridge.d.ts +2 -0
  75. package/dist/local-editor-agent-bridge.d.ts.map +1 -0
  76. package/dist/local-editor-agent-bridge.js +2 -0
  77. package/dist/local-editor-agent-bridge.js.map +1 -0
  78. package/dist/local-editor-agent-context.d.ts +29 -1
  79. package/dist/local-editor-agent-context.d.ts.map +1 -1
  80. package/dist/local-editor-agent-context.js +403 -0
  81. package/dist/local-editor-agent-context.js.map +1 -1
  82. package/dist/local-editor-harness.d.ts +128 -6
  83. package/dist/local-editor-harness.d.ts.map +1 -1
  84. package/dist/local-editor-harness.js +2730 -151
  85. package/dist/local-editor-harness.js.map +1 -1
  86. package/dist/local-editor-marker-graph.d.ts +92 -0
  87. package/dist/local-editor-marker-graph.d.ts.map +1 -0
  88. package/dist/local-editor-marker-graph.js +1432 -0
  89. package/dist/local-editor-marker-graph.js.map +1 -0
  90. package/dist/local-editor-performance-stats.js +1 -1
  91. package/dist/local-editor-performance-stats.js.map +1 -1
  92. package/dist/playable-babylon-facade.d.ts +2 -2
  93. package/dist/playable-babylon-facade.d.ts.map +1 -1
  94. package/dist/playable-babylon-facade.js +1 -1
  95. package/dist/playable-babylon-facade.js.map +1 -1
  96. package/dist/playable-babylon-rendering.js +20 -0
  97. package/dist/playable-babylon-rendering.js.map +1 -1
  98. package/dist/playable-local-editor-host.d.ts +57 -7
  99. package/dist/playable-local-editor-host.d.ts.map +1 -1
  100. package/dist/playable-local-editor-host.js +25 -1
  101. package/dist/playable-local-editor-host.js.map +1 -1
  102. package/dist/playable-sdk.d.ts +4 -2
  103. package/dist/playable-sdk.d.ts.map +1 -1
  104. package/dist/playable-sdk.js +2 -1
  105. package/dist/playable-sdk.js.map +1 -1
  106. package/node_modules/@fps-games/babylon-renderer/dist/shadows/blob-shadow-system.d.ts.map +1 -1
  107. package/node_modules/@fps-games/babylon-renderer/dist/shadows/blob-shadow-system.js +6 -4
  108. package/node_modules/@fps-games/babylon-renderer/dist/shadows/blob-shadow-system.js.map +1 -1
  109. package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-shaders.d.ts.map +1 -1
  110. package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-shaders.js +103 -1
  111. package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-shaders.js.map +1 -1
  112. package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-system.d.ts.map +1 -1
  113. package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-system.js +330 -27
  114. package/node_modules/@fps-games/babylon-renderer/dist/shadows/planar-shadow-system.js.map +1 -1
  115. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.d.ts.map +1 -1
  116. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.js +159 -0
  117. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-artifact-system.js.map +1 -1
  118. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.js +8 -1
  119. package/node_modules/@fps-games/babylon-renderer/dist/shadows/static-projected-shadow-baker.js.map +1 -1
  120. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.d.ts +53 -2
  121. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.d.ts.map +1 -1
  122. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.js +1 -0
  123. package/node_modules/@fps-games/babylon-renderer/dist/shadows/types.js.map +1 -1
  124. package/node_modules/@fps-games/babylon-renderer/package.json +1 -1
  125. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.d.ts.map +1 -1
  126. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js +11 -0
  127. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js.map +1 -1
  128. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts +3 -1
  129. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts.map +1 -1
  130. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js +114 -18
  131. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js.map +1 -1
  132. package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts +1 -0
  133. package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts.map +1 -1
  134. package/node_modules/@fps-games/editor-babylon/dist/editor-world.js +3 -0
  135. package/node_modules/@fps-games/editor-babylon/dist/editor-world.js.map +1 -1
  136. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +3 -0
  137. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -1
  138. package/node_modules/@fps-games/editor-babylon/dist/index.js +3 -0
  139. package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -1
  140. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.d.ts +52 -0
  141. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.d.ts.map +1 -0
  142. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.js +1395 -0
  143. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.js.map +1 -0
  144. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.d.ts.map +1 -1
  145. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js +4 -65
  146. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js.map +1 -1
  147. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.d.ts +28 -0
  148. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.d.ts.map +1 -0
  149. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.js +235 -0
  150. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.js.map +1 -0
  151. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.d.ts +37 -0
  152. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.d.ts.map +1 -0
  153. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.js +451 -0
  154. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.js.map +1 -0
  155. package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.d.ts.map +1 -1
  156. package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.js +14 -3
  157. package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.js.map +1 -1
  158. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.d.ts +1 -0
  159. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.d.ts.map +1 -1
  160. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.js +20 -4
  161. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.js.map +1 -1
  162. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.d.ts +3 -6
  163. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.d.ts.map +1 -1
  164. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.js +4 -37
  165. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.js.map +1 -1
  166. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +74 -1
  167. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
  168. package/node_modules/@fps-games/editor-babylon/dist/projection.js +641 -52
  169. package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
  170. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts +11 -0
  171. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts.map +1 -1
  172. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js +113 -29
  173. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js.map +1 -1
  174. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.d.ts +13 -1
  175. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.d.ts.map +1 -1
  176. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.js +543 -3
  177. package/node_modules/@fps-games/editor-babylon/dist/shadow-preview-controller.js.map +1 -1
  178. package/node_modules/@fps-games/editor-babylon/package.json +5 -5
  179. package/node_modules/@fps-games/editor-browser/dist/index.d.ts +8 -2
  180. package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -1
  181. package/node_modules/@fps-games/editor-browser/dist/index.js +4 -0
  182. package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -1
  183. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.d.ts +5 -0
  184. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.d.ts.map +1 -0
  185. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.js +23 -0
  186. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.js.map +1 -0
  187. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.js +1 -1
  188. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-context-menu.js.map +1 -1
  189. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts.map +1 -1
  190. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js +76 -9
  191. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js.map +1 -1
  192. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.d.ts.map +1 -1
  193. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.js +3 -2
  194. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.js.map +1 -1
  195. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.d.ts +21 -0
  196. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.d.ts.map +1 -0
  197. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.js +75 -0
  198. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-command-adapter.js.map +1 -0
  199. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts +2 -0
  200. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts.map +1 -1
  201. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js +326 -72
  202. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js.map +1 -1
  203. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.d.ts +5 -0
  204. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.d.ts.map +1 -0
  205. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.js +92 -0
  206. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-scope.js.map +1 -0
  207. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts +4 -1
  208. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts.map +1 -1
  209. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js +22 -7
  210. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.js.map +1 -1
  211. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts +4 -0
  212. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts.map +1 -1
  213. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js +24 -11
  214. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js.map +1 -1
  215. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts +1 -1
  216. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts.map +1 -1
  217. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js +7 -0
  218. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js.map +1 -1
  219. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js +1 -1
  220. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js.map +1 -1
  221. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +4 -0
  222. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
  223. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +1471 -29
  224. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
  225. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.d.ts +70 -0
  226. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.d.ts.map +1 -0
  227. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.js +171 -0
  228. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.js.map +1 -0
  229. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts +1 -1
  230. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts.map +1 -1
  231. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js +2 -2
  232. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js.map +1 -1
  233. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts.map +1 -1
  234. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js +9 -2
  235. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js.map +1 -1
  236. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +301 -3
  237. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
  238. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts +12 -1
  239. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts.map +1 -1
  240. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js +13 -1
  241. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js.map +1 -1
  242. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +6 -4
  243. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
  244. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +1501 -122
  245. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
  246. package/node_modules/@fps-games/editor-browser/package.json +3 -3
  247. package/node_modules/@fps-games/editor-core/dist/agent-bridge.d.ts +18 -0
  248. package/node_modules/@fps-games/editor-core/dist/agent-bridge.d.ts.map +1 -0
  249. package/node_modules/@fps-games/editor-core/dist/agent-bridge.js +102 -0
  250. package/node_modules/@fps-games/editor-core/dist/agent-bridge.js.map +1 -0
  251. package/node_modules/@fps-games/editor-core/dist/index.d.ts +1 -0
  252. package/node_modules/@fps-games/editor-core/dist/index.d.ts.map +1 -1
  253. package/node_modules/@fps-games/editor-core/dist/index.js +1 -0
  254. package/node_modules/@fps-games/editor-core/dist/index.js.map +1 -1
  255. package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts +1 -1
  256. package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts.map +1 -1
  257. package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts +3 -1
  258. package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts.map +1 -1
  259. package/node_modules/@fps-games/editor-core/dist/viewport-tools.js +1 -0
  260. package/node_modules/@fps-games/editor-core/dist/viewport-tools.js.map +1 -1
  261. package/node_modules/@fps-games/editor-core/package.json +2 -2
  262. package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
  263. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.d.ts +3 -0
  264. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.d.ts.map +1 -0
  265. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.js +9 -0
  266. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/config.js.map +1 -0
  267. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.d.ts +6 -0
  268. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.d.ts.map +1 -0
  269. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.js +89 -0
  270. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.js.map +1 -0
  271. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.d.ts +18 -0
  272. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.d.ts.map +1 -0
  273. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.js +121 -0
  274. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/identity.js.map +1 -0
  275. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.d.ts +4 -0
  276. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.d.ts.map +1 -0
  277. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.js +3 -0
  278. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.js.map +1 -0
  279. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.d.ts +27 -0
  280. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.d.ts.map +1 -0
  281. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.js +782 -0
  282. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/metadata.js.map +1 -0
  283. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.d.ts +5 -0
  284. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.d.ts.map +1 -0
  285. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.js +5 -0
  286. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/node.js.map +1 -0
  287. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.d.ts +80 -0
  288. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.d.ts.map +1 -0
  289. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.js +600 -0
  290. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/registry.js.map +1 -0
  291. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.d.ts +51 -0
  292. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.d.ts.map +1 -0
  293. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.js +2 -0
  294. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/types.js.map +1 -0
  295. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.d.ts.map +1 -1
  296. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.js +17 -3
  297. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.js.map +1 -1
  298. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.d.ts.map +1 -1
  299. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.js +2 -1
  300. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.js.map +1 -1
  301. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/types.d.ts +3 -2
  302. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/types.d.ts.map +1 -1
  303. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts +1 -1
  304. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts.map +1 -1
  305. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js +48 -20
  306. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js.map +1 -1
  307. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.d.ts +1 -1
  308. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.d.ts.map +1 -1
  309. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.js +1 -1
  310. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.js.map +1 -1
  311. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.d.ts.map +1 -1
  312. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.js +2 -1
  313. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/placement.js.map +1 -1
  314. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/types.d.ts +3 -0
  315. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/types.d.ts.map +1 -1
  316. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts +97 -2
  317. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts.map +1 -1
  318. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js +1143 -8
  319. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js.map +1 -1
  320. package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts +145 -2
  321. package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts.map +1 -1
  322. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.d.ts +1 -1
  323. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.d.ts.map +1 -1
  324. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.js +1 -1
  325. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.js.map +1 -1
  326. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.d.ts.map +1 -1
  327. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js +24 -9
  328. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js.map +1 -1
  329. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.d.ts +6 -0
  330. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.d.ts.map +1 -1
  331. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.js +31 -0
  332. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.js.map +1 -1
  333. package/node_modules/@fps-games/editor-playable-sdk/dist/index.d.ts +3 -0
  334. package/node_modules/@fps-games/editor-playable-sdk/dist/index.d.ts.map +1 -1
  335. package/node_modules/@fps-games/editor-playable-sdk/dist/index.js +3 -0
  336. package/node_modules/@fps-games/editor-playable-sdk/dist/index.js.map +1 -1
  337. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.d.ts +82 -2
  338. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.d.ts.map +1 -1
  339. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.js +396 -22
  340. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/document-sections.js.map +1 -1
  341. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.d.ts +1 -1
  342. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.d.ts.map +1 -1
  343. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.js +1 -1
  344. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/index.js.map +1 -1
  345. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/validation.d.ts.map +1 -1
  346. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/validation.js +0 -3
  347. package/node_modules/@fps-games/editor-playable-sdk/dist/inspector/validation.js.map +1 -1
  348. package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.d.ts +29 -1
  349. package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.d.ts.map +1 -1
  350. package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.js +143 -0
  351. package/node_modules/@fps-games/editor-playable-sdk/dist/lighting-debug/math.js.map +1 -1
  352. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.d.ts.map +1 -1
  353. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js +3 -7
  354. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js.map +1 -1
  355. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.d.ts.map +1 -1
  356. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js +6 -0
  357. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js.map +1 -1
  358. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/types.d.ts +2 -10
  359. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/types.d.ts.map +1 -1
  360. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.d.ts.map +1 -1
  361. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js +107 -11
  362. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js.map +1 -1
  363. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.d.ts.map +1 -1
  364. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.js +4 -1
  365. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/reducer.js.map +1 -1
  366. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/transform.d.ts.map +1 -1
  367. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/transform.js +19 -1
  368. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/transform.js.map +1 -1
  369. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.d.ts.map +1 -1
  370. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js +19 -3
  371. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js.map +1 -1
  372. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.d.ts +1 -2
  373. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.d.ts.map +1 -1
  374. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.js +0 -14
  375. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.js.map +1 -1
  376. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.d.ts +1 -7
  377. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.d.ts.map +1 -1
  378. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.js +3 -32
  379. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/import-plan.js.map +1 -1
  380. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.d.ts.map +1 -1
  381. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js +82 -63
  382. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js.map +1 -1
  383. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts +7 -23
  384. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts.map +1 -1
  385. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.d.ts +5 -0
  386. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.d.ts.map +1 -0
  387. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.js +996 -0
  388. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/compiler.js.map +1 -0
  389. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.d.ts +3 -0
  390. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.d.ts.map +1 -0
  391. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.js +3 -0
  392. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/index.js.map +1 -0
  393. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.d.ts +152 -0
  394. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.d.ts.map +1 -0
  395. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.js +2 -0
  396. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-compiler/types.js.map +1 -0
  397. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.d.ts.map +1 -1
  398. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.js +44 -2
  399. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.js.map +1 -1
  400. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts +1 -0
  401. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts.map +1 -1
  402. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js +244 -12
  403. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js.map +1 -1
  404. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.d.ts.map +1 -1
  405. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js +216 -67
  406. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js.map +1 -1
  407. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.d.ts.map +1 -1
  408. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js +7 -4
  409. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js.map +1 -1
  410. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/patch.d.ts.map +1 -1
  411. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/patch.js +45 -1
  412. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/patch.js.map +1 -1
  413. package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.d.ts.map +1 -1
  414. package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.js +2 -1
  415. package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.js.map +1 -1
  416. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.d.ts +5 -0
  417. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.d.ts.map +1 -0
  418. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.js +5 -0
  419. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/index.js.map +1 -0
  420. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.d.ts +21 -0
  421. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.d.ts.map +1 -0
  422. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.js +158 -0
  423. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/legacy.js.map +1 -0
  424. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.d.ts +5 -0
  425. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.d.ts.map +1 -0
  426. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.js +83 -0
  427. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/quality.js.map +1 -0
  428. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.d.ts +35 -0
  429. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.d.ts.map +1 -0
  430. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.js +363 -0
  431. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/resolver.js.map +1 -0
  432. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.d.ts +105 -0
  433. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.d.ts.map +1 -0
  434. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.js +6 -0
  435. package/node_modules/@fps-games/editor-playable-sdk/dist/shadow-system/types.js.map +1 -0
  436. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.d.ts +3 -0
  437. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.d.ts.map +1 -1
  438. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.js +44 -0
  439. package/node_modules/@fps-games/editor-playable-sdk/dist/static-shadows/artifact.js.map +1 -1
  440. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.d.ts +26 -0
  441. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.d.ts.map +1 -0
  442. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.js +105 -0
  443. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/asset-authoring.js.map +1 -0
  444. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.d.ts +3 -0
  445. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.d.ts.map +1 -1
  446. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.js +3 -0
  447. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.js.map +1 -1
  448. package/node_modules/@fps-games/editor-playable-sdk/package.json +3 -3
  449. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.d.ts +1127 -0
  450. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.d.ts.map +1 -0
  451. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.js +2180 -0
  452. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.js.map +1 -0
  453. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.d.ts +68 -0
  454. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.d.ts.map +1 -0
  455. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.js +23 -0
  456. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.js.map +1 -0
  457. package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts +57 -3
  458. package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts.map +1 -1
  459. package/node_modules/@fps-games/editor-protocol/dist/agent.js.map +1 -1
  460. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts +21 -0
  461. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts.map +1 -1
  462. package/node_modules/@fps-games/editor-protocol/dist/index.js +3 -0
  463. package/node_modules/@fps-games/editor-protocol/dist/index.js.map +1 -1
  464. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.d.ts +128 -0
  465. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.d.ts.map +1 -0
  466. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.js +2 -0
  467. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.js.map +1 -0
  468. package/node_modules/@fps-games/editor-protocol/package.json +1 -1
  469. package/package.json +8 -8
@@ -8,10 +8,10 @@ import { LOCAL_EDITOR_BROWSER_INSPECTOR_VEC3_AXES, resolveLocalEditorBrowserInsp
8
8
  import { DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, DEFAULT_EDITOR_TRANSFORM_TOOL_DESCRIPTORS, } from '@fps-games/editor-core';
9
9
  export { createLocalEditorViewportRevealController, isLocalEditorElementVisibleInViewport, resolveLocalEditorViewportRevealScrollTop, revealLocalEditorElementInViewport, } from './local-editor-ui-dock-panel.js';
10
10
  export { createLocalEditorHierarchyBlankMenu, createLocalEditorHierarchyCopyShortcutAction, createLocalEditorHierarchyDeleteShortcutAction, createLocalEditorHierarchyDuplicateShortcutAction, createLocalEditorHierarchyNodeMenu, createLocalEditorHierarchyPasteShortcutAction, createLocalEditorHierarchySelectAllShortcutAction, } from './local-editor-ui-hierarchy-actions.js';
11
- export { createLocalEditorHierarchyController, } from './local-editor-ui-hierarchy-controller.js';
11
+ export { createLocalEditorHierarchyController, resolveLocalEditorHierarchyCreateMarkerParentId, } from './local-editor-ui-hierarchy-controller.js';
12
12
  export { resolveLocalEditorHierarchySearchRows, } from './local-editor-ui-hierarchy-view.js';
13
13
  export { createLocalEditorHierarchyAttachDialog, resolveLocalEditorHierarchyAttachTargets, } from './local-editor-ui-hierarchy-attach-dialog.js';
14
- export { canLocalEditorHierarchyNodeHaveChildren, createLocalEditorHierarchyTreeModel, isLocalEditorHierarchyNodeSelectable, isLocalEditorHierarchyNodeMovable, } from './local-editor-ui-hierarchy-tree.js';
14
+ export { canLocalEditorHierarchyNodeHaveChildren, canLocalEditorHierarchyNodeDelete, canLocalEditorHierarchyNodeRename, canLocalEditorHierarchyNodeToggleEnabled, createLocalEditorHierarchyTreeModel, isLocalEditorHierarchyNodeSelectable, isLocalEditorHierarchyNodeMovable, } from './local-editor-ui-hierarchy-tree.js';
15
15
  export { createLocalEditorContextMenuController, } from './local-editor-ui-context-menu.js';
16
16
  export { createLocalEditorTooltipController, } from './local-editor-ui-tooltip.js';
17
17
  import { createLocalEditorWorkbenchInputRouter } from './local-editor-ui-input-router.js';
@@ -22,6 +22,8 @@ import { createShortcutHelpPanel as createLocalEditorShortcutHelpPanel } from '.
22
22
  import { applyLocalEditorTheme, ensureLocalEditorTheme, LOCAL_EDITOR_THEME_CLASS, normalizeLocalEditorThemeName, } from './local-editor-ui-theme.js';
23
23
  import { createDefaultLocalEditorWorkbenchLayout, createLocalEditorWorkbenchLayoutController, createLocalEditorWorkbench, createSceneHeaderToolbar, createWorkbenchPanelContent, } from './local-editor-ui-workbench.js';
24
24
  import { createLocalEditorIcon, isLocalEditorIconName } from './local-editor-ui-icons.js';
25
+ import { resolveLocalEditorBrowserAssetKind, } from './local-editor-ui-asset-kind.js';
26
+ import { createLocalEditorPrefabStageTitle, findLocalEditorPrefabStageStructureItem, formatLocalEditorPrefabStageComparisonPreviewStatus, LOCAL_EDITOR_PREFAB_COMPARISON_COLUMN_WIDTH_PX, resolveLocalEditorRightDockVisibility, resolveLocalEditorPrefabStageComparisonPreviewTone, resolveLocalEditorPrefabStageWorkbenchLayout, resolveLocalEditorPreviewToolSupport, shouldLocalEditorClosePerformanceMonitor, shouldLocalEditorPrefabStageBlockHierarchyShortcut, shouldShowLocalEditorPrefabComparisonColumn, shouldToggleLocalEditorPrefabComparisonShortcut, } from './local-editor-ui-prefab-stage.js';
25
27
  export { applyLocalEditorBrowserInspectorControlBinding, createLocalEditorBrowserInspectorControlRegistry, formatLocalEditorBrowserInspectorNumberValue, formatLocalEditorBrowserInspectorValue, parseLocalEditorBrowserInspectorNumberValue, resolveLocalEditorBrowserInspectorSectionStatus, resolveLocalEditorBrowserInspectorControlRegistration, } from './local-editor-ui-panels.js';
26
28
  export { createLocalEditorBrowserInspectorGroupValueClipboardPayload, createLocalEditorBrowserInspectorVectorCopyPayload, parseLocalEditorBrowserInspectorGroupValueClipboardPayload, } from './local-editor-inspector-clipboard.js';
27
29
  export { LOCAL_EDITOR_BROWSER_INSPECTOR_VEC3_AXES, isLocalEditorBrowserInspectorTransformVectorGroupPath, resolveLocalEditorBrowserInspectorVectorGroupAxisFromPropertyPath, resolveLocalEditorBrowserInspectorVectorGroupPathFromPropertyPath, resolveLocalEditorBrowserInspectorVectorGroupPathFromProperties, } from './local-editor-inspector-groups.js';
@@ -66,8 +68,24 @@ function readInspectorInputValue(input, source) {
66
68
  b: (numeric & 255) / 255,
67
69
  };
68
70
  }
71
+ if (input.dataset.serializedJsonValue === 'true') {
72
+ try {
73
+ const parsed = JSON.parse(input.value);
74
+ return isInspectorSerializedInputValue(parsed) ? parsed : null;
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
69
80
  return input.value;
70
81
  }
82
+ function isInspectorSerializedInputValue(value) {
83
+ return value == null
84
+ || typeof value === 'number'
85
+ || typeof value === 'string'
86
+ || typeof value === 'boolean'
87
+ || (!!value && typeof value === 'object' && !Array.isArray(value));
88
+ }
71
89
  const TRANSFORM_TOOL_ICONS = {
72
90
  select: 'select',
73
91
  move: 'move',
@@ -91,14 +109,24 @@ const PLACEMENT_MODE_DESCRIPTIONS = {
91
109
  const VIEW_PRESET_ICONS = {
92
110
  perspective: 'view-perspective',
93
111
  top: 'view-top',
112
+ bottom: 'view-top',
94
113
  front: 'view-front',
114
+ back: 'view-front',
115
+ left: 'view-right',
95
116
  right: 'view-right',
117
+ iso: 'view-perspective',
118
+ threeQuarterTop: 'view-perspective',
96
119
  };
97
120
  const VIEW_PRESET_TOOLTIPS = {
98
121
  perspective: '透视视图',
99
122
  top: '顶视图 · 自动切换正交',
123
+ bottom: '底视图 · 自动切换正交',
100
124
  front: '前视图 · 自动切换正交',
125
+ back: '后视图 · 自动切换正交',
126
+ left: '左视图 · 自动切换正交',
101
127
  right: '右视图 · 自动切换正交',
128
+ iso: '等距视图 · 自动切换正交',
129
+ threeQuarterTop: '斜 45° 俯视图',
102
130
  };
103
131
  const VIEWPORT_OVERLAY_TOGGLE_LABELS = {
104
132
  bounds: '包围盒',
@@ -152,6 +180,50 @@ function setToolbarButtonTooltip(button, tooltip) {
152
180
  button.dataset.editorTooltip = tooltip;
153
181
  button.setAttribute('aria-label', tooltip);
154
182
  }
183
+ function createAgentBridgeStatusTooltip(status) {
184
+ const label = formatAgentBridgeStatusLabel(status?.status);
185
+ const details = [
186
+ `Agent Bridge:${label}`,
187
+ status?.url ? `URL ${status.url}` : '',
188
+ status?.sessionId ? `Session ${status.sessionId}` : '',
189
+ status ? `Capabilities ${status.capabilityCount}` : '',
190
+ status?.lastError ? `Error ${status.lastError}` : '',
191
+ status?.connectedAt ? `Connected ${status.connectedAt}` : '',
192
+ status?.lastChangedAt ? `Updated ${status.lastChangedAt}` : '',
193
+ ].filter(Boolean);
194
+ return details.join(' · ');
195
+ }
196
+ function formatAgentBridgeStatusLabel(status) {
197
+ switch (status) {
198
+ case 'disabled':
199
+ return '未启用';
200
+ case 'connecting':
201
+ return '连接中';
202
+ case 'connected':
203
+ return '已连接';
204
+ case 'disconnected':
205
+ return '已断开';
206
+ case 'error':
207
+ return '错误';
208
+ default:
209
+ return '未知';
210
+ }
211
+ }
212
+ function resolveAgentBridgeStatusToneColor(status) {
213
+ switch (status?.status) {
214
+ case 'connected':
215
+ return 'var(--fps-editor-success)';
216
+ case 'connecting':
217
+ return 'var(--fps-editor-accent-strong)';
218
+ case 'disconnected':
219
+ return 'var(--fps-editor-warn)';
220
+ case 'error':
221
+ return 'var(--fps-editor-danger-strong)';
222
+ case 'disabled':
223
+ default:
224
+ return 'var(--fps-editor-muted)';
225
+ }
226
+ }
155
227
  function setToolbarButtonIcon(doc, button, icon) {
156
228
  const currentIcon = button.querySelector('[data-editor-icon]');
157
229
  if (currentIcon?.dataset.editorIcon === icon)
@@ -206,7 +278,8 @@ function createInspectorPropertyInputs(input, source, lockedVectorGroups) {
206
278
  if (!propertyInput)
207
279
  return null;
208
280
  const groupPath = resolveLocalEditorBrowserInspectorVectorGroupPathFromPropertyPath(propertyInput.path);
209
- if (!groupPath || !lockedVectorGroups.has(groupPath))
281
+ const forceVectorLock = input.dataset.serializedForceVectorLock === 'true';
282
+ if (!groupPath || (!forceVectorLock && !lockedVectorGroups.has(groupPath)))
210
283
  return [propertyInput];
211
284
  if (propertyInput.control !== 'number' || propertyInput.valueType !== 'number')
212
285
  return [propertyInput];
@@ -352,6 +425,33 @@ function createRenderingActionInput(button) {
352
425
  ...(params ? { params } : {}),
353
426
  };
354
427
  }
428
+ function createInspectorActionInput(button) {
429
+ const actionId = button.dataset.editorInspectorAction;
430
+ if (!actionId)
431
+ return null;
432
+ const params = parseRenderingActionParams(button.dataset.editorInspectorActionParams);
433
+ const targetIds = parseInspectorActionTargetIds(button.dataset.editorInspectorActionTargetIds);
434
+ return {
435
+ actionId,
436
+ targetId: button.dataset.editorInspectorActionTargetId || null,
437
+ targetIds,
438
+ path: button.dataset.editorInspectorActionPath,
439
+ ...(params ? { params } : {}),
440
+ };
441
+ }
442
+ function parseInspectorActionTargetIds(value) {
443
+ if (!value)
444
+ return undefined;
445
+ try {
446
+ const parsed = JSON.parse(value);
447
+ return Array.isArray(parsed) && parsed.every(item => typeof item === 'string')
448
+ ? parsed
449
+ : undefined;
450
+ }
451
+ catch {
452
+ return undefined;
453
+ }
454
+ }
355
455
  function parseRenderingActionParams(value) {
356
456
  if (!value)
357
457
  return null;
@@ -371,7 +471,40 @@ function readInspectorCommitMode(input) {
371
471
  function readRenderingCommitMode(input) {
372
472
  return input.dataset.renderingCommitMode ?? 'live';
373
473
  }
474
+ function isLocalEditorRightDockTab(value) {
475
+ return value === 'inspector' || value === 'rendering' || value === 'markers';
476
+ }
374
477
  function resolveLocalEditorRightDockContentKey(state, tab, inspectorFilter) {
478
+ if (tab === 'markers') {
479
+ const markerPanel = state.markerPanel;
480
+ if (!markerPanel)
481
+ return 'markers:none';
482
+ return [
483
+ 'markers',
484
+ markerPanel.activeMarkerId ?? '',
485
+ markerPanel.markersVisible === false ? 'markers-hidden' : 'markers-visible',
486
+ markerPanel.status ?? '',
487
+ markerPanel.markerTypes.map(markerType => [
488
+ markerType.type,
489
+ markerType.label,
490
+ markerType.kind ?? '',
491
+ markerType.description ?? '',
492
+ markerType.usedByCount ?? 0,
493
+ ].join('=')).join(';'),
494
+ (markerPanel.relations ?? []).map(relation => [
495
+ relation.id,
496
+ relation.type,
497
+ relation.from.kind,
498
+ relation.from.id,
499
+ relation.from.visibility ?? '',
500
+ relation.to.kind,
501
+ relation.to.id,
502
+ relation.to.visibility ?? '',
503
+ relation.selected ? 'selected' : '',
504
+ relation.status ?? '',
505
+ ].join('=')).join(';'),
506
+ ].join(':');
507
+ }
375
508
  if (tab === 'rendering') {
376
509
  const rendering = state.renderingPanel;
377
510
  if (!rendering)
@@ -396,20 +529,22 @@ function resolveLocalEditorRightDockContentKey(state, tab, inspectorFilter) {
396
529
  inspectorFilter,
397
530
  ].join(':');
398
531
  }
399
- function findLocalEditorRightDockScrollViewport(tab, inspectorPanel, renderingPanel) {
400
- const panel = tab === 'inspector' ? inspectorPanel : renderingPanel;
532
+ function findLocalEditorRightDockScrollViewport(tab, inspectorPanel, renderingPanel, markersPanel) {
533
+ const panel = tab === 'inspector' ? inspectorPanel : tab === 'rendering' ? renderingPanel : markersPanel;
401
534
  const selector = tab === 'inspector'
402
535
  ? '[data-editor-inspector-scroll-viewport]'
403
- : '[data-editor-rendering-scroll-viewport]';
536
+ : tab === 'rendering'
537
+ ? '[data-editor-rendering-scroll-viewport]'
538
+ : '[data-editor-markers-scroll-viewport]';
404
539
  return panel.querySelector(selector) ?? panel;
405
540
  }
406
- function captureLocalEditorRightDockScrollSnapshot(state, tab, inspectorFilter, inspectorPanel, renderingPanel) {
541
+ function captureLocalEditorRightDockScrollSnapshot(state, tab, inspectorFilter, inspectorPanel, renderingPanel, markersPanel) {
407
542
  if (!state || state.mode !== 'editor')
408
543
  return null;
409
- const viewport = findLocalEditorRightDockScrollViewport(tab, inspectorPanel, renderingPanel);
544
+ const viewport = findLocalEditorRightDockScrollViewport(tab, inspectorPanel, renderingPanel, markersPanel);
410
545
  if (!viewport)
411
546
  return null;
412
- const panel = tab === 'inspector' ? inspectorPanel : renderingPanel;
547
+ const panel = tab === 'inspector' ? inspectorPanel : tab === 'rendering' ? renderingPanel : markersPanel;
413
548
  return {
414
549
  tab,
415
550
  contentKey: resolveLocalEditorRightDockContentKey(state, tab, inspectorFilter),
@@ -418,15 +553,15 @@ function captureLocalEditorRightDockScrollSnapshot(state, tab, inspectorFilter,
418
553
  scrollTop: viewport.scrollTop,
419
554
  };
420
555
  }
421
- function restoreLocalEditorRightDockScrollSnapshot(snapshot, state, tab, inspectorFilter, inspectorPanel, renderingPanel) {
556
+ function restoreLocalEditorRightDockScrollSnapshot(snapshot, state, tab, inspectorFilter, inspectorPanel, renderingPanel, markersPanel) {
422
557
  if (!snapshot || snapshot.tab !== tab || state.mode !== 'editor')
423
558
  return;
424
- const panel = tab === 'inspector' ? inspectorPanel : renderingPanel;
559
+ const panel = tab === 'inspector' ? inspectorPanel : tab === 'rendering' ? renderingPanel : markersPanel;
425
560
  if ((panel.dataset.editorPanelId ?? tab) !== snapshot.panelId)
426
561
  return;
427
562
  if (resolveLocalEditorRightDockContentKey(state, tab, inspectorFilter) !== snapshot.contentKey)
428
563
  return;
429
- const viewport = findLocalEditorRightDockScrollViewport(tab, inspectorPanel, renderingPanel);
564
+ const viewport = findLocalEditorRightDockScrollViewport(tab, inspectorPanel, renderingPanel, markersPanel);
430
565
  if (!viewport)
431
566
  return;
432
567
  viewport.scrollLeft = snapshot.scrollLeft;
@@ -455,6 +590,132 @@ function readRenderingImmediateSource(input) {
455
590
  return 'list';
456
591
  return 'input';
457
592
  }
593
+ function createMarkerTypeActionInput(button) {
594
+ const action = button.dataset.editorMarkerTypeAction;
595
+ if (action === 'create') {
596
+ const block = button.closest('[data-editor-marker-type-create]');
597
+ if (!block)
598
+ return null;
599
+ const type = readMarkerTypeFieldValue(block, 'type');
600
+ if (!type)
601
+ return null;
602
+ const label = readMarkerTypeFieldValue(block, 'label') || type;
603
+ return {
604
+ action: 'create',
605
+ type,
606
+ label,
607
+ kind: readMarkerTypeFieldValue(block, 'kind') || undefined,
608
+ description: readMarkerTypeFieldValue(block, 'description') || undefined,
609
+ };
610
+ }
611
+ const row = button.closest('[data-editor-marker-type-row]');
612
+ const type = row?.dataset.editorMarkerTypeRow?.trim() ?? '';
613
+ if (!row || !type)
614
+ return null;
615
+ if (action === 'delete')
616
+ return { action: 'delete', type };
617
+ if (action !== 'update')
618
+ return null;
619
+ return {
620
+ action: 'update',
621
+ type,
622
+ label: readMarkerTypeFieldValue(row, 'label') || type,
623
+ kind: readMarkerTypeFieldValue(row, 'kind') || undefined,
624
+ description: readMarkerTypeFieldValue(row, 'description'),
625
+ };
626
+ }
627
+ function createMarkerRelationActionInput(target) {
628
+ const action = target.dataset.editorMarkerRelationAction;
629
+ if (action === 'delete') {
630
+ const row = target.closest('[data-editor-marker-relation-row]');
631
+ const relationId = row?.dataset.editorMarkerRelationRow?.trim() ?? '';
632
+ return relationId ? { action: 'delete', relationId } : null;
633
+ }
634
+ if (action === 'reverse') {
635
+ const row = target.closest('[data-editor-marker-relation-row]');
636
+ const relationId = row?.dataset.editorMarkerRelationRow?.trim() ?? '';
637
+ return relationId ? { action: 'reverse', relationId } : null;
638
+ }
639
+ if (action === 'delete-connected') {
640
+ const markerId = target.dataset.editorMarkerRelationMarkerId?.trim() ?? '';
641
+ return { action: 'delete-connected', ...(markerId ? { markerId } : {}) };
642
+ }
643
+ if (action === 'select') {
644
+ const row = target.closest('[data-editor-marker-relation-row]');
645
+ const relationId = row?.dataset.editorMarkerRelationRow?.trim() ?? '';
646
+ return relationId ? { action: 'select', relationId } : null;
647
+ }
648
+ if (action === 'pick-cancel')
649
+ return { action: 'pick-cancel' };
650
+ if (action !== 'create' && action !== 'pick-start')
651
+ return null;
652
+ const block = target.closest('[data-editor-marker-relation-create]');
653
+ if (!block)
654
+ return null;
655
+ const type = readMarkerRelationTypeFieldValue(block);
656
+ const from = readMarkerRelationEndpointFieldValue(block, 'from');
657
+ const to = readMarkerRelationEndpointFieldValue(block, 'to');
658
+ if (!type || !from || (action === 'create' && !to))
659
+ return null;
660
+ const directed = readMarkerRelationDirectionFieldValue(block);
661
+ if (action === 'pick-start') {
662
+ return {
663
+ action: 'pick-start',
664
+ type,
665
+ fromKind: from.kind,
666
+ fromId: from.id,
667
+ ...(directed === null ? {} : { directed }),
668
+ };
669
+ }
670
+ return {
671
+ action: 'create',
672
+ type,
673
+ fromKind: from.kind,
674
+ fromId: from.id,
675
+ toKind: to.kind,
676
+ toId: to.id,
677
+ ...(directed === null ? {} : { directed }),
678
+ };
679
+ }
680
+ function readMarkerTypeFieldValue(parent, field) {
681
+ const input = parent.querySelector(`[data-editor-marker-type-field="${field}"]`);
682
+ return input?.value.trim() ?? '';
683
+ }
684
+ function readMarkerRelationTypeFieldValue(parent) {
685
+ const select = parent.querySelector('[data-editor-marker-relation-field="type"]');
686
+ return select?.value.trim() ?? '';
687
+ }
688
+ function readMarkerRelationDirectionFieldValue(parent) {
689
+ const select = parent.querySelector('[data-editor-marker-relation-field="directed"]');
690
+ if (!select || select.value === 'default')
691
+ return null;
692
+ return select.value === 'true';
693
+ }
694
+ function readMarkerRelationEndpointFieldValue(parent, field) {
695
+ const select = parent.querySelector(`[data-editor-marker-relation-field="${field}"]`);
696
+ const option = select?.selectedOptions.item(0) ?? null;
697
+ const kind = option?.dataset.editorMarkerRelationEndpointKind?.trim();
698
+ const id = option?.dataset.editorMarkerRelationEndpointId?.trim();
699
+ if (kind && id)
700
+ return { kind, id };
701
+ return decodeMarkerRelationEndpointValue(select?.value);
702
+ }
703
+ function decodeMarkerRelationEndpointValue(value) {
704
+ const raw = value?.trim();
705
+ if (!raw)
706
+ return null;
707
+ const separator = raw.indexOf(':');
708
+ if (separator <= 0)
709
+ return null;
710
+ const kind = raw.slice(0, separator);
711
+ const encodedId = raw.slice(separator + 1);
712
+ try {
713
+ return { kind, id: decodeURIComponent(encodedId) };
714
+ }
715
+ catch {
716
+ return { kind, id: encodedId };
717
+ }
718
+ }
458
719
  function markLocalEditorKeyboardCommittedValue(input) {
459
720
  input.dataset.editorKeyboardCommittedValue = input.value;
460
721
  }
@@ -764,6 +1025,50 @@ const PERFORMANCE_MONITOR_METRIC_GROUPS = [
764
1025
  ],
765
1026
  },
766
1027
  ];
1028
+ const PREFAB_IMPORT_STATS_METRICS = [
1029
+ {
1030
+ key: 'source',
1031
+ label: 'Source',
1032
+ description: '当前 prefab preview 使用的 source model 或 source url。',
1033
+ format: stats => stats?.sourceId ?? stats?.assetId ?? '--',
1034
+ },
1035
+ {
1036
+ key: 'nodes',
1037
+ label: 'Nodes',
1038
+ description: 'Babylon 导入后 runtime snapshot 中的节点总数,包含虚拟 root。',
1039
+ format: stats => formatPerformanceInteger(stats?.nodeCount ?? null),
1040
+ },
1041
+ {
1042
+ key: 'transforms',
1043
+ label: 'Transforms',
1044
+ description: 'runtime snapshot 中 root/transform 节点数量。',
1045
+ format: stats => formatPerformanceInteger(stats?.transformCount ?? null),
1046
+ },
1047
+ {
1048
+ key: 'meshes',
1049
+ label: 'Meshes',
1050
+ description: 'runtime snapshot 中可渲染 mesh 节点数量。',
1051
+ format: stats => formatPerformanceInteger(stats?.meshCount ?? null),
1052
+ },
1053
+ {
1054
+ key: 'materials',
1055
+ label: 'Materials',
1056
+ description: 'runtime snapshot 关联到的材质数量。',
1057
+ format: stats => formatPerformanceInteger(stats?.materialCount ?? null),
1058
+ },
1059
+ {
1060
+ key: 'textures',
1061
+ label: 'Textures',
1062
+ description: 'runtime snapshot 关联到的贴图数量。',
1063
+ format: stats => formatPerformanceInteger(stats?.textureCount ?? null),
1064
+ },
1065
+ {
1066
+ key: 'animations',
1067
+ label: 'Animations',
1068
+ description: 'runtime snapshot 关联到的 animation group 数量。',
1069
+ format: stats => formatPerformanceInteger(stats?.animationCount ?? null),
1070
+ },
1071
+ ];
767
1072
  function createSceneFrameRateOverlay(doc) {
768
1073
  const root = doc.createElement('div');
769
1074
  root.classList.add(LOCAL_EDITOR_THEME_CLASS);
@@ -982,6 +1287,359 @@ function renderPerformanceMonitorOverlay(overlay, stats, open) {
982
1287
  stats?.activeReasons.length ? `active: ${stats.activeReasons.join(', ')}` : '',
983
1288
  ].filter(Boolean).join(' | ');
984
1289
  }
1290
+ function createPrefabImportStatsOverlay(doc) {
1291
+ const root = doc.createElement('section');
1292
+ root.classList.add(LOCAL_EDITOR_THEME_CLASS);
1293
+ root.dataset.editorPrefabImportStatsOverlay = 'true';
1294
+ root.setAttribute('aria-label', 'Prefab import diagnostics');
1295
+ root.style.cssText = [
1296
+ 'display:none',
1297
+ 'width:236px',
1298
+ 'max-width:100%',
1299
+ 'box-sizing:border-box',
1300
+ 'padding:10px',
1301
+ 'border:1px solid color-mix(in srgb, var(--fps-editor-border) 78%, transparent)',
1302
+ 'border-radius:6px',
1303
+ 'background:color-mix(in srgb, var(--fps-editor-chrome) 88%, transparent)',
1304
+ 'box-shadow:var(--fps-editor-shadow-panel)',
1305
+ 'backdrop-filter:blur(6px)',
1306
+ 'font-family:var(--fps-editor-font)',
1307
+ 'font-size:11px',
1308
+ 'font-weight:800',
1309
+ 'color:var(--fps-editor-text)',
1310
+ 'pointer-events:auto',
1311
+ ].join(';');
1312
+ const header = doc.createElement('div');
1313
+ header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;';
1314
+ const title = doc.createElement('div');
1315
+ title.textContent = 'Prefab Import';
1316
+ title.style.cssText = 'min-width:0;color:var(--fps-editor-text-strong);font-size:12px;font-weight:900;line-height:1.2;';
1317
+ const modeLabel = doc.createElement('span');
1318
+ modeLabel.textContent = 'MISSING';
1319
+ modeLabel.style.cssText = [
1320
+ 'flex:0 0 auto',
1321
+ 'padding:2px 5px',
1322
+ 'border:1px solid var(--fps-editor-border-soft)',
1323
+ 'border-radius:4px',
1324
+ 'background:color-mix(in srgb, var(--fps-editor-field) 72%, transparent)',
1325
+ 'color:var(--fps-editor-muted)',
1326
+ 'font-size:9px',
1327
+ 'line-height:1',
1328
+ 'font-weight:900',
1329
+ ].join(';');
1330
+ header.append(title, modeLabel);
1331
+ const grid = doc.createElement('div');
1332
+ grid.style.cssText = [
1333
+ 'display:grid',
1334
+ 'grid-template-columns:minmax(0,1fr) minmax(76px,108px)',
1335
+ 'gap:5px 10px',
1336
+ 'align-items:center',
1337
+ ].join(';');
1338
+ const values = {};
1339
+ for (const metric of PREFAB_IMPORT_STATS_METRICS) {
1340
+ const rowLabel = doc.createElement('span');
1341
+ rowLabel.textContent = metric.label;
1342
+ rowLabel.title = metric.description;
1343
+ rowLabel.setAttribute('aria-label', `${metric.label}: ${metric.description}`);
1344
+ rowLabel.style.cssText = [
1345
+ 'min-width:0',
1346
+ 'overflow:hidden',
1347
+ 'text-overflow:ellipsis',
1348
+ 'white-space:nowrap',
1349
+ 'color:var(--fps-editor-muted-strong)',
1350
+ 'cursor:help',
1351
+ ].join(';');
1352
+ const value = doc.createElement('span');
1353
+ value.textContent = '--';
1354
+ value.title = metric.description;
1355
+ value.setAttribute('aria-label', `${metric.label}: --。${metric.description}`);
1356
+ value.style.cssText = [
1357
+ 'min-width:0',
1358
+ 'justify-self:end',
1359
+ 'max-width:108px',
1360
+ 'overflow:hidden',
1361
+ 'text-overflow:ellipsis',
1362
+ 'white-space:nowrap',
1363
+ 'font-variant-numeric:tabular-nums',
1364
+ 'color:var(--fps-editor-text-strong)',
1365
+ 'text-align:right',
1366
+ 'cursor:help',
1367
+ ].join(';');
1368
+ values[metric.key] = value;
1369
+ grid.append(rowLabel, value);
1370
+ }
1371
+ root.append(header, grid);
1372
+ return { root, modeLabel, values };
1373
+ }
1374
+ function renderPrefabImportStatsOverlay(overlay, stage) {
1375
+ if (!stage) {
1376
+ overlay.root.style.display = 'none';
1377
+ return;
1378
+ }
1379
+ overlay.root.style.display = 'block';
1380
+ const stats = stage.importStats ?? null;
1381
+ const status = stats?.status ?? (stage.importStructureReady === false ? 'loading' : 'missing');
1382
+ overlay.modeLabel.textContent = formatPrefabImportStatsStatusLabel(status);
1383
+ overlay.modeLabel.style.color = status === 'ready'
1384
+ ? 'var(--fps-editor-success)'
1385
+ : status === 'loading'
1386
+ ? 'var(--fps-editor-warn)'
1387
+ : 'var(--fps-editor-danger-strong)';
1388
+ for (const metric of PREFAB_IMPORT_STATS_METRICS) {
1389
+ const value = metric.format(stats);
1390
+ overlay.values[metric.key].textContent = value;
1391
+ overlay.values[metric.key].title = `${metric.description}\n${value}`;
1392
+ overlay.values[metric.key].setAttribute('aria-label', `${metric.label}: ${value}。${metric.description}`);
1393
+ }
1394
+ overlay.root.title = [
1395
+ `status: ${status}`,
1396
+ stats?.projectionNodeId ? `preview: ${stats.projectionNodeId}` : stage.previewNodeId ? `preview: ${stage.previewNodeId}` : '',
1397
+ stats?.assetId ? `asset: ${stats.assetId}` : '',
1398
+ stats?.sourceId ? `source: ${stats.sourceId}` : '',
1399
+ ].filter(Boolean).join(' | ');
1400
+ }
1401
+ function createPrefabStagePreviewLayout(doc) {
1402
+ const root = doc.createElement('section');
1403
+ root.classList.add(LOCAL_EDITOR_THEME_CLASS);
1404
+ root.dataset.editorPrefabStagePreviewLayout = 'true';
1405
+ root.setAttribute('aria-label', 'Prefab stage preview layout');
1406
+ root.style.cssText = [
1407
+ 'position:absolute',
1408
+ 'left:0',
1409
+ 'right:0',
1410
+ 'top:38px',
1411
+ 'bottom:0',
1412
+ 'z-index:4',
1413
+ 'display:none',
1414
+ 'pointer-events:none',
1415
+ 'overflow:hidden',
1416
+ 'font-family:var(--fps-editor-font)',
1417
+ ].join(';');
1418
+ const mainRegion = doc.createElement('div');
1419
+ mainRegion.dataset.editorPrefabStageMainPreview = 'true';
1420
+ mainRegion.style.cssText = [
1421
+ 'position:absolute',
1422
+ 'left:0',
1423
+ 'top:0',
1424
+ 'bottom:0',
1425
+ 'right:0',
1426
+ 'min-width:0',
1427
+ 'overflow:hidden',
1428
+ 'pointer-events:none',
1429
+ ].join(';');
1430
+ const comparisonColumn = doc.createElement('aside');
1431
+ comparisonColumn.dataset.editorPrefabStageComparisonColumn = 'true';
1432
+ comparisonColumn.setAttribute('aria-label', 'Prefab comparison previews');
1433
+ comparisonColumn.style.cssText = [
1434
+ 'position:absolute',
1435
+ 'top:0',
1436
+ 'right:0',
1437
+ 'bottom:0',
1438
+ `width:${LOCAL_EDITOR_PREFAB_COMPARISON_COLUMN_WIDTH_PX}px`,
1439
+ 'display:none',
1440
+ 'flex-direction:column',
1441
+ 'box-sizing:border-box',
1442
+ 'gap:10px',
1443
+ 'padding:10px',
1444
+ 'border-left:1px solid color-mix(in srgb, var(--fps-editor-divider) 82%, transparent)',
1445
+ 'background:transparent',
1446
+ 'box-shadow:none',
1447
+ 'pointer-events:auto',
1448
+ 'overflow:hidden',
1449
+ ].join(';');
1450
+ root.append(mainRegion, comparisonColumn);
1451
+ return { root, mainRegion, comparisonColumn };
1452
+ }
1453
+ function createPrefabComparisonPreviewOverlay(doc) {
1454
+ const root = doc.createElement('section');
1455
+ root.classList.add(LOCAL_EDITOR_THEME_CLASS);
1456
+ root.dataset.editorPrefabComparisonPreviewOverlay = 'true';
1457
+ root.setAttribute('aria-label', 'Prefab clone and InstanceMesh comparison previews');
1458
+ root.style.cssText = [
1459
+ 'display:none',
1460
+ 'flex:1 1 auto',
1461
+ 'min-height:0',
1462
+ 'width:100%',
1463
+ 'box-sizing:border-box',
1464
+ 'grid-template-rows:minmax(0,1fr) minmax(0,1fr)',
1465
+ 'gap:10px',
1466
+ 'overflow:hidden',
1467
+ 'font-family:var(--fps-editor-font)',
1468
+ 'pointer-events:auto',
1469
+ ].join(';');
1470
+ return { root, cards: new Map() };
1471
+ }
1472
+ function renderPrefabComparisonPreviewOverlay(overlay, stage) {
1473
+ const previews = stage?.comparisonPreviews ?? [];
1474
+ if (!stage || previews.length === 0) {
1475
+ overlay.root.style.display = 'none';
1476
+ return;
1477
+ }
1478
+ overlay.root.style.display = 'grid';
1479
+ const visibleIds = new Set();
1480
+ for (const preview of previews) {
1481
+ const card = getOrCreatePrefabComparisonPreviewCard(overlay, preview);
1482
+ visibleIds.add(preview.id);
1483
+ card.root.style.display = 'flex';
1484
+ card.title.textContent = preview.label;
1485
+ card.statusLabel.textContent = formatLocalEditorPrefabStageComparisonPreviewStatus(preview.status);
1486
+ card.statusLabel.style.color = getPrefabComparisonPreviewStatusColor(preview.status);
1487
+ card.surface.dataset.editorPrefabComparisonPreviewId = preview.id;
1488
+ card.surface.dataset.editorPrefabComparisonPreviewSurface = preview.projectionNodeId;
1489
+ card.surface.dataset.editorPrefabComparisonPreviewStatus = preview.status;
1490
+ card.surface.style.background = preview.status === 'ready'
1491
+ ? 'transparent'
1492
+ : 'color-mix(in srgb, var(--fps-editor-field) 74%, transparent)';
1493
+ card.surface.textContent = preview.status === 'ready'
1494
+ ? ''
1495
+ : preview.status === 'loading'
1496
+ ? 'Preview loading'
1497
+ : 'Preview unavailable';
1498
+ card.root.title = [
1499
+ `${preview.label}: ${preview.status}`,
1500
+ `mode: ${preview.mode}`,
1501
+ `projection: ${preview.projectionNodeId}`,
1502
+ ].join(' | ');
1503
+ }
1504
+ for (const [id, card] of overlay.cards) {
1505
+ if (!visibleIds.has(id))
1506
+ card.root.style.display = 'none';
1507
+ }
1508
+ }
1509
+ function readPrefabComparisonPreviewSurfaces(overlay) {
1510
+ if (overlay.root.style.display === 'none')
1511
+ return [];
1512
+ const surfaces = [];
1513
+ for (const [previewId, card] of overlay.cards) {
1514
+ if (card.root.style.display === 'none')
1515
+ continue;
1516
+ const projectionNodeId = card.surface.dataset.editorPrefabComparisonPreviewSurface;
1517
+ if (!projectionNodeId)
1518
+ continue;
1519
+ const rect = card.surface.getBoundingClientRect();
1520
+ if (rect.width < 1 || rect.height < 1)
1521
+ continue;
1522
+ surfaces.push({
1523
+ previewId,
1524
+ projectionNodeId,
1525
+ element: card.surface,
1526
+ rect,
1527
+ });
1528
+ }
1529
+ return surfaces;
1530
+ }
1531
+ function findPrefabComparisonPreviewSurface(target) {
1532
+ return target instanceof HTMLElement
1533
+ ? target.closest('[data-editor-prefab-comparison-preview-surface]')
1534
+ : null;
1535
+ }
1536
+ function readPrefabComparisonPreviewSurfaceId(surface) {
1537
+ return surface.dataset.editorPrefabComparisonPreviewId
1538
+ ?? surface.closest('[data-editor-prefab-comparison-preview]')?.dataset.editorPrefabComparisonPreview
1539
+ ?? null;
1540
+ }
1541
+ function isPrefabComparisonPreviewSurfaceReady(surface) {
1542
+ return surface.dataset.editorPrefabComparisonPreviewStatus === 'ready';
1543
+ }
1544
+ function getOrCreatePrefabComparisonPreviewCard(overlay, preview) {
1545
+ const existing = overlay.cards.get(preview.id);
1546
+ if (existing)
1547
+ return existing;
1548
+ const doc = overlay.root.ownerDocument;
1549
+ const root = doc.createElement('article');
1550
+ root.dataset.editorPrefabComparisonPreview = preview.id;
1551
+ root.style.cssText = [
1552
+ 'display:flex',
1553
+ 'flex-direction:column',
1554
+ 'min-width:0',
1555
+ 'min-height:0',
1556
+ 'flex:1 1 0',
1557
+ 'box-sizing:border-box',
1558
+ 'padding:8px',
1559
+ 'border:1px solid color-mix(in srgb, var(--fps-editor-border) 78%, transparent)',
1560
+ 'border-radius:6px',
1561
+ 'background:transparent',
1562
+ 'box-shadow:none',
1563
+ 'color:var(--fps-editor-text)',
1564
+ 'pointer-events:auto',
1565
+ 'overflow:hidden',
1566
+ ].join(';');
1567
+ const header = doc.createElement('div');
1568
+ header.style.cssText = [
1569
+ 'display:flex',
1570
+ 'align-items:center',
1571
+ 'justify-content:space-between',
1572
+ 'gap:8px',
1573
+ 'margin-bottom:7px',
1574
+ 'padding:6px 8px',
1575
+ 'border:1px solid color-mix(in srgb, var(--fps-editor-border) 74%, transparent)',
1576
+ 'border-radius:5px',
1577
+ 'background:color-mix(in srgb, var(--fps-editor-chrome) 86%, transparent)',
1578
+ 'box-shadow:0 6px 14px color-mix(in srgb, #000 18%, transparent)',
1579
+ ].join(';');
1580
+ const title = doc.createElement('div');
1581
+ title.textContent = preview.label;
1582
+ title.style.cssText = [
1583
+ 'min-width:0',
1584
+ 'overflow:hidden',
1585
+ 'text-overflow:ellipsis',
1586
+ 'white-space:nowrap',
1587
+ 'color:var(--fps-editor-text-strong)',
1588
+ 'font-size:12px',
1589
+ 'line-height:1.2',
1590
+ 'font-weight:900',
1591
+ ].join(';');
1592
+ const statusLabel = doc.createElement('span');
1593
+ statusLabel.textContent = 'UNAVAILABLE';
1594
+ statusLabel.style.cssText = [
1595
+ 'flex:0 0 auto',
1596
+ 'padding:2px 5px',
1597
+ 'border:1px solid var(--fps-editor-border-soft)',
1598
+ 'border-radius:4px',
1599
+ 'background:color-mix(in srgb, var(--fps-editor-field) 72%, transparent)',
1600
+ 'font-size:9px',
1601
+ 'line-height:1',
1602
+ 'font-weight:900',
1603
+ ].join(';');
1604
+ header.append(title, statusLabel);
1605
+ const surface = doc.createElement('div');
1606
+ surface.style.cssText = [
1607
+ 'display:flex',
1608
+ 'flex:1 1 auto',
1609
+ 'align-items:center',
1610
+ 'justify-content:center',
1611
+ 'width:100%',
1612
+ 'min-height:0',
1613
+ 'box-sizing:border-box',
1614
+ 'border:1px solid color-mix(in srgb, var(--fps-editor-border-soft) 84%, transparent)',
1615
+ 'border-radius:4px',
1616
+ 'background:transparent',
1617
+ 'overflow:hidden',
1618
+ 'color:var(--fps-editor-muted)',
1619
+ 'font-size:10px',
1620
+ 'font-weight:800',
1621
+ 'text-align:center',
1622
+ 'touch-action:none',
1623
+ 'user-select:none',
1624
+ 'cursor:grab',
1625
+ ].join(';');
1626
+ root.append(header, surface);
1627
+ overlay.root.appendChild(root);
1628
+ const card = { root, title, statusLabel, surface };
1629
+ overlay.cards.set(preview.id, card);
1630
+ return card;
1631
+ }
1632
+ function getPrefabComparisonPreviewStatusColor(status) {
1633
+ const tone = resolveLocalEditorPrefabStageComparisonPreviewTone(status);
1634
+ return tone === 'success'
1635
+ ? 'var(--fps-editor-success)'
1636
+ : tone === 'warning'
1637
+ ? 'var(--fps-editor-warn)'
1638
+ : 'var(--fps-editor-danger-strong)';
1639
+ }
1640
+ function formatPrefabImportStatsStatusLabel(status) {
1641
+ return status === 'ready' ? 'READY' : status === 'loading' ? 'LOADING' : 'MISSING';
1642
+ }
985
1643
  function formatPerformanceInteger(value) {
986
1644
  return typeof value === 'number' && Number.isFinite(value) ? String(Math.round(value)) : '--';
987
1645
  }
@@ -1413,12 +2071,13 @@ function formatSvgNumber(value) {
1413
2071
  return Number.isFinite(value) ? value.toFixed(2) : '0';
1414
2072
  }
1415
2073
  function isLocalEditorAssetBrowserTab(value) {
1416
- return value === 'all' || value === 'models' || value === 'materials' || value === 'textures';
2074
+ return value === 'all' || value === 'models' || value === 'prefabs' || value === 'materials' || value === 'textures';
1417
2075
  }
1418
- function createAssetBrowserMenuItems(state, asset) {
1419
- const assetKind = resolveBrowserAssetKind(asset);
2076
+ export function createAssetBrowserMenuItems(state, asset) {
2077
+ const assetKind = resolveLocalEditorBrowserAssetKind(asset);
1420
2078
  const placeable = asset.placeable !== false && asset.disabled !== true;
1421
2079
  const activeId = state.activeId;
2080
+ const inPrefabStage = !!state.prefabStage;
1422
2081
  const items = [];
1423
2082
  if (assetKind === 'material') {
1424
2083
  const deleteDisabledReason = getMaterialAssetDeleteDisabledReason(asset);
@@ -1449,6 +2108,35 @@ function createAssetBrowserMenuItems(state, asset) {
1449
2108
  label: '查看贴图预览',
1450
2109
  });
1451
2110
  }
2111
+ else if (assetKind === 'prefab') {
2112
+ if (inPrefabStage) {
2113
+ items.push({
2114
+ id: 'asset.add-to-current-prefab',
2115
+ label: '添加到当前 Prefab',
2116
+ disabled: !placeable,
2117
+ disabledReason: '该 Prefab 当前不可添加到当前 Prefab。',
2118
+ });
2119
+ }
2120
+ items.push({
2121
+ id: 'asset.rename',
2122
+ label: '重命名 Prefab',
2123
+ disabled: !asset.assetId && !asset.id,
2124
+ disabledReason: '该预制体资产缺少可重命名的资产 ID。',
2125
+ });
2126
+ items.push({
2127
+ id: 'asset.edit-prefab',
2128
+ label: inPrefabStage ? '打开 Prefab Stage' : '编辑 Prefab',
2129
+ separatorBefore: inPrefabStage ? true : undefined,
2130
+ disabled: !asset.prefab,
2131
+ disabledReason: '该预制体资产缺少可编辑参数。',
2132
+ });
2133
+ items.push({
2134
+ id: 'asset.duplicate-prefab',
2135
+ label: '复制 Prefab',
2136
+ disabled: !asset.assetId && !asset.id,
2137
+ disabledReason: '该预制体资产缺少可复制的 Prefab ID。',
2138
+ });
2139
+ }
1452
2140
  if (assetKind === 'material') {
1453
2141
  items.push({
1454
2142
  id: 'asset.apply-material',
@@ -1459,19 +2147,21 @@ function createAssetBrowserMenuItems(state, asset) {
1459
2147
  });
1460
2148
  }
1461
2149
  else if (assetKind === 'texture') {
1462
- items.push({
1463
- id: 'asset.add-to-scene',
1464
- label: '作为地贴添加到场景',
1465
- separatorBefore: asset.preview ? true : undefined,
1466
- disabled: !placeable,
1467
- disabledReason: '该贴图当前不可放置。',
1468
- });
1469
- items.push({
1470
- id: 'asset.place',
1471
- label: '进入地面放置模式',
1472
- disabled: !placeable,
1473
- disabledReason: '该贴图当前不可放置。',
1474
- });
2150
+ if (!inPrefabStage) {
2151
+ items.push({
2152
+ id: 'asset.add-to-scene',
2153
+ label: '作为地贴添加到场景',
2154
+ separatorBefore: asset.preview ? true : undefined,
2155
+ disabled: !placeable,
2156
+ disabledReason: '该贴图当前不可放置。',
2157
+ });
2158
+ items.push({
2159
+ id: 'asset.place',
2160
+ label: '进入地面放置模式',
2161
+ disabled: !placeable,
2162
+ disabledReason: '该贴图当前不可放置。',
2163
+ });
2164
+ }
1475
2165
  items.push({
1476
2166
  id: 'asset.use-base-texture',
1477
2167
  label: '用作当前材质 Base 图',
@@ -1486,32 +2176,65 @@ function createAssetBrowserMenuItems(state, asset) {
1486
2176
  disabledReason: '自发光遮罩绑定将在下一步接入。',
1487
2177
  });
1488
2178
  }
2179
+ else if (assetKind === 'prefab') {
2180
+ if (!inPrefabStage) {
2181
+ items.push({
2182
+ id: 'asset.add-to-scene',
2183
+ label: '添加 Prefab 到场景',
2184
+ separatorBefore: true,
2185
+ disabled: !placeable,
2186
+ disabledReason: '该 Prefab 当前不可放置。',
2187
+ });
2188
+ items.push({
2189
+ id: 'asset.place',
2190
+ label: '进入 Prefab 放置模式',
2191
+ disabled: !placeable,
2192
+ disabledReason: '该 Prefab 当前不可放置。',
2193
+ });
2194
+ }
2195
+ }
1489
2196
  else {
1490
- items.push({
1491
- id: 'asset.add-to-scene',
1492
- label: '添加到场景',
1493
- disabled: !placeable,
1494
- disabledReason: '该模型当前不可放置。',
1495
- });
1496
- items.push({
1497
- id: 'asset.place',
1498
- label: '进入放置模式',
1499
- disabled: !placeable,
1500
- disabledReason: '该模型当前不可放置。',
1501
- });
1502
- items.push({
1503
- id: 'asset.add-as-child',
1504
- label: '添加为当前节点子对象',
1505
- disabled: true,
1506
- disabledReason: '子对象添加动作将在资产 patch 中接入。',
1507
- separatorBefore: true,
1508
- });
1509
- items.push({
1510
- id: 'asset.replace-selected-model',
1511
- label: '替换当前模型',
1512
- disabled: true,
1513
- disabledReason: '模型替换动作将在资产 patch 中接入。',
1514
- });
2197
+ if (inPrefabStage) {
2198
+ items.push({
2199
+ id: 'asset.add-to-current-prefab',
2200
+ label: '添加到当前 Prefab',
2201
+ disabled: !placeable,
2202
+ disabledReason: '该模型当前不可添加到当前 Prefab。',
2203
+ });
2204
+ }
2205
+ if (!inPrefabStage) {
2206
+ items.push({
2207
+ id: 'asset.add-to-scene',
2208
+ label: '添加到场景',
2209
+ disabled: !placeable,
2210
+ disabledReason: '该模型当前不可放置。',
2211
+ });
2212
+ items.push({
2213
+ id: 'asset.place',
2214
+ label: '进入放置模式',
2215
+ disabled: !placeable,
2216
+ disabledReason: '该模型当前不可放置。',
2217
+ });
2218
+ items.push({
2219
+ id: 'asset.create-prefab',
2220
+ label: '创建 Prefab',
2221
+ disabled: !asset.assetId && !asset.id,
2222
+ disabledReason: '该模型缺少可创建 Prefab 的 Asset ID。',
2223
+ separatorBefore: true,
2224
+ });
2225
+ items.push({
2226
+ id: 'asset.add-as-child',
2227
+ label: '添加为当前节点子对象',
2228
+ disabled: true,
2229
+ disabledReason: '子对象添加动作将在资产 patch 中接入。',
2230
+ });
2231
+ items.push({
2232
+ id: 'asset.replace-selected-model',
2233
+ label: '替换当前模型',
2234
+ disabled: true,
2235
+ disabledReason: '模型替换动作将在资产 patch 中接入。',
2236
+ });
2237
+ }
1515
2238
  }
1516
2239
  items.push({
1517
2240
  id: 'asset.copy-id',
@@ -1532,24 +2255,24 @@ function getMaterialAssetDeleteDisabledReason(asset) {
1532
2255
  return `该材质正在被 ${usageCount} 处使用,请先替换或解绑。`;
1533
2256
  return undefined;
1534
2257
  }
1535
- function resolveBrowserAssetKind(asset) {
1536
- const kind = `${asset.kind ?? ''}`.trim().toLowerCase();
1537
- const id = `${asset.id ?? ''}`.trim().toLowerCase();
1538
- const assetId = `${asset.assetId ?? ''}`.trim().toLowerCase();
1539
- if (kind === 'material' || id.startsWith('material:') || assetId.startsWith('mat_'))
1540
- return 'material';
1541
- if (kind === 'texture' || kind === 'image' || id.startsWith('texture:') || assetId.startsWith('texture_'))
1542
- return 'texture';
1543
- return 'model';
1544
- }
1545
- function createAssetBrowserActionInput(actionId, asset) {
2258
+ function createAssetBrowserActionInput(actionId, asset, context) {
1546
2259
  return {
1547
2260
  actionId,
1548
2261
  assetId: asset.assetId ?? asset.id,
1549
2262
  browserAssetId: asset.id,
1550
- assetKind: asset.kind,
2263
+ assetKind: asset.kind ?? resolveLocalEditorBrowserAssetKind(asset),
2264
+ ...(context?.targetPrefabAssetId ? { targetPrefabAssetId: context.targetPrefabAssetId } : {}),
2265
+ ...(context?.parentNodeId ? { parentNodeId: context.parentNodeId } : {}),
1551
2266
  };
1552
2267
  }
2268
+ export function resolveAssetBrowserDoubleClickAction(state, asset) {
2269
+ const assetKind = resolveLocalEditorBrowserAssetKind(asset);
2270
+ if (state.prefabStage && (assetKind === 'model' || assetKind === 'prefab'))
2271
+ return 'asset.add-to-current-prefab';
2272
+ if (!state.prefabStage && assetKind === 'prefab')
2273
+ return 'asset.edit-prefab';
2274
+ return null;
2275
+ }
1553
2276
  function copyTextToClipboard(win, text) {
1554
2277
  void win?.navigator?.clipboard?.writeText?.(text);
1555
2278
  }
@@ -1755,6 +2478,7 @@ export function createLocalEditorBrowserUi(options = {}) {
1755
2478
  const redoButton = createToolbarIconButton(doc, '重做', 'redo', '重做');
1756
2479
  let helpOpen = false;
1757
2480
  let performanceMonitorOpen = false;
2481
+ let prefabComparisonPreviewOpen = true;
1758
2482
  let assetPreviewOpen = false;
1759
2483
  let previewedAsset = null;
1760
2484
  let assetPreviewMode = 'preview';
@@ -1762,9 +2486,14 @@ export function createLocalEditorBrowserUi(options = {}) {
1762
2486
  let assetPickerFilter = '';
1763
2487
  let assetPickerInput = null;
1764
2488
  let assetPickerProperty = null;
2489
+ let prefabComparisonPreviewDrag = null;
2490
+ let prefabStageMainWorkbenchLayoutSnapshot = null;
1765
2491
  const editorStatusButton = createToolbarIconButton(doc, '编辑器状态', 'status', '编辑器状态');
1766
2492
  editorStatusButton.dataset.editorStatusButton = 'true';
1767
2493
  editorStatusButton.style.cursor = 'help';
2494
+ const agentBridgeStatusButton = createToolbarIconButton(doc, 'Agent Bridge 状态', 'status', 'Agent Bridge 状态');
2495
+ agentBridgeStatusButton.dataset.editorAgentBridgeStatusButton = 'true';
2496
+ agentBridgeStatusButton.style.cursor = 'help';
1768
2497
  const workbench = createLocalEditorWorkbench(doc);
1769
2498
  const leftDockTabs = doc.createElement('div');
1770
2499
  const hierarchyPanel = createWorkbenchPanelContent(doc);
@@ -1772,14 +2501,22 @@ export function createLocalEditorBrowserUi(options = {}) {
1772
2501
  const rightDockTabs = doc.createElement('div');
1773
2502
  const inspectorPanel = createWorkbenchPanelContent(doc);
1774
2503
  const renderingPanel = createWorkbenchPanelContent(doc);
2504
+ const markersPanel = createWorkbenchPanelContent(doc);
1775
2505
  workbench.leftDock.appendChild(leftDockTabs);
1776
2506
  workbench.leftDock.appendChild(hierarchyPanel);
1777
2507
  workbench.rightDock.appendChild(rightDockTabs);
1778
2508
  workbench.rightDock.appendChild(inspectorPanel);
1779
2509
  workbench.rightDock.appendChild(renderingPanel);
2510
+ workbench.rightDock.appendChild(markersPanel);
1780
2511
  root.appendChild(workbench.root);
1781
2512
  tooltipSurfaces.add(workbench.root);
1782
- const workbenchLayoutController = createLocalEditorWorkbenchLayoutController(doc, workbench);
2513
+ const workbenchLayoutController = createLocalEditorWorkbenchLayoutController(doc, workbench, {
2514
+ onAfterApply(layout) {
2515
+ if (currentState?.mode === 'editor' && currentState.prefabStage) {
2516
+ applyPrefabStageWorkbenchLayoutOverride(layout);
2517
+ }
2518
+ },
2519
+ });
1783
2520
  const findAssetBrowserScrollViewport = () => (assetPanel.querySelector('[data-editor-asset-browser-scroll-viewport]'));
1784
2521
  const assetBrowserViewportReveal = createLocalEditorViewportRevealController({
1785
2522
  getViewport: findAssetBrowserScrollViewport,
@@ -2152,13 +2889,20 @@ export function createLocalEditorBrowserUi(options = {}) {
2152
2889
  performanceMonitorButton.dataset.performanceMonitorToggle = 'true';
2153
2890
  const gridToggleButton = createToolbarIconButton(doc, '网格', 'grid', '显示 / 隐藏 Scene View 网格');
2154
2891
  gridToggleButton.dataset.editorGridToggle = 'true';
2892
+ const prefabComparisonPreviewButton = createToolbarIconButton(doc, '对比预览', 'eye', 'Compare Previews (Shift+P)', 'toggle');
2893
+ prefabComparisonPreviewButton.dataset.prefabComparisonPreviewToggle = 'true';
2155
2894
  const sceneHelpButton = createToolbarIconButton(doc, '快捷键', 'help', '快捷键与操作说明');
2156
2895
  sceneQuickActions.appendChild(localTestGroup);
2896
+ const prefabStageBackButton = createToolbarIconButton(doc, '返回场景', 'chevron-right', '返回主场景');
2897
+ prefabStageBackButton.dataset.editorPrefabStageBack = 'true';
2898
+ prefabStageBackButton.style.display = 'none';
2899
+ sceneQuickActions.appendChild(prefabStageBackButton);
2157
2900
  sceneQuickActions.appendChild(undoButton);
2158
2901
  sceneQuickActions.appendChild(redoButton);
2159
2902
  sceneQuickActions.appendChild(dirtyBadge);
2160
2903
  sceneUtilityActions.appendChild(performanceMonitorButton);
2161
2904
  sceneUtilityActions.appendChild(gridToggleButton);
2905
+ sceneUtilityActions.appendChild(prefabComparisonPreviewButton);
2162
2906
  sceneUtilityActions.appendChild(themeToggleButton);
2163
2907
  sceneUtilityActions.appendChild(sceneHelpButton);
2164
2908
  const cameraPreviewGroup = doc.createElement('div');
@@ -2190,6 +2934,9 @@ export function createLocalEditorBrowserUi(options = {}) {
2190
2934
  const projectionToggleButton = createToolbarIconButton(doc, '投影模式', 'projection-perspective', '切换投影模式');
2191
2935
  projectionToggleButton.dataset.viewportProjectionToggle = 'true';
2192
2936
  viewportToolsGroup.appendChild(projectionToggleButton);
2937
+ const markerVisibilityButton = createToolbarIconButton(doc, '标记视图', 'view-overlay', '隐藏标记与关系线', 'toggle');
2938
+ markerVisibilityButton.dataset.viewportMarkerVisibilityToggle = 'true';
2939
+ viewportToolsGroup.appendChild(markerVisibilityButton);
2193
2940
  const overlaySettingsButton = createToolbarIconButton(doc, '视口信息层设置', 'view-overlay', '视口信息层设置', 'settings');
2194
2941
  overlaySettingsButton.dataset.viewportOverlaySettingsToggle = 'true';
2195
2942
  viewportToolsGroup.appendChild(overlaySettingsButton);
@@ -2266,6 +3013,112 @@ export function createLocalEditorBrowserUi(options = {}) {
2266
3013
  const coordinateAxesOverlay = createCoordinateAxesOverlay(doc);
2267
3014
  const sceneFrameRateOverlay = createSceneFrameRateOverlay(doc);
2268
3015
  const performanceMonitorOverlay = createPerformanceMonitorOverlay(doc);
3016
+ const prefabImportStatsOverlay = createPrefabImportStatsOverlay(doc);
3017
+ const prefabComparisonPreviewOverlay = createPrefabComparisonPreviewOverlay(doc);
3018
+ const prefabStagePreviewLayout = createPrefabStagePreviewLayout(doc);
3019
+ prefabImportStatsOverlay.root.style.position = 'absolute';
3020
+ prefabImportStatsOverlay.root.style.top = '10px';
3021
+ prefabImportStatsOverlay.root.style.right = '14px';
3022
+ prefabComparisonPreviewOverlay.root.style.height = '100%';
3023
+ prefabStagePreviewLayout.mainRegion.appendChild(prefabImportStatsOverlay.root);
3024
+ prefabStagePreviewLayout.comparisonColumn.appendChild(prefabComparisonPreviewOverlay.root);
3025
+ const emitPrefabComparisonPreviewInteraction = (input) => {
3026
+ if (currentState?.mode !== 'editor' || !currentState.prefabStage)
3027
+ return;
3028
+ callbacks.onPrefabComparisonPreviewInteraction?.(input);
3029
+ };
3030
+ const endPrefabComparisonPreviewDrag = (pointerId) => {
3031
+ const drag = prefabComparisonPreviewDrag;
3032
+ if (!drag || (pointerId != null && drag.pointerId !== pointerId))
3033
+ return;
3034
+ try {
3035
+ if (!drag.surface.hasPointerCapture || drag.surface.hasPointerCapture(drag.pointerId)) {
3036
+ drag.surface.releasePointerCapture?.(drag.pointerId);
3037
+ }
3038
+ }
3039
+ catch {
3040
+ // Pointer capture may already be released by the browser when this cleanup runs.
3041
+ }
3042
+ drag.surface.style.cursor = 'grab';
3043
+ prefabComparisonPreviewDrag = null;
3044
+ };
3045
+ const onPrefabComparisonPreviewPointerDown = (event) => {
3046
+ if (event.button !== 0 || currentState?.mode !== 'editor' || !currentState.prefabStage)
3047
+ return;
3048
+ const surface = findPrefabComparisonPreviewSurface(event.target);
3049
+ if (!surface || !isPrefabComparisonPreviewSurfaceReady(surface))
3050
+ return;
3051
+ const previewId = readPrefabComparisonPreviewSurfaceId(surface);
3052
+ if (!previewId)
3053
+ return;
3054
+ event.preventDefault();
3055
+ event.stopPropagation();
3056
+ endPrefabComparisonPreviewDrag();
3057
+ try {
3058
+ surface.setPointerCapture?.(event.pointerId);
3059
+ }
3060
+ catch {
3061
+ // Pointer capture is an input nicety; drag state still works through the overlay listener.
3062
+ }
3063
+ surface.style.cursor = 'grabbing';
3064
+ prefabComparisonPreviewDrag = {
3065
+ pointerId: event.pointerId,
3066
+ previewId,
3067
+ surface,
3068
+ lastClientX: event.clientX,
3069
+ lastClientY: event.clientY,
3070
+ };
3071
+ };
3072
+ const onPrefabComparisonPreviewPointerMove = (event) => {
3073
+ const drag = prefabComparisonPreviewDrag;
3074
+ if (!drag || drag.pointerId !== event.pointerId)
3075
+ return;
3076
+ event.preventDefault();
3077
+ event.stopPropagation();
3078
+ const deltaX = event.clientX - drag.lastClientX;
3079
+ const deltaY = event.clientY - drag.lastClientY;
3080
+ drag.lastClientX = event.clientX;
3081
+ drag.lastClientY = event.clientY;
3082
+ if (Math.abs(deltaX) < 0.001 && Math.abs(deltaY) < 0.001)
3083
+ return;
3084
+ emitPrefabComparisonPreviewInteraction({
3085
+ kind: 'orbit',
3086
+ previewId: drag.previewId,
3087
+ deltaX,
3088
+ deltaY,
3089
+ });
3090
+ };
3091
+ const onPrefabComparisonPreviewPointerEnd = (event) => {
3092
+ const drag = prefabComparisonPreviewDrag;
3093
+ if (!drag || drag.pointerId !== event.pointerId)
3094
+ return;
3095
+ event.preventDefault();
3096
+ event.stopPropagation();
3097
+ endPrefabComparisonPreviewDrag(event.pointerId);
3098
+ };
3099
+ const onPrefabComparisonPreviewWheel = (event) => {
3100
+ if (currentState?.mode !== 'editor' || !currentState.prefabStage)
3101
+ return;
3102
+ const surface = findPrefabComparisonPreviewSurface(event.target);
3103
+ if (!surface || !isPrefabComparisonPreviewSurfaceReady(surface))
3104
+ return;
3105
+ const previewId = readPrefabComparisonPreviewSurfaceId(surface);
3106
+ if (!previewId)
3107
+ return;
3108
+ event.preventDefault();
3109
+ event.stopPropagation();
3110
+ emitPrefabComparisonPreviewInteraction({
3111
+ kind: 'zoom',
3112
+ previewId,
3113
+ deltaY: event.deltaY,
3114
+ });
3115
+ };
3116
+ prefabComparisonPreviewOverlay.root.addEventListener('pointerdown', onPrefabComparisonPreviewPointerDown);
3117
+ prefabComparisonPreviewOverlay.root.addEventListener('pointermove', onPrefabComparisonPreviewPointerMove);
3118
+ prefabComparisonPreviewOverlay.root.addEventListener('pointerup', onPrefabComparisonPreviewPointerEnd);
3119
+ prefabComparisonPreviewOverlay.root.addEventListener('pointercancel', onPrefabComparisonPreviewPointerEnd);
3120
+ prefabComparisonPreviewOverlay.root.addEventListener('lostpointercapture', onPrefabComparisonPreviewPointerEnd);
3121
+ prefabComparisonPreviewOverlay.root.addEventListener('wheel', onPrefabComparisonPreviewWheel, { passive: false });
2269
3122
  const spatialOverlay = createSpatialOverlay(doc);
2270
3123
  const measurementOverlay = createMeasurementOverlay(doc);
2271
3124
  sceneToolOverlay.appendChild(sceneTitle);
@@ -2279,6 +3132,7 @@ export function createLocalEditorBrowserUi(options = {}) {
2279
3132
  sceneToolOverlay.appendChild(viewportToolsGroup);
2280
3133
  sceneToolOverlay.appendChild(sceneUtilityActions);
2281
3134
  sceneToolOverlay.appendChild(cameraPreviewGroup);
3135
+ sceneToolOverlay.appendChild(agentBridgeStatusButton);
2282
3136
  sceneToolOverlay.appendChild(editorStatusButton);
2283
3137
  sceneToolOverlay.appendChild(toolbarOverflowButton);
2284
3138
  workbench.sceneHeader.appendChild(sceneToolOverlay);
@@ -2286,6 +3140,7 @@ export function createLocalEditorBrowserUi(options = {}) {
2286
3140
  workbench.sceneFrame.appendChild(measurementOverlay.root);
2287
3141
  workbench.sceneFrame.appendChild(sceneFrameRateOverlay.root);
2288
3142
  workbench.sceneFrame.appendChild(performanceMonitorOverlay.root);
3143
+ workbench.sceneFrame.appendChild(prefabStagePreviewLayout.root);
2289
3144
  workbench.sceneFrame.appendChild(coordinateAxesOverlay.root);
2290
3145
  root.appendChild(localTestMenu);
2291
3146
  root.appendChild(toolbarOverflowMenu);
@@ -2483,6 +3338,9 @@ export function createLocalEditorBrowserUi(options = {}) {
2483
3338
  applyLocalEditorTheme(measurementOverlay.root, activeTheme);
2484
3339
  applyLocalEditorTheme(sceneFrameRateOverlay.root, activeTheme);
2485
3340
  applyLocalEditorTheme(performanceMonitorOverlay.root, activeTheme);
3341
+ applyLocalEditorTheme(prefabStagePreviewLayout.root, activeTheme);
3342
+ applyLocalEditorTheme(prefabImportStatsOverlay.root, activeTheme);
3343
+ applyLocalEditorTheme(prefabComparisonPreviewOverlay.root, activeTheme);
2486
3344
  applyLocalEditorTheme(shortcutHelpPanel, activeTheme);
2487
3345
  applyLocalEditorTheme(assetPreviewModal, activeTheme);
2488
3346
  applyLocalEditorTheme(assetPickerModal, activeTheme);
@@ -2700,6 +3558,7 @@ export function createLocalEditorBrowserUi(options = {}) {
2700
3558
  viewportToolsGroup,
2701
3559
  sceneUtilityActions,
2702
3560
  cameraPreviewGroup,
3561
+ agentBridgeStatusButton,
2703
3562
  editorStatusButton,
2704
3563
  toolbarOverflowButton,
2705
3564
  ];
@@ -2713,6 +3572,7 @@ export function createLocalEditorBrowserUi(options = {}) {
2713
3572
  { id: 'snap', element: snapGroup, kind: 'group' },
2714
3573
  { id: 'space', element: spaceGroup, kind: 'group' },
2715
3574
  { id: 'static-shadow-bake', element: staticShadowBakeGroup, kind: 'group' },
3575
+ { id: 'agent-bridge-status', element: agentBridgeStatusButton, kind: 'group' },
2716
3576
  ];
2717
3577
  let toolbarOverflowOpen = false;
2718
3578
  let toolbarOverflowRaf = null;
@@ -3002,6 +3862,9 @@ export function createLocalEditorBrowserUi(options = {}) {
3002
3862
  performanceMonitorButton.addEventListener('click', () => {
3003
3863
  setPerformanceMonitorOpen(!performanceMonitorOpen);
3004
3864
  });
3865
+ prefabComparisonPreviewButton.addEventListener('click', () => {
3866
+ setPrefabComparisonPreviewOpen(!prefabComparisonPreviewOpen);
3867
+ });
3005
3868
  gridToggleButton.addEventListener('click', () => {
3006
3869
  const visible = currentState?.grid?.visible ?? true;
3007
3870
  callbacks.onGridVisibleChange?.(!visible);
@@ -3055,6 +3918,12 @@ export function createLocalEditorBrowserUi(options = {}) {
3055
3918
  callbacks.onViewportProjectionModeChange?.(nextMode);
3056
3919
  return;
3057
3920
  }
3921
+ const markerVisibilityToggle = target?.closest('[data-viewport-marker-visibility-toggle]');
3922
+ if (markerVisibilityToggle) {
3923
+ const markersVisible = currentState?.viewportTools?.markersVisible ?? true;
3924
+ callbacks.onMarkerViewportVisibilityChange?.(!markersVisible);
3925
+ return;
3926
+ }
3058
3927
  const overlayToggle = target?.closest('[data-viewport-overlay-settings-toggle]');
3059
3928
  if (overlayToggle) {
3060
3929
  event.stopPropagation();
@@ -3088,10 +3957,21 @@ export function createLocalEditorBrowserUi(options = {}) {
3088
3957
  contextMenu.close();
3089
3958
  performanceMonitorOpen = open;
3090
3959
  LocalEditorShared.applyButtonActiveState(performanceMonitorButton, performanceMonitorOpen);
3091
- renderPerformanceMonitorOverlay(performanceMonitorOverlay, currentState?.mode === 'editor' ? currentState.performanceStats ?? null : null, currentState?.mode === 'editor' && performanceMonitorOpen);
3960
+ renderPerformanceMonitorOverlay(performanceMonitorOverlay, currentState?.mode === 'editor' && !currentState.prefabStage ? currentState.performanceStats ?? null : null, currentState?.mode === 'editor' && !currentState.prefabStage && performanceMonitorOpen);
3092
3961
  if (notify)
3093
3962
  callbacks.onPerformanceMonitorOpenChange?.(performanceMonitorOpen);
3094
3963
  };
3964
+ const setPrefabComparisonPreviewOpen = (open) => {
3965
+ if (prefabComparisonPreviewOpen === open)
3966
+ return;
3967
+ if (!open)
3968
+ endPrefabComparisonPreviewDrag();
3969
+ prefabComparisonPreviewOpen = open;
3970
+ if (currentState)
3971
+ renderPreviewState(currentState);
3972
+ LocalEditorShared.applyButtonActiveState(prefabComparisonPreviewButton, prefabComparisonPreviewOpen);
3973
+ callbacks.onPrefabComparisonPreviewLayoutChange?.();
3974
+ };
3095
3975
  const openAssetPreviewModal = (asset) => {
3096
3976
  if (!asset.preview)
3097
3977
  return;
@@ -3116,6 +3996,20 @@ export function createLocalEditorBrowserUi(options = {}) {
3116
3996
  syncInputModalOpen();
3117
3997
  assetPreviewCloseButton.focus({ preventScroll: true });
3118
3998
  };
3999
+ const openAssetRenameModal = (asset) => {
4000
+ contextMenu.close();
4001
+ previewedAsset = asset;
4002
+ assetPreviewMode = 'rename';
4003
+ assetPreviewDialog.setAttribute('aria-label', '重命名资产');
4004
+ assetPreviewOpen = true;
4005
+ renderAssetPreviewModal();
4006
+ syncInputModalOpen();
4007
+ setTimeout(() => {
4008
+ const input = assetPreviewBody.querySelector('[data-editor-asset-rename-input]');
4009
+ input?.focus({ preventScroll: true });
4010
+ input?.select();
4011
+ }, 0);
4012
+ };
3119
4013
  const closeAssetPreviewModal = () => {
3120
4014
  if (!assetPreviewOpen)
3121
4015
  return;
@@ -3164,7 +4058,10 @@ export function createLocalEditorBrowserUi(options = {}) {
3164
4058
  }
3165
4059
  function renderAssetPreviewModal() {
3166
4060
  const asset = resolvePreviewedAssetFromState();
3167
- if (!assetPreviewOpen || !asset || (assetPreviewMode === 'preview' && !asset.preview) || (assetPreviewMode === 'material-editor' && !asset.material)) {
4061
+ if (!assetPreviewOpen
4062
+ || !asset
4063
+ || (assetPreviewMode === 'preview' && !asset.preview)
4064
+ || (assetPreviewMode === 'material-editor' && !asset.material)) {
3168
4065
  assetPreviewModal.style.display = 'none';
3169
4066
  assetPreviewTitle.textContent = '';
3170
4067
  assetPreviewMeta.textContent = '';
@@ -3177,6 +4074,11 @@ export function createLocalEditorBrowserUi(options = {}) {
3177
4074
  assetPreviewModal.style.display = 'flex';
3178
4075
  return;
3179
4076
  }
4077
+ if (assetPreviewMode === 'rename') {
4078
+ renderAssetRenameModal(asset);
4079
+ assetPreviewModal.style.display = 'flex';
4080
+ return;
4081
+ }
3180
4082
  assetPreviewDialog.style.width = 'min(420px,calc(100vw - 64px))';
3181
4083
  assetPreviewBody.style.cssText = [
3182
4084
  'display:flex',
@@ -3197,6 +4099,49 @@ export function createLocalEditorBrowserUi(options = {}) {
3197
4099
  assetPreviewBody.appendChild(LocalEditorPanels.createAssetPreviewElement(doc, asset, 'modal'));
3198
4100
  assetPreviewModal.style.display = 'flex';
3199
4101
  }
4102
+ function renderAssetRenameModal(asset) {
4103
+ assetPreviewDialog.style.width = 'min(420px,calc(100vw - 64px))';
4104
+ assetPreviewTitle.textContent = '重命名 Prefab';
4105
+ assetPreviewMeta.textContent = asset.assetId ?? asset.id;
4106
+ while (assetPreviewBody.firstChild)
4107
+ assetPreviewBody.removeChild(assetPreviewBody.firstChild);
4108
+ assetPreviewBody.style.cssText = [
4109
+ 'display:flex',
4110
+ 'align-items:stretch',
4111
+ 'justify-content:stretch',
4112
+ 'min-height:0',
4113
+ 'border:1px solid var(--fps-editor-divider)',
4114
+ 'border-radius:4px',
4115
+ 'background:var(--fps-editor-panel-soft)',
4116
+ 'padding:12px',
4117
+ ].join(';');
4118
+ const form = doc.createElement('form');
4119
+ form.dataset.editorAssetRenameForm = 'true';
4120
+ form.style.cssText = 'display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;width:100%;align-items:center';
4121
+ const input = doc.createElement('input');
4122
+ input.type = 'text';
4123
+ input.dataset.editorAssetRenameInput = 'true';
4124
+ input.value = asset.label;
4125
+ input.maxLength = 80;
4126
+ input.required = true;
4127
+ input.style.cssText = [
4128
+ 'height:30px',
4129
+ 'min-width:0',
4130
+ 'box-sizing:border-box',
4131
+ 'border:1px solid var(--fps-editor-border)',
4132
+ 'border-radius:3px',
4133
+ 'background:var(--fps-editor-field)',
4134
+ 'color:var(--fps-editor-text)',
4135
+ 'font-size:12px',
4136
+ 'padding:0 8px',
4137
+ 'outline:none',
4138
+ ].join(';');
4139
+ const submit = LocalEditorShared.createButton(doc, '确认');
4140
+ submit.type = 'submit';
4141
+ form.appendChild(input);
4142
+ form.appendChild(submit);
4143
+ assetPreviewBody.appendChild(form);
4144
+ }
3200
4145
  function renderAssetMaterialEditorModal(asset) {
3201
4146
  const material = asset.material;
3202
4147
  const profile = material.profile ?? {};
@@ -3404,7 +4349,7 @@ export function createLocalEditorBrowserUi(options = {}) {
3404
4349
  const options = [{ label: '继承 / 无', value: '', meta: '清空贴图引用' }];
3405
4350
  const seen = new Set(['']);
3406
4351
  for (const asset of currentState?.assets ?? []) {
3407
- if (resolveBrowserAssetKind(asset) !== 'texture')
4352
+ if (resolveLocalEditorBrowserAssetKind(asset) !== 'texture')
3408
4353
  continue;
3409
4354
  const value = asset.preview?.kind === 'image'
3410
4355
  ? asset.preview.url
@@ -3564,6 +4509,9 @@ export function createLocalEditorBrowserUi(options = {}) {
3564
4509
  sceneHelpButton.addEventListener('click', () => {
3565
4510
  setShortcutHelpOpen(!helpOpen);
3566
4511
  });
4512
+ prefabStageBackButton.addEventListener('click', () => {
4513
+ callbacks.onExitPrefabStage?.();
4514
+ });
3567
4515
  themeToggleButton.addEventListener('click', () => {
3568
4516
  setActiveTheme(activeTheme === 'dark' ? 'light' : 'dark');
3569
4517
  });
@@ -3583,14 +4531,32 @@ export function createLocalEditorBrowserUi(options = {}) {
3583
4531
  closeAssetPreviewModal();
3584
4532
  });
3585
4533
  assetPreviewBody.addEventListener('change', (event) => {
4534
+ const target = event.target instanceof HTMLElement ? event.target : null;
3586
4535
  if (assetPreviewMode !== 'material-editor')
3587
4536
  return;
3588
- const target = event.target instanceof HTMLElement ? event.target : null;
3589
4537
  const input = target?.closest('[data-editor-asset-material-field]');
3590
4538
  if (!input)
3591
4539
  return;
3592
4540
  dispatchMaterialEditorFieldChange(input);
3593
4541
  });
4542
+ assetPreviewBody.addEventListener('submit', (event) => {
4543
+ if (assetPreviewMode !== 'rename')
4544
+ return;
4545
+ event.preventDefault();
4546
+ const asset = resolvePreviewedAssetFromState();
4547
+ const form = event.target instanceof HTMLFormElement
4548
+ ? event.target.closest('[data-editor-asset-rename-form]')
4549
+ : null;
4550
+ const input = form?.querySelector('[data-editor-asset-rename-input]');
4551
+ const name = input?.value.trim() ?? '';
4552
+ if (!asset || !name)
4553
+ return;
4554
+ callbacks.onAssetAction?.({
4555
+ ...createAssetBrowserActionInput('asset.rename', asset),
4556
+ value: name,
4557
+ });
4558
+ closeAssetPreviewModal();
4559
+ });
3594
4560
  assetPickerModal.addEventListener('click', (event) => {
3595
4561
  const target = event.target instanceof HTMLElement ? event.target : null;
3596
4562
  if (target?.closest('[data-editor-asset-picker-close]')) {
@@ -3705,6 +4671,18 @@ export function createLocalEditorBrowserUi(options = {}) {
3705
4671
  return;
3706
4672
  }
3707
4673
  }
4674
+ function createCurrentAssetBrowserActionContext() {
4675
+ const stage = currentState?.prefabStage;
4676
+ if (!stage)
4677
+ return undefined;
4678
+ const selectedItem = findLocalEditorPrefabStageStructureItem(stage, stage.selectedItemId);
4679
+ return {
4680
+ targetPrefabAssetId: stage.assetId,
4681
+ ...(selectedItem?.itemType === 'prefab-node' && selectedItem.nodeId
4682
+ ? { parentNodeId: selectedItem.nodeId }
4683
+ : {}),
4684
+ };
4685
+ }
3708
4686
  assetPanel.addEventListener('click', (event) => {
3709
4687
  const target = event.target instanceof HTMLElement ? event.target : null;
3710
4688
  const tabButton = target?.closest('[data-editor-dock-tab]');
@@ -3738,6 +4716,22 @@ export function createLocalEditorBrowserUi(options = {}) {
3738
4716
  return;
3739
4717
  }
3740
4718
  });
4719
+ assetPanel.addEventListener('dblclick', (event) => {
4720
+ const target = event.target instanceof HTMLElement ? event.target : null;
4721
+ const assetButton = target?.closest('[data-editor-asset-id]');
4722
+ const browserAssetId = assetButton?.dataset.editorAssetId;
4723
+ if (!browserAssetId || !currentState)
4724
+ return;
4725
+ const asset = currentState.assets.find(candidate => candidate.id === browserAssetId);
4726
+ const actionId = asset ? resolveAssetBrowserDoubleClickAction(currentState, asset) : null;
4727
+ if (!asset || !actionId)
4728
+ return;
4729
+ event.preventDefault();
4730
+ event.stopPropagation();
4731
+ suppressAssetBrowserRevealIfVisible(assetButton);
4732
+ callbacks.onSelectAsset?.(browserAssetId);
4733
+ callbacks.onAssetAction?.(createAssetBrowserActionInput(actionId, asset, createCurrentAssetBrowserActionContext()));
4734
+ });
3741
4735
  assetPanel.addEventListener('contextmenu', (event) => {
3742
4736
  const target = event.target instanceof HTMLElement ? event.target : null;
3743
4737
  const assetButton = target?.closest('[data-editor-asset-id]');
@@ -3764,11 +4758,19 @@ export function createLocalEditorBrowserUi(options = {}) {
3764
4758
  openAssetMaterialEditorModal(asset);
3765
4759
  return;
3766
4760
  }
4761
+ if (item.id === 'asset.rename') {
4762
+ openAssetRenameModal(asset);
4763
+ return;
4764
+ }
4765
+ if (item.id === 'asset.edit-prefab' || item.id === 'asset.add-to-current-prefab') {
4766
+ callbacks.onAssetAction?.(createAssetBrowserActionInput(item.id, asset, createCurrentAssetBrowserActionContext()));
4767
+ return;
4768
+ }
3767
4769
  if (item.id === 'asset.copy-id') {
3768
4770
  copyTextToClipboard(doc.defaultView, asset.assetId ?? asset.id);
3769
4771
  return;
3770
4772
  }
3771
- callbacks.onAssetAction?.(createAssetBrowserActionInput(item.id, asset));
4773
+ callbacks.onAssetAction?.(createAssetBrowserActionInput(item.id, asset, createCurrentAssetBrowserActionContext()));
3772
4774
  },
3773
4775
  });
3774
4776
  });
@@ -3776,7 +4778,7 @@ export function createLocalEditorBrowserUi(options = {}) {
3776
4778
  const target = event.target instanceof HTMLElement ? event.target : null;
3777
4779
  const openTabButton = target?.closest('[data-editor-open-right-dock-tab]');
3778
4780
  const openTab = openTabButton?.dataset.editorOpenRightDockTab;
3779
- if (openTab === 'inspector' || openTab === 'rendering') {
4781
+ if (isLocalEditorRightDockTab(openTab)) {
3780
4782
  panelRegistry.setRightDockTab(openTab);
3781
4783
  if (currentState)
3782
4784
  render(currentState);
@@ -3784,7 +4786,7 @@ export function createLocalEditorBrowserUi(options = {}) {
3784
4786
  }
3785
4787
  const tabButton = target?.closest('[data-editor-right-dock-tab]');
3786
4788
  const tab = tabButton?.dataset.editorRightDockTab;
3787
- if (tab === 'inspector' || tab === 'rendering') {
4789
+ if (isLocalEditorRightDockTab(tab)) {
3788
4790
  panelRegistry.setRightDockTab(tab);
3789
4791
  if (currentState)
3790
4792
  render(currentState);
@@ -3882,6 +4884,28 @@ export function createLocalEditorBrowserUi(options = {}) {
3882
4884
  callbacks.onRenderingAction?.(actionInput);
3883
4885
  return;
3884
4886
  }
4887
+ const inspectorActionButton = target?.closest('[data-editor-inspector-action]');
4888
+ if (inspectorActionButton) {
4889
+ if (inspectorActionButton.disabled)
4890
+ return;
4891
+ const actionInput = createInspectorActionInput(inspectorActionButton);
4892
+ if (!actionInput)
4893
+ return;
4894
+ event.preventDefault();
4895
+ event.stopPropagation();
4896
+ callbacks.onInspectorAction?.(actionInput);
4897
+ return;
4898
+ }
4899
+ const relationTarget = target?.closest('[data-editor-marker-relation-action]');
4900
+ if (relationTarget && !(relationTarget instanceof HTMLButtonElement && relationTarget.disabled)) {
4901
+ const relationInput = createMarkerRelationActionInput(relationTarget);
4902
+ if (!relationInput)
4903
+ return;
4904
+ event.preventDefault();
4905
+ event.stopPropagation();
4906
+ callbacks.onMarkerRelationAction?.(relationInput);
4907
+ return;
4908
+ }
3885
4909
  const vectorLockButton = target?.closest('[data-editor-inspector-vector-lock]');
3886
4910
  if (vectorLockButton) {
3887
4911
  const groupPath = vectorLockButton.dataset.editorInspectorVectorLock;
@@ -4084,6 +5108,28 @@ export function createLocalEditorBrowserUi(options = {}) {
4084
5108
  openStaticShadowBakePopover();
4085
5109
  callbacks.onRenderingAction?.(actionInput);
4086
5110
  });
5111
+ markersPanel.addEventListener('click', (event) => {
5112
+ const eventTarget = event.target instanceof HTMLElement ? event.target : null;
5113
+ const relationTarget = eventTarget?.closest('[data-editor-marker-relation-action]');
5114
+ if (relationTarget && !(relationTarget instanceof HTMLButtonElement && relationTarget.disabled)) {
5115
+ const relationInput = createMarkerRelationActionInput(relationTarget);
5116
+ if (!relationInput)
5117
+ return;
5118
+ event.preventDefault();
5119
+ event.stopPropagation();
5120
+ callbacks.onMarkerRelationAction?.(relationInput);
5121
+ return;
5122
+ }
5123
+ const actionButton = eventTarget?.closest('[data-editor-marker-type-action]');
5124
+ if (!actionButton || actionButton.disabled)
5125
+ return;
5126
+ const actionInput = createMarkerTypeActionInput(actionButton);
5127
+ if (!actionInput)
5128
+ return;
5129
+ event.preventDefault();
5130
+ event.stopPropagation();
5131
+ callbacks.onMarkerTypeAction?.(actionInput);
5132
+ });
4087
5133
  const onKeyDown = (event) => {
4088
5134
  if (event.defaultPrevented)
4089
5135
  return;
@@ -4128,7 +5174,24 @@ export function createLocalEditorBrowserUi(options = {}) {
4128
5174
  const primaryModifier = event.metaKey || event.ctrlKey;
4129
5175
  const handleDocumentShortcut = inputRouter.shouldHandleDocumentShortcut(event);
4130
5176
  const handleGlobalShortcut = inputRouter.shouldHandleGlobalShortcut(event);
4131
- if (handleDocumentShortcut && localTestActionsEnabled && primaryModifier && key === 's') {
5177
+ if (shouldToggleLocalEditorPrefabComparisonShortcut({
5178
+ inPrefabStage: currentState.prefabStage != null,
5179
+ handleGlobalShortcut,
5180
+ key,
5181
+ shiftKey: event.shiftKey,
5182
+ metaKey: event.metaKey,
5183
+ ctrlKey: event.ctrlKey,
5184
+ altKey: event.altKey,
5185
+ })) {
5186
+ event.preventDefault();
5187
+ setPrefabComparisonPreviewOpen(!prefabComparisonPreviewOpen);
5188
+ return;
5189
+ }
5190
+ if (handleDocumentShortcut
5191
+ && localTestActionsEnabled
5192
+ && isPreviewToolEnabled('local-test')
5193
+ && primaryModifier
5194
+ && key === 's') {
4132
5195
  event.preventDefault();
4133
5196
  callbacks.onSaveScene?.();
4134
5197
  return;
@@ -4146,7 +5209,18 @@ export function createLocalEditorBrowserUi(options = {}) {
4146
5209
  callbacks.onRedo?.();
4147
5210
  return;
4148
5211
  }
4149
- if (handleGlobalShortcut && hierarchyController.handleEditShortcut(event)) {
5212
+ if (shouldLocalEditorPrefabStageBlockHierarchyShortcut({
5213
+ inPrefabStage: currentState.prefabStage != null,
5214
+ handleGlobalShortcut,
5215
+ key,
5216
+ metaKey: event.metaKey,
5217
+ ctrlKey: event.ctrlKey,
5218
+ altKey: event.altKey,
5219
+ })) {
5220
+ event.preventDefault();
5221
+ return;
5222
+ }
5223
+ if (!currentState.prefabStage && handleGlobalShortcut && hierarchyController.handleEditShortcut(event)) {
4150
5224
  return;
4151
5225
  }
4152
5226
  if (!handleGlobalShortcut || event.metaKey || event.ctrlKey || event.altKey)
@@ -4160,20 +5234,24 @@ export function createLocalEditorBrowserUi(options = {}) {
4160
5234
  const tool = toolByKey[key];
4161
5235
  if (tool) {
4162
5236
  event.preventDefault();
4163
- callbacks.onTransformToolChange?.(tool);
5237
+ if (isPreviewToolEnabled(tool))
5238
+ callbacks.onTransformToolChange?.(tool);
4164
5239
  return;
4165
5240
  }
4166
5241
  if (key === 'f') {
4167
5242
  event.preventDefault();
4168
- callbacks.onFocusSelection?.();
5243
+ if (isPreviewToolEnabled('focus-selection'))
5244
+ callbacks.onFocusSelection?.();
4169
5245
  return;
4170
5246
  }
4171
5247
  if (key === 'escape') {
4172
5248
  event.preventDefault();
4173
- if (callbacks.onCancelEditorIntent)
4174
- callbacks.onCancelEditorIntent();
4175
- else
4176
- callbacks.onCancelActiveOperation?.();
5249
+ if (isPreviewToolEnabled('cancel-selection')) {
5250
+ if (callbacks.onCancelEditorIntent)
5251
+ callbacks.onCancelEditorIntent();
5252
+ else
5253
+ callbacks.onCancelActiveOperation?.();
5254
+ }
4177
5255
  }
4178
5256
  };
4179
5257
  doc.addEventListener('keydown', onKeyDown);
@@ -4190,8 +5268,193 @@ export function createLocalEditorBrowserUi(options = {}) {
4190
5268
  ? operationState.canAlign
4191
5269
  : operationState.canDistribute;
4192
5270
  }
5271
+ function getPreviewToolSupport(tool) {
5272
+ const inPrefabStage = currentState?.mode === 'editor' && !!currentState.prefabStage;
5273
+ return resolveLocalEditorPreviewToolSupport({ inPrefabStage, tool });
5274
+ }
5275
+ function isPreviewToolVisible(tool) {
5276
+ return currentState?.mode === 'editor' && getPreviewToolSupport(tool).support !== 'hidden';
5277
+ }
5278
+ function isPreviewToolEnabled(tool) {
5279
+ return currentState?.mode === 'editor'
5280
+ && currentState.busy !== true
5281
+ && getPreviewToolSupport(tool).support === 'enabled';
5282
+ }
5283
+ function applyPrefabStageWorkbenchLayoutOverride(layout = workbenchLayoutController.getLayout()) {
5284
+ const { leftWidth, rightWidth, bottomEdge, bottomVisible } = resolveLocalEditorPrefabStageWorkbenchLayout(layout, readLocalEditorWorkbenchViewport(doc));
5285
+ workbench.leftDock.style.display = 'flex';
5286
+ workbench.leftDock.style.width = `${leftWidth}px`;
5287
+ workbench.leftDock.style.bottom = `${bottomEdge}px`;
5288
+ workbench.leftDock.style.zIndex = '';
5289
+ workbench.leftDock.style.boxShadow = '';
5290
+ workbench.rightDock.style.display = 'flex';
5291
+ workbench.rightDock.style.width = `${rightWidth}px`;
5292
+ workbench.rightDock.style.zIndex = '';
5293
+ workbench.rightDock.style.boxShadow = '';
5294
+ workbench.sceneFrame.style.left = `${leftWidth}px`;
5295
+ workbench.sceneFrame.style.right = `${rightWidth}px`;
5296
+ workbench.sceneFrame.style.bottom = `${bottomEdge}px`;
5297
+ if (bottomVisible) {
5298
+ workbench.bottomDock.style.right = `${rightWidth}px`;
5299
+ workbench.bottomResizer.style.right = `${rightWidth}px`;
5300
+ }
5301
+ workbench.leftToggle.style.display = 'none';
5302
+ workbench.rightToggle.style.display = 'none';
5303
+ workbench.leftResizer.style.bottom = `${bottomEdge}px`;
5304
+ workbench.rightResizer.style.bottom = '0';
5305
+ }
5306
+ function readLocalEditorWorkbenchViewport(docRef) {
5307
+ const win = docRef.defaultView;
5308
+ return {
5309
+ width: Math.max(320, win?.innerWidth ?? docRef.documentElement.clientWidth ?? 1280),
5310
+ height: Math.max(320, win?.innerHeight ?? docRef.documentElement.clientHeight ?? 720),
5311
+ };
5312
+ }
5313
+ function renderPrefabStagePropertiesPanel(stage) {
5314
+ inspectorPanel.dataset.editorPanelId = 'prefab-properties';
5315
+ inspectorPanel.style.display = '';
5316
+ renderingPanel.style.display = 'none';
5317
+ if (stage.inspectorObject) {
5318
+ LocalEditorPanels.renderInspectorPanel(doc, inspectorPanel, {
5319
+ ...currentState,
5320
+ selectedIds: stage.inspectorObject.targetIds,
5321
+ activeId: stage.inspectorObject.activeId,
5322
+ selectionSummary: {
5323
+ count: stage.inspectorObject.targetIds.length,
5324
+ activeId: stage.inspectorObject.activeId,
5325
+ },
5326
+ serializedObject: null,
5327
+ serializedMultiObject: null,
5328
+ inspectorObject: stage.inspectorObject,
5329
+ inspectorMultiObject: null,
5330
+ }, inspectorFilter, {
5331
+ ...options.inspector,
5332
+ title: 'Prefab Properties',
5333
+ emptyText: 'Select an item in Prefab Explorer.',
5334
+ summaryTitle: 'Prefab',
5335
+ lockedVectorGroups: lockedInspectorVectorGroups,
5336
+ });
5337
+ return;
5338
+ }
5339
+ LocalEditorShared.clearElement(inspectorPanel);
5340
+ inspectorPanel.appendChild(createPrefabStagePanelHeader('Prefab Properties', 'inspector'));
5341
+ const selectedItem = findLocalEditorPrefabStageStructureItem(stage, stage.selectedItemId);
5342
+ const grid = doc.createElement('div');
5343
+ grid.style.cssText = 'display:flex;flex-direction:column;gap:7px;min-width:0';
5344
+ appendPrefabStageReadonlyRow(grid, '名称', stage.label);
5345
+ appendPrefabStageReadonlyRow(grid, 'Prefab ID', stage.assetId);
5346
+ appendPrefabStageReadonlyRow(grid, 'Source', stage.sourceAssetId ?? '未设置');
5347
+ appendPrefabStageReadonlyRow(grid, 'Preview', stage.previewNodeId ?? '未生成');
5348
+ appendPrefabStageReadonlyRow(grid, 'Selected', selectedItem?.label ?? stage.selectedItemId ?? 'Prefab Root');
5349
+ appendPrefabStageReadonlyRow(grid, 'Mode', stage.readonly ? '只读' : '可编辑');
5350
+ appendPrefabStageSelectedItemDetails(grid, selectedItem);
5351
+ inspectorPanel.appendChild(grid);
5352
+ }
5353
+ function appendPrefabStageSelectedItemDetails(container, item) {
5354
+ if (!item)
5355
+ return;
5356
+ appendPrefabStageReadonlyRow(container, 'Kind', item.kind);
5357
+ if (item.sourceAssetId)
5358
+ appendPrefabStageReadonlyRow(container, 'Source Asset', item.sourceAssetId);
5359
+ if (item.slotId)
5360
+ appendPrefabStageReadonlyRow(container, 'Slot ID', item.slotId);
5361
+ if (item.ownerNodePath)
5362
+ appendPrefabStageReadonlyRow(container, 'Owner Path', item.ownerNodePath);
5363
+ if (item.meshIndex != null)
5364
+ appendPrefabStageReadonlyRow(container, 'Mesh Index', String(item.meshIndex));
5365
+ if (item.primitiveIndex != null)
5366
+ appendPrefabStageReadonlyRow(container, 'Primitive', String(item.primitiveIndex));
5367
+ if (item.sourceMaterialIndex != null) {
5368
+ appendPrefabStageReadonlyRow(container, 'Material Index', String(item.sourceMaterialIndex));
5369
+ }
5370
+ if (item.sourceMaterialIndices?.length) {
5371
+ appendPrefabStageReadonlyRow(container, 'Material Indices', item.sourceMaterialIndices.join(', '));
5372
+ }
5373
+ if (item.sourceMaterialName)
5374
+ appendPrefabStageReadonlyRow(container, 'Material Name', item.sourceMaterialName);
5375
+ if (item.sourceMaterialNames?.length) {
5376
+ appendPrefabStageReadonlyRow(container, 'Material Names', item.sourceMaterialNames.join(', '));
5377
+ }
5378
+ if (item.meta)
5379
+ appendPrefabStageReadonlyRow(container, 'Meta', item.meta);
5380
+ }
5381
+ function resolvePrefabStageAssetFromState(stage) {
5382
+ return currentState?.assets.find(asset => (asset.id === stage.browserAssetId
5383
+ || asset.id === `prefab:${stage.assetId}`
5384
+ || asset.assetId === stage.assetId
5385
+ || asset.prefab?.id === stage.assetId)) ?? null;
5386
+ }
5387
+ function createPrefabStagePanelHeader(title, icon) {
5388
+ const header = doc.createElement('div');
5389
+ header.style.cssText = [
5390
+ 'display:flex',
5391
+ 'align-items:center',
5392
+ 'gap:8px',
5393
+ 'min-height:30px',
5394
+ 'margin:-8px -8px 8px',
5395
+ 'padding:0 8px',
5396
+ 'border-bottom:1px solid var(--fps-editor-divider)',
5397
+ 'background:var(--fps-editor-chrome-dark)',
5398
+ ].join(';');
5399
+ header.appendChild(createLocalEditorIcon(doc, icon, { size: 14 }));
5400
+ const label = doc.createElement('h2');
5401
+ label.textContent = title;
5402
+ label.style.cssText = [
5403
+ 'min-width:0',
5404
+ 'margin:0',
5405
+ 'overflow:hidden',
5406
+ 'text-overflow:ellipsis',
5407
+ 'white-space:nowrap',
5408
+ 'font-size:13px',
5409
+ 'font-weight:800',
5410
+ 'color:var(--fps-editor-text-strong)',
5411
+ ].join(';');
5412
+ header.appendChild(label);
5413
+ return header;
5414
+ }
5415
+ function appendPrefabStageReadonlyRow(container, label, value) {
5416
+ const row = doc.createElement('div');
5417
+ row.style.cssText = [
5418
+ 'display:grid',
5419
+ 'grid-template-columns:92px minmax(0,1fr)',
5420
+ 'gap:8px',
5421
+ 'align-items:center',
5422
+ 'min-height:26px',
5423
+ ].join(';');
5424
+ const rowLabel = doc.createElement('div');
5425
+ rowLabel.textContent = label;
5426
+ rowLabel.style.cssText = [
5427
+ 'min-width:0',
5428
+ 'overflow:hidden',
5429
+ 'text-overflow:ellipsis',
5430
+ 'white-space:nowrap',
5431
+ 'color:var(--fps-editor-muted)',
5432
+ 'font-size:11px',
5433
+ 'font-weight:800',
5434
+ ].join(';');
5435
+ const output = doc.createElement('div');
5436
+ output.textContent = value;
5437
+ output.title = value;
5438
+ output.style.cssText = [
5439
+ 'min-width:0',
5440
+ 'overflow:hidden',
5441
+ 'text-overflow:ellipsis',
5442
+ 'white-space:nowrap',
5443
+ 'padding:4px 7px',
5444
+ 'border:1px solid var(--fps-editor-border)',
5445
+ 'border-radius:3px',
5446
+ 'background:var(--fps-editor-field)',
5447
+ 'color:var(--fps-editor-text-strong)',
5448
+ 'font-size:12px',
5449
+ 'font-weight:800',
5450
+ ].join(';');
5451
+ row.appendChild(rowLabel);
5452
+ row.appendChild(output);
5453
+ container.appendChild(row);
5454
+ }
4193
5455
  const renderPreviewState = (state) => {
4194
5456
  const inEditor = state.mode === 'editor';
5457
+ const inPrefabStage = !!state.prefabStage;
4195
5458
  const disabled = state.busy;
4196
5459
  const transformTool = state.transformTool ?? null;
4197
5460
  const transformOperations = state.transformOperations ?? {
@@ -4234,9 +5497,30 @@ export function createLocalEditorBrowserUi(options = {}) {
4234
5497
  editorStatusButton.style.borderColor = state.statusTone == null || state.statusTone === 'default'
4235
5498
  ? 'var(--fps-editor-border)'
4236
5499
  : statusToneColor;
5500
+ const agentBridgeStatusColor = resolveAgentBridgeStatusToneColor(state.agentBridge);
5501
+ agentBridgeStatusButton.style.display = inEditor ? 'inline-flex' : 'none';
5502
+ agentBridgeStatusButton.style.color = agentBridgeStatusColor;
5503
+ agentBridgeStatusButton.style.borderColor = state.agentBridge?.status === 'disabled'
5504
+ ? 'var(--fps-editor-border)'
5505
+ : agentBridgeStatusColor;
5506
+ setToolbarButtonTooltip(agentBridgeStatusButton, createAgentBridgeStatusTooltip(state.agentBridge));
4237
5507
  renderCoordinateAxesOverlay(coordinateAxesOverlay, inEditor ? state.coordinateAxes ?? null : null);
4238
- renderSceneFrameRateOverlay(sceneFrameRateOverlay, inEditor ? state.sceneFrameStats ?? null : null);
4239
- renderPerformanceMonitorOverlay(performanceMonitorOverlay, inEditor ? state.performanceStats ?? null : null, inEditor && performanceMonitorOpen);
5508
+ renderSceneFrameRateOverlay(sceneFrameRateOverlay, inEditor && !inPrefabStage ? state.sceneFrameStats ?? null : null);
5509
+ renderPerformanceMonitorOverlay(performanceMonitorOverlay, inEditor && !inPrefabStage ? state.performanceStats ?? null : null, inEditor && !inPrefabStage && performanceMonitorOpen);
5510
+ const comparisonColumnVisible = shouldShowLocalEditorPrefabComparisonColumn({
5511
+ inPrefabStage: inEditor && inPrefabStage,
5512
+ userOpen: prefabComparisonPreviewOpen,
5513
+ sceneWidth: workbench.sceneFrame.clientWidth,
5514
+ });
5515
+ if (!comparisonColumnVisible)
5516
+ endPrefabComparisonPreviewDrag();
5517
+ prefabStagePreviewLayout.root.style.display = inEditor && inPrefabStage ? 'block' : 'none';
5518
+ prefabStagePreviewLayout.mainRegion.style.right = comparisonColumnVisible
5519
+ ? `${LOCAL_EDITOR_PREFAB_COMPARISON_COLUMN_WIDTH_PX}px`
5520
+ : '0';
5521
+ prefabStagePreviewLayout.comparisonColumn.style.display = comparisonColumnVisible ? 'flex' : 'none';
5522
+ renderPrefabImportStatsOverlay(prefabImportStatsOverlay, inEditor && inPrefabStage ? state.prefabStage ?? null : null);
5523
+ renderPrefabComparisonPreviewOverlay(prefabComparisonPreviewOverlay, inEditor && inPrefabStage && comparisonColumnVisible ? state.prefabStage ?? null : null);
4240
5524
  renderSpatialOverlay(spatialOverlay, inEditor ? state.viewportSpatialOverlay ?? null : null);
4241
5525
  renderMeasurementOverlay(measurementOverlay, inEditor ? state.viewportMeasurement ?? null : null);
4242
5526
  const boxSelection = state.boxSelection;
@@ -4263,38 +5547,42 @@ export function createLocalEditorBrowserUi(options = {}) {
4263
5547
  };
4264
5548
  renderPreviewState(currentState);
4265
5549
  if (shouldRenderInspectorPreview && panelRegistry.getRightDockTab() === 'inspector') {
4266
- const rightDockScrollSnapshot = captureLocalEditorRightDockScrollSnapshot(currentState, 'inspector', inspectorFilter, inspectorPanel, renderingPanel);
5550
+ const rightDockScrollSnapshot = captureLocalEditorRightDockScrollSnapshot(currentState, 'inspector', inspectorFilter, inspectorPanel, renderingPanel, markersPanel);
4267
5551
  LocalEditorPanels.renderInspectorPanel(doc, inspectorPanel, currentState, inspectorFilter, {
4268
5552
  ...options.inspector,
4269
5553
  lockedVectorGroups: lockedInspectorVectorGroups,
4270
5554
  });
4271
- restoreLocalEditorRightDockScrollSnapshot(rightDockScrollSnapshot, currentState, 'inspector', inspectorFilter, inspectorPanel, renderingPanel);
5555
+ restoreLocalEditorRightDockScrollSnapshot(rightDockScrollSnapshot, currentState, 'inspector', inspectorFilter, inspectorPanel, renderingPanel, markersPanel);
4272
5556
  }
4273
5557
  };
4274
5558
  const render = (state) => {
4275
5559
  const previousState = currentState;
4276
5560
  const previousRightTab = panelRegistry.getRightDockTab();
4277
- const rightDockScrollSnapshot = captureLocalEditorRightDockScrollSnapshot(previousState, previousRightTab, inspectorFilter, inspectorPanel, renderingPanel);
5561
+ const rightDockScrollSnapshot = captureLocalEditorRightDockScrollSnapshot(previousState, previousRightTab, inspectorFilter, inspectorPanel, renderingPanel, markersPanel);
4278
5562
  currentState = state;
4279
5563
  const focusSnapshot = captureLocalEditorEditableFocus(doc);
4280
5564
  const inEditor = state.mode === 'editor';
4281
5565
  const disabled = state.busy;
5566
+ const prefabStage = inEditor ? state.prefabStage ?? null : null;
5567
+ const inPrefabStage = !!prefabStage;
5568
+ const previousInPrefabStage = previousState?.mode === 'editor' && !!previousState.prefabStage;
4282
5569
  if (!inEditor || disabled)
4283
5570
  contextMenu.close();
4284
5571
  hostChrome.style.display = !inEditor && localTestActionsEnabled ? 'flex' : 'none';
4285
5572
  enterEditorButton.disabled = disabled;
4286
- for (const button of [saveButton, saveAndRunButton, discardRunButton, undoButton, redoButton, sceneHelpButton, sceneCameraButton, performanceMonitorButton, gridToggleButton]) {
5573
+ for (const button of [saveButton, saveAndRunButton, discardRunButton, undoButton, redoButton, sceneHelpButton, sceneCameraButton, performanceMonitorButton, gridToggleButton, prefabComparisonPreviewButton]) {
4287
5574
  button.style.display = 'inline-flex';
4288
5575
  button.disabled = disabled;
4289
5576
  }
4290
- localTestGroup.style.display = inEditor && localTestActionsEnabled ? 'flex' : 'none';
4291
- localTestButton.disabled = disabled;
4292
- if (!inEditor || !localTestActionsEnabled)
5577
+ localTestGroup.style.display = isPreviewToolVisible('local-test') && localTestActionsEnabled ? 'flex' : 'none';
5578
+ localTestButton.disabled = !isPreviewToolEnabled('local-test') || !localTestActionsEnabled;
5579
+ if (!inEditor || !localTestActionsEnabled || localTestGroup.style.display === 'none')
4293
5580
  closeLocalTestMenu();
4294
5581
  if (!inEditor)
4295
5582
  helpOpen = false;
4296
- if (!inEditor && performanceMonitorOpen)
5583
+ if (shouldLocalEditorClosePerformanceMonitor({ inEditor, inPrefabStage, performanceMonitorOpen })) {
4297
5584
  setPerformanceMonitorOpen(false);
5585
+ }
4298
5586
  if (!inEditor || disabled) {
4299
5587
  assetPreviewOpen = false;
4300
5588
  previewedAsset = null;
@@ -4306,7 +5594,24 @@ export function createLocalEditorBrowserUi(options = {}) {
4306
5594
  syncInputModalOpen();
4307
5595
  const transformTool = state.transformTool ?? null;
4308
5596
  workbench.root.style.display = inEditor ? '' : 'none';
5597
+ workbench.root.dataset.editorPrefabStage = String(inPrefabStage);
5598
+ sceneTitle.textContent = createLocalEditorPrefabStageTitle(prefabStage);
4309
5599
  sceneToolOverlay.style.display = inEditor ? 'flex' : 'none';
5600
+ prefabStageBackButton.style.display = inPrefabStage ? 'inline-flex' : 'none';
5601
+ if (inPrefabStage && !previousInPrefabStage) {
5602
+ prefabStageMainWorkbenchLayoutSnapshot = workbenchLayoutController.getLayout();
5603
+ workbenchLayoutController.setBottomCollapsed(false);
5604
+ }
5605
+ else if (!inPrefabStage && previousInPrefabStage && prefabStageMainWorkbenchLayoutSnapshot) {
5606
+ workbenchLayoutController.setLayout(prefabStageMainWorkbenchLayoutSnapshot, true);
5607
+ prefabStageMainWorkbenchLayoutSnapshot = null;
5608
+ }
5609
+ workbench.leftToggle.style.display = '';
5610
+ workbench.rightToggle.style.display = '';
5611
+ workbench.bottomToggle.style.display = '';
5612
+ workbenchLayoutController.refresh();
5613
+ if (inPrefabStage)
5614
+ applyPrefabStageWorkbenchLayoutOverride();
4310
5615
  if (!inEditor)
4311
5616
  closeSnapSettingsPopover();
4312
5617
  if (!inEditor)
@@ -4318,34 +5623,40 @@ export function createLocalEditorBrowserUi(options = {}) {
4318
5623
  if (!inEditor)
4319
5624
  closeStaticShadowBakePopover();
4320
5625
  const staticShadowBakeAction = findLocalEditorRenderingAction(state.renderingPanel, STATIC_SHADOW_BAKE_ACTION_ID);
4321
- const staticShadowBakeVisible = inEditor && !!staticShadowBakeAction;
5626
+ const staticShadowBakeVisible = isPreviewToolVisible('static-shadow-bake') && !!staticShadowBakeAction;
4322
5627
  staticShadowBakeGroup.style.display = staticShadowBakeVisible ? 'flex' : 'none';
4323
- const staticShadowBakeDisabled = disabled || !staticShadowBakeAction || staticShadowBakeAction.action.disabled === true;
5628
+ const staticShadowBakeSupport = getPreviewToolSupport('static-shadow-bake');
5629
+ const staticShadowBakeDisabled = !isPreviewToolEnabled('static-shadow-bake') || !staticShadowBakeAction || staticShadowBakeAction.action.disabled === true;
4324
5630
  staticShadowBakeButton.disabled = staticShadowBakeDisabled;
4325
5631
  staticShadowBakeButton.style.opacity = staticShadowBakeDisabled ? '0.62' : '1';
4326
5632
  staticShadowBakeButton.style.cursor = staticShadowBakeDisabled ? 'not-allowed' : 'pointer';
4327
5633
  const staticShadowBakeIcon = staticShadowBakeAction?.action.icon;
4328
5634
  setToolbarButtonIcon(doc, staticShadowBakeButton, isLocalEditorIconName(staticShadowBakeIcon) ? staticShadowBakeIcon : 'save');
4329
- setToolbarButtonTooltip(staticShadowBakeButton, staticShadowBakeAction?.action.tooltip ?? staticShadowBakeAction?.action.label ?? '烘焙静态阴影');
5635
+ setToolbarButtonTooltip(staticShadowBakeButton, staticShadowBakeSupport.support === 'enabled'
5636
+ ? staticShadowBakeAction?.action.tooltip ?? staticShadowBakeAction?.action.label ?? '烘焙静态阴影'
5637
+ : staticShadowBakeSupport.reason);
4330
5638
  LocalEditorShared.applyButtonActiveState(staticShadowBakeButton, !!staticShadowBakeAction?.system?.progress);
4331
5639
  renderStaticShadowBakePopover(state);
4332
5640
  const sceneCameraPreview = state.sceneCameraPreview ?? { enabled: false, available: false };
4333
- cameraPreviewGroup.style.display = inEditor ? 'flex' : 'none';
4334
- sceneCameraButton.disabled = disabled || !sceneCameraPreview.available;
5641
+ cameraPreviewGroup.style.display = isPreviewToolVisible('scene-camera-preview') ? 'flex' : 'none';
5642
+ const sceneCameraPreviewSupport = getPreviewToolSupport('scene-camera-preview');
5643
+ sceneCameraButton.disabled = !isPreviewToolEnabled('scene-camera-preview') || !sceneCameraPreview.available;
4335
5644
  const sceneCameraTooltip = sceneCameraPreview.available
4336
5645
  ? '从 Main Camera 查看当前场景'
4337
5646
  : '当前场景没有可预览的 Main Camera';
4338
- setToolbarButtonTooltip(sceneCameraButton, sceneCameraTooltip);
5647
+ setToolbarButtonTooltip(sceneCameraButton, sceneCameraPreviewSupport.support === 'enabled'
5648
+ ? sceneCameraTooltip
5649
+ : sceneCameraPreviewSupport.reason);
4339
5650
  LocalEditorShared.applyButtonActiveState(sceneCameraButton, sceneCameraPreview.enabled);
4340
5651
  const viewportTools = state.viewportTools ?? null;
4341
- const viewportControlsDisabled = disabled || sceneCameraPreview.enabled;
5652
+ const viewportControlsDisabled = !isPreviewToolEnabled('viewport-camera') || sceneCameraPreview.enabled;
4342
5653
  const viewportControlsTooltip = sceneCameraPreview.enabled
4343
5654
  ? '当前为 Main Camera 预览,请关闭后再使用视口工具'
4344
5655
  : '';
4345
5656
  const viewportProjectionTooltip = sceneCameraPreview.enabled
4346
5657
  ? '当前为 Main Camera 预览,投影由 Main Camera 决定;关闭预览后可切换编辑视口投影'
4347
5658
  : '';
4348
- viewportToolsGroup.style.display = inEditor ? 'flex' : 'none';
5659
+ viewportToolsGroup.style.display = isPreviewToolVisible('viewport-camera') ? 'flex' : 'none';
4349
5660
  for (const [preset, button] of viewportPresetButtons) {
4350
5661
  button.disabled = viewportControlsDisabled;
4351
5662
  setToolbarButtonTooltip(button, viewportControlsTooltip || VIEW_PRESET_TOOLTIPS[preset]);
@@ -4357,12 +5668,16 @@ export function createLocalEditorBrowserUi(options = {}) {
4357
5668
  setToolbarButtonIcon(doc, projectionToggleButton, projectionMode === 'orthographic' ? 'projection-ortho' : 'projection-perspective');
4358
5669
  setToolbarButtonTooltip(projectionToggleButton, viewportProjectionTooltip || `投影模式:${VIEWPORT_PROJECTION_LABELS[projectionMode]}。切换为${VIEWPORT_PROJECTION_LABELS[nextProjectionMode]}`);
4359
5670
  LocalEditorShared.applyButtonActiveState(projectionToggleButton, projectionMode === 'orthographic');
4360
- overlaySettingsButton.disabled = disabled;
5671
+ const markersVisible = viewportTools?.markersVisible ?? true;
5672
+ markerVisibilityButton.disabled = disabled;
5673
+ setToolbarButtonTooltip(markerVisibilityButton, markersVisible ? '隐藏标记与关系线' : '显示标记与关系线');
5674
+ LocalEditorShared.applyButtonActiveState(markerVisibilityButton, markersVisible);
5675
+ overlaySettingsButton.disabled = !isPreviewToolEnabled('spatial-overlay');
4361
5676
  setToolbarButtonTooltip(overlaySettingsButton, '视口信息层设置');
4362
5677
  LocalEditorShared.applyButtonActiveState(overlaySettingsButton, overlaySettingsOpen);
4363
5678
  const overlaySettings = viewportTools?.overlay;
4364
5679
  for (const [key, input] of overlayInputs) {
4365
- input.disabled = disabled;
5680
+ input.disabled = !isPreviewToolEnabled('spatial-overlay');
4366
5681
  input.checked = overlaySettings?.[key] ?? false;
4367
5682
  }
4368
5683
  measureButton.disabled = viewportControlsDisabled;
@@ -4378,18 +5693,33 @@ export function createLocalEditorBrowserUi(options = {}) {
4378
5693
  if (!inEditor || disabled || viewportToolsGroup.style.display === 'none')
4379
5694
  closeOverlaySettingsPopover();
4380
5695
  const gridState = state.grid ?? { visible: false, available: false };
4381
- performanceMonitorButton.disabled = disabled;
4382
- setToolbarButtonTooltip(performanceMonitorButton, performanceMonitorOpen ? '隐藏性能监控' : '显示性能监控');
5696
+ performanceMonitorButton.style.display = isPreviewToolVisible('performance-monitor') ? 'inline-flex' : 'none';
5697
+ performanceMonitorButton.disabled = !isPreviewToolEnabled('performance-monitor');
5698
+ const performanceMonitorSupport = getPreviewToolSupport('performance-monitor');
5699
+ setToolbarButtonTooltip(performanceMonitorButton, performanceMonitorSupport.support === 'enabled'
5700
+ ? performanceMonitorOpen ? '隐藏性能监控' : '显示性能监控'
5701
+ : performanceMonitorSupport.reason);
4383
5702
  LocalEditorShared.applyButtonActiveState(performanceMonitorButton, performanceMonitorOpen);
5703
+ prefabComparisonPreviewButton.style.display = isPreviewToolVisible('prefab-comparison') ? 'inline-flex' : 'none';
5704
+ prefabComparisonPreviewButton.disabled = !isPreviewToolEnabled('prefab-comparison');
5705
+ const prefabComparisonSupport = getPreviewToolSupport('prefab-comparison');
5706
+ setToolbarButtonTooltip(prefabComparisonPreviewButton, prefabComparisonSupport.support === 'enabled'
5707
+ ? prefabComparisonPreviewOpen
5708
+ ? '隐藏对比预览 (Shift+P)'
5709
+ : '显示对比预览 (Shift+P)'
5710
+ : prefabComparisonSupport.reason);
5711
+ LocalEditorShared.applyButtonActiveState(prefabComparisonPreviewButton, inPrefabStage && prefabComparisonPreviewOpen);
4384
5712
  gridToggleButton.disabled = disabled || !gridState.available;
4385
5713
  setToolbarButtonTooltip(gridToggleButton, gridState.visible ? '隐藏 Scene View 网格' : '显示 Scene View 网格');
4386
5714
  LocalEditorShared.applyButtonActiveState(gridToggleButton, gridState.visible);
5715
+ toolGroup.style.display = isPreviewToolVisible('select') ? 'flex' : 'none';
5716
+ spaceGroup.style.display = isPreviewToolVisible('transform-space') ? 'flex' : 'none';
4387
5717
  for (const [tool, button] of toolButtons) {
4388
- button.disabled = disabled;
5718
+ button.disabled = !isPreviewToolEnabled(tool);
4389
5719
  LocalEditorShared.applyButtonActiveState(button, transformTool?.activeTool === tool);
4390
5720
  }
4391
5721
  for (const [space, button] of Object.entries(spaceButtons)) {
4392
- button.disabled = disabled;
5722
+ button.disabled = !isPreviewToolEnabled('transform-space');
4393
5723
  LocalEditorShared.applyButtonActiveState(button, transformTool?.activeSpace === space);
4394
5724
  }
4395
5725
  sceneHelpButton.disabled = disabled;
@@ -4401,38 +5731,38 @@ export function createLocalEditorBrowserUi(options = {}) {
4401
5731
  canDistribute: false,
4402
5732
  };
4403
5733
  const operationSettings = transformOperations.settings;
4404
- snapGroup.style.display = inEditor ? 'flex' : 'none';
4405
- snapButton.disabled = disabled;
4406
- snapEnabledInput.disabled = disabled;
5734
+ snapGroup.style.display = isPreviewToolVisible('snap') ? 'flex' : 'none';
5735
+ snapButton.disabled = !isPreviewToolEnabled('snap');
5736
+ snapEnabledInput.disabled = !isPreviewToolEnabled('snap');
4407
5737
  snapEnabledInput.checked = operationSettings.snap.enabled;
4408
5738
  LocalEditorShared.applyButtonActiveState(snapButton, operationSettings.snap.enabled || snapSettingsOpen);
4409
5739
  setToolbarButtonTooltip(snapButton, `吸附设置 · 位移 ${formatSnapStepInputValue(operationSettings.snap, 'move')} · 旋转 ${formatSnapStepInputValue(operationSettings.snap, 'rotate')}° · 缩放 ${formatSnapStepInputValue(operationSettings.snap, 'scale')}`);
4410
5740
  for (const [kind, input] of snapStepInputs) {
4411
- input.disabled = disabled;
5741
+ input.disabled = !isPreviewToolEnabled('snap');
4412
5742
  if (doc.activeElement !== input)
4413
5743
  input.value = formatSnapStepInputValue(operationSettings.snap, kind);
4414
5744
  }
4415
5745
  if (!inEditor || disabled || snapGroup.style.display === 'none')
4416
5746
  closeSnapSettingsPopover();
4417
- placementGroup.style.display = inEditor ? 'flex' : 'none';
4418
- placementButton.disabled = disabled;
5747
+ placementGroup.style.display = isPreviewToolVisible('placement') ? 'flex' : 'none';
5748
+ placementButton.disabled = !isPreviewToolEnabled('placement');
4419
5749
  setToolbarButtonIcon(doc, placementButton, PLACEMENT_MODE_ICONS[operationSettings.placementMode]);
4420
5750
  setToolbarButtonTooltip(placementButton, `放置模式 · ${PLACEMENT_MODE_DESCRIPTIONS[operationSettings.placementMode]}`);
4421
5751
  LocalEditorShared.applyButtonActiveState(placementButton, operationSettings.placementMode !== 'off' || placementSettingsOpen);
4422
5752
  for (const [mode, button] of Object.entries(placementButtons)) {
4423
- button.disabled = disabled;
5753
+ button.disabled = !isPreviewToolEnabled('placement');
4424
5754
  LocalEditorShared.applyButtonActiveState(button, operationSettings.placementMode === mode);
4425
5755
  }
4426
5756
  if (!inEditor || disabled || placementGroup.style.display === 'none')
4427
5757
  closePlacementSettingsPopover();
4428
- actionGroup.style.display = inEditor ? 'flex' : 'none';
5758
+ actionGroup.style.display = isPreviewToolVisible('transform-actions') ? 'flex' : 'none';
4429
5759
  const hasTransformAction = transformOperations.canAlign || transformOperations.canDistribute;
4430
- transformActionButton.disabled = disabled || !hasTransformAction;
5760
+ transformActionButton.disabled = !isPreviewToolEnabled('transform-actions') || !hasTransformAction;
4431
5761
  setToolbarButtonTooltip(transformActionButton, hasTransformAction ? '对齐与分布' : '选择至少 2 个对象后可用');
4432
5762
  LocalEditorShared.applyButtonActiveState(transformActionButton, transformActionOpen);
4433
5763
  for (const [action, button] of transformActionButtons) {
4434
5764
  const enabled = isTransformActionEnabled(action, transformOperations);
4435
- button.disabled = disabled || !enabled;
5765
+ button.disabled = !isPreviewToolEnabled('transform-actions') || !enabled;
4436
5766
  button.style.opacity = button.disabled ? '0.45' : '1';
4437
5767
  button.style.cursor = button.disabled ? 'not-allowed' : 'pointer';
4438
5768
  }
@@ -4449,9 +5779,49 @@ export function createLocalEditorBrowserUi(options = {}) {
4449
5779
  scheduleToolbarOverflowLayout();
4450
5780
  if (!inEditor)
4451
5781
  return;
5782
+ const activeRightTab = panelRegistry.getRightDockTab();
5783
+ if (inPrefabStage && prefabStage) {
5784
+ const rightDockVisibility = resolveLocalEditorRightDockVisibility({
5785
+ inPrefabStage: true,
5786
+ activeRightTab,
5787
+ });
5788
+ const activeBottomTab = panelRegistry.getBottomDockTab();
5789
+ const assetBrowserTabChanged = assetBrowserTab !== lastRenderedAssetBrowserTab;
5790
+ const bottomDockTabChanged = activeBottomTab !== lastRenderedBottomDockTab;
5791
+ const selectedAssetChanged = state.selectedAssetId !== lastRenderedSelectedAssetId;
5792
+ const assetBrowserScrollSnapshot = activeBottomTab === 'assets'
5793
+ ? assetBrowserViewportReveal.captureScrollSnapshot()
5794
+ : { scrollTop: null };
5795
+ leftDockTabs.style.display = 'none';
5796
+ rightDockTabs.style.display = rightDockVisibility.tabsDisplay;
5797
+ inspectorPanel.style.display = rightDockVisibility.inspectorDisplay;
5798
+ renderingPanel.style.display = rightDockVisibility.renderingDisplay;
5799
+ hierarchyController.render(state);
5800
+ renderPrefabStagePropertiesPanel(prefabStage);
5801
+ LocalEditorPanels.renderWorkbenchBottomDockPanel(doc, assetPanel, state, activeBottomTab, panelRegistry.getPanels('bottom'), assetBrowserTab);
5802
+ if (activeBottomTab === 'assets' && !assetBrowserTabChanged && !bottomDockTabChanged) {
5803
+ assetBrowserViewportReveal.restoreScrollSnapshot(assetBrowserScrollSnapshot);
5804
+ }
5805
+ const suppressAssetScroll = state.selectedAssetId
5806
+ ? assetBrowserViewportReveal.consumeRevealSuppression(state.selectedAssetId, { clearWhenDifferent: selectedAssetChanged })
5807
+ : false;
5808
+ if (activeBottomTab === 'assets' && selectedAssetChanged && state.selectedAssetId && !suppressAssetScroll) {
5809
+ revealSelectedAssetBrowserItem(state.selectedAssetId);
5810
+ }
5811
+ lastRenderedAssetBrowserTab = assetBrowserTab;
5812
+ lastRenderedBottomDockTab = activeBottomTab;
5813
+ lastRenderedSelectedAssetId = state.selectedAssetId ?? null;
5814
+ restoreLocalEditorEditableFocus(doc, focusSnapshot);
5815
+ return;
5816
+ }
5817
+ leftDockTabs.style.display = '';
4452
5818
  const hierarchyDescriptor = panelRegistry.getActivePanel('left');
4453
5819
  const rightDescriptor = panelRegistry.getActivePanel('right');
4454
- const activeRightTab = panelRegistry.getRightDockTab();
5820
+ const rightDockVisibility = resolveLocalEditorRightDockVisibility({
5821
+ inPrefabStage: false,
5822
+ activeRightTab,
5823
+ });
5824
+ rightDockTabs.style.display = rightDockVisibility.tabsDisplay;
4455
5825
  const activeBottomTab = panelRegistry.getBottomDockTab();
4456
5826
  const assetBrowserTabChanged = assetBrowserTab !== lastRenderedAssetBrowserTab;
4457
5827
  const bottomDockTabChanged = activeBottomTab !== lastRenderedBottomDockTab;
@@ -4462,8 +5832,10 @@ export function createLocalEditorBrowserUi(options = {}) {
4462
5832
  hierarchyPanel.dataset.editorPanelId = hierarchyDescriptor?.id ?? 'hierarchy';
4463
5833
  inspectorPanel.dataset.editorPanelId = activeRightTab === 'inspector' ? rightDescriptor?.id ?? 'inspector' : 'inspector';
4464
5834
  renderingPanel.dataset.editorPanelId = activeRightTab === 'rendering' ? rightDescriptor?.id ?? 'rendering' : 'rendering';
4465
- inspectorPanel.style.display = activeRightTab === 'inspector' ? '' : 'none';
4466
- renderingPanel.style.display = activeRightTab === 'rendering' ? '' : 'none';
5835
+ markersPanel.dataset.editorPanelId = activeRightTab === 'markers' ? rightDescriptor?.id ?? 'markers' : 'markers';
5836
+ inspectorPanel.style.display = rightDockVisibility.inspectorDisplay;
5837
+ renderingPanel.style.display = rightDockVisibility.renderingDisplay;
5838
+ markersPanel.style.display = activeRightTab === 'markers' ? '' : 'none';
4467
5839
  LocalEditorPanels.renderWorkbenchLeftDockTabs(doc, leftDockTabs, 'hierarchy', panelRegistry.getPanels('left'));
4468
5840
  hierarchyController.render(state);
4469
5841
  LocalEditorPanels.renderWorkbenchBottomDockPanel(doc, assetPanel, state, activeBottomTab, panelRegistry.getPanels('bottom'), assetBrowserTab);
@@ -4486,11 +5858,14 @@ export function createLocalEditorBrowserUi(options = {}) {
4486
5858
  lockedVectorGroups: lockedInspectorVectorGroups,
4487
5859
  });
4488
5860
  }
4489
- else {
5861
+ else if (activeRightTab === 'rendering') {
4490
5862
  LocalEditorPanels.renderRenderingPanel(doc, renderingPanel, state);
4491
5863
  }
5864
+ else {
5865
+ LocalEditorPanels.renderMarkerPanel(doc, markersPanel, state);
5866
+ }
4492
5867
  restoreLocalEditorEditableFocus(doc, focusSnapshot);
4493
- restoreLocalEditorRightDockScrollSnapshot(rightDockScrollSnapshot, state, activeRightTab, inspectorFilter, inspectorPanel, renderingPanel);
5868
+ restoreLocalEditorRightDockScrollSnapshot(rightDockScrollSnapshot, state, activeRightTab, inspectorFilter, inspectorPanel, renderingPanel, markersPanel);
4494
5869
  };
4495
5870
  return {
4496
5871
  update(state) {
@@ -4500,12 +5875,15 @@ export function createLocalEditorBrowserUi(options = {}) {
4500
5875
  updateSceneFrameStats(stats) {
4501
5876
  if (currentState)
4502
5877
  currentState = { ...currentState, sceneFrameStats: stats };
4503
- renderSceneFrameRateOverlay(sceneFrameRateOverlay, currentState?.mode === 'editor' ? stats : null);
5878
+ renderSceneFrameRateOverlay(sceneFrameRateOverlay, currentState?.mode === 'editor' && !currentState.prefabStage ? stats : null);
4504
5879
  },
4505
5880
  updatePerformanceStats(stats) {
4506
5881
  if (currentState)
4507
5882
  currentState = { ...currentState, performanceStats: stats };
4508
- renderPerformanceMonitorOverlay(performanceMonitorOverlay, currentState?.mode === 'editor' ? stats : null, currentState?.mode === 'editor' && performanceMonitorOpen);
5883
+ renderPerformanceMonitorOverlay(performanceMonitorOverlay, currentState?.mode === 'editor' && !currentState.prefabStage ? stats : null, currentState?.mode === 'editor' && !currentState.prefabStage && performanceMonitorOpen);
5884
+ },
5885
+ getPrefabComparisonPreviewSurfaces() {
5886
+ return readPrefabComparisonPreviewSurfaces(prefabComparisonPreviewOverlay);
4509
5887
  },
4510
5888
  setTheme(theme) {
4511
5889
  setActiveTheme(theme);
@@ -4535,6 +5913,7 @@ export function createLocalEditorBrowserUi(options = {}) {
4535
5913
  measurementOverlay.root.remove();
4536
5914
  sceneFrameRateOverlay.root.remove();
4537
5915
  performanceMonitorOverlay.root.remove();
5916
+ prefabStagePreviewLayout.root.remove();
4538
5917
  boxSelectionOverlay.remove();
4539
5918
  shortcutHelpPanel.remove();
4540
5919
  assetPreviewModal.remove();