@fps-games/editor 0.2.1-beta.2 → 0.2.1-beta.4

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 (595) hide show
  1. package/dist/build-info.json +46 -46
  2. package/dist/editor-commands/capabilities/assets.d.ts +8 -0
  3. package/dist/editor-commands/capabilities/assets.d.ts.map +1 -0
  4. package/dist/{agent-bridge → editor-commands}/capabilities/assets.js +41 -41
  5. package/dist/editor-commands/capabilities/assets.js.map +1 -0
  6. package/dist/editor-commands/capabilities/editor-state.d.ts +5 -0
  7. package/dist/editor-commands/capabilities/editor-state.d.ts.map +1 -0
  8. package/dist/{agent-bridge → editor-commands}/capabilities/editor-state.js +22 -22
  9. package/dist/editor-commands/capabilities/editor-state.js.map +1 -0
  10. package/dist/editor-commands/capabilities/hierarchy.d.ts +4 -0
  11. package/dist/editor-commands/capabilities/hierarchy.d.ts.map +1 -0
  12. package/dist/{agent-bridge → editor-commands}/capabilities/hierarchy.js +5 -5
  13. package/dist/editor-commands/capabilities/hierarchy.js.map +1 -0
  14. package/dist/editor-commands/capabilities/host-lifecycle.d.ts +11 -0
  15. package/dist/editor-commands/capabilities/host-lifecycle.d.ts.map +1 -0
  16. package/dist/editor-commands/capabilities/host-lifecycle.js +149 -0
  17. package/dist/editor-commands/capabilities/host-lifecycle.js.map +1 -0
  18. package/dist/editor-commands/capabilities/prefabs.d.ts +5 -0
  19. package/dist/editor-commands/capabilities/prefabs.d.ts.map +1 -0
  20. package/dist/{agent-bridge → editor-commands}/capabilities/prefabs.js +93 -93
  21. package/dist/editor-commands/capabilities/prefabs.js.map +1 -0
  22. package/dist/editor-commands/capabilities/scene-objects.d.ts +8 -0
  23. package/dist/editor-commands/capabilities/scene-objects.d.ts.map +1 -0
  24. package/dist/editor-commands/capabilities/scene-objects.js +480 -0
  25. package/dist/editor-commands/capabilities/scene-objects.js.map +1 -0
  26. package/dist/editor-commands/capabilities/selection.d.ts +5 -0
  27. package/dist/editor-commands/capabilities/selection.d.ts.map +1 -0
  28. package/dist/editor-commands/capabilities/selection.js +60 -0
  29. package/dist/editor-commands/capabilities/selection.js.map +1 -0
  30. package/dist/editor-commands/capabilities/shadows.d.ts +5 -0
  31. package/dist/editor-commands/capabilities/shadows.d.ts.map +1 -0
  32. package/dist/{agent-bridge → editor-commands}/capabilities/shadows.js +74 -74
  33. package/dist/editor-commands/capabilities/shadows.js.map +1 -0
  34. package/dist/editor-commands/capabilities/transform.d.ts +5 -0
  35. package/dist/editor-commands/capabilities/transform.d.ts.map +1 -0
  36. package/dist/editor-commands/capabilities/transform.js +164 -0
  37. package/dist/editor-commands/capabilities/transform.js.map +1 -0
  38. package/dist/editor-commands/capabilities/ui-regions.d.ts +4 -0
  39. package/dist/editor-commands/capabilities/ui-regions.d.ts.map +1 -0
  40. package/dist/{agent-bridge → editor-commands}/capabilities/ui-regions.js +55 -57
  41. package/dist/editor-commands/capabilities/ui-regions.js.map +1 -0
  42. package/dist/editor-commands/capabilities/viewport.d.ts +5 -0
  43. package/dist/editor-commands/capabilities/viewport.d.ts.map +1 -0
  44. package/dist/{agent-bridge → editor-commands}/capabilities/viewport.js +100 -100
  45. package/dist/editor-commands/capabilities/viewport.js.map +1 -0
  46. package/dist/editor-commands/command-sources.d.ts +7 -0
  47. package/dist/editor-commands/command-sources.d.ts.map +1 -0
  48. package/dist/editor-commands/command-sources.js +34 -0
  49. package/dist/editor-commands/command-sources.js.map +1 -0
  50. package/dist/editor-commands/diagnostics.d.ts +12 -0
  51. package/dist/editor-commands/diagnostics.d.ts.map +1 -0
  52. package/dist/{agent-bridge → editor-commands}/diagnostics.js +4 -4
  53. package/dist/editor-commands/diagnostics.js.map +1 -0
  54. package/dist/{agent-bridge → editor-commands}/index.d.ts +1 -1
  55. package/dist/editor-commands/index.d.ts.map +1 -0
  56. package/dist/{agent-bridge → editor-commands}/index.js +1 -1
  57. package/dist/editor-commands/index.js.map +1 -0
  58. package/dist/editor-commands/register.d.ts +4 -0
  59. package/dist/editor-commands/register.d.ts.map +1 -0
  60. package/dist/{agent-bridge → editor-commands}/register.js +323 -286
  61. package/dist/editor-commands/register.js.map +1 -0
  62. package/dist/{agent-bridge → editor-commands}/shared.d.ts +80 -80
  63. package/dist/editor-commands/shared.d.ts.map +1 -0
  64. package/dist/{agent-bridge → editor-commands}/shared.js +29 -29
  65. package/dist/editor-commands/shared.js.map +1 -0
  66. package/dist/editor-commands/source-types.d.ts +110 -0
  67. package/dist/editor-commands/source-types.d.ts.map +1 -0
  68. package/dist/editor-commands/source-types.js.map +1 -0
  69. package/dist/editor-plugin-commands.d.ts +4 -0
  70. package/dist/editor-plugin-commands.d.ts.map +1 -0
  71. package/dist/editor-plugin-commands.js +18 -0
  72. package/dist/editor-plugin-commands.js.map +1 -0
  73. package/dist/index.d.ts +2 -2
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +1 -1
  76. package/dist/index.js.map +1 -1
  77. package/dist/local-editor-commands.d.ts +2 -0
  78. package/dist/local-editor-commands.d.ts.map +1 -0
  79. package/dist/local-editor-commands.js +2 -0
  80. package/dist/local-editor-commands.js.map +1 -0
  81. package/dist/local-editor-harness.d.ts +35 -21
  82. package/dist/local-editor-harness.d.ts.map +1 -1
  83. package/dist/local-editor-harness.js +1737 -374
  84. package/dist/local-editor-harness.js.map +1 -1
  85. package/dist/local-editor-prefab-stage-transaction.d.ts +2 -1
  86. package/dist/local-editor-prefab-stage-transaction.d.ts.map +1 -1
  87. package/dist/local-editor-prefab-stage-transaction.js +6 -5
  88. package/dist/local-editor-prefab-stage-transaction.js.map +1 -1
  89. package/dist/local-editor-scene-view-interaction-runtime.d.ts.map +1 -1
  90. package/dist/local-editor-scene-view-interaction-runtime.js +2 -5
  91. package/dist/local-editor-scene-view-interaction-runtime.js.map +1 -1
  92. package/dist/playable-babylon-rendering.d.ts +8 -7
  93. package/dist/playable-babylon-rendering.d.ts.map +1 -1
  94. package/dist/playable-babylon-rendering.js +77 -32
  95. package/dist/playable-babylon-rendering.js.map +1 -1
  96. package/dist/playable-local-editor-entry.d.ts +10 -0
  97. package/dist/playable-local-editor-entry.d.ts.map +1 -1
  98. package/dist/playable-local-editor-entry.js +10 -2
  99. package/dist/playable-local-editor-entry.js.map +1 -1
  100. package/dist/playable-local-editor-host.d.ts +3 -32
  101. package/dist/playable-local-editor-host.d.ts.map +1 -1
  102. package/dist/playable-local-editor-host.js +6 -70
  103. package/dist/playable-local-editor-host.js.map +1 -1
  104. package/dist/playable-product-local-editor.d.ts +1 -2
  105. package/dist/playable-product-local-editor.d.ts.map +1 -1
  106. package/dist/playable-product-local-editor.js +0 -1
  107. package/dist/playable-product-local-editor.js.map +1 -1
  108. package/dist/playable-product-projection-preview.d.ts +2 -0
  109. package/dist/playable-product-projection-preview.d.ts.map +1 -1
  110. package/dist/playable-product-projection-preview.js +8 -5
  111. package/dist/playable-product-projection-preview.js.map +1 -1
  112. package/dist/playable-product-scene-capabilities.d.ts +0 -2
  113. package/dist/playable-product-scene-capabilities.d.ts.map +1 -1
  114. package/dist/playable-product-scene-capabilities.js +33 -6
  115. package/dist/playable-product-scene-capabilities.js.map +1 -1
  116. package/dist/playable-runtime-babylon.d.ts +4 -0
  117. package/dist/playable-runtime-babylon.d.ts.map +1 -1
  118. package/dist/playable-runtime-babylon.js +4 -0
  119. package/dist/playable-runtime-babylon.js.map +1 -1
  120. package/dist/playable-sdk.d.ts +2 -2
  121. package/dist/playable-sdk.d.ts.map +1 -1
  122. package/dist/playable-sdk.js +1 -1
  123. package/dist/playable-sdk.js.map +1 -1
  124. package/dist/playable-standard-project.d.ts +0 -3
  125. package/dist/playable-standard-project.d.ts.map +1 -1
  126. package/dist/playable-standard-project.js +14 -6
  127. package/dist/playable-standard-project.js.map +1 -1
  128. package/dist/project-service-projection.d.ts +16 -0
  129. package/dist/project-service-projection.d.ts.map +1 -0
  130. package/dist/project-service-projection.js +67 -0
  131. package/dist/project-service-projection.js.map +1 -0
  132. package/node_modules/@fps-games/babylon-renderer/dist/environment/environment-texture-controller.d.ts +4 -2
  133. package/node_modules/@fps-games/babylon-renderer/dist/environment/environment-texture-controller.d.ts.map +1 -1
  134. package/node_modules/@fps-games/babylon-renderer/dist/environment/environment-texture-controller.js +301 -121
  135. package/node_modules/@fps-games/babylon-renderer/dist/environment/environment-texture-controller.js.map +1 -1
  136. package/node_modules/@fps-games/babylon-renderer/dist/environment/profile.js +5 -4
  137. package/node_modules/@fps-games/babylon-renderer/dist/environment/profile.js.map +1 -1
  138. package/node_modules/@fps-games/babylon-renderer/dist/environment/types.d.ts +4 -4
  139. package/node_modules/@fps-games/babylon-renderer/dist/environment/types.d.ts.map +1 -1
  140. package/node_modules/@fps-games/babylon-renderer/dist/environment/types.js +1 -1
  141. package/node_modules/@fps-games/babylon-renderer/dist/environment/types.js.map +1 -1
  142. package/node_modules/@fps-games/babylon-renderer/dist/game-world-plugin-lifecycle.d.ts +2 -0
  143. package/node_modules/@fps-games/babylon-renderer/dist/game-world-plugin-lifecycle.d.ts.map +1 -1
  144. package/node_modules/@fps-games/babylon-renderer/dist/game-world-plugin-lifecycle.js +12 -1
  145. package/node_modules/@fps-games/babylon-renderer/dist/game-world-plugin-lifecycle.js.map +1 -1
  146. package/node_modules/@fps-games/babylon-renderer/dist/plugin.d.ts +6 -3
  147. package/node_modules/@fps-games/babylon-renderer/dist/plugin.d.ts.map +1 -1
  148. package/node_modules/@fps-games/babylon-renderer/dist/plugin.js +100 -39
  149. package/node_modules/@fps-games/babylon-renderer/dist/plugin.js.map +1 -1
  150. package/node_modules/@fps-games/babylon-renderer/dist/post-process/babylon-default-pipeline.d.ts +18 -0
  151. package/node_modules/@fps-games/babylon-renderer/dist/post-process/babylon-default-pipeline.d.ts.map +1 -1
  152. package/node_modules/@fps-games/babylon-renderer/dist/post-process/babylon-default-pipeline.js +54 -18
  153. package/node_modules/@fps-games/babylon-renderer/dist/post-process/babylon-default-pipeline.js.map +1 -1
  154. package/node_modules/@fps-games/babylon-renderer/dist/reference.d.ts +1 -3
  155. package/node_modules/@fps-games/babylon-renderer/dist/reference.d.ts.map +1 -1
  156. package/node_modules/@fps-games/babylon-renderer/dist/reference.js.map +1 -1
  157. package/node_modules/@fps-games/babylon-renderer/package.json +11 -8
  158. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +1 -0
  159. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
  160. package/node_modules/@fps-games/editor-babylon/dist/projection.js +1 -1
  161. package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
  162. package/node_modules/@fps-games/editor-babylon/dist/selection-presentation-controller.d.ts.map +1 -1
  163. package/node_modules/@fps-games/editor-babylon/dist/selection-presentation-controller.js +127 -13
  164. package/node_modules/@fps-games/editor-babylon/dist/selection-presentation-controller.js.map +1 -1
  165. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts.map +1 -1
  166. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js +66 -1
  167. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js.map +1 -1
  168. package/node_modules/@fps-games/editor-babylon/package.json +6 -6
  169. package/node_modules/@fps-games/editor-browser/dist/editor-command-service-client.d.ts +32 -0
  170. package/node_modules/@fps-games/editor-browser/dist/editor-command-service-client.d.ts.map +1 -0
  171. package/node_modules/@fps-games/editor-browser/dist/editor-command-service-client.js +254 -0
  172. package/node_modules/@fps-games/editor-browser/dist/editor-command-service-client.js.map +1 -0
  173. package/node_modules/@fps-games/editor-browser/dist/index.d.ts +3 -1
  174. package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -1
  175. package/node_modules/@fps-games/editor-browser/dist/index.js +2 -0
  176. package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -1
  177. package/node_modules/@fps-games/editor-browser/dist/local-editor-command-center.d.ts +68 -0
  178. package/node_modules/@fps-games/editor-browser/dist/local-editor-command-center.d.ts.map +1 -0
  179. package/node_modules/@fps-games/editor-browser/dist/local-editor-command-center.js +650 -0
  180. package/node_modules/@fps-games/editor-browser/dist/local-editor-command-center.js.map +1 -0
  181. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-formal-surface-visibility.d.ts +1 -0
  182. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-formal-surface-visibility.d.ts.map +1 -1
  183. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-formal-surface-visibility.js +22 -0
  184. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-formal-surface-visibility.js.map +1 -1
  185. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts +8 -0
  186. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts.map +1 -1
  187. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js +117 -6
  188. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js.map +1 -1
  189. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts +14 -1
  190. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts.map +1 -1
  191. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js +100 -1
  192. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js.map +1 -1
  193. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +8 -1
  194. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
  195. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +75 -2
  196. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
  197. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +37 -12
  198. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
  199. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.js.map +1 -1
  200. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +25 -2
  201. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
  202. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +332 -107
  203. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
  204. package/node_modules/@fps-games/editor-browser/package.json +7 -7
  205. package/node_modules/@fps-games/editor-core/dist/editor-authoring-host.d.ts +107 -0
  206. package/node_modules/@fps-games/editor-core/dist/editor-authoring-host.d.ts.map +1 -0
  207. package/node_modules/@fps-games/editor-core/dist/editor-authoring-host.js +1211 -0
  208. package/node_modules/@fps-games/editor-core/dist/editor-authoring-host.js.map +1 -0
  209. package/node_modules/@fps-games/editor-core/dist/editor-command-capability-adapter.d.ts +34 -0
  210. package/node_modules/@fps-games/editor-core/dist/editor-command-capability-adapter.d.ts.map +1 -0
  211. package/node_modules/@fps-games/editor-core/dist/editor-command-capability-adapter.js +260 -0
  212. package/node_modules/@fps-games/editor-core/dist/editor-command-capability-adapter.js.map +1 -0
  213. package/node_modules/@fps-games/editor-core/dist/editor-command-composed-authority.d.ts +9 -0
  214. package/node_modules/@fps-games/editor-core/dist/editor-command-composed-authority.d.ts.map +1 -0
  215. package/node_modules/@fps-games/editor-core/dist/editor-command-composed-authority.js +14 -0
  216. package/node_modules/@fps-games/editor-core/dist/editor-command-composed-authority.js.map +1 -0
  217. package/node_modules/@fps-games/editor-core/dist/editor-command-observability.d.ts +18 -0
  218. package/node_modules/@fps-games/editor-core/dist/editor-command-observability.d.ts.map +1 -0
  219. package/node_modules/@fps-games/editor-core/dist/editor-command-observability.js +113 -0
  220. package/node_modules/@fps-games/editor-core/dist/editor-command-observability.js.map +1 -0
  221. package/node_modules/@fps-games/editor-core/dist/editor-command-system.d.ts +82 -0
  222. package/node_modules/@fps-games/editor-core/dist/editor-command-system.d.ts.map +1 -0
  223. package/node_modules/@fps-games/editor-core/dist/editor-command-system.js +1098 -0
  224. package/node_modules/@fps-games/editor-core/dist/editor-command-system.js.map +1 -0
  225. package/node_modules/@fps-games/editor-core/dist/editor-plugin-host.d.ts +6 -7
  226. package/node_modules/@fps-games/editor-core/dist/editor-plugin-host.d.ts.map +1 -1
  227. package/node_modules/@fps-games/editor-core/dist/editor-plugin-host.js +62 -103
  228. package/node_modules/@fps-games/editor-core/dist/editor-plugin-host.js.map +1 -1
  229. package/node_modules/@fps-games/editor-core/dist/editor-service-gateway.d.ts +30 -0
  230. package/node_modules/@fps-games/editor-core/dist/editor-service-gateway.d.ts.map +1 -0
  231. package/node_modules/@fps-games/editor-core/dist/editor-service-gateway.js +540 -0
  232. package/node_modules/@fps-games/editor-core/dist/editor-service-gateway.js.map +1 -0
  233. package/node_modules/@fps-games/editor-core/dist/editor-session-authority.d.ts +9 -0
  234. package/node_modules/@fps-games/editor-core/dist/editor-session-authority.d.ts.map +1 -0
  235. package/node_modules/@fps-games/editor-core/dist/editor-session-authority.js +61 -0
  236. package/node_modules/@fps-games/editor-core/dist/editor-session-authority.js.map +1 -0
  237. package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts +55 -0
  238. package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts.map +1 -1
  239. package/node_modules/@fps-games/editor-core/dist/editor-session.js +247 -6
  240. package/node_modules/@fps-games/editor-core/dist/editor-session.js.map +1 -1
  241. package/node_modules/@fps-games/editor-core/dist/index.d.ts +6 -2
  242. package/node_modules/@fps-games/editor-core/dist/index.d.ts.map +1 -1
  243. package/node_modules/@fps-games/editor-core/dist/index.js +6 -2
  244. package/node_modules/@fps-games/editor-core/dist/index.js.map +1 -1
  245. package/node_modules/@fps-games/editor-core/package.json +6 -6
  246. package/node_modules/@fps-games/editor-forge-play/dist/index.d.ts +0 -1
  247. package/node_modules/@fps-games/editor-forge-play/dist/index.d.ts.map +1 -1
  248. package/node_modules/@fps-games/editor-forge-play/dist/index.js +0 -1
  249. package/node_modules/@fps-games/editor-forge-play/dist/index.js.map +1 -1
  250. package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
  251. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.d.ts.map +1 -1
  252. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.js +10 -3
  253. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/generated-module.js.map +1 -1
  254. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.d.ts +2 -1
  255. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.d.ts.map +1 -1
  256. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.js +1 -1
  257. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-database/index.js.map +1 -1
  258. package/node_modules/@fps-games/editor-playable-sdk/dist/bridge-command/protocol.d.ts +2 -0
  259. package/node_modules/@fps-games/editor-playable-sdk/dist/bridge-command/protocol.d.ts.map +1 -1
  260. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts.map +1 -1
  261. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js +41 -1
  262. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js.map +1 -1
  263. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play-types.d.ts +27 -1
  264. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play-types.d.ts.map +1 -1
  265. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play-types.js.map +1 -1
  266. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play.d.ts +2 -0
  267. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play.d.ts.map +1 -1
  268. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play.js +214 -7
  269. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/forge-play.js.map +1 -1
  270. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/host-controller.d.ts +1 -0
  271. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/host-controller.d.ts.map +1 -1
  272. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/host-controller.js +11 -3
  273. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/host-controller.js.map +1 -1
  274. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/index.d.ts +2 -4
  275. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/index.d.ts.map +1 -1
  276. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/index.js +0 -1
  277. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/index.js.map +1 -1
  278. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.d.ts.map +1 -1
  279. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js +77 -31
  280. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js.map +1 -1
  281. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/types.d.ts +8 -1
  282. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/types.d.ts.map +1 -1
  283. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/types.js.map +1 -1
  284. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/asset-fields.d.ts +21 -1
  285. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/asset-fields.d.ts.map +1 -1
  286. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/asset-fields.js +90 -4
  287. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/asset-fields.js.map +1 -1
  288. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.d.ts +27 -1
  289. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.d.ts.map +1 -1
  290. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js +161 -1
  291. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js.map +1 -1
  292. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/inspector.d.ts +2 -2
  293. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/inspector.d.ts.map +1 -1
  294. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/inspector.js +5 -92
  295. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/inspector.js.map +1 -1
  296. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/scene-inspector.d.ts +7 -0
  297. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/scene-inspector.d.ts.map +1 -1
  298. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/scene-inspector.js +26 -9
  299. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/scene-inspector.js.map +1 -1
  300. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/slot-inspector.d.ts +9 -0
  301. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/slot-inspector.d.ts.map +1 -1
  302. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/slot-inspector.js +19 -8
  303. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/slot-inspector.js.map +1 -1
  304. package/node_modules/@fps-games/editor-playable-sdk/dist/package-resolution/aliases.d.ts +1 -1
  305. package/node_modules/@fps-games/editor-playable-sdk/dist/package-resolution/aliases.d.ts.map +1 -1
  306. package/node_modules/@fps-games/editor-playable-sdk/dist/package-resolution/aliases.js +4 -0
  307. package/node_modules/@fps-games/editor-playable-sdk/dist/package-resolution/aliases.js.map +1 -1
  308. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/material-override-inspector.d.ts +5 -0
  309. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/material-override-inspector.d.ts.map +1 -1
  310. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/material-override-inspector.js +16 -4
  311. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/material-override-inspector.js.map +1 -1
  312. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/stage-inspector.d.ts +9 -0
  313. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/stage-inspector.d.ts.map +1 -1
  314. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/stage-inspector.js +12 -2
  315. package/node_modules/@fps-games/editor-playable-sdk/dist/prefab-stage/stage-inspector.js.map +1 -1
  316. package/node_modules/@fps-games/editor-playable-sdk/dist/product/ground-decal.d.ts +2 -1
  317. package/node_modules/@fps-games/editor-playable-sdk/dist/product/ground-decal.d.ts.map +1 -1
  318. package/node_modules/@fps-games/editor-playable-sdk/dist/product/ground-decal.js +10 -5
  319. package/node_modules/@fps-games/editor-playable-sdk/dist/product/ground-decal.js.map +1 -1
  320. package/node_modules/@fps-games/editor-playable-sdk/dist/product/index.d.ts +1 -0
  321. package/node_modules/@fps-games/editor-playable-sdk/dist/product/index.d.ts.map +1 -1
  322. package/node_modules/@fps-games/editor-playable-sdk/dist/product/index.js +1 -0
  323. package/node_modules/@fps-games/editor-playable-sdk/dist/product/index.js.map +1 -1
  324. package/node_modules/@fps-games/editor-playable-sdk/dist/product/project-host-services.d.ts +17 -82
  325. package/node_modules/@fps-games/editor-playable-sdk/dist/product/project-host-services.d.ts.map +1 -1
  326. package/node_modules/@fps-games/editor-playable-sdk/dist/product/project-host-services.js +53 -57
  327. package/node_modules/@fps-games/editor-playable-sdk/dist/product/project-host-services.js.map +1 -1
  328. package/node_modules/@fps-games/editor-playable-sdk/dist/product/scene-session.d.ts.map +1 -1
  329. package/node_modules/@fps-games/editor-playable-sdk/dist/product/scene-session.js +3 -2
  330. package/node_modules/@fps-games/editor-playable-sdk/dist/product/scene-session.js.map +1 -1
  331. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-authoring-commands.d.ts +10 -0
  332. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-authoring-commands.d.ts.map +1 -0
  333. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-authoring-commands.js +256 -0
  334. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-authoring-commands.js.map +1 -0
  335. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-scene-assembly.d.ts.map +1 -1
  336. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-scene-assembly.js +7 -5
  337. package/node_modules/@fps-games/editor-playable-sdk/dist/product/standard-scene-assembly.js.map +1 -1
  338. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js +4 -4
  339. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/panel.js.map +1 -1
  340. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/types.d.ts +2 -1
  341. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/types.d.ts.map +1 -1
  342. package/node_modules/@fps-games/editor-playable-sdk/dist/rendering-profile/types.js.map +1 -1
  343. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.js +1 -5
  344. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/assets.js.map +1 -1
  345. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/client.d.ts.map +1 -1
  346. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/client.js +8 -0
  347. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/client.js.map +1 -1
  348. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/types.d.ts +1 -0
  349. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/types.d.ts.map +1 -1
  350. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/types.js.map +1 -1
  351. package/node_modules/@fps-games/editor-playable-sdk/dist/upgrade-doctor/inspectors.js +187 -12
  352. package/node_modules/@fps-games/editor-playable-sdk/dist/upgrade-doctor/inspectors.js.map +1 -1
  353. package/node_modules/@fps-games/editor-playable-sdk/dist/upgrade-doctor/types.d.ts +2 -0
  354. package/node_modules/@fps-games/editor-playable-sdk/dist/upgrade-doctor/types.d.ts.map +1 -1
  355. package/node_modules/@fps-games/editor-playable-sdk/dist/upgrade-doctor/types.js.map +1 -1
  356. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-scene-workflow.d.ts.map +1 -1
  357. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-scene-workflow.js +47 -0
  358. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-scene-workflow.js.map +1 -1
  359. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-service-vite.d.ts +27 -0
  360. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-service-vite.d.ts.map +1 -0
  361. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-service-vite.js +592 -0
  362. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/editor-service-vite.js.map +1 -0
  363. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.d.ts +3 -1
  364. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.d.ts.map +1 -1
  365. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.js +2 -1
  366. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/index.js.map +1 -1
  367. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/plugin.d.ts.map +1 -1
  368. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/plugin.js +61 -6
  369. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/plugin.js.map +1 -1
  370. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-adapter.d.ts +0 -2
  371. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-adapter.d.ts.map +1 -1
  372. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-adapter.js +1 -10
  373. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-adapter.js.map +1 -1
  374. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-authoring-api.d.ts.map +1 -1
  375. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-authoring-api.js +21 -0
  376. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/product-authoring-api.js.map +1 -1
  377. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-authoring-backend.d.ts +13 -0
  378. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-authoring-backend.d.ts.map +1 -0
  379. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-authoring-backend.js +18 -0
  380. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-authoring-backend.js.map +1 -0
  381. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-editor-service.d.ts +28 -0
  382. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-editor-service.d.ts.map +1 -0
  383. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-editor-service.js +863 -0
  384. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/project-editor-service.js.map +1 -0
  385. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/types.d.ts +2 -0
  386. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/types.d.ts.map +1 -1
  387. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/types.js.map +1 -1
  388. package/node_modules/@fps-games/editor-playable-sdk/package.json +6 -6
  389. package/node_modules/@fps-games/editor-protocol/dist/editor-command-capabilities.d.ts +1626 -0
  390. package/node_modules/@fps-games/editor-protocol/dist/editor-command-capabilities.d.ts.map +1 -0
  391. package/node_modules/@fps-games/editor-protocol/dist/{agent-bridge.js → editor-command-capabilities.js} +766 -620
  392. package/node_modules/@fps-games/editor-protocol/dist/editor-command-capabilities.js.map +1 -0
  393. package/node_modules/@fps-games/editor-protocol/dist/editor-command-trace.d.ts +69 -0
  394. package/node_modules/@fps-games/editor-protocol/dist/editor-command-trace.d.ts.map +1 -0
  395. package/node_modules/@fps-games/editor-protocol/dist/editor-command-trace.js +22 -0
  396. package/node_modules/@fps-games/editor-protocol/dist/editor-command-trace.js.map +1 -0
  397. package/node_modules/@fps-games/editor-protocol/dist/editor-command.d.ts +136 -0
  398. package/node_modules/@fps-games/editor-protocol/dist/editor-command.d.ts.map +1 -0
  399. package/node_modules/@fps-games/editor-protocol/dist/editor-command.js +2 -0
  400. package/node_modules/@fps-games/editor-protocol/dist/editor-command.js.map +1 -0
  401. package/node_modules/@fps-games/editor-protocol/dist/editor-service.d.ts +225 -0
  402. package/node_modules/@fps-games/editor-protocol/dist/editor-service.d.ts.map +1 -0
  403. package/node_modules/@fps-games/editor-protocol/dist/editor-service.js +4 -0
  404. package/node_modules/@fps-games/editor-protocol/dist/editor-service.js.map +1 -0
  405. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts +6 -3
  406. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts.map +1 -1
  407. package/node_modules/@fps-games/editor-protocol/dist/index.js +6 -3
  408. package/node_modules/@fps-games/editor-protocol/dist/index.js.map +1 -1
  409. package/node_modules/@fps-games/editor-protocol/package.json +2 -2
  410. package/node_modules/@fps-games/editor-tooling/package.json +3 -3
  411. package/node_modules/@fps-games/editor-ui/package.json +1 -1
  412. package/node_modules/@fps-games/playable-assets/dist/identity.d.ts +1 -0
  413. package/node_modules/@fps-games/playable-assets/dist/identity.d.ts.map +1 -1
  414. package/node_modules/@fps-games/playable-assets/dist/identity.js +1 -1
  415. package/node_modules/@fps-games/playable-assets/dist/identity.js.map +1 -1
  416. package/node_modules/@fps-games/playable-assets/dist/index.d.ts +1 -0
  417. package/node_modules/@fps-games/playable-assets/dist/index.d.ts.map +1 -1
  418. package/node_modules/@fps-games/playable-assets/dist/index.js +1 -0
  419. package/node_modules/@fps-games/playable-assets/dist/index.js.map +1 -1
  420. package/node_modules/@fps-games/playable-assets/dist/resource-resolver.d.ts +46 -0
  421. package/node_modules/@fps-games/playable-assets/dist/resource-resolver.d.ts.map +1 -0
  422. package/node_modules/@fps-games/playable-assets/dist/resource-resolver.js +109 -0
  423. package/node_modules/@fps-games/playable-assets/dist/resource-resolver.js.map +1 -0
  424. package/node_modules/@fps-games/playable-assets/package.json +1 -1
  425. package/node_modules/@fps-games/playable-contracts/package.json +1 -1
  426. package/node_modules/@fps-games/playable-rendering/package.json +2 -2
  427. package/node_modules/@fps-games/playable-runtime/dist/runtime.d.ts.map +1 -1
  428. package/node_modules/@fps-games/playable-runtime/dist/runtime.js +5 -0
  429. package/node_modules/@fps-games/playable-runtime/dist/runtime.js.map +1 -1
  430. package/node_modules/@fps-games/playable-runtime/dist/types.d.ts +2 -0
  431. package/node_modules/@fps-games/playable-runtime/dist/types.d.ts.map +1 -1
  432. package/node_modules/@fps-games/playable-runtime/dist/types.js.map +1 -1
  433. package/node_modules/@fps-games/playable-runtime/package.json +12 -12
  434. package/node_modules/@fps-games/playable-runtime-data/package.json +4 -4
  435. package/node_modules/@fps-games/playable-scene/package.json +2 -2
  436. package/node_modules/@fps-games/plugin-api/package.json +1 -1
  437. package/node_modules/@fps-games/plugin-assets/dist/reference.d.ts.map +1 -1
  438. package/node_modules/@fps-games/plugin-assets/dist/reference.js +11 -4
  439. package/node_modules/@fps-games/plugin-assets/dist/reference.js.map +1 -1
  440. package/node_modules/@fps-games/plugin-assets/dist/renderer.d.ts +8 -0
  441. package/node_modules/@fps-games/plugin-assets/dist/renderer.d.ts.map +1 -0
  442. package/node_modules/@fps-games/plugin-assets/dist/renderer.js +13 -0
  443. package/node_modules/@fps-games/plugin-assets/dist/renderer.js.map +1 -0
  444. package/node_modules/@fps-games/plugin-assets/dist/resources.d.ts +12 -0
  445. package/node_modules/@fps-games/plugin-assets/dist/resources.d.ts.map +1 -0
  446. package/node_modules/@fps-games/plugin-assets/dist/resources.js +8 -0
  447. package/node_modules/@fps-games/plugin-assets/dist/resources.js.map +1 -0
  448. package/node_modules/@fps-games/plugin-assets/dist/runtime.d.ts +2 -1
  449. package/node_modules/@fps-games/plugin-assets/dist/runtime.d.ts.map +1 -1
  450. package/node_modules/@fps-games/plugin-assets/dist/runtime.js +3 -0
  451. package/node_modules/@fps-games/plugin-assets/dist/runtime.js.map +1 -1
  452. package/node_modules/@fps-games/plugin-assets/dist/version.d.ts +1 -1
  453. package/node_modules/@fps-games/plugin-assets/dist/version.js +1 -1
  454. package/node_modules/@fps-games/plugin-assets/dist/version.js.map +1 -1
  455. package/node_modules/@fps-games/plugin-assets/package.json +32 -8
  456. package/node_modules/@fps-games/plugin-hierarchy/dist/kernel.d.ts +1 -0
  457. package/node_modules/@fps-games/plugin-hierarchy/dist/kernel.d.ts.map +1 -1
  458. package/node_modules/@fps-games/plugin-hierarchy/dist/kernel.js +78 -4
  459. package/node_modules/@fps-games/plugin-hierarchy/dist/kernel.js.map +1 -1
  460. package/node_modules/@fps-games/plugin-hierarchy/dist/version.d.ts +1 -1
  461. package/node_modules/@fps-games/plugin-hierarchy/dist/version.js +1 -1
  462. package/node_modules/@fps-games/plugin-hierarchy/dist/version.js.map +1 -1
  463. package/node_modules/@fps-games/plugin-hierarchy/package.json +5 -5
  464. package/node_modules/@fps-games/plugin-host/package.json +2 -2
  465. package/node_modules/@fps-games/plugin-markers/dist/version.d.ts +1 -1
  466. package/node_modules/@fps-games/plugin-markers/dist/version.js +1 -1
  467. package/node_modules/@fps-games/plugin-markers/dist/version.js.map +1 -1
  468. package/node_modules/@fps-games/plugin-markers/package.json +5 -5
  469. package/node_modules/@fps-games/plugin-materials/dist/version.d.ts +1 -1
  470. package/node_modules/@fps-games/plugin-materials/dist/version.js +1 -1
  471. package/node_modules/@fps-games/plugin-materials/dist/version.js.map +1 -1
  472. package/node_modules/@fps-games/plugin-materials/package.json +5 -5
  473. package/node_modules/@fps-games/plugin-rendering/dist/version.d.ts +1 -1
  474. package/node_modules/@fps-games/plugin-rendering/dist/version.js +1 -1
  475. package/node_modules/@fps-games/plugin-rendering/dist/version.js.map +1 -1
  476. package/node_modules/@fps-games/plugin-rendering/package.json +5 -5
  477. package/node_modules/@fps-games/plugin-scene/dist/version.d.ts +1 -1
  478. package/node_modules/@fps-games/plugin-scene/dist/version.js +1 -1
  479. package/node_modules/@fps-games/plugin-scene/dist/version.js.map +1 -1
  480. package/node_modules/@fps-games/plugin-scene/package.json +5 -5
  481. package/node_modules/@fps-games/plugin-shadow-map-experiment/dist/version.d.ts +1 -1
  482. package/node_modules/@fps-games/plugin-shadow-map-experiment/dist/version.js +1 -1
  483. package/node_modules/@fps-games/plugin-shadow-map-experiment/dist/version.js.map +1 -1
  484. package/node_modules/@fps-games/plugin-shadow-map-experiment/package.json +5 -5
  485. package/node_modules/@fps-games/plugin-shadows/dist/version.d.ts +1 -1
  486. package/node_modules/@fps-games/plugin-shadows/dist/version.js +1 -1
  487. package/node_modules/@fps-games/plugin-shadows/dist/version.js.map +1 -1
  488. package/node_modules/@fps-games/plugin-shadows/package.json +7 -7
  489. package/package.json +24 -22
  490. package/dist/agent-bridge/capabilities/assets.d.ts +0 -8
  491. package/dist/agent-bridge/capabilities/assets.d.ts.map +0 -1
  492. package/dist/agent-bridge/capabilities/assets.js.map +0 -1
  493. package/dist/agent-bridge/capabilities/editor-state.d.ts +0 -5
  494. package/dist/agent-bridge/capabilities/editor-state.d.ts.map +0 -1
  495. package/dist/agent-bridge/capabilities/editor-state.js.map +0 -1
  496. package/dist/agent-bridge/capabilities/hierarchy.d.ts +0 -4
  497. package/dist/agent-bridge/capabilities/hierarchy.d.ts.map +0 -1
  498. package/dist/agent-bridge/capabilities/hierarchy.js.map +0 -1
  499. package/dist/agent-bridge/capabilities/host-lifecycle.d.ts +0 -11
  500. package/dist/agent-bridge/capabilities/host-lifecycle.d.ts.map +0 -1
  501. package/dist/agent-bridge/capabilities/host-lifecycle.js +0 -149
  502. package/dist/agent-bridge/capabilities/host-lifecycle.js.map +0 -1
  503. package/dist/agent-bridge/capabilities/prefabs.d.ts +0 -5
  504. package/dist/agent-bridge/capabilities/prefabs.d.ts.map +0 -1
  505. package/dist/agent-bridge/capabilities/prefabs.js.map +0 -1
  506. package/dist/agent-bridge/capabilities/scene-objects.d.ts +0 -8
  507. package/dist/agent-bridge/capabilities/scene-objects.d.ts.map +0 -1
  508. package/dist/agent-bridge/capabilities/scene-objects.js +0 -480
  509. package/dist/agent-bridge/capabilities/scene-objects.js.map +0 -1
  510. package/dist/agent-bridge/capabilities/selection.d.ts +0 -5
  511. package/dist/agent-bridge/capabilities/selection.d.ts.map +0 -1
  512. package/dist/agent-bridge/capabilities/selection.js +0 -60
  513. package/dist/agent-bridge/capabilities/selection.js.map +0 -1
  514. package/dist/agent-bridge/capabilities/shadows.d.ts +0 -5
  515. package/dist/agent-bridge/capabilities/shadows.d.ts.map +0 -1
  516. package/dist/agent-bridge/capabilities/shadows.js.map +0 -1
  517. package/dist/agent-bridge/capabilities/transform.d.ts +0 -5
  518. package/dist/agent-bridge/capabilities/transform.d.ts.map +0 -1
  519. package/dist/agent-bridge/capabilities/transform.js +0 -164
  520. package/dist/agent-bridge/capabilities/transform.js.map +0 -1
  521. package/dist/agent-bridge/capabilities/ui-regions.d.ts +0 -4
  522. package/dist/agent-bridge/capabilities/ui-regions.d.ts.map +0 -1
  523. package/dist/agent-bridge/capabilities/ui-regions.js.map +0 -1
  524. package/dist/agent-bridge/capabilities/viewport.d.ts +0 -5
  525. package/dist/agent-bridge/capabilities/viewport.d.ts.map +0 -1
  526. package/dist/agent-bridge/capabilities/viewport.js.map +0 -1
  527. package/dist/agent-bridge/capability-sources.d.ts +0 -7
  528. package/dist/agent-bridge/capability-sources.d.ts.map +0 -1
  529. package/dist/agent-bridge/capability-sources.js +0 -34
  530. package/dist/agent-bridge/capability-sources.js.map +0 -1
  531. package/dist/agent-bridge/diagnostics.d.ts +0 -12
  532. package/dist/agent-bridge/diagnostics.d.ts.map +0 -1
  533. package/dist/agent-bridge/diagnostics.js.map +0 -1
  534. package/dist/agent-bridge/index.d.ts.map +0 -1
  535. package/dist/agent-bridge/index.js.map +0 -1
  536. package/dist/agent-bridge/register.d.ts +0 -4
  537. package/dist/agent-bridge/register.d.ts.map +0 -1
  538. package/dist/agent-bridge/register.js.map +0 -1
  539. package/dist/agent-bridge/shared.d.ts.map +0 -1
  540. package/dist/agent-bridge/shared.js.map +0 -1
  541. package/dist/agent-bridge/source-types.d.ts +0 -110
  542. package/dist/agent-bridge/source-types.d.ts.map +0 -1
  543. package/dist/agent-bridge/source-types.js.map +0 -1
  544. package/dist/editor-plugin-agent-capabilities.d.ts +0 -4
  545. package/dist/editor-plugin-agent-capabilities.d.ts.map +0 -1
  546. package/dist/editor-plugin-agent-capabilities.js +0 -64
  547. package/dist/editor-plugin-agent-capabilities.js.map +0 -1
  548. package/dist/local-editor-agent-actions.d.ts +0 -43
  549. package/dist/local-editor-agent-actions.d.ts.map +0 -1
  550. package/dist/local-editor-agent-actions.js +0 -321
  551. package/dist/local-editor-agent-actions.js.map +0 -1
  552. package/dist/local-editor-agent-bridge-transport.d.ts +0 -129
  553. package/dist/local-editor-agent-bridge-transport.d.ts.map +0 -1
  554. package/dist/local-editor-agent-bridge-transport.js +0 -403
  555. package/dist/local-editor-agent-bridge-transport.js.map +0 -1
  556. package/dist/local-editor-agent-bridge.d.ts +0 -2
  557. package/dist/local-editor-agent-bridge.d.ts.map +0 -1
  558. package/dist/local-editor-agent-bridge.js +0 -2
  559. package/dist/local-editor-agent-bridge.js.map +0 -1
  560. package/dist/local-editor-agent-context.d.ts +0 -68
  561. package/dist/local-editor-agent-context.d.ts.map +0 -1
  562. package/dist/local-editor-agent-context.js +0 -716
  563. package/dist/local-editor-agent-context.js.map +0 -1
  564. package/node_modules/@fps-games/editor-core/dist/agent-bridge.d.ts +0 -22
  565. package/node_modules/@fps-games/editor-core/dist/agent-bridge.d.ts.map +0 -1
  566. package/node_modules/@fps-games/editor-core/dist/agent-bridge.js +0 -106
  567. package/node_modules/@fps-games/editor-core/dist/agent-bridge.js.map +0 -1
  568. package/node_modules/@fps-games/editor-core/dist/agent-interaction.d.ts +0 -17
  569. package/node_modules/@fps-games/editor-core/dist/agent-interaction.d.ts.map +0 -1
  570. package/node_modules/@fps-games/editor-core/dist/agent-interaction.js +0 -14
  571. package/node_modules/@fps-games/editor-core/dist/agent-interaction.js.map +0 -1
  572. package/node_modules/@fps-games/editor-forge-play/dist/agent-transport.d.ts +0 -23
  573. package/node_modules/@fps-games/editor-forge-play/dist/agent-transport.d.ts.map +0 -1
  574. package/node_modules/@fps-games/editor-forge-play/dist/agent-transport.js +0 -47
  575. package/node_modules/@fps-games/editor-forge-play/dist/agent-transport.js.map +0 -1
  576. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/agent-descriptions.d.ts +0 -112
  577. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/agent-descriptions.d.ts.map +0 -1
  578. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/agent-descriptions.js +0 -159
  579. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/agent-descriptions.js.map +0 -1
  580. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/session-metadata.d.ts +0 -15
  581. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/session-metadata.d.ts.map +0 -1
  582. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/session-metadata.js +0 -76
  583. package/node_modules/@fps-games/editor-playable-sdk/dist/vite/session-metadata.js.map +0 -1
  584. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.d.ts +0 -1622
  585. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.d.ts.map +0 -1
  586. package/node_modules/@fps-games/editor-protocol/dist/agent-bridge.js.map +0 -1
  587. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.d.ts +0 -68
  588. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.d.ts.map +0 -1
  589. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.js +0 -23
  590. package/node_modules/@fps-games/editor-protocol/dist/agent-trace.js.map +0 -1
  591. package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts +0 -187
  592. package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts.map +0 -1
  593. package/node_modules/@fps-games/editor-protocol/dist/agent.js +0 -5
  594. package/node_modules/@fps-games/editor-protocol/dist/agent.js.map +0 -1
  595. /package/dist/{agent-bridge → editor-commands}/source-types.js +0 -0
@@ -1,8 +1,9 @@
1
- import { createEditorSession, FPS_EDITOR_ACTIVE_TOOL_CHANGED, FPS_EDITOR_DOCUMENT_CHANGED, FPS_EDITOR_HISTORY_CHANGED, FPS_EDITOR_SELECTION_CHANGED, createEditorAgentBridge, createInspectorRegistry, DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, DEFAULT_EDITOR_VIEWPORT_TOOL_STATE, createEmptyEditorViewportSpatialOverlayState, cloneEditorTransformSnapshot as cloneCoreEditorTransformSnapshot, composeEditorTransformMatrix, editorTransformMatricesAlmostEqual, cloneEditorViewportToolState, cloneEditorViewportSpatialOverlayState, aggregateInspectorObjectsToMultiObject, createInspectorEditPayload, compareInspectorSections, computeEditorTransformActionTargets, mergeInspectorSections, isEditorTransformTrsSnapshot, normalizeEditorTransformConstraint, readEditorTransformPosition, resolveEditorSelectionCommand, validateSceneGraphDelete, validateSceneGraphDrop, validateSceneGraphGroupSelection, validateSceneGraphMove, validateSceneGraphRename, } from '@fps-games/editor-core';
1
+ import { createEditorAuthoringHost, createEditorSession, FPS_EDITOR_ACTIVE_TOOL_CHANGED, FPS_EDITOR_DOCUMENT_CHANGED, FPS_EDITOR_HISTORY_CHANGED, FPS_EDITOR_SELECTION_CHANGED, createEditorCommandCapabilityAdapter, createEditorCommandSystem, createInspectorRegistry, DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, DEFAULT_EDITOR_VIEWPORT_TOOL_STATE, createEmptyEditorViewportSpatialOverlayState, callWithEditorAuthoringSerializedAccess, createEditorAuthoringSerializedSessionView, cloneEditorTransformSnapshot as cloneCoreEditorTransformSnapshot, composeEditorTransformMatrix, editorTransformMatricesAlmostEqual, cloneEditorViewportToolState, cloneEditorViewportSpatialOverlayState, aggregateInspectorObjectsToMultiObject, createInspectorEditPayload, compareInspectorSections, computeEditorTransformActionTargets, mergeInspectorSections, isEditorTransformTrsSnapshot, normalizeEditorTransformConstraint, readEditorTransformPosition, resolveEditorSelectionCommand, validateSceneGraphDelete, validateSceneGraphDrop, validateSceneGraphGroupSelection, validateSceneGraphMove, validateSceneGraphRename, } from '@fps-games/editor-core';
2
2
  import { createEditorToolManager, createEditorToolRegistry, resolveEditingContextProvider, } from '@fps-games/editor-core/tools';
3
3
  import { createEditorDiagnosticStore, normalizeEditorDiagnostic, normalizeEditorDiagnosticDetails, } from '@fps-games/editor-core/diagnostics';
4
- import {} from '@fps-games/editor-protocol';
5
- import { createLocalEditorBrowserUi, resolveLocalEditorBrowserAssetKind, resolveLocalEditorStatusDiagnosticLocator, toTransformOperationPolicyStatusLabel, } from '@fps-games/editor-browser';
4
+ import { EDITOR_COMMAND_ID, } from '@fps-games/editor-protocol';
5
+ import { createLocalEditorBrowserUi, createLocalEditorCommandServiceClient, resolveLocalEditorBrowserAssetKind, resolveLocalEditorStatusDiagnosticLocator, toTransformOperationPolicyStatusLabel, } from '@fps-games/editor-browser';
6
+ import { classifyProjectServiceSnapshot, createProjectServiceProjectionSessionAuthority, shouldReplacePendingProjectServiceSnapshot, waitForProjectServiceOperation, } from './project-service-projection.js';
6
7
  import { mountLocalEditorProjectModelPreview, resolveLocalEditorProjectModelThumbnail, } from './internal/project-model-preview.js';
7
8
  import { mountLocalEditorMaterialPreview } from './internal/material-preview.js';
8
9
  import { bindFpsEditorTools, } from '@fps-games/editor-core/plugin-host';
@@ -17,14 +18,12 @@ import { createPlayableBabylonOutlineInspectorSection, createPlayableBabylonOutl
17
18
  import { createLocalEditorViewportRenderCoordinator, } from './local-editor-viewport-render-coordinator.js';
18
19
  import { createLocalEditorSceneViewInteractionRuntime, } from './local-editor-scene-view-interaction-runtime.js';
19
20
  import { cloneLocalEditorPerformanceStats, countLocalEditorAuthoredObjects, createLocalEditorPerformanceStats, LOCAL_EDITOR_PERFORMANCE_MONITOR_REASON, } from './local-editor-performance-stats.js';
20
- import { registerLocalEditorAgentBridgeCapabilities } from './local-editor-agent-bridge.js';
21
- import { registerEditorPluginAgentCapabilities } from './editor-plugin-agent-capabilities.js';
21
+ import { registerLocalEditorCommandCapabilities } from './local-editor-commands.js';
22
+ import { registerEditorPluginCommands } from './editor-plugin-commands.js';
22
23
  import { createLocalEditorStandardToolRegistrations, LOCAL_EDITOR_SELECTION_CAPABILITY_ID, LOCAL_EDITOR_STANDARD_TOOL_IDS, LOCAL_EDITOR_TRANSFORM_CAPABILITY_ID, resolveLocalEditorTransformTool, } from './local-editor-tools.js';
23
24
  import { createHierarchyScopeSnapshot, createHierarchyTreeSnapshot, resolveHierarchyScopeProviders, resolveHierarchySurfaceContribution, } from '@fps-games/plugin-hierarchy';
24
- import { createLocalEditorAgentBridgeCapabilitySources, } from './agent-bridge/capability-sources.js';
25
- import { createDisabledLocalEditorAgentBridgeTransportStatus, createLocalEditorAgentBridgeWebSocketTransportFromQuery, } from './local-editor-agent-bridge-transport.js';
25
+ import { createLocalEditorCommandCapabilitySources, } from './editor-commands/command-sources.js';
26
26
  import { PLAYABLE_LOCAL_EDITOR_APPLICATION_SCOPE_ID, PLAYABLE_LOCAL_EDITOR_MAIN_DOCUMENT_SCOPE_ID, PLAYABLE_LOCAL_EDITOR_MAIN_PREVIEW_SCOPE_ID, PLAYABLE_LOCAL_EDITOR_MAIN_SESSION_SCOPE_ID, PLAYABLE_LOCAL_EDITOR_PROJECT_SCOPE_ID, } from '@fps-games/editor-playable-sdk/internal/local-harness';
27
- import { FPS_EDITOR_LIFECYCLE_TRANSITION_TYPES } from '@fps-games/editor-core/lifecycle';
28
27
  import { createMarkerGraphHierarchyItems, createMarkerGraphInspectorObject, createMarkerGraphRootInspectorObject, createMarkerPanelState, createMarkerRelationCommand, createMarkerRelationCreateManyCommand, createMarkerRelationDeleteConnectedCommand, createMarkerRelationReverseCommand, createMarkerGraphPatchFromInspectorEdit, findSpatialMarkerById, getSpatialMarkerDirectRelations, isMarkerGraphHierarchyId, isMarkerGraphHierarchyRootId, isMarkerGraphHierarchyRootRowId, isSpatialMarkerBackedByHierarchyRow, isSpatialMarkerHierarchyVisible, readMarkerGraphHierarchyMarkerIdForGraph, readSpatialMarkerIdFromHierarchySelection, } from './local-editor-marker-graph.js';
29
28
  const BATCH_EDIT_REQUIRES_MULTI_PATCH_REASON = 'Batch edit requires multi-property patch support.';
30
29
  const LARGE_SELECTION_THRESHOLD = 200;
@@ -32,6 +31,7 @@ const LARGE_SHADOW_METADATA_BATCH_THRESHOLD = 200;
32
31
  const EDITOR_PROJECTION_VALIDATION_TIMEOUT_MS = 10000;
33
32
  const EDITOR_WORLD_DISPOSE_BOUNDARY_DELAY_MS = 500;
34
33
  const RENDERING_ACTION_PROGRESS_MIN_VISIBLE_MS = 1000;
34
+ const SERIALIZED_HIERARCHY_INVOCATION = Symbol('fps.editor.serialized-hierarchy-invocation');
35
35
  const PREFAB_STAGE_CONTEXT_ACTION_IDS = Object.freeze({
36
36
  save: 'fps.editor.context.prefab.save',
37
37
  discard: 'fps.editor.context.prefab.discard',
@@ -264,22 +264,36 @@ export function createLocalEditorHarness(options) {
264
264
  }
265
265
  function createLocalEditorHarnessImplementation(options, construction) {
266
266
  const root = options.root ?? document.body;
267
+ const projectCommandService = createLocalEditorCommandServiceClient();
268
+ const browserCommandAttachmentId = `browser-command-host-${createLocalEditorAuthoringServiceInstanceId()}`;
269
+ let disposeBrowserCommandAttachment = null;
270
+ let projectedServiceInstanceId = null;
271
+ let projectedServiceRevision = null;
272
+ let projectedBrowserDocumentFingerprint = null;
273
+ let pendingProjectServiceSnapshot = null;
274
+ let stopProjectServiceWatch = null;
267
275
  let lifecycleController = null;
268
276
  let releaseApplicationAuthorityScopeResource = null;
269
277
  let releaseLifecycleRenderScopeResource = null;
270
278
  let unsubscribeLifecycleRender = null;
271
- let unregisterAgentBridgeLifecycleParticipant = null;
272
- const agentBridgeLifecycleTransports = new Map();
279
+ let suppressedDocumentMarkDirtyTransitionId = null;
280
+ let lifecyclePresentationOnlyRenderDepth = 0;
273
281
  let releaseMainSessionScopeResource = null;
274
282
  let releaseMainPreviewScopeResource = null;
275
283
  let pendingScheduledLifecycleExit = null;
276
284
  let harnessDisposed = false;
285
+ const commandServiceCommandSystem = createEditorCommandSystem();
286
+ const projectionSessionAuthority = createProjectServiceProjectionSessionAuthority();
287
+ const replaceProjectionSessionAuthority = (session) => projectionSessionAuthority.replace(session);
288
+ const runProjectionSessionMutation = (session, mutation) => projectionSessionAuthority.run(session, mutation);
277
289
  const state = {
278
290
  get mode() {
291
+ if (state.session)
292
+ return 'editor';
279
293
  const lifecycleMode = lifecycleController?.lifecycle.getSnapshot().mode;
280
294
  if (lifecycleMode)
281
295
  return lifecycleMode === 'edit' ? 'editor' : 'game';
282
- return state.world ? 'editor' : 'game';
296
+ return 'game';
283
297
  },
284
298
  get lifecycle() {
285
299
  return lifecycleController?.lifecycle ?? null;
@@ -294,6 +308,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
294
308
  hierarchyItemsCacheSession: null,
295
309
  hierarchyItemsCacheRevision: -1,
296
310
  hierarchyItemsCache: Object.freeze([]),
311
+ hierarchyPresentationFallbackRevision: 0,
297
312
  diagnosticStore: createEditorDiagnosticStore(),
298
313
  diagnosticPhase: 'edit',
299
314
  reuseDiagnosticSnapshotOnNextRender: false,
@@ -303,6 +318,17 @@ function createLocalEditorHarnessImplementation(options, construction) {
303
318
  busy: false,
304
319
  documentOperationActive: false,
305
320
  session: null,
321
+ authoringHost: null,
322
+ projectAuthoringSnapshot: null,
323
+ replaceProjectionSessionAuthority,
324
+ runBrowserAuthoringMutation: async () => {
325
+ throw new Error('Browser authoring authority is unavailable.');
326
+ },
327
+ tryRunBrowserAuthoringMutationImmediately: () => ({
328
+ ok: false,
329
+ reason: 'Browser authoring authority is unavailable.',
330
+ }),
331
+ reconcilePendingProjectServiceSnapshot: async () => { },
306
332
  createSessionChangeObserver: () => () => { },
307
333
  handleSessionObserverError: () => { },
308
334
  source: null,
@@ -345,8 +371,13 @@ function createLocalEditorHarnessImplementation(options, construction) {
345
371
  sceneViewSpatialOverlay: null,
346
372
  selectionController: null,
347
373
  selectionInspectorRefreshGeneration: 0,
348
- selectionInspectorRefreshFrame: null,
349
374
  selectionInspectorRefreshTimeout: null,
375
+ suppressDocumentMarkDirtyInspectorRefresh: false,
376
+ suppressedProjectionInspectorRefreshBatchIds: new Set(),
377
+ suppressedProjectionInspectorRefreshNodeBatches: new Map(),
378
+ inspectorPresentationGeneration: 0,
379
+ inspectorPresentationFrame: null,
380
+ inspectorPresentationPatches: null,
350
381
  sceneRenderScheduler: null,
351
382
  viewportRenderCoordinator: null,
352
383
  sceneFrameStats: null,
@@ -383,10 +414,387 @@ function createLocalEditorHarnessImplementation(options, construction) {
383
414
  statusDetails: '',
384
415
  renderingAction: null,
385
416
  summary: '',
386
- agentBridge: createEditorAgentBridge(),
387
- unregisterAgentBridgeCapabilities: null,
388
- agentBridgeTransport: null,
389
- agentBridgeStatus: createDisabledLocalEditorAgentBridgeTransportStatus(),
417
+ commandService: createEditorCommandCapabilityAdapter({
418
+ commandSystem: commandServiceCommandSystem,
419
+ resolveAuthoringRevision: () => projectCommandService
420
+ ? projectedServiceRevision
421
+ : state.authoringHost?.getSnapshot().documentRevision ?? null,
422
+ }),
423
+ unregisterCommandCapabilities: null,
424
+ };
425
+ let browserAuthoringMutationSequence = 0;
426
+ let projectServiceSyncTail = Promise.resolve();
427
+ let projectServiceSyncPending = 0;
428
+ const acquireProjectServiceSync = async () => {
429
+ projectServiceSyncPending += 1;
430
+ const previous = projectServiceSyncTail;
431
+ let releaseCurrent;
432
+ projectServiceSyncTail = new Promise(resolve => { releaseCurrent = resolve; });
433
+ await previous;
434
+ let active = true;
435
+ return () => {
436
+ if (!active)
437
+ return;
438
+ active = false;
439
+ projectServiceSyncPending -= 1;
440
+ releaseCurrent();
441
+ };
442
+ };
443
+ const tryAcquireProjectServiceSync = () => {
444
+ if (projectServiceSyncPending > 0)
445
+ return null;
446
+ projectServiceSyncPending = 1;
447
+ let releaseCurrent;
448
+ projectServiceSyncTail = new Promise(resolve => { releaseCurrent = resolve; });
449
+ let active = true;
450
+ return () => {
451
+ if (!active)
452
+ return;
453
+ active = false;
454
+ projectServiceSyncPending = 0;
455
+ releaseCurrent();
456
+ };
457
+ };
458
+ const readProjectServiceSnapshot = async () => {
459
+ if (!projectCommandService)
460
+ return null;
461
+ const response = await projectCommandService.request({ kind: 'authoring.snapshot' });
462
+ if (!response.ok || response.kind !== 'authoring.snapshot'
463
+ || response.result.kind !== 'snapshot-required')
464
+ return null;
465
+ return response.result.snapshot;
466
+ };
467
+ const commitProjectAuthoringProjection = (snapshot, documentFingerprint = createLocalEditorDocumentFingerprint(snapshot.document)) => {
468
+ state.projectAuthoringSnapshot = {
469
+ serviceInstanceId: snapshot.serviceInstanceId,
470
+ documentRevision: snapshot.documentRevision,
471
+ dirty: snapshot.dirty,
472
+ canUndo: snapshot.canUndo,
473
+ canRedo: snapshot.canRedo,
474
+ history: snapshot.history
475
+ ? { entries: snapshot.history.entries.map(entry => ({ ...entry })) }
476
+ : { entries: [] },
477
+ };
478
+ projectedServiceRevision = snapshot.documentRevision;
479
+ projectedServiceInstanceId = snapshot.serviceInstanceId;
480
+ projectedBrowserDocumentFingerprint = documentFingerprint;
481
+ if (pendingProjectServiceSnapshot?.serviceInstanceId === snapshot.serviceInstanceId
482
+ && pendingProjectServiceSnapshot.documentRevision === snapshot.documentRevision) {
483
+ pendingProjectServiceSnapshot = null;
484
+ }
485
+ };
486
+ const invokeProjectServiceCommand = async (commandId, input = {}, expectedDocumentRevision) => {
487
+ if (!projectCommandService)
488
+ throw new Error('Project Editor Service is unavailable.');
489
+ if (projectedServiceRevision === null || projectedServiceInstanceId === null) {
490
+ const snapshot = await readProjectServiceSnapshot();
491
+ if (snapshot)
492
+ await applyProjectServiceSnapshot(snapshot, true);
493
+ }
494
+ const invocationExpectedRevision = expectedDocumentRevision ?? projectedServiceRevision;
495
+ if (invocationExpectedRevision === null || projectedServiceInstanceId === null) {
496
+ throw new Error('Project Editor Service revision is not ready.');
497
+ }
498
+ const requestId = `browser-project-${++browserAuthoringMutationSequence}`;
499
+ const response = await projectCommandService.request({
500
+ kind: 'command.invoke',
501
+ invocation: {
502
+ commandId,
503
+ input: input,
504
+ requestId,
505
+ idempotencyKey: requestId,
506
+ expectedRevision: {
507
+ serviceInstanceId: projectedServiceInstanceId,
508
+ document: invocationExpectedRevision,
509
+ },
510
+ principal: { type: 'human' },
511
+ source: 'browser-ui',
512
+ clientId: browserCommandAttachmentId,
513
+ },
514
+ timeoutMs: 10000,
515
+ });
516
+ const operation = await waitForProjectServiceOperation(projectCommandService.request, response);
517
+ if (operation?.status !== 'completed') {
518
+ throw new Error(operation?.diagnostics?.map(diagnostic => diagnostic.message).join('; ')
519
+ || `Project Editor Service rejected ${commandId}.`);
520
+ }
521
+ return operation.output && typeof operation.output === 'object' && !Array.isArray(operation.output)
522
+ ? operation.output
523
+ : {};
524
+ };
525
+ const prepareProjectServiceDocumentExport = async () => {
526
+ if (!projectCommandService)
527
+ return null;
528
+ const prepared = await invokeProjectServiceCommand('document.export');
529
+ const transactionId = typeof prepared.transactionId === 'string'
530
+ ? prepared.transactionId
531
+ : null;
532
+ if (!transactionId) {
533
+ throw new Error('Project Editor Service did not return an export transaction.');
534
+ }
535
+ const response = await projectCommandService.request({
536
+ kind: 'document.export.get',
537
+ transactionId,
538
+ });
539
+ if (!response.ok || response.kind !== 'document.export' || !response.artifact) {
540
+ throw new Error('Project Editor Service did not return the prepared export artifact.');
541
+ }
542
+ return response.artifact;
543
+ };
544
+ const applyProjectServiceSnapshot = async (snapshot, syncLeaseHeld = false) => {
545
+ if (projectCommandService && !syncLeaseHeld) {
546
+ const release = await acquireProjectServiceSync();
547
+ try {
548
+ return await applyProjectServiceSnapshot(snapshot, true);
549
+ }
550
+ finally {
551
+ release();
552
+ }
553
+ }
554
+ const classification = classifyProjectServiceSnapshot(projectedServiceInstanceId, projectedServiceRevision, snapshot);
555
+ if (classification === 'stale')
556
+ return;
557
+ const serviceChanged = classification === 'service-changed';
558
+ if (shouldReplacePendingProjectServiceSnapshot(pendingProjectServiceSnapshot, snapshot)) {
559
+ pendingProjectServiceSnapshot = snapshot;
560
+ }
561
+ const session = state.session;
562
+ if (!session || state.prefabStage)
563
+ return;
564
+ const stateSnapshot = session.getState({ cloneDocuments: false });
565
+ const localDocumentFingerprint = createLocalEditorDocumentFingerprint(stateSnapshot.workingDocument);
566
+ const snapshotDocumentFingerprint = createLocalEditorDocumentFingerprint(snapshot.document);
567
+ if (!serviceChanged
568
+ && projectedServiceRevision !== null
569
+ && projectedBrowserDocumentFingerprint !== null
570
+ && localDocumentFingerprint !== projectedBrowserDocumentFingerprint) {
571
+ throw new Error('The project snapshot cannot replace Browser working state because a newer local authoring transaction is not projected.');
572
+ }
573
+ if (localDocumentFingerprint === snapshotDocumentFingerprint
574
+ && createLocalEditorDocumentFingerprint(stateSnapshot.persistedDocument)
575
+ === createLocalEditorDocumentFingerprint(snapshot.savedDocument)) {
576
+ commitProjectAuthoringProjection(snapshot, snapshotDocumentFingerprint);
577
+ return;
578
+ }
579
+ const rebaseProjection = (activeSession) => {
580
+ if (state.session !== session || state.prefabStage) {
581
+ throw new Error('Browser authoring scope changed before applying the project snapshot.');
582
+ }
583
+ runProjectionSessionMutation(activeSession, () => {
584
+ activeSession.rebaseExternalDocuments({
585
+ persistedDocument: snapshot.savedDocument,
586
+ workingDocument: snapshot.document,
587
+ });
588
+ });
589
+ };
590
+ const host = state.authoringHost;
591
+ if (host) {
592
+ const sequence = ++browserAuthoringMutationSequence;
593
+ await host.runExternalCommandMutation({
594
+ commandId: 'authoring.snapshot.project',
595
+ requestId: `project-snapshot-${sequence}`,
596
+ idempotencyKey: `project-snapshot-${sequence}`,
597
+ expectedDocumentRevision: stateSnapshot.documentRevision,
598
+ fingerprint: JSON.stringify({ serviceInstanceId: snapshot.serviceInstanceId, documentRevision: snapshot.documentRevision }),
599
+ }, rebaseProjection);
600
+ }
601
+ else {
602
+ rebaseProjection(session);
603
+ }
604
+ commitProjectAuthoringProjection(snapshot, snapshotDocumentFingerprint);
605
+ harness.render();
606
+ };
607
+ const pushBrowserDocumentToProjectService = async (document, commandId, inputFingerprint, expectedServiceInstanceId, expectedServiceRevision, baseDocumentFingerprint, rollbackSession) => {
608
+ if (!projectCommandService)
609
+ return;
610
+ if (!disposeBrowserCommandAttachment || await disposeBrowserCommandAttachment === null) {
611
+ throw new Error('Browser command attachment is unavailable.');
612
+ }
613
+ const requestId = `browser-project-${++browserAuthoringMutationSequence}`;
614
+ const response = await projectCommandService.request({
615
+ kind: 'command.invoke',
616
+ invocation: {
617
+ commandId: 'authoring.proposal.commit',
618
+ intentCommandId: commandId,
619
+ input: { commandId, inputFingerprint, document },
620
+ requestId,
621
+ idempotencyKey: requestId,
622
+ expectedRevision: {
623
+ serviceInstanceId: expectedServiceInstanceId,
624
+ document: expectedServiceRevision,
625
+ },
626
+ principal: { type: 'human' },
627
+ source: 'browser-ui',
628
+ clientId: browserCommandAttachmentId,
629
+ },
630
+ timeoutMs: 10000,
631
+ });
632
+ const operation = await waitForProjectServiceOperation(projectCommandService.request, response);
633
+ if (operation?.status === 'completed') {
634
+ return;
635
+ }
636
+ const snapshot = await readProjectServiceSnapshot();
637
+ if (snapshot) {
638
+ if (shouldReplacePendingProjectServiceSnapshot(pendingProjectServiceSnapshot, snapshot)) {
639
+ pendingProjectServiceSnapshot = snapshot;
640
+ }
641
+ }
642
+ if (snapshot && rollbackSession) {
643
+ runProjectionSessionMutation(rollbackSession, () => {
644
+ rollbackSession.rebaseExternalDocuments({
645
+ persistedDocument: snapshot.savedDocument,
646
+ workingDocument: snapshot.document,
647
+ });
648
+ });
649
+ commitProjectAuthoringProjection(snapshot);
650
+ }
651
+ const remoteFingerprint = snapshot
652
+ ? createLocalEditorDocumentFingerprint(snapshot.document)
653
+ : null;
654
+ throw new Error(remoteFingerprint !== baseDocumentFingerprint
655
+ ? 'Browser authoring was rejected because the project document changed in another client.'
656
+ : operation?.diagnostics?.map(diagnostic => diagnostic.message).join('; ')
657
+ || 'Project Editor Service rejected the Browser authoring transaction.');
658
+ };
659
+ state.reconcilePendingProjectServiceSnapshot = async () => {
660
+ if (pendingProjectServiceSnapshot) {
661
+ await applyProjectServiceSnapshot(pendingProjectServiceSnapshot);
662
+ }
663
+ };
664
+ state.runBrowserAuthoringMutation = async (commandId, fingerprint, handler) => {
665
+ const releaseProjectSync = projectCommandService ? await acquireProjectServiceSync() : () => { };
666
+ try {
667
+ const session = state.session;
668
+ if (!session)
669
+ throw new Error('Browser authoring projection is unavailable.');
670
+ if (projectCommandService) {
671
+ if (projectedServiceRevision === null) {
672
+ const remote = await readProjectServiceSnapshot();
673
+ if (remote)
674
+ await applyProjectServiceSnapshot(remote, true);
675
+ }
676
+ const expectedServiceInstanceId = projectedServiceInstanceId;
677
+ const expectedServiceRevision = projectedServiceRevision;
678
+ if (expectedServiceInstanceId === null || expectedServiceRevision === null) {
679
+ throw new Error('Project Editor Service revision is not ready.');
680
+ }
681
+ const baseDocumentFingerprint = createLocalEditorDocumentFingerprint(session.getWorkingDocument());
682
+ const transaction = session.beginTransaction();
683
+ try {
684
+ const authoringState = new Proxy(state, {
685
+ get(target, property, receiver) {
686
+ if (property === 'session')
687
+ return transaction.session;
688
+ return Reflect.get(target, property, receiver);
689
+ },
690
+ set(target, property, value, receiver) {
691
+ if (property === 'session') {
692
+ throw new Error('Browser authoring proposal handlers cannot replace the projection Session.');
693
+ }
694
+ return Reflect.set(target, property, value, receiver);
695
+ },
696
+ });
697
+ const value = await handler(authoringState);
698
+ if (state.session !== session) {
699
+ throw new Error(`Browser authoring scope changed before ${commandId}.`);
700
+ }
701
+ const proposedDocument = transaction.session.getWorkingDocument();
702
+ await pushBrowserDocumentToProjectService(proposedDocument, commandId, fingerprint, expectedServiceInstanceId, expectedServiceRevision, baseDocumentFingerprint, session);
703
+ const committedSnapshot = await readProjectServiceSnapshot();
704
+ if (!committedSnapshot) {
705
+ throw new Error('Project Editor Service did not return the committed authoring snapshot.');
706
+ }
707
+ if (state.prefabStage && state.session === session) {
708
+ const projectionState = session.getState({ cloneDocuments: false });
709
+ runProjectionSessionMutation(session, () => {
710
+ session.rebaseExternalDocuments({
711
+ persistedDocument: projectionState.persistedDocument,
712
+ workingDocument: committedSnapshot.document,
713
+ });
714
+ });
715
+ commitProjectAuthoringProjection(committedSnapshot);
716
+ harness.render();
717
+ }
718
+ else {
719
+ await applyProjectServiceSnapshot(committedSnapshot, true);
720
+ }
721
+ return value;
722
+ }
723
+ finally {
724
+ transaction.discard();
725
+ }
726
+ }
727
+ const host = state.authoringHost;
728
+ if (!host)
729
+ throw new Error('Browser authoring authority is unavailable.');
730
+ const expectedDocumentRevision = session.getState({ cloneDocuments: false }).documentRevision;
731
+ const sequence = ++browserAuthoringMutationSequence;
732
+ const requestId = `browser-${sequence}`;
733
+ return await host.runExternalCommandMutation({
734
+ commandId,
735
+ requestId,
736
+ idempotencyKey: requestId,
737
+ expectedDocumentRevision,
738
+ fingerprint,
739
+ }, activeSession => {
740
+ if (state.session !== session) {
741
+ throw new Error(`Browser authoring scope changed before ${commandId}.`);
742
+ }
743
+ const authoringState = new Proxy(state, {
744
+ get(target, property, receiver) {
745
+ if (property === 'session')
746
+ return activeSession;
747
+ return Reflect.get(target, property, receiver);
748
+ },
749
+ set(target, property, value, receiver) {
750
+ if (property === 'session') {
751
+ throw new Error('Browser authoring handlers cannot replace the active Session.');
752
+ }
753
+ return Reflect.set(target, property, value, receiver);
754
+ },
755
+ });
756
+ return handler(authoringState);
757
+ });
758
+ }
759
+ finally {
760
+ releaseProjectSync();
761
+ }
762
+ };
763
+ state.tryRunBrowserAuthoringMutationImmediately = (commandId, fingerprint, handler) => {
764
+ if (projectCommandService) {
765
+ return { ok: false, reason: 'Project Editor Service authoring is asynchronous.' };
766
+ }
767
+ const host = state.authoringHost;
768
+ const session = state.session;
769
+ if (!host || !session)
770
+ return { ok: false, reason: 'Browser authoring authority is unavailable.' };
771
+ const releaseProjectSync = tryAcquireProjectServiceSync();
772
+ if (!releaseProjectSync)
773
+ return { ok: false, reason: 'An authoring transaction is still pending.' };
774
+ const expectedDocumentRevision = session.getState({ cloneDocuments: false }).documentRevision;
775
+ const sequence = ++browserAuthoringMutationSequence;
776
+ const requestId = `browser-${sequence}`;
777
+ try {
778
+ const result = host.tryRunExternalCommandMutationImmediately({
779
+ commandId,
780
+ requestId,
781
+ idempotencyKey: requestId,
782
+ expectedDocumentRevision,
783
+ fingerprint,
784
+ }, activeSession => {
785
+ if (state.session !== session) {
786
+ throw new Error(`Browser authoring scope changed before ${commandId}.`);
787
+ }
788
+ return handler(activeSession);
789
+ });
790
+ return result.ok ? { ok: true, value: result.value } : {
791
+ ok: false,
792
+ reason: 'Another authoring transaction is running.',
793
+ };
794
+ }
795
+ finally {
796
+ releaseProjectSync();
797
+ }
390
798
  };
391
799
  const getDocumentDirty = () => {
392
800
  const stageSnapshot = state.prefabStage?.transaction.snapshot();
@@ -398,6 +806,8 @@ function createLocalEditorHarnessImplementation(options, construction) {
398
806
  if (change.documentChanged)
399
807
  state.diagnosticPhase = 'edit';
400
808
  void lifecycleController?.synchronizeDocumentState(getDocumentDirty()).catch(error => {
809
+ state.suppressDocumentMarkDirtyInspectorRefresh = false;
810
+ suppressedDocumentMarkDirtyTransitionId = null;
401
811
  console.error('[LocalEditorHarness] lifecycle document synchronization failed', error);
402
812
  });
403
813
  const eventPublisher = options.pluginHost?.eventPublisher;
@@ -456,11 +866,93 @@ function createLocalEditorHarnessImplementation(options, construction) {
456
866
  state.createSessionChangeObserver = createSessionChangeObserver;
457
867
  state.handleSessionObserverError = handleEditorSessionObserverError;
458
868
  let harness;
869
+ const runProjectServiceHistoryOperation = async (operation, historyOptions = {}) => {
870
+ const origin = historyOptions.origin ?? 'user';
871
+ const waitForProjection = historyOptions.waitForProjection ?? 'none';
872
+ const releaseProjectSync = await acquireProjectServiceSync();
873
+ try {
874
+ cancelActiveOperation(state);
875
+ const before = await readProjectServiceSnapshot();
876
+ if (!before)
877
+ throw new Error('Project Editor Service history is unavailable.');
878
+ await applyProjectServiceSnapshot(before, true);
879
+ const available = operation === 'undo' ? before.canUndo : before.canRedo;
880
+ if (!available) {
881
+ return {
882
+ ok: false,
883
+ operation,
884
+ origin,
885
+ waitForProjection,
886
+ documentChanged: false,
887
+ transactionLabel: null,
888
+ workingDocument: before.document,
889
+ dirty: before.dirty,
890
+ history: { canUndo: before.canUndo, canRedo: before.canRedo },
891
+ status: operation === 'undo' ? 'Undo unavailable' : 'Redo unavailable',
892
+ projection: createHistoryProjectionResult(waitForProjection, null, state),
893
+ };
894
+ }
895
+ await invokeProjectServiceCommand(`history.${operation}`);
896
+ const after = await readProjectServiceSnapshot();
897
+ if (!after)
898
+ throw new Error('Project Editor Service did not return the updated history snapshot.');
899
+ await applyProjectServiceSnapshot(after, true);
900
+ state.summary = summarizeDocument(options, after.document, state.session?.getSource());
901
+ state.status = operation === 'undo' ? 'Undo' : 'Redo';
902
+ state.statusTone = 'default';
903
+ state.statusToneStatus = state.status;
904
+ state.statusDetails = '';
905
+ harness.render();
906
+ const idleState = waitForProjection === 'settled'
907
+ ? await state.projection?.waitForIdle() ?? null
908
+ : null;
909
+ return {
910
+ ok: true,
911
+ operation,
912
+ origin,
913
+ waitForProjection,
914
+ documentChanged: after.documentRevision !== before.documentRevision,
915
+ transactionLabel: null,
916
+ workingDocument: after.document,
917
+ dirty: after.dirty,
918
+ history: { canUndo: after.canUndo, canRedo: after.canRedo },
919
+ status: state.status,
920
+ projection: createHistoryProjectionResult(waitForProjection, idleState, state),
921
+ };
922
+ }
923
+ catch (error) {
924
+ reportBrowserAuthoringFailure(state, () => harness.render(), error);
925
+ const snapshot = state.projectAuthoringSnapshot;
926
+ return {
927
+ ok: false,
928
+ operation,
929
+ origin,
930
+ waitForProjection,
931
+ documentChanged: false,
932
+ transactionLabel: null,
933
+ workingDocument: state.session?.getWorkingDocument() ?? null,
934
+ dirty: snapshot?.dirty ?? state.session?.isDirty() ?? false,
935
+ history: {
936
+ canUndo: snapshot?.canUndo ?? false,
937
+ canRedo: snapshot?.canRedo ?? false,
938
+ },
939
+ status: state.status,
940
+ projection: createHistoryProjectionResult(waitForProjection, null, state),
941
+ };
942
+ }
943
+ finally {
944
+ releaseProjectSync();
945
+ }
946
+ };
459
947
  let renderSelectionChange = () => harness.render();
948
+ let applySceneRenamePresentation = (_input) => false;
949
+ let applyHistoryPresentation = (_impact) => false;
950
+ let applyInspectorPresentation = (_input) => false;
951
+ let applyRenderingPresentation = () => false;
460
952
  const busyOperationExecutors = new WeakMap();
461
953
  let agentLifecycleController;
462
954
  const pluginInspector = createLocalEditorHarnessPluginInspectorOptions(options.pluginHost, options.inspector);
463
- const builtInSceneHierarchyProvider = createLocalEditorHarnessHierarchyScopeProvider(state, options, () => harness.render(), createLocalEditorSceneHierarchyScopeAdapter(state, options), busyOperationExecutors, () => renderSelectionChange());
955
+ const builtInSceneHierarchyProvider = createLocalEditorHarnessHierarchyScopeProvider(state, options, () => harness.render(), createLocalEditorSceneHierarchyScopeAdapter(state, options, input => applySceneRenamePresentation(input)), busyOperationExecutors, () => renderSelectionChange());
464
956
  const builtInPrefabStageHierarchyProvider = createLocalEditorHarnessHierarchyScopeProvider(state, options, () => harness.render(), createLocalEditorPrefabHierarchyScopeAdapter(state, options), busyOperationExecutors, () => renderSelectionChange());
465
957
  const hierarchySurface = options.pluginHost
466
958
  ? resolveHierarchySurfaceContribution(options.pluginHost.contributions)
@@ -551,6 +1043,8 @@ function createLocalEditorHarnessImplementation(options, construction) {
551
1043
  theme: options.theme,
552
1044
  localTestActions: options.localTestActions,
553
1045
  gameModeEntryVisible: options.gameModeEntryVisible,
1046
+ commandService: projectCommandService,
1047
+ commandClientId: browserCommandAttachmentId,
554
1048
  input: {
555
1049
  isShortcutReserved: (event) => state.sceneViewInput?.ownsKeyboardEvent(event) ?? false,
556
1050
  },
@@ -686,8 +1180,10 @@ function createLocalEditorHarnessImplementation(options, construction) {
686
1180
  })();
687
1181
  },
688
1182
  onCreateFromAsset: (assetId) => {
689
- if (createAssetFromBrowserIntent(state, options, assetId))
690
- harness.render();
1183
+ void state.runBrowserAuthoringMutation('object.createFromAsset', JSON.stringify({ assetId }), authoringState => createAssetFromBrowserIntent(authoringState, options, assetId)).then(changed => {
1184
+ if (changed)
1185
+ harness.render();
1186
+ }).catch(error => reportBrowserAuthoringFailure(state, harness.render, error));
691
1187
  },
692
1188
  onSelectAsset: (assetId) => {
693
1189
  if (selectBrowserAsset(state, assetId))
@@ -715,7 +1211,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
715
1211
  return;
716
1212
  }
717
1213
  else if (choice === 'discard') {
718
- discardPrefabStageChanges();
1214
+ await discardPrefabStageChanges();
719
1215
  }
720
1216
  else {
721
1217
  return;
@@ -729,12 +1225,18 @@ function createLocalEditorHarnessImplementation(options, construction) {
729
1225
  void runExclusive(state, harness.render, executor => (runPrefabContextAction(actionId, executor)), busyOperationExecutors);
730
1226
  },
731
1227
  onMarkerTypeAction: (input) => {
732
- if (patchMarkerTypeCatalog(state, options, input))
733
- harness.render();
1228
+ void state.runBrowserAuthoringMutation('marker.type.apply', JSON.stringify(input), authoringState => patchMarkerTypeCatalog(authoringState, options, input)).then(changed => {
1229
+ if (changed)
1230
+ harness.render();
1231
+ }).catch(error => reportBrowserAuthoringFailure(state, harness.render, error));
734
1232
  },
735
1233
  onMarkerRelationAction: (input) => {
736
- if (patchMarkerRelation(state, options, input))
737
- harness.render();
1234
+ void state.runBrowserAuthoringMutation('marker.relation.apply', JSON.stringify(input), authoringState => {
1235
+ const changed = patchMarkerRelation(authoringState, options, input);
1236
+ if (changed)
1237
+ harness.render();
1238
+ return changed;
1239
+ }).catch(error => reportBrowserAuthoringFailure(state, harness.render, error));
738
1240
  },
739
1241
  onAssetBrowserRefresh: () => runExclusive(state, harness.render, async () => {
740
1242
  await harness.reloadAssets();
@@ -742,9 +1244,6 @@ function createLocalEditorHarnessImplementation(options, construction) {
742
1244
  onProjectFileRead: options.persistenceAdapter.loadProjectFile
743
1245
  ? path => Promise.resolve(options.persistenceAdapter.loadProjectFile(path))
744
1246
  : undefined,
745
- onProjectEntrySendToAgent: options.agentContext
746
- ? input => Promise.resolve(options.agentContext.sendProjectEntry(input)).then(() => undefined)
747
- : undefined,
748
1247
  onProjectMediaResolve: options.persistenceAdapter.resolveProjectMedia
749
1248
  ? path => Promise.resolve(options.persistenceAdapter.resolveProjectMedia(path))
750
1249
  : undefined,
@@ -756,10 +1255,46 @@ function createLocalEditorHarnessImplementation(options, construction) {
756
1255
  harness.render();
757
1256
  },
758
1257
  onPropertyInput: (input) => {
759
- const previousStatus = state.status;
760
- const patched = patchSerializedProperty(state, options, input);
761
- if (patched || state.status !== previousStatus)
762
- harness.render();
1258
+ const refreshInspector = input.refreshInspector
1259
+ ?? !(input.source === 'custom' && input.commitMode === 'live');
1260
+ const normalizedInput = refreshInspector === input.refreshInspector
1261
+ ? input
1262
+ : { ...input, refreshInspector };
1263
+ const lifecycleSnapshot = lifecycleController?.lifecycle.getSnapshot();
1264
+ state.suppressDocumentMarkDirtyInspectorRefresh = !refreshInspector
1265
+ && normalizedInput.persistence === 'document'
1266
+ && lifecycleSnapshot?.mode === 'edit'
1267
+ && lifecycleSnapshot.document !== 'dirty';
1268
+ void state.runBrowserAuthoringMutation('inspector.property.set', JSON.stringify(normalizedInput), authoringState => {
1269
+ const previousStatus = authoringState.status;
1270
+ const patched = patchSerializedProperty(authoringState, options, normalizedInput);
1271
+ return {
1272
+ patched,
1273
+ statusChanged: authoringState.status !== previousStatus,
1274
+ };
1275
+ })
1276
+ .then(({ patched, statusChanged }) => {
1277
+ const presentationApplied = patched
1278
+ ? applyInspectorPresentation(normalizedInput)
1279
+ : false;
1280
+ if (!refreshInspector) {
1281
+ if (!presentationApplied && (patched || statusChanged)) {
1282
+ ui.updatePreview?.({
1283
+ status: state.status,
1284
+ statusTone: state.statusToneStatus === state.status ? state.statusTone : 'default',
1285
+ statusDetails: state.statusToneStatus === state.status ? state.statusDetails : '',
1286
+ session: createUiSessionState(state),
1287
+ });
1288
+ }
1289
+ return;
1290
+ }
1291
+ if ((patched || statusChanged) && !presentationApplied)
1292
+ harness.render();
1293
+ })
1294
+ .catch(error => reportBrowserAuthoringFailure(state, harness.render, error))
1295
+ .finally(() => {
1296
+ state.suppressDocumentMarkDirtyInspectorRefresh = false;
1297
+ });
763
1298
  },
764
1299
  onInspectorAction: (input) => {
765
1300
  void runExclusive(state, harness.render, async () => {
@@ -769,20 +1304,31 @@ function createLocalEditorHarnessImplementation(options, construction) {
769
1304
  },
770
1305
  onRenderingPropertyChange: options.documentAdapter.onRenderingPropertyChange
771
1306
  ? (input) => {
772
- void applyRenderingPropertyChange(state, options, input)
1307
+ void state.runBrowserAuthoringMutation('rendering.property.set', JSON.stringify(input), authoringState => applyRenderingPropertyChange(authoringState, options, input))
773
1308
  .then((changed) => {
774
- if (changed)
1309
+ if (changed && !applyRenderingPresentation())
775
1310
  harness.render();
776
- });
1311
+ })
1312
+ .catch(error => reportBrowserAuthoringFailure(state, harness.render, error));
777
1313
  }
778
1314
  : undefined,
779
1315
  onRenderingAction: options.documentAdapter.onRenderingAction
780
1316
  ? (input) => {
781
- return applyRenderingAction(state, options, input, harness.render)
782
- .then((changed) => {
783
- if (changed)
1317
+ return state.runBrowserAuthoringMutation(`rendering.${input.actionId ?? 'action'}`, JSON.stringify(input), authoringState => applyRenderingAction(authoringState, options, input, harness.render))
1318
+ .then((result) => {
1319
+ if (result.rendered && !applyRenderingPresentation())
784
1320
  harness.render();
785
- return changed;
1321
+ return result;
1322
+ })
1323
+ .catch(error => {
1324
+ reportBrowserAuthoringFailure(state, harness.render, error);
1325
+ return {
1326
+ ok: false,
1327
+ changed: false,
1328
+ rendered: false,
1329
+ status: error instanceof Error ? error.message : String(error),
1330
+ statusTone: 'error',
1331
+ };
786
1332
  });
787
1333
  }
788
1334
  : undefined,
@@ -870,8 +1416,10 @@ function createLocalEditorHarnessImplementation(options, construction) {
870
1416
  });
871
1417
  },
872
1418
  onTransformAction: (action) => {
873
- if (executeTransformAction(state, options, action))
874
- harness.render();
1419
+ void state.runBrowserAuthoringMutation(`transform.${action}`, JSON.stringify({ action }), authoringState => executeTransformAction(authoringState, options, action)).then(changed => {
1420
+ if (changed)
1421
+ harness.render();
1422
+ }).catch(error => reportBrowserAuthoringFailure(state, harness.render, error));
875
1423
  },
876
1424
  onViewportViewPresetChange: (preset) => {
877
1425
  if (setViewportViewPreset(state, options, preset))
@@ -935,28 +1483,38 @@ function createLocalEditorHarnessImplementation(options, construction) {
935
1483
  }
936
1484
  publishLocalEditorSelectionPresentation(state, options, previewState => ui.updatePreview?.(previewState), 'hierarchy-selection-presentation');
937
1485
  };
938
- const discardPrefabStageChanges = () => {
1486
+ const discardPrefabStageChanges = async (serializedAccess) => {
939
1487
  const stage = state.prefabStage;
940
1488
  if (!stage || !stage.transaction.snapshot().stageDirty)
941
1489
  return false;
942
1490
  cancelActiveOperation(state);
943
- stage.transaction.discard();
1491
+ stage.transaction.assertParentUnchanged();
944
1492
  const draftState = stage.transaction.draftSession.getState({ cloneDocuments: false });
945
- rebuildProjectionFromDocument(state, options, draftState.workingDocument, EMPTY_EDITOR_SELECTION);
1493
+ if (state.authoringHost) {
1494
+ await state.authoringHost.reset(draftState.persistedDocument, draftState.source, {
1495
+ expectedDocumentRevision: draftState.documentRevision,
1496
+ ...(serializedAccess ? { serializedAccess } : {}),
1497
+ });
1498
+ }
1499
+ else {
1500
+ await state.runBrowserAuthoringMutation('prefab.stage.discard', JSON.stringify({ documentRevision: draftState.documentRevision }), authoringState => authoringState.session?.reset(draftState.persistedDocument, draftState.source));
1501
+ }
1502
+ const resetState = stage.transaction.draftSession.getState({ cloneDocuments: false });
1503
+ rebuildProjectionFromDocument(state, options, resetState.workingDocument, EMPTY_EDITOR_SELECTION);
946
1504
  state.status = `Discarded changes to Prefab ${stage.descriptor.label}`;
947
1505
  state.statusTone = 'default';
948
1506
  state.statusToneStatus = state.status;
949
1507
  state.statusDetails = '';
950
1508
  return true;
951
1509
  };
952
- runPrefabContextAction = async (actionId, executor) => {
1510
+ runPrefabContextAction = async (actionId, executor, serializedAccess) => {
953
1511
  const stage = state.prefabStage;
954
1512
  if (!stage)
955
1513
  return false;
956
1514
  if (actionId === PREFAB_STAGE_CONTEXT_ACTION_IDS.save) {
957
1515
  if (!stage.transaction.snapshot().documentDirty)
958
1516
  return false;
959
- return harness.saveScene(executor);
1517
+ return harness.saveScene(executor, undefined, serializedAccess);
960
1518
  }
961
1519
  if (actionId === PREFAB_STAGE_CONTEXT_ACTION_IDS.discard) {
962
1520
  if (!stage.transaction.snapshot().stageDirty)
@@ -968,7 +1526,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
968
1526
  confirmLabel: '废弃更改',
969
1527
  cancelLabel: '继续编辑',
970
1528
  });
971
- return confirmed ? discardPrefabStageChanges() : false;
1529
+ return confirmed ? discardPrefabStageChanges(serializedAccess) : false;
972
1530
  }
973
1531
  if (actionId !== PREFAB_STAGE_CONTEXT_ACTION_IDS.exit)
974
1532
  return false;
@@ -984,17 +1542,155 @@ function createLocalEditorHarnessImplementation(options, construction) {
984
1542
  cancelLabel: '取消',
985
1543
  });
986
1544
  if (choice === 'save') {
987
- if (!await harness.saveScene(executor))
1545
+ if (!await harness.saveScene(executor, undefined, serializedAccess))
988
1546
  return false;
989
1547
  }
990
1548
  else if (choice === 'discard') {
991
- discardPrefabStageChanges();
1549
+ await discardPrefabStageChanges(serializedAccess);
992
1550
  }
993
1551
  else {
994
1552
  return false;
995
1553
  }
996
1554
  }
997
- return exitPrefabStage(state, options, 'reject');
1555
+ return exitPrefabStage(state, options, 'reject', serializedAccess);
1556
+ };
1557
+ applySceneRenamePresentation = ({ id, name }) => {
1558
+ const sessionState = state.session?.getState({ cloneDocuments: false });
1559
+ const document = sessionState?.workingDocument ?? null;
1560
+ const authoritativeName = document
1561
+ ? resolveAuthoritativeHierarchyLabels(state, options, document, [id])[id] ?? name
1562
+ : name;
1563
+ let applied = false;
1564
+ try {
1565
+ applied = ui.updatePresentationDelta?.({
1566
+ hierarchyLabelIds: [id],
1567
+ hierarchyLabels: { [id]: authoritativeName },
1568
+ materialUsageOwnerNames: { [id]: authoritativeName },
1569
+ inspector: ['summary'],
1570
+ session: createUiSessionState(state),
1571
+ status: state.status,
1572
+ statusTone: state.statusTone,
1573
+ statusDetails: state.statusDetails,
1574
+ }) === true;
1575
+ }
1576
+ catch {
1577
+ applied = false;
1578
+ }
1579
+ if (!applied)
1580
+ state.hierarchyPresentationFallbackRevision += 1;
1581
+ return applied;
1582
+ };
1583
+ applyHistoryPresentation = impact => {
1584
+ if (!impact || impact.hierarchy === 'full')
1585
+ return false;
1586
+ const inspectorNeedsAssembly = impact.inspector === 'full'
1587
+ || (Array.isArray(impact.inspector) && impact.inspector.includes('material'));
1588
+ if (inspectorNeedsAssembly)
1589
+ cancelInspectorPresentationPreview(state);
1590
+ const sessionState = state.session?.getState({ cloneDocuments: false });
1591
+ const document = sessionState?.workingDocument ?? null;
1592
+ const labelIds = impact.hierarchy?.labelIds ?? [];
1593
+ const labels = document
1594
+ ? resolveAuthoritativeHierarchyLabels(state, options, document, labelIds)
1595
+ : {};
1596
+ const inspectorState = inspectorNeedsAssembly && document
1597
+ ? createUiSelectionInspectorPreviewState(state, options)
1598
+ : null;
1599
+ const inspectorValuePatches = Array.isArray(impact.inspector)
1600
+ && impact.inspector.includes('transform')
1601
+ && document
1602
+ ? createHistoryTransformInspectorPresentationPatches(state, document, sessionState?.selection)
1603
+ : [];
1604
+ const renderingPanel = impact.rendering && document
1605
+ ? options.documentAdapter.getRenderingPanelState?.(document, {
1606
+ scene: state.world?.scene ?? null,
1607
+ projection: state.projection,
1608
+ renderingAction: state.renderingAction,
1609
+ }) ?? null
1610
+ : undefined;
1611
+ let applied = false;
1612
+ try {
1613
+ applied = ui.updatePresentationDelta?.({
1614
+ hierarchyLabelIds: labelIds,
1615
+ hierarchyLabels: labels,
1616
+ materialUsageOwnerNames: labels,
1617
+ inspector: impact.inspector,
1618
+ ...(inspectorValuePatches.length > 0 ? { inspectorValuePatches } : {}),
1619
+ ...(inspectorState ? {
1620
+ inspectorObject: inspectorState.inspectorObject,
1621
+ inspectorMultiObject: inspectorState.inspectorMultiObject,
1622
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
1623
+ } : {}),
1624
+ rendering: impact.rendering,
1625
+ ...(renderingPanel !== undefined ? { renderingPanel } : {}),
1626
+ session: createUiSessionState(state),
1627
+ status: state.status, statusTone: state.statusTone, statusDetails: state.statusDetails,
1628
+ }) === true;
1629
+ }
1630
+ catch {
1631
+ applied = false;
1632
+ }
1633
+ if (!applied && labelIds.length > 0)
1634
+ state.hierarchyPresentationFallbackRevision += 1;
1635
+ return applied;
1636
+ };
1637
+ applyInspectorPresentation = input => {
1638
+ if (isSerializedNamePath(input.path) && typeof input.value === 'string') {
1639
+ return applySceneRenamePresentation({ id: input.targetId, name: input.value });
1640
+ }
1641
+ const impact = resolveSerializedPresentationImpact(input.path);
1642
+ if (!impact)
1643
+ return false;
1644
+ if (impact.inspector?.includes('material'))
1645
+ cancelInspectorPresentationPreview(state);
1646
+ const sessionState = state.session?.getState({ cloneDocuments: false });
1647
+ const inspectorState = impact.inspector?.includes('material')
1648
+ ? createUiSelectionInspectorPreviewState(state, options)
1649
+ : null;
1650
+ try {
1651
+ return ui.updatePresentationDelta?.({
1652
+ inspector: impact.inspector,
1653
+ ...(impact.inspector?.includes('transform') ? {
1654
+ inspectorValuePatches: [{
1655
+ targetId: input.targetId,
1656
+ propertyPath: input.path,
1657
+ value: input.value,
1658
+ generation: state.inspectorPresentationGeneration,
1659
+ }],
1660
+ } : {}),
1661
+ ...(inspectorState ? {
1662
+ inspectorObject: inspectorState.inspectorObject,
1663
+ inspectorMultiObject: inspectorState.inspectorMultiObject,
1664
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
1665
+ } : {}),
1666
+ session: createUiSessionState(state),
1667
+ status: state.status, statusTone: state.statusTone, statusDetails: state.statusDetails,
1668
+ }) === true;
1669
+ }
1670
+ catch {
1671
+ return false;
1672
+ }
1673
+ };
1674
+ applyRenderingPresentation = () => {
1675
+ const sessionState = state.session?.getState({ cloneDocuments: false });
1676
+ const document = sessionState?.workingDocument ?? null;
1677
+ if (!document)
1678
+ return false;
1679
+ try {
1680
+ return ui.updatePresentationDelta?.({
1681
+ rendering: true,
1682
+ renderingPanel: options.documentAdapter.getRenderingPanelState?.(document, {
1683
+ scene: state.world?.scene ?? null,
1684
+ projection: state.projection,
1685
+ renderingAction: state.renderingAction,
1686
+ }) ?? null,
1687
+ session: createUiSessionState(state),
1688
+ status: state.status, statusTone: state.statusTone, statusDetails: state.statusDetails,
1689
+ }) === true;
1690
+ }
1691
+ catch {
1692
+ return false;
1693
+ }
998
1694
  };
999
1695
  const unsubscribeToolManager = toolManager.subscribe(snapshot => {
1000
1696
  if (state.toolManagerRenderSuppression !== 0)
@@ -1019,11 +1715,12 @@ function createLocalEditorHarnessImplementation(options, construction) {
1019
1715
  });
1020
1716
  construction.setCleanup(() => {
1021
1717
  harnessDisposed = true;
1718
+ stopProjectServiceWatch?.();
1719
+ stopProjectServiceWatch = null;
1720
+ void disposeBrowserCommandAttachment?.then(dispose => dispose?.());
1721
+ disposeBrowserCommandAttachment = null;
1022
1722
  pendingScheduledLifecycleExit?.cancel();
1023
1723
  pendingScheduledLifecycleExit = null;
1024
- unregisterAgentBridgeLifecycleParticipant?.();
1025
- unregisterAgentBridgeLifecycleParticipant = null;
1026
- agentBridgeLifecycleTransports.clear();
1027
1724
  releaseApplicationAuthorityScopeResource?.();
1028
1725
  releaseApplicationAuthorityScopeResource = null;
1029
1726
  releaseMainSessionScopeResource?.();
@@ -1038,6 +1735,9 @@ function createLocalEditorHarnessImplementation(options, construction) {
1038
1735
  unbindPluginTools?.();
1039
1736
  for (const unregister of [...unregisterStandardTools].reverse())
1040
1737
  unregister();
1738
+ state.authoringHost?.dispose();
1739
+ state.authoringHost = null;
1740
+ state.replaceProjectionSessionAuthority(null);
1041
1741
  disposeLocalEditorHarnessResources(state, ui, hierarchyKernel);
1042
1742
  });
1043
1743
  const startGameRuntime = async (reason) => {
@@ -1053,6 +1753,10 @@ function createLocalEditorHarnessImplementation(options, construction) {
1053
1753
  return;
1054
1754
  // The lifecycle-owned Session Scope clears these before runGame. Keep the
1055
1755
  // assignment idempotent for direct harness consumers without a coordinator.
1756
+ state.authoringHost?.dispose();
1757
+ await state.authoringHost?.drain();
1758
+ state.authoringHost = null;
1759
+ state.replaceProjectionSessionAuthority(null);
1056
1760
  state.session = null;
1057
1761
  state.source = null;
1058
1762
  state.status = reason === 'save' ? 'Saved scene; starting game' : 'Discarded editor changes; starting game';
@@ -1100,6 +1804,25 @@ function createLocalEditorHarnessImplementation(options, construction) {
1100
1804
  }, executor);
1101
1805
  return runResult.accepted ? runResult.value : false;
1102
1806
  };
1807
+ const replaceAuthoringHost = async (session) => {
1808
+ state.unregisterCommandCapabilities?.();
1809
+ state.unregisterCommandCapabilities = null;
1810
+ const previousHost = state.authoringHost;
1811
+ previousHost?.dispose();
1812
+ await previousHost?.drain();
1813
+ if (projectCommandService) {
1814
+ state.authoringHost = null;
1815
+ state.replaceProjectionSessionAuthority(session);
1816
+ return;
1817
+ }
1818
+ state.replaceProjectionSessionAuthority(null);
1819
+ state.authoringHost = createEditorAuthoringHost({
1820
+ serviceInstanceId: createLocalEditorAuthoringServiceInstanceId(),
1821
+ session,
1822
+ commandSystem: commandServiceCommandSystem,
1823
+ disposeCommandSystem: false,
1824
+ });
1825
+ };
1103
1826
  const loadOptionalProjectFiles = async () => {
1104
1827
  if (!options.persistenceAdapter.loadProjectFiles) {
1105
1828
  return { projectFiles: state.projectFiles, warning: null };
@@ -1153,7 +1876,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
1153
1876
  cloneDocument: options.documentAdapter.cloneDocument,
1154
1877
  compareDocuments: options.documentAdapter.compareDocuments,
1155
1878
  reduceDocument: options.documentAdapter.reduceDocument,
1156
- isDocumentStructureChange: options.documentAdapter.isHierarchyStructureChange,
1879
+ isDocumentStructureChange: command => resolveLocalEditorDocumentStructureChange(options.documentAdapter.isHierarchyStructureChange, command),
1157
1880
  onChange: createSessionChangeObserver(() => mainSession, {
1158
1881
  document: PLAYABLE_LOCAL_EDITOR_MAIN_DOCUMENT_SCOPE_ID,
1159
1882
  session: PLAYABLE_LOCAL_EDITOR_MAIN_SESSION_SCOPE_ID,
@@ -1162,14 +1885,22 @@ function createLocalEditorHarnessImplementation(options, construction) {
1162
1885
  });
1163
1886
  state.session = mainSession;
1164
1887
  try {
1888
+ await replaceAuthoringHost(mainSession);
1165
1889
  attachLifecycleOwnedSessionAuthority();
1890
+ activateCommandAuthority();
1166
1891
  }
1167
1892
  catch (error) {
1893
+ state.authoringHost?.dispose();
1894
+ state.authoringHost = null;
1895
+ state.replaceProjectionSessionAuthority(null);
1168
1896
  state.session = null;
1169
1897
  state.source = null;
1170
1898
  throw error;
1171
1899
  }
1172
1900
  state.summary = loadedSource?.summary ?? summarizeDocument(options, preparedDocument, source);
1901
+ if (pendingProjectServiceSnapshot) {
1902
+ await applyProjectServiceSnapshot(pendingProjectServiceSnapshot);
1903
+ }
1173
1904
  };
1174
1905
  const enterEditorWorld = async () => {
1175
1906
  if (!state.session)
@@ -1220,13 +1951,33 @@ function createLocalEditorHarnessImplementation(options, construction) {
1220
1951
  if (prefabTransaction) {
1221
1952
  prefabTransaction.assertParentUnchanged();
1222
1953
  const parentState = prefabTransaction.parentSession.getState({ cloneDocuments: false });
1223
- prefabTransaction.parentSession.reset(parentState.persistedDocument, parentState.source);
1224
- prefabTransaction.draftSession.reset(parentState.persistedDocument, parentState.source);
1954
+ if (state.authoringHost) {
1955
+ await state.authoringHost.resetWithRelatedSession(parentState.persistedDocument, parentState.source, {
1956
+ expectedDocumentRevision: sessionState.documentRevision,
1957
+ relatedSession: prefabTransaction.parentSession,
1958
+ expectedRelatedDocumentRevision: parentState.documentRevision,
1959
+ mutateRelatedSession(parentDraftSession) {
1960
+ parentDraftSession.reset(parentState.persistedDocument, parentState.source);
1961
+ },
1962
+ });
1963
+ }
1964
+ else {
1965
+ await state.runBrowserAuthoringMutation('document.discard', JSON.stringify({ documentRevision: sessionState.documentRevision }), authoringState => authoringState.session?.reset(parentState.persistedDocument, parentState.source));
1966
+ prefabTransaction.parentSession.reset(parentState.persistedDocument, parentState.source);
1967
+ }
1968
+ prefabTransaction.acceptParentRevision();
1225
1969
  state.source = parentState.source ?? null;
1226
1970
  state.summary = summarizeDocument(options, parentState.persistedDocument, state.source);
1227
1971
  }
1228
1972
  else {
1229
- state.session.reset(sessionState.persistedDocument, sessionState.source);
1973
+ if (state.authoringHost) {
1974
+ await state.authoringHost.reset(sessionState.persistedDocument, sessionState.source, {
1975
+ expectedDocumentRevision: sessionState.documentRevision,
1976
+ });
1977
+ }
1978
+ else {
1979
+ await state.runBrowserAuthoringMutation('document.discard', JSON.stringify({ documentRevision: sessionState.documentRevision }), authoringState => authoringState.session?.reset(sessionState.persistedDocument, sessionState.source));
1980
+ }
1230
1981
  state.source = sessionState.source ?? null;
1231
1982
  state.summary = summarizeDocument(options, sessionState.persistedDocument, state.source);
1232
1983
  }
@@ -1235,21 +1986,76 @@ function createLocalEditorHarnessImplementation(options, construction) {
1235
1986
  state.statusToneStatus = state.status;
1236
1987
  state.statusDetails = '';
1237
1988
  };
1238
- const markDocumentCommitted = async (expectedDocumentFingerprint) => {
1989
+ const markDocumentCommitted = async (expectedDocumentFingerprint, expectedDocumentRevision, preparedAuthoringSource) => {
1239
1990
  const sessionState = state.session?.getState({ cloneDocuments: false });
1240
1991
  if (!state.session || !sessionState)
1241
1992
  throw new Error('Cannot commit an unloaded editor document.');
1242
- if (createLocalEditorDocumentFingerprint(sessionState.workingDocument) !== expectedDocumentFingerprint) {
1993
+ const hasProjectServiceTransaction = Boolean(projectCommandService
1994
+ && typeof preparedAuthoringSource?.serviceTransactionId === 'string'
1995
+ && preparedAuthoringSource.serviceTransactionId.length > 0);
1996
+ if (!hasProjectServiceTransaction
1997
+ && createLocalEditorDocumentFingerprint(sessionState.workingDocument) !== expectedDocumentFingerprint) {
1243
1998
  throw new Error('Editor document changed after export; refusing to commit a stale snapshot.');
1244
1999
  }
2000
+ const committedDocument = (preparedAuthoringSource?.document
2001
+ ?? sessionState.workingDocument);
2002
+ const committedSource = preparedAuthoringSource?.source ?? sessionState.source;
1245
2003
  const prefabTransaction = state.prefabStage?.transaction ?? null;
2004
+ if (projectCommandService) {
2005
+ const transactionId = typeof preparedAuthoringSource?.serviceTransactionId === 'string'
2006
+ ? preparedAuthoringSource.serviceTransactionId
2007
+ : null;
2008
+ if (!transactionId) {
2009
+ throw new Error('Platform save confirmation is missing the Project Editor Service transaction.');
2010
+ }
2011
+ const serviceDocumentRevision = preparedAuthoringSource?.serviceDocumentRevision;
2012
+ if (!Number.isSafeInteger(serviceDocumentRevision) || (serviceDocumentRevision ?? -1) < 0) {
2013
+ throw new Error('Platform save confirmation is missing the Project Editor Service document revision.');
2014
+ }
2015
+ await invokeProjectServiceCommand('document.commit', { transactionId }, serviceDocumentRevision);
2016
+ const snapshot = await readProjectServiceSnapshot();
2017
+ if (!snapshot)
2018
+ throw new Error('Project Editor Service did not return the committed checkpoint.');
2019
+ await applyProjectServiceSnapshot(snapshot, true);
2020
+ state.source = sessionState.source ?? null;
2021
+ state.status = 'Platform save committed';
2022
+ state.statusTone = 'success';
2023
+ state.statusToneStatus = state.status;
2024
+ state.statusDetails = '';
2025
+ return;
2026
+ }
1246
2027
  if (prefabTransaction) {
1247
- prefabTransaction.commitSavedDocument(sessionState.workingDocument, sessionState.source, `Apply Prefab ${state.prefabStage?.descriptor.label ?? 'changes'}`);
2028
+ if (!state.authoringHost)
2029
+ throw new Error('Cannot commit Prefab without an Editor Authoring Host.');
2030
+ if (expectedDocumentRevision === null) {
2031
+ throw new Error('Platform save confirmation is missing the exported document revision.');
2032
+ }
2033
+ await state.authoringHost.markSavedWithRelatedSession(committedDocument, {
2034
+ expectedDocumentRevision,
2035
+ source: committedSource,
2036
+ resetHistory: true,
2037
+ relatedSession: prefabTransaction.parentSession,
2038
+ expectedRelatedDocumentRevision: prefabTransaction.parentSession
2039
+ .getState({ cloneDocuments: false }).documentRevision,
2040
+ mutateRelatedSession(parentDraftSession) {
2041
+ prefabTransaction.stageParentSavedDocument(parentDraftSession, committedDocument, committedSource, `Apply Prefab ${state.prefabStage?.descriptor.label ?? 'changes'}`);
2042
+ },
2043
+ });
2044
+ prefabTransaction.acceptParentRevision();
1248
2045
  }
1249
2046
  else {
1250
- state.session.markSaved(sessionState.workingDocument, sessionState.source);
2047
+ if (!state.authoringHost)
2048
+ throw new Error('Cannot commit without an Editor Authoring Host.');
2049
+ if (expectedDocumentRevision === null) {
2050
+ throw new Error('Platform save confirmation is missing the exported document revision.');
2051
+ }
2052
+ await state.authoringHost.markSaved(committedDocument, {
2053
+ expectedDocumentRevision,
2054
+ source: committedSource,
2055
+ });
1251
2056
  }
1252
- state.source = sessionState.source ?? null;
2057
+ state.source = committedSource ?? null;
2058
+ state.summary = summarizeDocument(options, committedDocument, committedSource);
1253
2059
  state.status = 'Platform save committed';
1254
2060
  state.statusTone = 'success';
1255
2061
  state.statusToneStatus = state.status;
@@ -1330,10 +2136,36 @@ function createLocalEditorHarnessImplementation(options, construction) {
1330
2136
  throw error;
1331
2137
  }
1332
2138
  };
2139
+ const renderSuppressedDocumentMarkDirtyPreview = () => {
2140
+ const lifecycleSnapshot = lifecycleController?.lifecycle.getSnapshot();
2141
+ const activeTransition = lifecycleSnapshot?.activeTransition;
2142
+ if (state.suppressDocumentMarkDirtyInspectorRefresh
2143
+ && activeTransition?.type === 'document.markDirty') {
2144
+ suppressedDocumentMarkDirtyTransitionId = activeTransition.id;
2145
+ if (!ui.updatePreview)
2146
+ return false;
2147
+ ui.updatePreview({ session: createUiSessionState(state) });
2148
+ return true;
2149
+ }
2150
+ if (suppressedDocumentMarkDirtyTransitionId && lifecycleSnapshot && !lifecycleSnapshot.transitioning) {
2151
+ suppressedDocumentMarkDirtyTransitionId = null;
2152
+ state.suppressDocumentMarkDirtyInspectorRefresh = false;
2153
+ if (!ui.updatePreview)
2154
+ return false;
2155
+ ui.updatePreview({ session: createUiSessionState(state) });
2156
+ return true;
2157
+ }
2158
+ return false;
2159
+ };
1333
2160
  harness = {
1334
2161
  render() {
1335
2162
  if (harnessDisposed)
1336
2163
  return;
2164
+ if (renderSuppressedDocumentMarkDirtyPreview())
2165
+ return;
2166
+ if (lifecyclePresentationOnlyRenderDepth > 0)
2167
+ return;
2168
+ cancelInspectorPresentationPreview(state);
1337
2169
  syncViewportCameraState(state);
1338
2170
  syncViewportMeasurementState(state);
1339
2171
  syncViewportSpatialOverlay(state, options);
@@ -1352,12 +2184,13 @@ function createLocalEditorHarnessImplementation(options, construction) {
1352
2184
  getHostServices() {
1353
2185
  return options.hostServices ?? null;
1354
2186
  },
1355
- getAgentBridge() {
1356
- return state.agentBridge;
2187
+ getCommandService() {
2188
+ return state.commandService;
1357
2189
  },
1358
2190
  getWorkingDocument() {
1359
2191
  return state.session?.getState().workingDocument ?? null;
1360
2192
  },
2193
+ prepareProjectServiceDocumentExport,
1361
2194
  projectAssetDropPoint(point) {
1362
2195
  return projectBabylonViewportPointToGround({
1363
2196
  babylon: state.babylon,
@@ -1429,7 +2262,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
1429
2262
  }
1430
2263
  return runExclusiveResult(state, harness.render, transactionExecutor => executeLocalEditorDocumentOperation(busyOperationExecutors, transactionExecutor, operation), busyOperationExecutors);
1431
2264
  },
1432
- async reloadAssets() {
2265
+ async reloadAssets(serializedAccess) {
1433
2266
  try {
1434
2267
  const previousAssets = state.assets;
1435
2268
  const [assets, projectFilesResult] = await Promise.all([
@@ -1440,7 +2273,8 @@ function createLocalEditorHarnessImplementation(options, construction) {
1440
2273
  ? findLocalEditorUpdatedAssetIds(options.documentAdapter.listAssetSnapshots(previousAssets), options.documentAdapter.listAssetSnapshots(assets))
1441
2274
  : [];
1442
2275
  if (state.session && options.documentAdapter.hydrateDocumentAssets) {
1443
- const result = applyLocalEditorUpdatedAssetsRefresh(state.session, {
2276
+ const expectedDocumentRevision = state.session.getState({ cloneDocuments: false }).documentRevision;
2277
+ const applyRefresh = (session = state.session) => applyLocalEditorUpdatedAssetsRefresh(session, {
1444
2278
  assetIds: refreshedAssetIds,
1445
2279
  assets,
1446
2280
  hydrateDocumentAssets: options.documentAdapter.hydrateDocumentAssets,
@@ -1451,6 +2285,9 @@ function createLocalEditorHarnessImplementation(options, construction) {
1451
2285
  ? { compareDocuments: options.documentAdapter.compareDocuments }
1452
2286
  : {}),
1453
2287
  });
2288
+ const result = serializedAccess
2289
+ ? state.authoringHost?.runSerializedExternalMutation(serializedAccess, expectedDocumentRevision, session => applyRefresh(session)) ?? (() => { throw new Error('Asset refresh authoring authority is unavailable.'); })()
2290
+ : await state.runBrowserAuthoringMutation('asset.library.refresh', JSON.stringify({ refreshedAssetIds }), authoringState => applyRefresh(authoringState.session));
1454
2291
  syncLocalEditorUpdatedAssetProjection(state.updatedAssetProjection, result.changed, () => {
1455
2292
  rebuildProjectionFromDocument(state, options, result.workingDocument, result.selection);
1456
2293
  });
@@ -1515,7 +2352,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
1515
2352
  loadOptionalProjectFiles(),
1516
2353
  ]);
1517
2354
  assertLocalEditorUpdatedAssetSnapshotFreshness(options.documentAdapter.resolveUpdatedAssetSnapshot(assets, { assetId: input.assetId }), input);
1518
- const result = applyLocalEditorUpdatedAssetRefresh(state.session, {
2355
+ const applyRefresh = (authoringState) => applyLocalEditorUpdatedAssetRefresh(authoringState.session, {
1519
2356
  assetId: input.assetId,
1520
2357
  assets,
1521
2358
  hydrateDocumentAssets: options.documentAdapter.hydrateDocumentAssets,
@@ -1526,6 +2363,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
1526
2363
  ? { compareDocuments: options.documentAdapter.compareDocuments }
1527
2364
  : {}),
1528
2365
  });
2366
+ const result = await state.runBrowserAuthoringMutation('asset.library.refreshUpdated', JSON.stringify(input), applyRefresh);
1529
2367
  state.assets = assets;
1530
2368
  state.projectFiles = projectFilesResult.projectFiles;
1531
2369
  state.projectFilesWarning = projectFilesResult.warning;
@@ -1579,19 +2417,33 @@ function createLocalEditorHarnessImplementation(options, construction) {
1579
2417
  }
1580
2418
  },
1581
2419
  createAssetFromAssetId(assetId, createOptions) {
1582
- const result = addAssetToDocument(state, options, assetId, createOptions);
2420
+ const execute = (session = state.session ?? undefined) => addAssetToDocument(state, options, assetId, createOptions, session);
2421
+ const immediate = state.tryRunBrowserAuthoringMutationImmediately('object.createFromAsset', JSON.stringify({ assetId, createOptions }), session => execute(session));
2422
+ const result = immediate.ok ? immediate.value : {
2423
+ ok: false,
2424
+ assetId,
2425
+ changed: false,
2426
+ status: `Asset creation unavailable: ${immediate.reason}`,
2427
+ error: 'authoring_busy',
2428
+ };
1583
2429
  harness.render();
1584
2430
  return result;
1585
2431
  },
1586
2432
  async undo(historyOptions) {
1587
- const result = applyHistoryOperation(state, options, 'undo', historyOptions);
1588
- if (result.ok)
2433
+ if (projectCommandService) {
2434
+ return runProjectServiceHistoryOperation('undo', historyOptions);
2435
+ }
2436
+ const result = await state.runBrowserAuthoringMutation('history.undo', JSON.stringify(historyOptions ?? {}), authoringState => applyHistoryOperation(authoringState, options, 'undo', historyOptions));
2437
+ if (result.ok && !applyHistoryPresentation(result.presentationImpact))
1589
2438
  harness.render();
1590
2439
  return waitForHistoryOperationProjection(state, result);
1591
2440
  },
1592
2441
  async redo(historyOptions) {
1593
- const result = applyHistoryOperation(state, options, 'redo', historyOptions);
1594
- if (result.ok)
2442
+ if (projectCommandService) {
2443
+ return runProjectServiceHistoryOperation('redo', historyOptions);
2444
+ }
2445
+ const result = await state.runBrowserAuthoringMutation('history.redo', JSON.stringify(historyOptions ?? {}), authoringState => applyHistoryOperation(authoringState, options, 'redo', historyOptions));
2446
+ if (result.ok && !applyHistoryPresentation(result.presentationImpact))
1595
2447
  harness.render();
1596
2448
  return waitForHistoryOperationProjection(state, result);
1597
2449
  },
@@ -1599,13 +2451,13 @@ function createLocalEditorHarnessImplementation(options, construction) {
1599
2451
  await loadEditorDocument();
1600
2452
  await enterEditorWorld();
1601
2453
  },
1602
- async saveScene(executor, saveOptions) {
2454
+ async saveScene(executor, saveOptions, serializedAccess) {
1603
2455
  cancelActiveOperation(state);
1604
2456
  const validationPhases = [...new Set([
1605
2457
  ...(saveOptions?.validationPhases ?? []),
1606
2458
  'save',
1607
2459
  ])];
1608
- const refreshResult = await runValidatedExclusiveDocumentOperation('save', () => harness.reloadAssets(), executor, validationPhases);
2460
+ const refreshResult = await runValidatedExclusiveDocumentOperation('save', () => harness.reloadAssets(serializedAccess), executor, validationPhases);
1609
2461
  if (!refreshResult.accepted)
1610
2462
  return false;
1611
2463
  const assetRefresh = refreshResult.value;
@@ -1620,6 +2472,19 @@ function createLocalEditorHarnessImplementation(options, construction) {
1620
2472
  const prefabTransaction = state.prefabStage?.transaction ?? null;
1621
2473
  try {
1622
2474
  prefabTransaction?.assertParentUnchanged();
2475
+ if (projectCommandService) {
2476
+ await invokeProjectServiceCommand('document.save');
2477
+ const snapshot = await readProjectServiceSnapshot();
2478
+ if (!snapshot)
2479
+ throw new Error('Project Editor Service did not return the saved checkpoint.');
2480
+ await applyProjectServiceSnapshot(snapshot, true);
2481
+ state.summary = summarizeDocument(options, snapshot.document, state.source);
2482
+ state.status = prefabTransaction ? 'Prefab saved' : 'Scene saved';
2483
+ state.statusTone = 'success';
2484
+ state.statusToneStatus = state.status;
2485
+ state.statusDetails = '';
2486
+ return true;
2487
+ }
1623
2488
  let savedSource = source;
1624
2489
  let result;
1625
2490
  if (source && options.authoringHost) {
@@ -1663,10 +2528,34 @@ function createLocalEditorHarnessImplementation(options, construction) {
1663
2528
  state.source = savedSource ?? null;
1664
2529
  if (state.session) {
1665
2530
  if (prefabTransaction && state.prefabStage?.transaction === prefabTransaction) {
1666
- prefabTransaction.commitSavedDocument(preparedDocument, savedSource ?? undefined, `Apply Prefab ${state.prefabStage.descriptor.label}`);
2531
+ if (!state.authoringHost)
2532
+ throw new Error('Cannot save Prefab without an Editor Authoring Host.');
2533
+ if (expectedAuthoredVersion === null)
2534
+ throw new Error('Cannot save without an expected document revision.');
2535
+ await state.authoringHost.markSavedWithRelatedSession(preparedDocument, {
2536
+ expectedDocumentRevision: expectedAuthoredVersion,
2537
+ source: savedSource ?? undefined,
2538
+ resetHistory: true,
2539
+ relatedSession: prefabTransaction.parentSession,
2540
+ expectedRelatedDocumentRevision: prefabTransaction.parentSession
2541
+ .getState({ cloneDocuments: false }).documentRevision,
2542
+ mutateRelatedSession(parentDraftSession) {
2543
+ prefabTransaction.stageParentSavedDocument(parentDraftSession, preparedDocument, savedSource ?? undefined, `Apply Prefab ${state.prefabStage?.descriptor.label ?? 'changes'}`);
2544
+ },
2545
+ ...(serializedAccess ? { serializedAccess } : {}),
2546
+ });
2547
+ prefabTransaction.acceptParentRevision();
1667
2548
  }
1668
2549
  else {
1669
- state.session.markSaved(preparedDocument, savedSource ?? undefined);
2550
+ if (!state.authoringHost)
2551
+ throw new Error('Cannot save without an Editor Authoring Host.');
2552
+ if (expectedAuthoredVersion === null)
2553
+ throw new Error('Cannot save without an expected document revision.');
2554
+ await state.authoringHost.markSaved(preparedDocument, {
2555
+ expectedDocumentRevision: expectedAuthoredVersion,
2556
+ source: savedSource ?? undefined,
2557
+ ...(serializedAccess ? { serializedAccess } : {}),
2558
+ });
1670
2559
  }
1671
2560
  }
1672
2561
  else {
@@ -1678,7 +2567,7 @@ function createLocalEditorHarnessImplementation(options, construction) {
1678
2567
  cloneDocument: options.documentAdapter.cloneDocument,
1679
2568
  compareDocuments: options.documentAdapter.compareDocuments,
1680
2569
  reduceDocument: options.documentAdapter.reduceDocument,
1681
- isDocumentStructureChange: options.documentAdapter.isHierarchyStructureChange,
2570
+ isDocumentStructureChange: command => resolveLocalEditorDocumentStructureChange(options.documentAdapter.isHierarchyStructureChange, command),
1682
2571
  onChange: createSessionChangeObserver(() => mainSession, {
1683
2572
  document: PLAYABLE_LOCAL_EDITOR_MAIN_DOCUMENT_SCOPE_ID,
1684
2573
  session: PLAYABLE_LOCAL_EDITOR_MAIN_SESSION_SCOPE_ID,
@@ -1687,9 +2576,14 @@ function createLocalEditorHarnessImplementation(options, construction) {
1687
2576
  });
1688
2577
  state.session = mainSession;
1689
2578
  try {
2579
+ await replaceAuthoringHost(mainSession);
1690
2580
  attachLifecycleOwnedSessionAuthority();
2581
+ activateCommandAuthority();
1691
2582
  }
1692
2583
  catch (error) {
2584
+ state.authoringHost?.dispose();
2585
+ state.authoringHost = null;
2586
+ state.replaceProjectionSessionAuthority(null);
1693
2587
  state.session = null;
1694
2588
  state.source = null;
1695
2589
  throw error;
@@ -1736,20 +2630,22 @@ function createLocalEditorHarnessImplementation(options, construction) {
1736
2630
  };
1737
2631
  agentLifecycleController = {
1738
2632
  enterEditor: () => harness.enterEditor(),
1739
- saveScene: (_operation, _context, executor) => harness.saveScene(executor),
2633
+ saveScene: (_operation, context, executor) => harness.saveScene(executor, undefined, context
2634
+ ?.serializedAuthoringAccess),
1740
2635
  saveAndRunGame: (_context, executor) => harness.saveAndRunGame(executor),
1741
2636
  async discardAndRunGame(_context, executor) {
1742
2637
  await harness.discardAndRunGame(executor);
1743
2638
  return true;
1744
2639
  },
1745
- async prepareSaveAndRunGame(_context, executor) {
2640
+ async prepareSaveAndRunGame(context, executor) {
1746
2641
  return harness.runExclusiveDocumentOperation(async (transactionExecutor) => {
1747
2642
  const initialValidation = await runValidatedExclusiveDocumentOperation('run', async () => true, transactionExecutor);
1748
2643
  if (!initialValidation.accepted)
1749
2644
  return { accepted: false };
1750
2645
  const saved = await harness.saveScene(transactionExecutor, {
1751
2646
  validationPhases: ['run', 'save'],
1752
- });
2647
+ }, context
2648
+ ?.serializedAuthoringAccess);
1753
2649
  if (!saved)
1754
2650
  return { accepted: false };
1755
2651
  const finalValidation = await runValidatedExclusiveDocumentOperation('run', async (documentRevision) => documentRevision, transactionExecutor);
@@ -1797,21 +2693,26 @@ function createLocalEditorHarnessImplementation(options, construction) {
1797
2693
  }, executor);
1798
2694
  },
1799
2695
  };
1800
- const agentBridgeCapabilitySourceOperations = {
1801
- createAssetFromAssetId: (assetId, createOptions) => harness.createAssetFromAssetId(assetId, createOptions),
1802
- getPrefabStage: () => summarizeAgentBridgePrefabStage(state, options),
1803
- getPrefabStageDetails: () => summarizeAgentBridgePrefabStageDetails(state, options),
1804
- openPrefabStage: input => runExclusiveResult(state, harness.render, async (executor) => {
1805
- const previousStage = summarizeAgentBridgePrefabStage(state, options);
2696
+ const commandServiceCapabilitySourceOperations = {
2697
+ createAssetFromAssetId: (assetId, createOptions) => {
2698
+ const result = addAssetToDocument(state, options, assetId, createOptions);
2699
+ harness.render();
2700
+ return result;
2701
+ },
2702
+ getPrefabStage: () => summarizeEditorCommandPrefabStage(state, options),
2703
+ getPrefabStageDetails: () => summarizeEditorCommandPrefabStageDetails(state, options),
2704
+ openPrefabStage: (input, access) => runExclusiveResult(state, harness.render, async (executor) => {
2705
+ const serializedAccess = access;
2706
+ const previousStage = summarizeEditorCommandPrefabStage(state, options);
1806
2707
  if (previousStage
1807
2708
  && previousStage.assetId !== input.assetId
1808
2709
  && state.prefabStage?.transaction.snapshot().stageDirty) {
1809
2710
  if (input.dirtyAction === 'save') {
1810
- if (!await harness.saveScene(executor))
2711
+ if (!await harness.saveScene(executor, undefined, serializedAccess))
1811
2712
  return null;
1812
2713
  }
1813
2714
  else if (input.dirtyAction === 'discard') {
1814
- discardPrefabStageChanges();
2715
+ await discardPrefabStageChanges(serializedAccess);
1815
2716
  }
1816
2717
  else {
1817
2718
  state.status = 'Prefab has unsaved changes';
@@ -1826,32 +2727,33 @@ function createLocalEditorHarnessImplementation(options, construction) {
1826
2727
  assetId: input.assetId,
1827
2728
  browserAssetId: input.browserAssetId,
1828
2729
  assetKind: 'prefab',
1829
- });
1830
- const stage = summarizeAgentBridgePrefabStage(state, options);
2730
+ }, serializedAccess);
2731
+ const stage = summarizeEditorCommandPrefabStage(state, options);
1831
2732
  if (!opened || !stage)
1832
2733
  return null;
1833
- const alreadyOpen = isSameAgentBridgePrefabStage(previousStage, stage);
2734
+ const alreadyOpen = isSameEditorCommandPrefabStage(previousStage, stage);
1834
2735
  return {
1835
2736
  opened: !alreadyOpen,
1836
2737
  alreadyOpen,
1837
- prefab: createAgentBridgePrefabSummaryFromStage(stage),
2738
+ prefab: createEditorCommandPrefabSummaryFromStage(stage),
1838
2739
  stage,
1839
2740
  status: state.status,
1840
2741
  };
1841
2742
  }, busyOperationExecutors),
1842
- exitPrefabStage: (input = {}) => runExclusiveResult(state, harness.render, async (executor) => {
1843
- const previousStage = summarizeAgentBridgePrefabStage(state, options);
2743
+ exitPrefabStage: (input = {}, access) => runExclusiveResult(state, harness.render, async (executor) => {
2744
+ const serializedAccess = access;
2745
+ const previousStage = summarizeEditorCommandPrefabStage(state, options);
1844
2746
  if (state.prefabStage?.transaction.snapshot().stageDirty) {
1845
2747
  if (input.dirtyAction === 'save') {
1846
- if (!await harness.saveScene(executor)) {
2748
+ if (!await harness.saveScene(executor, undefined, serializedAccess)) {
1847
2749
  return { exited: false, wasOpen: true, previousStage, status: state.status };
1848
2750
  }
1849
2751
  }
1850
2752
  else if (input.dirtyAction === 'discard') {
1851
- discardPrefabStageChanges();
2753
+ await discardPrefabStageChanges(serializedAccess);
1852
2754
  }
1853
2755
  }
1854
- const exited = await exitPrefabStage(state, options, 'reject');
2756
+ const exited = await exitPrefabStage(state, options, 'reject', serializedAccess);
1855
2757
  return {
1856
2758
  exited,
1857
2759
  wasOpen: !!previousStage,
@@ -1859,8 +2761,8 @@ function createLocalEditorHarnessImplementation(options, construction) {
1859
2761
  status: exited ? state.status : previousStage ? state.status : 'No Prefab stage is open.',
1860
2762
  };
1861
2763
  }, busyOperationExecutors),
1862
- savePrefabStage: () => runExclusiveResult(state, harness.render, executor => (runPrefabContextAction(PREFAB_STAGE_CONTEXT_ACTION_IDS.save, executor)), busyOperationExecutors),
1863
- discardPrefabStage: () => discardPrefabStageChanges(),
2764
+ savePrefabStage: access => runExclusiveResult(state, harness.render, executor => (runPrefabContextAction(PREFAB_STAGE_CONTEXT_ACTION_IDS.save, executor, access)), busyOperationExecutors),
2765
+ discardPrefabStage: access => discardPrefabStageChanges(access),
1864
2766
  selectPrefabStageItem: itemId => selectPrefabStageItemWithPreviewSync(state, options, itemId),
1865
2767
  runPrefabStageAssetAction: input => patchBrowserAssetAction(state, options, input),
1866
2768
  getHierarchyReadModel,
@@ -1933,10 +2835,10 @@ function createLocalEditorHarnessImplementation(options, construction) {
1933
2835
  })),
1934
2836
  };
1935
2837
  },
1936
- executeHierarchyOperation: async (input) => {
2838
+ executeHierarchyOperation: async (input, serializedAccess) => {
1937
2839
  const model = getRequiredHierarchyViewModel();
1938
2840
  const { snapshot } = model;
1939
- const result = await hierarchyKernel.dispatch({
2841
+ const invocation = {
1940
2842
  type: 'operation.execute',
1941
2843
  operationId: input.operationId,
1942
2844
  expectedAuthorityToken: model.authorityToken,
@@ -1948,9 +2850,13 @@ function createLocalEditorHarnessImplementation(options, construction) {
1948
2850
  contextNodeId: 'contextNodeId' in input ? input.contextNodeId ?? null : snapshot.activeId,
1949
2851
  targetIds: input.targetIds ?? [...snapshot.selectedIds],
1950
2852
  activeId: 'activeId' in input ? input.activeId ?? null : snapshot.activeId,
2853
+ ...(serializedAccess !== undefined
2854
+ ? { [SERIALIZED_HIERARCHY_INVOCATION]: serializedAccess }
2855
+ : {}),
1951
2856
  },
1952
2857
  ...(input.input ? { input: input.input } : {}),
1953
- });
2858
+ };
2859
+ const result = await hierarchyKernel.dispatch(invocation);
1954
2860
  return {
1955
2861
  ok: result.ok,
1956
2862
  changed: result.changed,
@@ -2012,10 +2918,10 @@ function createLocalEditorHarnessImplementation(options, construction) {
2012
2918
  },
2013
2919
  runRenderingAction: actionId => applyRenderingAction(state, options, { actionId }, () => harness.render()),
2014
2920
  };
2015
- const registerAgentBridgeCapabilities = () => {
2016
- if (state.unregisterAgentBridgeCapabilities)
2921
+ const registerCommandCapabilities = () => {
2922
+ if (state.unregisterCommandCapabilities)
2017
2923
  return;
2018
- const unregisterStandardAgentCapabilities = registerLocalEditorAgentBridgeCapabilities(state.agentBridge, createLocalEditorAgentBridgeCapabilitySources(state, options, () => harness.render(), context => runExclusive(state, harness.render, () => agentLifecycleController.enterEditor(context), busyOperationExecutors), async (context) => {
2924
+ const unregisterStandardAgentCapabilities = registerLocalEditorCommandCapabilities(state.commandService, createLocalEditorCommandCapabilitySources(state, options, () => harness.render(), context => runExclusive(state, harness.render, () => agentLifecycleController.enterEditor(context), busyOperationExecutors), async (context) => {
2019
2925
  const prepared = await runExclusiveResult(state, harness.render, executor => agentLifecycleController.prepareSaveAndRunGame(context, executor), busyOperationExecutors);
2020
2926
  if (prepared.accepted)
2021
2927
  scheduleEditorLifecycleExit(executor => prepared.run(executor));
@@ -2025,10 +2931,12 @@ function createLocalEditorHarnessImplementation(options, construction) {
2025
2931
  if (prepared.accepted)
2026
2932
  scheduleEditorLifecycleExit(executor => prepared.run(executor));
2027
2933
  return prepared.accepted;
2028
- }, agentBridgeCapabilitySourceOperations));
2934
+ }, commandServiceCapabilitySourceOperations), state.authoringHost ?? undefined);
2029
2935
  try {
2030
- const unregisterPluginAgentCapabilities = registerEditorPluginAgentCapabilities(state.agentBridge, options.pluginHost);
2031
- state.unregisterAgentBridgeCapabilities = () => {
2936
+ const unregisterPluginAgentCapabilities = state.authoringHost
2937
+ ? registerEditorPluginCommands(state.commandService, options.pluginHost, state.authoringHost)
2938
+ : () => undefined;
2939
+ state.unregisterCommandCapabilities = () => {
2032
2940
  const errors = [];
2033
2941
  try {
2034
2942
  unregisterPluginAgentCapabilities();
@@ -2043,44 +2951,50 @@ function createLocalEditorHarnessImplementation(options, construction) {
2043
2951
  errors.push(error);
2044
2952
  }
2045
2953
  if (errors.length > 0) {
2046
- const error = new Error('Local Editor Agent capability cleanup failed.');
2954
+ const error = new Error('Local Editor command cleanup failed.');
2047
2955
  error.errors = errors;
2048
2956
  throw error;
2049
2957
  }
2050
2958
  };
2959
+ if (projectCommandService && !disposeBrowserCommandAttachment) {
2960
+ const handlers = Object.fromEntries(state.commandService.commandSystem.listManifests()
2961
+ .map(manifest => [manifest.id, async (input, request) => {
2962
+ if (harnessDisposed)
2963
+ throw new Error('Local editor harness has been disposed.');
2964
+ const result = await state.commandService.callCapability(manifest.id, input, {
2965
+ ...(request.invocation.traceId ? { traceId: request.invocation.traceId } : {}),
2966
+ ...(request.invocation.traceStepId ? { traceStepId: request.invocation.traceStepId } : {}),
2967
+ });
2968
+ if (!result.ok)
2969
+ throw new Error(result.diagnostics.map(diagnostic => diagnostic.message).join('; '));
2970
+ return result.output;
2971
+ }]));
2972
+ disposeBrowserCommandAttachment = projectCommandService.attach({
2973
+ attachmentId: browserCommandAttachmentId,
2974
+ label: 'Local Editor Command Host',
2975
+ handlers,
2976
+ }).catch(() => null);
2977
+ }
2051
2978
  }
2052
2979
  catch (error) {
2053
2980
  try {
2054
2981
  unregisterStandardAgentCapabilities();
2055
2982
  }
2056
2983
  catch (cleanupError) {
2057
- const combined = new Error('Plugin Agent capability registration failed and standard capability rollback reported errors.');
2984
+ const combined = new Error('Plugin command registration failed and standard command rollback reported errors.');
2058
2985
  combined.errors = [error, cleanupError];
2059
2986
  throw combined;
2060
2987
  }
2061
2988
  throw error;
2062
2989
  }
2063
2990
  };
2064
- const activateAgentBridgeAuthority = () => {
2065
- registerAgentBridgeCapabilities();
2066
- if (state.agentBridgeTransport)
2067
- return;
2068
- state.agentBridgeTransport = createLocalEditorAgentBridgeWebSocketTransportFromQuery(state.agentBridge, {
2069
- metadata: options.agentBridge?.sessionMetadata,
2070
- onStatusChange: agentBridgeStatus => {
2071
- state.agentBridgeStatus = agentBridgeStatus;
2072
- harness.render();
2073
- },
2074
- });
2991
+ const activateCommandAuthority = () => {
2992
+ registerCommandCapabilities();
2075
2993
  };
2076
- const disposeAgentBridgeAuthority = () => {
2077
- if (state.agentBridgeTransport) {
2078
- state.agentBridgeTransport.dispose();
2079
- state.agentBridgeTransport = null;
2080
- }
2081
- if (state.unregisterAgentBridgeCapabilities) {
2082
- state.unregisterAgentBridgeCapabilities();
2083
- state.unregisterAgentBridgeCapabilities = null;
2994
+ const disposeCommandAuthority = () => {
2995
+ if (state.unregisterCommandCapabilities) {
2996
+ state.unregisterCommandCapabilities();
2997
+ state.unregisterCommandCapabilities = null;
2084
2998
  }
2085
2999
  };
2086
3000
  const attachLifecycleOwnedApplicationAuthority = () => {
@@ -2088,46 +3002,14 @@ function createLocalEditorHarnessImplementation(options, construction) {
2088
3002
  return;
2089
3003
  if (!unsubscribeLifecycleRender)
2090
3004
  attachLifecycleRenderSubscription();
2091
- activateAgentBridgeAuthority();
2092
- attachAgentBridgeLifecycleParticipant();
3005
+ activateCommandAuthority();
2093
3006
  if (!releaseApplicationAuthorityScopeResource) {
2094
3007
  releaseApplicationAuthorityScopeResource = lifecycleController.addScopeResource(PLAYABLE_LOCAL_EDITOR_APPLICATION_SCOPE_ID, () => {
2095
- disposeAgentBridgeAuthority();
3008
+ disposeCommandAuthority();
2096
3009
  releaseApplicationAuthorityScopeResource = null;
2097
3010
  });
2098
3011
  }
2099
3012
  };
2100
- const reportAgentBridgeLifecycleTransition = (event) => {
2101
- const transitionId = event.transition.id;
2102
- const transport = agentBridgeLifecycleTransports.get(transitionId)
2103
- ?? state.agentBridgeTransport;
2104
- transport?.reportLifecycleTransition(event);
2105
- if (event.status !== 'started')
2106
- agentBridgeLifecycleTransports.delete(transitionId);
2107
- };
2108
- const attachAgentBridgeLifecycleParticipant = () => {
2109
- unregisterAgentBridgeLifecycleParticipant?.();
2110
- unregisterAgentBridgeLifecycleParticipant = null;
2111
- if (!lifecycleController)
2112
- return;
2113
- unregisterAgentBridgeLifecycleParticipant = lifecycleController.registerParticipant({
2114
- id: 'fps.editor.agent-bridge.lifecycle-trace',
2115
- transitions: FPS_EDITOR_LIFECYCLE_TRANSITION_TYPES,
2116
- prepare(context) {
2117
- const transport = state.agentBridgeTransport;
2118
- if (transport)
2119
- agentBridgeLifecycleTransports.set(context.transition.id, transport);
2120
- reportAgentBridgeLifecycleTransition({
2121
- status: 'started',
2122
- transition: context.transition,
2123
- previous: context.before,
2124
- current: context.getSnapshot(),
2125
- });
2126
- },
2127
- settled: reportAgentBridgeLifecycleTransition,
2128
- failed: reportAgentBridgeLifecycleTransition,
2129
- });
2130
- };
2131
3013
  const attachLifecycleRenderSubscription = () => {
2132
3014
  releaseLifecycleRenderScopeResource?.();
2133
3015
  releaseLifecycleRenderScopeResource = null;
@@ -2136,7 +3018,26 @@ function createLocalEditorHarnessImplementation(options, construction) {
2136
3018
  if (!lifecycleController)
2137
3019
  return;
2138
3020
  const lifecycle = lifecycleController.lifecycle;
2139
- const unsubscribe = lifecycle.subscribe(() => harness.render());
3021
+ const unsubscribe = lifecycle.subscribe(() => {
3022
+ let presentationApplied = false;
3023
+ try {
3024
+ presentationApplied = ui.updatePresentationDelta?.({
3025
+ pluginPanel: createLocalEditorPluginPanelState(options.pluginHost, state.lifecycle),
3026
+ }) === true;
3027
+ }
3028
+ catch {
3029
+ // The authoritative full render below preserves lifecycle presentation on adapter failure.
3030
+ }
3031
+ if (presentationApplied)
3032
+ lifecyclePresentationOnlyRenderDepth += 1;
3033
+ try {
3034
+ harness.render();
3035
+ }
3036
+ finally {
3037
+ if (presentationApplied)
3038
+ lifecyclePresentationOnlyRenderDepth -= 1;
3039
+ }
3040
+ });
2140
3041
  unsubscribeLifecycleRender = unsubscribe;
2141
3042
  releaseLifecycleRenderScopeResource = lifecycleController.addScopeResource(PLAYABLE_LOCAL_EDITOR_APPLICATION_SCOPE_ID, () => {
2142
3043
  unsubscribe();
@@ -2149,14 +3050,18 @@ function createLocalEditorHarnessImplementation(options, construction) {
2149
3050
  if (!lifecycleController || !state.session)
2150
3051
  return;
2151
3052
  if (!releaseMainSessionScopeResource) {
2152
- releaseMainSessionScopeResource = lifecycleController.addScopeResource(PLAYABLE_LOCAL_EDITOR_MAIN_SESSION_SCOPE_ID, () => {
3053
+ releaseMainSessionScopeResource = lifecycleController.addScopeResource(PLAYABLE_LOCAL_EDITOR_MAIN_SESSION_SCOPE_ID, async () => {
3054
+ state.authoringHost?.dispose();
3055
+ await state.authoringHost?.drain();
3056
+ state.authoringHost = null;
3057
+ state.replaceProjectionSessionAuthority(null);
2153
3058
  state.session = null;
2154
3059
  state.source = null;
2155
3060
  releaseMainSessionScopeResource = null;
2156
3061
  });
2157
3062
  }
2158
3063
  };
2159
- activateAgentBridgeAuthority();
3064
+ activateCommandAuthority();
2160
3065
  registerLocalEditorHarnessLifecycleOperations(harness, {
2161
3066
  runGame: startGameRuntime,
2162
3067
  validateRun: async () => {
@@ -2197,9 +3102,45 @@ function createLocalEditorHarnessImplementation(options, construction) {
2197
3102
  state.statusDetails = stringifyLocalEditorError(error) ?? 'Unknown Tool activation error';
2198
3103
  harness.render();
2199
3104
  });
3105
+ if (projectCommandService) {
3106
+ void projectCommandService.watchAuthoring({
3107
+ onSnapshot: snapshot => applyProjectServiceSnapshot(snapshot),
3108
+ async onEvents(events) {
3109
+ if (events.length === 0)
3110
+ return;
3111
+ const snapshot = await readProjectServiceSnapshot();
3112
+ if (snapshot)
3113
+ await applyProjectServiceSnapshot(snapshot);
3114
+ },
3115
+ onIdle: () => state.reconcilePendingProjectServiceSnapshot(),
3116
+ onError(error) {
3117
+ if (harnessDisposed)
3118
+ return;
3119
+ reportBrowserAuthoringFailure(state, () => harness.render(), error);
3120
+ },
3121
+ }).then((stop) => {
3122
+ if (harnessDisposed)
3123
+ stop();
3124
+ else
3125
+ stopProjectServiceWatch = stop;
3126
+ }).catch((error) => {
3127
+ if (harnessDisposed)
3128
+ return;
3129
+ state.status = 'Project Editor Service connection failed';
3130
+ state.statusTone = 'error';
3131
+ state.statusToneStatus = state.status;
3132
+ state.statusDetails = stringifyLocalEditorError(error) ?? 'Unknown Editor Service error';
3133
+ harness.render();
3134
+ });
3135
+ }
2200
3136
  harness.render();
2201
3137
  return harness;
2202
3138
  }
3139
+ let localEditorAuthoringServiceSequence = 0;
3140
+ function createLocalEditorAuthoringServiceInstanceId() {
3141
+ localEditorAuthoringServiceSequence += 1;
3142
+ return `local-editor-${Date.now().toString(36)}-${localEditorAuthoringServiceSequence.toString(36)}`;
3143
+ }
2203
3144
  function createLocalEditorDocumentFingerprint(document) {
2204
3145
  if (document == null)
2205
3146
  return null;
@@ -2221,11 +3162,13 @@ function disposeLocalEditorHarnessResources(state, ui, hierarchyKernel) {
2221
3162
  errors.push(error);
2222
3163
  }
2223
3164
  };
2224
- dispose(() => state.agentBridgeTransport?.dispose(), () => { state.agentBridgeTransport = null; });
2225
- dispose(() => state.unregisterAgentBridgeCapabilities?.(), () => {
2226
- state.unregisterAgentBridgeCapabilities = null;
3165
+ dispose(() => state.unregisterCommandCapabilities?.(), () => {
3166
+ state.unregisterCommandCapabilities = null;
3167
+ });
3168
+ dispose(() => disposeEditorWorld(state), () => {
3169
+ state.replaceProjectionSessionAuthority(null);
3170
+ state.session = null;
2227
3171
  });
2228
- dispose(() => disposeEditorWorld(state), () => { state.session = null; });
2229
3172
  dispose(() => ui.dispose());
2230
3173
  dispose(() => hierarchyKernel.setProviders([]));
2231
3174
  if (errors.length > 0) {
@@ -2274,7 +3217,7 @@ export function mergeLocalEditorHarnessInspectorComponentSections(input) {
2274
3217
  }),
2275
3218
  };
2276
3219
  }
2277
- function isAgentBridgeObjectSelectable(options, document, objectId, hierarchyItems) {
3220
+ function isEditorCommandObjectSelectable(options, document, objectId, hierarchyItems) {
2278
3221
  const inHierarchy = hierarchyItems.some(item => item.id === objectId);
2279
3222
  const hasProjectionNode = !!options.documentAdapter.getProjectionNode(document, objectId);
2280
3223
  if (!inHierarchy && !hasProjectionNode)
@@ -2678,10 +3621,31 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
2678
3621
  },
2679
3622
  onProjectionReady(event) {
2680
3623
  getLocalEditorEditingContext(state).handleProjectionReady(event.nodeId);
3624
+ if (isProjectionInspectorRefreshSuppressed(state, event.nodeId, event.batchId)) {
3625
+ renderPreviewUi({
3626
+ status: state.status,
3627
+ statusTone: state.statusToneStatus === state.status ? state.statusTone : 'default',
3628
+ statusDetails: state.statusToneStatus === state.status ? state.statusDetails : '',
3629
+ session: createUiSessionState(state),
3630
+ });
3631
+ return;
3632
+ }
2681
3633
  renderUi();
2682
3634
  },
2683
3635
  onProjectionBatchSettled(event) {
2684
3636
  getLocalEditorEditingContext(state).handleProjectionBatchSettled(event.batchId);
3637
+ const suppressInspectorRefresh = state.suppressedProjectionInspectorRefreshBatchIds.has(event.batchId)
3638
+ || (event.nodeIds ?? []).some(nodeId => state.suppressedProjectionInspectorRefreshNodeBatches.has(nodeId));
3639
+ releaseProjectionInspectorRefreshSuppression(state, event.batchId);
3640
+ if (suppressInspectorRefresh) {
3641
+ renderPreviewUi({
3642
+ status: state.status,
3643
+ statusTone: state.statusToneStatus === state.status ? state.statusTone : 'default',
3644
+ statusDetails: state.statusToneStatus === state.status ? state.statusDetails : '',
3645
+ session: createUiSessionState(state),
3646
+ });
3647
+ return;
3648
+ }
2685
3649
  renderUi();
2686
3650
  },
2687
3651
  });
@@ -2710,27 +3674,41 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
2710
3674
  state.statusTone = policyStatus ? 'warning' : 'default';
2711
3675
  state.statusToneStatus = state.status;
2712
3676
  state.statusDetails = '';
2713
- render();
3677
+ renderPreviewUi({
3678
+ status: state.status,
3679
+ statusTone: state.statusTone,
3680
+ statusDetails: state.statusDetails,
3681
+ transformTool: {
3682
+ activeTool: event.tool,
3683
+ activeSpace: event.space,
3684
+ activeConstraint: event.constraint,
3685
+ dragPhase: 'dragging',
3686
+ draggingNodeId: event.nodeId ?? event.activeId ?? null,
3687
+ },
3688
+ });
3689
+ requestEditorSceneFrame(state, 'gizmo-drag-start');
2714
3690
  },
2715
3691
  onDragUpdate(event) {
2716
3692
  updateActiveTransformPreview(state, event);
2717
- syncMarkerOverlayToSceneArtifacts(state, options, state.session?.getState().selection ?? { selectedIds: [], activeId: null });
3693
+ syncMarkerOverlayToSceneArtifacts(state, options, state.session?.getSelection() ?? { selectedIds: [], activeId: null });
2718
3694
  state.gizmo?.refreshSelection();
2719
- preview('gizmo-drag-update');
3695
+ scheduleInspectorPresentationPreview(state, options, renderPreviewUi, 'gizmo-drag-update');
3696
+ requestEditorSceneFrame(state, 'gizmo-drag-update');
2720
3697
  },
2721
3698
  onDragEnd(event) {
2722
3699
  sceneViewInteraction.endGizmoDrag();
2723
3700
  clearActiveTransformPreview(state);
2724
- const changed = getLocalEditorEditingContext(state).commitTransform(event);
2725
- if (!changed)
2726
- requestEditorSceneFrame(state, 'gizmo-drag-end');
2727
- renderUi();
3701
+ void state.runBrowserAuthoringMutation('transform.gizmo.commit', JSON.stringify(event), authoringState => getLocalEditorEditingContext(authoringState).commitTransform(event)).then(changed => {
3702
+ if (!changed)
3703
+ requestEditorSceneFrame(state, 'gizmo-drag-end');
3704
+ renderUi();
3705
+ }).catch(error => reportBrowserAuthoringFailure(state, renderUi, error));
2728
3706
  },
2729
3707
  onDragCancel(event) {
2730
3708
  sceneViewInteraction.endGizmoDrag();
2731
3709
  clearActiveTransformPreview(state);
2732
- if (event.duplicate && cancelDuplicateDrag(state, options)) {
2733
- render();
3710
+ if (event.duplicate) {
3711
+ void state.runBrowserAuthoringMutation('transform.duplicate.cancel', JSON.stringify(event), authoringState => cancelDuplicateDrag(authoringState, options)).then(() => render()).catch(error => reportBrowserAuthoringFailure(state, render, error));
2734
3712
  return;
2735
3713
  }
2736
3714
  state.status = event.targetIds.length > 1
@@ -2741,8 +3719,9 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
2741
3719
  onDragBlocked(event) {
2742
3720
  sceneViewInteraction.endGizmoDrag();
2743
3721
  clearActiveTransformPreview(state);
2744
- if (event.duplicate)
2745
- cancelDuplicateDrag(state, options);
3722
+ if (event.duplicate) {
3723
+ void state.runBrowserAuthoringMutation('transform.duplicate.cancel', JSON.stringify(event), authoringState => cancelDuplicateDrag(authoringState, options)).catch(error => reportBrowserAuthoringFailure(state, renderUi, error));
3724
+ }
2746
3725
  requestEditorSceneFrame(state, 'gizmo-drag-blocked');
2747
3726
  state.status = formatBlockedGizmoTransformStatus(event);
2748
3727
  state.statusTone = 'warning';
@@ -2750,10 +3729,17 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
2750
3729
  renderUi();
2751
3730
  },
2752
3731
  onDuplicateDragStart(input) {
2753
- const result = getLocalEditorEditingContext(state).beginDuplicateDrag(input);
2754
- if (!result)
3732
+ const result = state.tryRunBrowserAuthoringMutationImmediately('transform.duplicate.begin', JSON.stringify(input), session => getLocalEditorEditingContext(state).beginDuplicateDrag(input, session));
3733
+ if (!result.ok) {
3734
+ state.status = `Duplicate drag unavailable: ${result.reason}`;
3735
+ state.statusTone = 'warning';
3736
+ state.statusToneStatus = state.status;
2755
3737
  renderUi();
2756
- return result;
3738
+ return null;
3739
+ }
3740
+ if (!result.value)
3741
+ renderUi();
3742
+ return result.value;
2757
3743
  },
2758
3744
  });
2759
3745
  state.gizmo = gizmo;
@@ -2865,8 +3851,10 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
2865
3851
  return;
2866
3852
  }
2867
3853
  if (event.state.intent === 'placement') {
2868
- if (commitArmedPlacement(state, options, event.originalEvent))
2869
- render();
3854
+ void state.runBrowserAuthoringMutation('asset.place', JSON.stringify({ x: event.originalEvent.clientX, y: event.originalEvent.clientY }), authoringState => commitArmedPlacement(authoringState, options, event.originalEvent)).then(changed => {
3855
+ if (changed)
3856
+ render();
3857
+ }).catch(error => reportBrowserAuthoringFailure(state, render, error));
2870
3858
  return;
2871
3859
  }
2872
3860
  if (event.state.intent === 'view-plane-move') {
@@ -2963,9 +3951,9 @@ async function createEditorWorld(state, options, renderUi, renderPreviewUi, upda
2963
3951
  });
2964
3952
  state.postProcess = postProcess;
2965
3953
  postProcess.setProfile(initialRendering.postProcess ?? null);
2966
- const environmentTexture = createBabylonEnvironmentTextureController(world.scene, null);
3954
+ const environmentTexture = createBabylonEnvironmentTextureController(world.scene);
2967
3955
  state.environmentTexture = environmentTexture;
2968
- environmentTexture.setProfile(initialRendering.environment ?? null);
3956
+ await environmentTexture.applyProfile(initialRendering.environment ?? null);
2969
3957
  world.refreshSkyBackdrop();
2970
3958
  const resize = () => {
2971
3959
  engine.resize?.();
@@ -3002,7 +3990,7 @@ function disposeEditorWorld(state) {
3002
3990
  });
3003
3991
  run(() => clearPrefabStageForEditorTeardown(state));
3004
3992
  run(() => cancelScheduledSelectionInspectorRefresh(state));
3005
- state.activeTransformPreview = null;
3993
+ clearActiveTransformPreview(state);
3006
3994
  disposeField(() => state.sceneViewInteraction, () => { state.sceneViewInteraction = null; });
3007
3995
  if (state.resizeHandler) {
3008
3996
  run(() => {
@@ -3202,7 +4190,7 @@ function requestEditorPreviewFrame(state, options, renderPreviewUi, reason) {
3202
4190
  function updateActiveTransformPreview(state, event) {
3203
4191
  const activeId = event.activeId ?? event.nodeId ?? event.targetIds[0] ?? null;
3204
4192
  if (!activeId) {
3205
- state.activeTransformPreview = null;
4193
+ clearActiveTransformPreview(state);
3206
4194
  return;
3207
4195
  }
3208
4196
  state.activeTransformPreview = {
@@ -3215,6 +4203,74 @@ function updateActiveTransformPreview(state, event) {
3215
4203
  }
3216
4204
  function clearActiveTransformPreview(state) {
3217
4205
  state.activeTransformPreview = null;
4206
+ cancelInspectorPresentationPreview(state);
4207
+ }
4208
+ function cancelInspectorPresentationPreview(state) {
4209
+ state.inspectorPresentationGeneration += 1;
4210
+ state.inspectorPresentationPatches = null;
4211
+ if (state.inspectorPresentationFrame !== null) {
4212
+ globalThis.cancelAnimationFrame?.(state.inspectorPresentationFrame);
4213
+ state.inspectorPresentationFrame = null;
4214
+ }
4215
+ }
4216
+ function scheduleInspectorPresentationPreview(state, options, renderPreviewUi, _reason) {
4217
+ const preview = state.activeTransformPreview;
4218
+ const transform = preview?.activeId ? preview.transforms[preview.activeId] : null;
4219
+ if (!preview?.activeId || !transform || !isEditorTransformTrsSnapshot(transform))
4220
+ return;
4221
+ const generation = state.inspectorPresentationGeneration;
4222
+ const targetId = preview.activeId;
4223
+ state.inspectorPresentationPatches = createTransformInspectorPresentationPatches(targetId, transform, generation);
4224
+ if (state.inspectorPresentationFrame !== null)
4225
+ return;
4226
+ const publish = () => {
4227
+ if (generation !== state.inspectorPresentationGeneration)
4228
+ return;
4229
+ state.inspectorPresentationFrame = null;
4230
+ const patches = state.inspectorPresentationPatches;
4231
+ state.inspectorPresentationPatches = null;
4232
+ if (!patches?.length || !state.world)
4233
+ return;
4234
+ renderPreviewUi({ inspectorPresentationPatches: patches });
4235
+ };
4236
+ if (typeof globalThis.requestAnimationFrame === 'function') {
4237
+ state.inspectorPresentationFrame = globalThis.requestAnimationFrame(publish);
4238
+ }
4239
+ else {
4240
+ publish();
4241
+ }
4242
+ }
4243
+ function createTransformInspectorPresentationPatches(targetId, transform, generation) {
4244
+ const patches = [];
4245
+ for (const group of ['position', 'rotation', 'scale']) {
4246
+ for (const axis of ['x', 'y', 'z']) {
4247
+ const rawValue = transform[group][axis];
4248
+ patches.push({
4249
+ targetId,
4250
+ propertyPath: `transform.${group}.${axis}`,
4251
+ value: group === 'rotation' ? radiansToInspectorDegrees(rawValue) : rawValue,
4252
+ generation,
4253
+ });
4254
+ }
4255
+ }
4256
+ return patches;
4257
+ }
4258
+ function createHistoryTransformInspectorPresentationPatches(state, document, selection) {
4259
+ const activeId = selection?.activeId ?? null;
4260
+ if (!activeId || !selection?.selectedIds.includes(activeId))
4261
+ return [];
4262
+ const transform = state.projection?.readNodeTransform(activeId) ?? null;
4263
+ if (!transform)
4264
+ return [];
4265
+ const preview = {
4266
+ targetIds: [...selection.selectedIds],
4267
+ activeId,
4268
+ transforms: { [activeId]: cloneEditorTransformSnapshot(transform) },
4269
+ };
4270
+ const resolved = getLocalEditorEditingContext(state).resolveInspectorPreviewTransform(document, activeId, transform, preview);
4271
+ return resolved && isEditorTransformTrsSnapshot(resolved)
4272
+ ? createTransformInspectorPresentationPatches(activeId, resolved, state.inspectorPresentationGeneration)
4273
+ : [];
3218
4274
  }
3219
4275
  function scheduleProjectionShadowPreviewRebuild(state, reason) {
3220
4276
  if (state.projectionShadowPreviewRebuildFrame !== null) {
@@ -3283,8 +4339,9 @@ async function runExclusiveLocalEditorDocumentOperation(state, render, operation
3283
4339
  render();
3284
4340
  }
3285
4341
  }
3286
- async function runExclusiveResult(state, render, action, executorStates) {
3287
- const lease = acquireLocalEditorBusyOperationLease(state, render, executorStates);
4342
+ async function runExclusiveResult(state, render, action, executorStates, options = {}) {
4343
+ const renderBoundary = options.renderBoundary !== false;
4344
+ const lease = acquireLocalEditorBusyOperationLease(state, render, executorStates, { renderBoundary });
3288
4345
  let failed = false;
3289
4346
  try {
3290
4347
  return await action(lease.executor);
@@ -3296,22 +4353,25 @@ async function runExclusiveResult(state, render, action, executorStates) {
3296
4353
  finally {
3297
4354
  lease.release();
3298
4355
  state.busy = false;
3299
- try {
3300
- render();
3301
- }
3302
- catch (error) {
3303
- if (!failed)
3304
- throw error;
4356
+ if (renderBoundary || failed) {
4357
+ try {
4358
+ render();
4359
+ }
4360
+ catch (error) {
4361
+ if (!failed)
4362
+ throw error;
4363
+ }
3305
4364
  }
3306
4365
  }
3307
4366
  }
3308
- function acquireLocalEditorBusyOperationLease(state, render, executorStates) {
4367
+ function acquireLocalEditorBusyOperationLease(state, render, executorStates, options = {}) {
3309
4368
  if (state.busy)
3310
4369
  throw new Error('Local editor host is busy. Retry this operation.');
3311
4370
  state.busy = true;
3312
4371
  const lease = createLocalEditorBusyOperationLease(state, render, executorStates);
3313
4372
  try {
3314
- render();
4373
+ if (options.renderBoundary !== false)
4374
+ render();
3315
4375
  return lease;
3316
4376
  }
3317
4377
  catch (error) {
@@ -3544,7 +4604,7 @@ function consumeMarkerRelationPickSelectionCommand(state, options, command, rend
3544
4604
  renderUi();
3545
4605
  return true;
3546
4606
  }
3547
- const handled = patchMarkerRelation(state, options, {
4607
+ const relationInput = {
3548
4608
  action: 'create',
3549
4609
  type: pick.type ?? '',
3550
4610
  fromKind: pick.from.kind,
@@ -3552,16 +4612,18 @@ function consumeMarkerRelationPickSelectionCommand(state, options, command, rend
3552
4612
  toKind: endpoint.kind,
3553
4613
  toId: endpoint.id,
3554
4614
  directed: pick.directed,
3555
- });
3556
- if (handled && state.markerRelationPick) {
3557
- state.markerRelationPick = {
3558
- ...state.markerRelationPick,
3559
- status: state.status,
3560
- statusTone: state.statusTone,
3561
- };
3562
- }
3563
- if (renderUi)
3564
- renderUi();
4615
+ };
4616
+ void state.runBrowserAuthoringMutation('marker.relation.pick.create', JSON.stringify(relationInput), authoringState => patchMarkerRelation(authoringState, options, relationInput)).then(handled => {
4617
+ if (handled && state.markerRelationPick) {
4618
+ state.markerRelationPick = {
4619
+ ...state.markerRelationPick,
4620
+ status: state.status,
4621
+ statusTone: state.statusTone,
4622
+ };
4623
+ }
4624
+ if (renderUi)
4625
+ renderUi();
4626
+ }).catch(error => reportBrowserAuthoringFailure(state, renderUi ?? (() => undefined), error));
3565
4627
  return true;
3566
4628
  }
3567
4629
  function readMarkerRelationPickTargetId(command) {
@@ -3617,13 +4679,14 @@ function renameSceneGraphNode(state, options, intent) {
3617
4679
  label: patch.label ?? `Rename ${intent.id}`,
3618
4680
  patch: patch.patch,
3619
4681
  targetId: intent.id,
3620
- ...withProjectionImpact(patch.projectionImpact),
4682
+ ...withProjectionImpact(createMetadataProjectionImpact([intent.id])),
4683
+ ...withPresentationImpact({ hierarchy: { labelIds: [intent.id] }, inspector: ['summary'] }),
3621
4684
  });
3622
4685
  if (!result.documentChanged) {
3623
4686
  state.status = `Rename unchanged: ${intent.id}`;
3624
4687
  return 'rejected';
3625
4688
  }
3626
- rebuildProjectionFromDocument(state, options, result.workingDocument, result.selection);
4689
+ applyRenameProjectionImpact(state, options, result.workingDocument, result.selection, [intent.id], 'scene-rename');
3627
4690
  state.summary = summarizeDocument(options, result.workingDocument, session.getSource());
3628
4691
  state.status = patch.label ?? `Renamed ${intent.id}`;
3629
4692
  return 'changed';
@@ -4139,7 +5202,7 @@ function sanitizeSelection(state, options, document, selection) {
4139
5202
  const hierarchy = graph
4140
5203
  ? createMarkerGraphHierarchyItems(documentHierarchy, graph, createMarkerGraphHierarchyVisibility(state))
4141
5204
  : documentHierarchy;
4142
- const selectedIds = selection.selectedIds.filter(id => isAgentBridgeObjectSelectable(options, document, id, hierarchy));
5205
+ const selectedIds = selection.selectedIds.filter(id => isEditorCommandObjectSelectable(options, document, id, hierarchy));
4143
5206
  const activeId = selection.activeId && selectedIds.includes(selection.activeId)
4144
5207
  ? selection.activeId
4145
5208
  : selectedIds[selectedIds.length - 1] ?? null;
@@ -4614,12 +5677,21 @@ function syncEditorWorldRenderingFromDocument(state, options, document, reason,
4614
5677
  state.world?.refreshSkyBackdrop();
4615
5678
  return;
4616
5679
  }
4617
- state.worldRenderingKey = key;
4618
5680
  state.shadowPreview?.setOptions(rendering.shadowPreview, refreshOptions);
4619
- state.environmentTexture?.setProfile(rendering.environment);
4620
- state.world?.refreshSkyBackdrop();
4621
- state.postProcess?.setProfile(rendering.postProcess);
4622
- requestEditorSceneFrame(state, reason);
5681
+ const environmentUpdate = state.environmentTexture?.applyProfile(rendering.environment ?? null);
5682
+ if (!environmentUpdate)
5683
+ return;
5684
+ void environmentUpdate.then(() => {
5685
+ state.worldRenderingKey = key;
5686
+ state.world?.refreshSkyBackdrop();
5687
+ state.postProcess?.setProfile(rendering.postProcess);
5688
+ requestEditorSceneFrame(state, reason);
5689
+ }).catch((error) => {
5690
+ if (error?.name === 'AbortError')
5691
+ return;
5692
+ reportLocalEditorWorldRenderingResolutionError(state, error, true);
5693
+ requestEditorSceneFrame(state, `${reason}-failed`);
5694
+ });
4623
5695
  }
4624
5696
  function reportLocalEditorWorldRenderingResolutionError(state, error, keptPrevious) {
4625
5697
  state.status = keptPrevious
@@ -4783,7 +5855,9 @@ async function handleBrowserAssetAction(state, options, input) {
4783
5855
  return enterPrefabStage(state, options, input);
4784
5856
  }
4785
5857
  if (input.actionId === 'asset.add-to-scene') {
4786
- return input.assetId ? addAssetToDocument(state, options, input.assetId).ok : false;
5858
+ return input.assetId
5859
+ ? state.runBrowserAuthoringMutation('object.createFromAsset', JSON.stringify({ assetId: input.assetId, source: 'asset-browser-action' }), authoringState => addAssetToDocument(authoringState, options, input.assetId).ok)
5860
+ : false;
4787
5861
  }
4788
5862
  if (input.actionId === 'asset.place') {
4789
5863
  if (!input.assetId)
@@ -4796,7 +5870,7 @@ async function handleBrowserAssetAction(state, options, input) {
4796
5870
  }
4797
5871
  return armAssetPlacement(state, options, input.assetId);
4798
5872
  }
4799
- const patched = patchBrowserAssetAction(state, options, input);
5873
+ const patched = await state.runBrowserAuthoringMutation(input.actionId, JSON.stringify(input), authoringState => patchBrowserAssetAction(authoringState, options, input));
4800
5874
  if (patched)
4801
5875
  return true;
4802
5876
  state.status = `Asset action unavailable: ${input.actionId}`;
@@ -4808,11 +5882,11 @@ async function handleInspectorAction(state, options, input) {
4808
5882
  if (!input.actionId.startsWith('prefab.')) {
4809
5883
  const activeId = input.targetId ?? state.session?.getState().selection.activeId ?? null;
4810
5884
  const selectedIds = input.targetIds ?? (activeId ? [activeId] : []);
4811
- return patchBrowserAssetAction(state, options, {
5885
+ return state.runBrowserAuthoringMutation(input.actionId, JSON.stringify([input, activeId, selectedIds]), authoringState => patchBrowserAssetAction(authoringState, options, {
4812
5886
  actionId: input.actionId,
4813
5887
  fieldPath: input.path,
4814
5888
  value: input.params,
4815
- }, { activeId, selectedIds });
5889
+ }, { activeId, selectedIds }));
4816
5890
  }
4817
5891
  const assetId = readInspectorActionParamString(input, 'assetId');
4818
5892
  const browserAssetId = readInspectorActionParamString(input, 'browserAssetId')
@@ -4863,7 +5937,7 @@ function readInspectorActionParamString(input, key) {
4863
5937
  const value = input.params?.[key];
4864
5938
  return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
4865
5939
  }
4866
- async function enterPrefabStage(state, options, input) {
5940
+ async function enterPrefabStage(state, options, input, serializedAccess) {
4867
5941
  if (state.mode !== 'editor')
4868
5942
  return false;
4869
5943
  const sessionState = state.session?.getState({ cloneDocuments: false });
@@ -4888,13 +5962,14 @@ async function enterPrefabStage(state, options, input) {
4888
5962
  return true;
4889
5963
  }
4890
5964
  if (previousPrefabStage) {
4891
- const exited = await exitPrefabStage(state, options, 'reject');
5965
+ const exited = await exitPrefabStage(state, options, 'reject', serializedAccess);
4892
5966
  if (!exited)
4893
5967
  return true;
4894
5968
  }
4895
5969
  const parentSession = state.session;
4896
5970
  if (!parentSession)
4897
5971
  throw new Error('Prefab Stage requires an active parent Session.');
5972
+ const expectedParentRevision = parentSession.getState({ cloneDocuments: false }).documentRevision;
4898
5973
  const prefabScopeRevision = ++state.nextPrefabScopeRevision;
4899
5974
  const documentScopeId = state.scopeOperations
4900
5975
  ? `editor:document:prefab:${prefabScopeRevision}`
@@ -4949,12 +6024,32 @@ async function enterPrefabStage(state, options, input) {
4949
6024
  selectedItemIds: ['prefab-root'],
4950
6025
  restoreSceneCameraPreviewEnabled: previousPrefabStage?.restoreSceneCameraPreviewEnabled ?? state.sceneCameraPreviewEnabled,
4951
6026
  };
4952
- const previousSceneContext = getLocalEditorEditingContextById(state, 'fps.editor.context.scene').getSnapshot();
6027
+ const previousSceneContext = state.toolManager?.snapshot().context
6028
+ ?? getLocalEditorEditingContextById(state, 'fps.editor.context.scene').getSnapshot();
6029
+ let projectionAuthoritySwitched = false;
4953
6030
  try {
4954
6031
  await rebindLocalEditorToolContext(state, createLocalEditorPrefabEditingContextSnapshot(state, nextPrefabStage));
6032
+ if (state.authoringHost) {
6033
+ await state.authoringHost.switchSession(transaction.draftSession, {
6034
+ expectedDocumentRevision: expectedParentRevision,
6035
+ ...(serializedAccess ? { serializedAccess } : {}),
6036
+ });
6037
+ }
6038
+ else {
6039
+ state.replaceProjectionSessionAuthority(transaction.draftSession);
6040
+ projectionAuthoritySwitched = true;
6041
+ }
4955
6042
  }
4956
6043
  catch (error) {
4957
6044
  const rollbackErrors = [error];
6045
+ if (projectionAuthoritySwitched) {
6046
+ try {
6047
+ state.replaceProjectionSessionAuthority(parentSession);
6048
+ }
6049
+ catch (authorityRollbackError) {
6050
+ rollbackErrors.push(authorityRollbackError);
6051
+ }
6052
+ }
4958
6053
  try {
4959
6054
  await rebindLocalEditorToolContext(state, previousSceneContext);
4960
6055
  }
@@ -4988,7 +6083,7 @@ async function enterPrefabStage(state, options, input) {
4988
6083
  syncTransformOperationSettingsToSceneArtifacts(state, 'prefab-stage-enter-operation-settings');
4989
6084
  return true;
4990
6085
  }
4991
- async function exitPrefabStage(state, options, dirtyAction = 'reject') {
6086
+ async function exitPrefabStage(state, options, dirtyAction = 'reject', serializedAccess) {
4992
6087
  if (!state.prefabStage)
4993
6088
  return false;
4994
6089
  const transactionSnapshot = state.prefabStage.transaction.snapshot();
@@ -5000,13 +6095,25 @@ async function exitPrefabStage(state, options, dirtyAction = 'reject') {
5000
6095
  state.statusDetails = 'Save or discard the Prefab changes before returning to the Scene.';
5001
6096
  return false;
5002
6097
  }
5003
- state.prefabStage.transaction.discard();
6098
+ state.prefabStage.transaction.assertParentUnchanged();
6099
+ const checkpoint = state.prefabStage.transaction.draftSession.getState({ cloneDocuments: false });
6100
+ if (state.authoringHost) {
6101
+ await state.authoringHost.reset(checkpoint.persistedDocument, checkpoint.source, {
6102
+ expectedDocumentRevision: checkpoint.documentRevision,
6103
+ ...(serializedAccess ? { serializedAccess } : {}),
6104
+ });
6105
+ }
6106
+ else {
6107
+ await state.runBrowserAuthoringMutation('prefab.stage.discard', JSON.stringify({ documentRevision: checkpoint.documentRevision }), authoringState => authoringState.session?.reset(checkpoint.persistedDocument, checkpoint.source));
6108
+ }
5004
6109
  }
5005
6110
  const sessionState = state.session?.getState({ cloneDocuments: false });
5006
6111
  const label = sessionState?.workingDocument
5007
6112
  ? resolvePrefabStageDescriptorForDocument(state, options, sessionState.workingDocument)?.label ?? state.prefabStage.descriptor.label
5008
6113
  : state.prefabStage.descriptor.label;
5009
6114
  const prefabStage = state.prefabStage;
6115
+ const expectedDraftRevision = prefabStage.transaction.draftSession
6116
+ .getState({ cloneDocuments: false }).documentRevision;
5010
6117
  const restoreSceneCameraPreviewEnabled = prefabStage.restoreSceneCameraPreviewEnabled;
5011
6118
  const currentSceneContext = getLocalEditorEditingContextById(state, 'fps.editor.context.scene').getSnapshot();
5012
6119
  const parentDocumentRevision = prefabStage.transaction.parentSession
@@ -5015,17 +6122,48 @@ async function exitPrefabStage(state, options, dirtyAction = 'reject') {
5015
6122
  ...currentSceneContext,
5016
6123
  revision: parentDocumentRevision + state.editorStateRevision + 1,
5017
6124
  };
6125
+ const prefabContext = state.toolManager?.snapshot().context
6126
+ ?? createLocalEditorPrefabEditingContextSnapshot(state, prefabStage);
6127
+ let projectionAuthoritySwitched = false;
5018
6128
  await closePrefabStageLifecycleScopes(state, prefabStage);
5019
6129
  try {
5020
6130
  await rebindLocalEditorToolContext(state, sceneContext);
6131
+ if (state.authoringHost) {
6132
+ await state.authoringHost.switchSession(prefabStage.transaction.parentSession, {
6133
+ expectedDocumentRevision: expectedDraftRevision,
6134
+ ...(serializedAccess ? { serializedAccess } : {}),
6135
+ });
6136
+ }
6137
+ else {
6138
+ state.replaceProjectionSessionAuthority(prefabStage.transaction.parentSession);
6139
+ projectionAuthoritySwitched = true;
6140
+ }
5021
6141
  }
5022
6142
  catch (error) {
6143
+ const rollbackErrors = [error];
6144
+ if (projectionAuthoritySwitched) {
6145
+ try {
6146
+ state.replaceProjectionSessionAuthority(prefabStage.transaction.draftSession);
6147
+ }
6148
+ catch (authorityRollbackError) {
6149
+ rollbackErrors.push(authorityRollbackError);
6150
+ }
6151
+ }
5023
6152
  try {
5024
6153
  await openPrefabStageLifecycleScopes(state, prefabStage);
5025
6154
  }
5026
6155
  catch (rollbackError) {
6156
+ rollbackErrors.push(rollbackError);
6157
+ }
6158
+ try {
6159
+ await rebindLocalEditorToolContext(state, prefabContext);
6160
+ }
6161
+ catch (rollbackError) {
6162
+ rollbackErrors.push(rollbackError);
6163
+ }
6164
+ if (rollbackErrors.length > 1) {
5027
6165
  const combined = new Error('Prefab Tool context exit and lifecycle scope rollback failed.');
5028
- combined.errors = [error, rollbackError];
6166
+ combined.errors = rollbackErrors;
5029
6167
  throw combined;
5030
6168
  }
5031
6169
  throw error;
@@ -5033,6 +6171,13 @@ async function exitPrefabStage(state, options, dirtyAction = 'reject') {
5033
6171
  state.session = prefabStage.transaction.parentSession;
5034
6172
  state.prefabStage = null;
5035
6173
  state.editorStateRevision += 1;
6174
+ let reconciliationError;
6175
+ try {
6176
+ await state.reconcilePendingProjectServiceSnapshot();
6177
+ }
6178
+ catch (error) {
6179
+ reconciliationError = error;
6180
+ }
5036
6181
  activateLocalEditorSceneViewContext(state, getLocalEditorEditingContext(state).getViewStateKey(), false);
5037
6182
  const parentSessionState = state.session.getState({ cloneDocuments: false });
5038
6183
  if (parentSessionState.workingDocument) {
@@ -5044,10 +6189,12 @@ async function exitPrefabStage(state, options, dirtyAction = 'reject') {
5044
6189
  syncSceneCameraPreview(state, options);
5045
6190
  else
5046
6191
  state.sceneCameraPreview?.setActive(false);
5047
- state.status = `Exited Prefab ${label}`;
5048
- state.statusTone = 'default';
6192
+ state.status = reconciliationError ? 'Project Editor Service reconciliation failed' : `Exited Prefab ${label}`;
6193
+ state.statusTone = reconciliationError ? 'error' : 'default';
5049
6194
  state.statusToneStatus = state.status;
5050
- state.statusDetails = '';
6195
+ state.statusDetails = reconciliationError
6196
+ ? stringifyLocalEditorError(reconciliationError) ?? 'Unknown project snapshot reconciliation error'
6197
+ : '';
5051
6198
  return true;
5052
6199
  }
5053
6200
  async function rebindLocalEditorToolContext(state, nextContext = getLocalEditorEditingContext(state).getSnapshot()) {
@@ -5088,7 +6235,7 @@ async function openPrefabStageLifecycleScopes(state, stage) {
5088
6235
  parentId: stage.sessionScopeId,
5089
6236
  });
5090
6237
  state.scopeOperations.addScopeResource(stage.previewScopeId, () => {
5091
- state.activeTransformPreview = null;
6238
+ clearActiveTransformPreview(state);
5092
6239
  });
5093
6240
  }
5094
6241
  function selectPrefabStageItem(state, itemId) {
@@ -5541,13 +6688,13 @@ function clearArmedPlacement(state) {
5541
6688
  state.armedPlacement = null;
5542
6689
  state.gizmo?.setPlacementMarker(null);
5543
6690
  }
5544
- function addAssetToDocument(state, options, assetId, createOptions = {}) {
6691
+ function addAssetToDocument(state, options, assetId, createOptions = {}, sessionOverride) {
5545
6692
  if (state.mode !== 'editor') {
5546
6693
  state.status = 'Asset creation rejected: editor is not active';
5547
6694
  return { ok: false, assetId, changed: false, status: state.status, error: 'editor_not_active' };
5548
6695
  }
5549
6696
  cancelActiveOperation(state);
5550
- const session = state.session;
6697
+ const session = sessionOverride ?? state.session;
5551
6698
  const beforeDocument = session?.getState().workingDocument;
5552
6699
  if (!session || !beforeDocument) {
5553
6700
  state.status = 'Asset creation rejected: document is not loaded';
@@ -5609,13 +6756,13 @@ function addAssetToDocument(state, options, assetId, createOptions = {}) {
5609
6756
  createdId: createdId ?? null,
5610
6757
  };
5611
6758
  }
5612
- function patchSerializedProperty(state, options, input) {
6759
+ function patchSerializedProperty(state, options, input, onCommitted) {
5613
6760
  if (state.mode !== 'editor')
5614
6761
  return false;
5615
6762
  cancelActiveOperation(state);
5616
- return getLocalEditorEditingContext(state).patchInspectorProperty(input);
6763
+ return getLocalEditorEditingContext(state).patchInspectorProperty(input, onCommitted);
5617
6764
  }
5618
- function patchSceneSerializedProperty(state, options, input) {
6765
+ function patchSceneSerializedProperty(state, options, input, onCommitted) {
5619
6766
  if (!state.session)
5620
6767
  return false;
5621
6768
  const sessionState = state.session.getState({ cloneDocuments: false });
@@ -5647,6 +6794,7 @@ function patchSceneSerializedProperty(state, options, input) {
5647
6794
  if (!patch)
5648
6795
  return false;
5649
6796
  const changedIds = patch.changedIds ?? targetIds;
6797
+ const serializedNamePatch = isSerializedNamePath(payload.path);
5650
6798
  const projectionMetadataPatch = isSerializedProjectionMetadataPath(payload.path);
5651
6799
  const projectionMetadataSyncIds = projectionMetadataPatch
5652
6800
  ? resolveSerializedProjectionMetadataSyncIds(options, document, payload.path, changedIds)
@@ -5658,15 +6806,18 @@ function patchSceneSerializedProperty(state, options, input) {
5658
6806
  label: patch.label ?? `Patch ${payload.path} on ${targetIds.length} objects`,
5659
6807
  patch: patch.patch,
5660
6808
  targetId: sessionState.selection.activeId ?? undefined,
5661
- ...withProjectionImpact(resolveProjectionImpact(patch, patch.reprojectIds?.length
5662
- ? createReprojectProjectionImpact(patch.reprojectIds)
5663
- : shouldReprojectInspectorEdit
5664
- ? createReprojectProjectionImpact(changedIds)
5665
- : isSerializedTransformPath(payload.path)
5666
- ? createTransformProjectionImpact(targetIds)
5667
- : projectionMetadataPatch
5668
- ? createMetadataProjectionImpact(projectionMetadataSyncIds)
5669
- : undefined)),
6809
+ ...withProjectionImpact(serializedNamePatch
6810
+ ? createMetadataProjectionImpact(changedIds)
6811
+ : resolveProjectionImpact(patch, patch.reprojectIds?.length
6812
+ ? createReprojectProjectionImpact(patch.reprojectIds)
6813
+ : shouldReprojectInspectorEdit
6814
+ ? createReprojectProjectionImpact(changedIds)
6815
+ : isSerializedTransformPath(payload.path)
6816
+ ? createTransformProjectionImpact(targetIds)
6817
+ : projectionMetadataPatch
6818
+ ? createMetadataProjectionImpact(projectionMetadataSyncIds)
6819
+ : undefined)),
6820
+ ...withPresentationImpact(resolveSerializedPresentationImpact(payload.path, changedIds)),
5670
6821
  }, largeProjectionMetadataPatch
5671
6822
  ? {
5672
6823
  assumeDocumentChanged: true,
@@ -5678,15 +6829,27 @@ function patchSceneSerializedProperty(state, options, input) {
5678
6829
  if (!result.documentChanged)
5679
6830
  return false;
5680
6831
  const workingDocument = result.workingDocument;
6832
+ state.status = patch.label ?? `Patch ${payload.path} on ${targetIds.length} objects`;
6833
+ if (isSerializedTransformPath(payload.path))
6834
+ onCommitted?.();
5681
6835
  const projectionSyncIds = projectionMetadataPatch
5682
6836
  ? resolveSerializedProjectionMetadataSyncIds(options, workingDocument, payload.path, changedIds)
5683
6837
  : isSerializedTransformPath(payload.path)
5684
6838
  ? targetIds
5685
6839
  : changedIds;
5686
- if (patch.reprojectIds?.length)
5687
- reprojectProjectionForChangedIds(state, options, workingDocument, patch.reprojectIds);
5688
- else if (shouldReprojectInspectorEdit)
5689
- reprojectProjectionForChangedIds(state, options, workingDocument, changedIds);
6840
+ if (serializedNamePatch) {
6841
+ applyRenameProjectionImpact(state, options, workingDocument, result.selection, changedIds, 'inspector-name');
6842
+ }
6843
+ else if (patch.reprojectIds?.length) {
6844
+ reprojectProjectionForChangedIds(state, options, workingDocument, patch.reprojectIds, {
6845
+ refreshInspector: input.refreshInspector !== false,
6846
+ });
6847
+ }
6848
+ else if (shouldReprojectInspectorEdit) {
6849
+ reprojectProjectionForChangedIds(state, options, workingDocument, changedIds, {
6850
+ refreshInspector: input.refreshInspector !== false,
6851
+ });
6852
+ }
5690
6853
  else if (projectionMetadataPatch) {
5691
6854
  syncProjectionMetadataForChangedIds(state, options, workingDocument, projectionSyncIds, {
5692
6855
  deferShadowPreviewRefresh: largeProjectionMetadataPatch,
@@ -5699,7 +6862,6 @@ function patchSceneSerializedProperty(state, options, input) {
5699
6862
  state.gizmo?.refreshSelection();
5700
6863
  }
5701
6864
  state.summary = summarizeDocument(options, workingDocument, state.session.getSource());
5702
- state.status = patch.label ?? `Patch ${payload.path} on ${targetIds.length} objects`;
5703
6865
  return true;
5704
6866
  }
5705
6867
  const patch = options.documentAdapter.createSerializedPropertyPatch({
@@ -5717,6 +6879,7 @@ function patchSceneSerializedProperty(state, options, input) {
5717
6879
  if (!patch)
5718
6880
  return false;
5719
6881
  const changedIds = patch.changedIds ?? [patch.changedId ?? payload.targetId];
6882
+ const serializedNamePatch = isSerializedNamePath(payload.path);
5720
6883
  const projectionMetadataPatch = isSerializedProjectionMetadataPath(payload.path);
5721
6884
  const projectionMetadataSyncIds = projectionMetadataPatch
5722
6885
  ? resolveSerializedProjectionMetadataSyncIds(options, document, payload.path, changedIds)
@@ -5725,20 +6888,34 @@ function patchSceneSerializedProperty(state, options, input) {
5725
6888
  type: 'document.patch',
5726
6889
  label: patch.label ?? `Patch ${payload.path}`,
5727
6890
  patch: patch.patch,
5728
- ...withProjectionImpact(resolveProjectionImpact(patch, patch.reprojectIds?.length
5729
- ? createReprojectProjectionImpact(patch.reprojectIds)
5730
- : shouldReprojectInspectorEdit
5731
- ? createReprojectProjectionImpact(changedIds)
5732
- : isSerializedTransformPath(payload.path)
5733
- ? createTransformProjectionImpact([patch.changedId ?? payload.targetId])
5734
- : projectionMetadataPatch
5735
- ? createMetadataProjectionImpact(projectionMetadataSyncIds)
5736
- : undefined)),
6891
+ ...withProjectionImpact(serializedNamePatch
6892
+ ? createMetadataProjectionImpact(changedIds)
6893
+ : resolveProjectionImpact(patch, patch.reprojectIds?.length
6894
+ ? createReprojectProjectionImpact(patch.reprojectIds)
6895
+ : shouldReprojectInspectorEdit
6896
+ ? createReprojectProjectionImpact(changedIds)
6897
+ : isSerializedTransformPath(payload.path)
6898
+ ? createTransformProjectionImpact([patch.changedId ?? payload.targetId])
6899
+ : projectionMetadataPatch
6900
+ ? createMetadataProjectionImpact(projectionMetadataSyncIds)
6901
+ : undefined)),
6902
+ ...withPresentationImpact(resolveSerializedPresentationImpact(payload.path, changedIds)),
5737
6903
  });
5738
- if (patch.reprojectIds?.length)
5739
- reprojectProjectionForChangedIds(state, options, result.workingDocument, patch.reprojectIds);
6904
+ state.status = patch.label ?? `Patched ${payload.path}`;
6905
+ if (result.documentChanged && isSerializedTransformPath(payload.path))
6906
+ onCommitted?.();
6907
+ if (result.documentChanged && serializedNamePatch) {
6908
+ applyRenameProjectionImpact(state, options, result.workingDocument, result.selection, changedIds, 'inspector-name');
6909
+ }
6910
+ else if (patch.reprojectIds?.length) {
6911
+ reprojectProjectionForChangedIds(state, options, result.workingDocument, patch.reprojectIds, {
6912
+ refreshInspector: input.refreshInspector !== false,
6913
+ });
6914
+ }
5740
6915
  else if (shouldReprojectInspectorEdit) {
5741
- reprojectProjectionForChangedIds(state, options, result.workingDocument, changedIds);
6916
+ reprojectProjectionForChangedIds(state, options, result.workingDocument, changedIds, {
6917
+ refreshInspector: input.refreshInspector !== false,
6918
+ });
5742
6919
  }
5743
6920
  else if (projectionMetadataPatch) {
5744
6921
  const syncIds = resolveSerializedProjectionMetadataSyncIds(options, result.workingDocument, payload.path, changedIds);
@@ -5755,7 +6932,6 @@ function patchSceneSerializedProperty(state, options, input) {
5755
6932
  state.gizmo?.refreshSelection();
5756
6933
  }
5757
6934
  state.summary = summarizeDocument(options, result.workingDocument, state.session.getSource());
5758
- state.status = patch.label ?? `Patched ${payload.path}`;
5759
6935
  return true;
5760
6936
  }
5761
6937
  function patchPrefabSerializedProperty(state, options, input) {
@@ -6460,6 +7636,7 @@ function applyRenderingDocumentPatch(state, options, document, patch, fallbackLa
6460
7636
  patch: patch.patch,
6461
7637
  targetId: patch.changedId,
6462
7638
  ...withProjectionImpact(projectionImpact),
7639
+ ...withPresentationImpact({ rendering: true }),
6463
7640
  });
6464
7641
  if (!result.documentChanged) {
6465
7642
  return { changed: false, workingDocument: result.workingDocument, label };
@@ -6565,6 +7742,9 @@ function isSerializedTransformPath(path) {
6565
7742
  || path.startsWith('transform.rotation.')
6566
7743
  || path.startsWith('transform.scale.');
6567
7744
  }
7745
+ function isSerializedNamePath(path) {
7746
+ return path === 'name';
7747
+ }
6568
7748
  function isSerializedProjectionMetadataPath(path) {
6569
7749
  return isSerializedShadowMetadataPath(path);
6570
7750
  }
@@ -6577,12 +7757,30 @@ function resolveSerializedProjectionMetadataSyncIds(options, document, path, cha
6577
7757
  }
6578
7758
  return uniqueProjectionIds(changedIds);
6579
7759
  }
6580
- function beginDuplicateDrag(state, options, input) {
6581
- if (state.mode !== 'editor' || !state.session)
7760
+ function isSerializedMaterialPath(path) {
7761
+ return path.startsWith('overrides.material')
7762
+ || path.startsWith('material.')
7763
+ || path.startsWith('scene.materialAssets.');
7764
+ }
7765
+ function resolveSerializedPresentationImpact(path, targetIds = []) {
7766
+ if (isSerializedNamePath(path)) {
7767
+ const labelIds = uniqueProjectionIds(targetIds);
7768
+ return labelIds.length > 0
7769
+ ? { hierarchy: { labelIds }, inspector: ['summary'] }
7770
+ : undefined;
7771
+ }
7772
+ if (isSerializedTransformPath(path))
7773
+ return { inspector: ['transform'] };
7774
+ if (isSerializedMaterialPath(path))
7775
+ return { inspector: ['material'] };
7776
+ return undefined;
7777
+ }
7778
+ function beginDuplicateDrag(state, options, input, sessionOverride) {
7779
+ if (state.mode !== 'editor' || !(sessionOverride ?? state.session))
6582
7780
  return null;
6583
7781
  if (state.duplicateDrag)
6584
7782
  return null;
6585
- const session = state.session;
7783
+ const session = sessionOverride ?? state.session;
6586
7784
  const document = session.getState().workingDocument;
6587
7785
  const patch = options.documentAdapter.createDuplicateSelectionPatch?.({
6588
7786
  document,
@@ -6610,7 +7808,7 @@ function beginDuplicateDrag(state, options, input) {
6610
7808
  const selectedIds = (patch.selectedIds?.length ? patch.selectedIds : patch.createdIds)
6611
7809
  .filter(id => isNodeSelectableInDocument(options, result.workingDocument, id));
6612
7810
  if (selectedIds.length === 0) {
6613
- const undone = state.session.undo();
7811
+ const undone = session.undo();
6614
7812
  if (undone)
6615
7813
  rebuildProjectionFromDocument(state, options, undone.workingDocument, originalSelection);
6616
7814
  state.status = 'Duplicate drag rejected: duplicated selection is not selectable';
@@ -6619,7 +7817,7 @@ function beginDuplicateDrag(state, options, input) {
6619
7817
  const activeId = patch.activeId && selectedIds.includes(patch.activeId)
6620
7818
  ? patch.activeId
6621
7819
  : selectedIds[selectedIds.length - 1] ?? null;
6622
- const selectionResult = state.session.dispatch({
7820
+ const selectionResult = session.dispatch({
6623
7821
  type: 'selection.replace',
6624
7822
  selectedIds,
6625
7823
  activeId,
@@ -7213,6 +8411,9 @@ function formatAssetLabel(asset, fallback) {
7213
8411
  const label = record?.label ?? record?.displayName ?? record?.name;
7214
8412
  return typeof label === 'string' && label.trim() ? label : fallback;
7215
8413
  }
8414
+ function withPresentationImpact(impact) {
8415
+ return impact ? { presentationImpact: impact } : {};
8416
+ }
7216
8417
  function withProjectionImpact(impact) {
7217
8418
  return impact ? { projectionImpact: impact } : {};
7218
8419
  }
@@ -7225,6 +8426,18 @@ function createTransformProjectionImpact(ids) {
7225
8426
  function createMetadataProjectionImpact(ids) {
7226
8427
  return createIncrementalProjectionImpact({ syncMetadataIds: ids });
7227
8428
  }
8429
+ function applyRenameProjectionImpact(state, options, document, selection, ids, reason) {
8430
+ const impact = createMetadataProjectionImpact(ids);
8431
+ const applied = applyProjectionImpactToDocument(state, options, {
8432
+ document,
8433
+ selection,
8434
+ impact,
8435
+ reason,
8436
+ syncWorld: false,
8437
+ });
8438
+ if (!applied)
8439
+ rebuildProjectionFromDocument(state, options, document, selection);
8440
+ }
7228
8441
  function createReprojectProjectionImpact(ids) {
7229
8442
  return createIncrementalProjectionImpact({ reprojectIds: ids });
7230
8443
  }
@@ -7347,6 +8560,7 @@ function createHistoryOperationResult(state, input) {
7347
8560
  },
7348
8561
  status: input.status,
7349
8562
  projection: createHistoryProjectionResult(input.waitForProjection, null, state),
8563
+ ...(input.result?.transaction.presentationImpact ? { presentationImpact: input.result.transaction.presentationImpact } : {}),
7350
8564
  };
7351
8565
  }
7352
8566
  function createHistoryProjectionResult(waitPolicy, idleState, state) {
@@ -7364,10 +8578,41 @@ function applyHistoryProjectionImpact(state, options, result, operation) {
7364
8578
  rebuildProjection(state, options, result);
7365
8579
  return;
7366
8580
  }
7367
- const applied = applyIncrementalHistoryProjectionImpact(state, options, result, operation, impact);
8581
+ const applied = applyIncrementalHistoryProjectionImpact(state, options, result, operation, impact, !isRenameTransactionImpact(result.transaction));
7368
8582
  if (!applied)
7369
8583
  rebuildProjection(state, options, result);
7370
8584
  }
8585
+ function isRenameTransactionImpact(transaction) {
8586
+ return isRenameImpact(transaction);
8587
+ }
8588
+ function resolveLocalEditorDocumentStructureChange(classify, command) {
8589
+ if (isRenameImpact(command))
8590
+ return false;
8591
+ return classify?.(command) ?? true;
8592
+ }
8593
+ function isRenameImpact(input) {
8594
+ const presentation = input.presentationImpact;
8595
+ const projection = input.projectionImpact;
8596
+ if (!presentation
8597
+ || presentation.hierarchy === 'full'
8598
+ || !presentation.hierarchy
8599
+ || presentation.rendering === true
8600
+ || !Array.isArray(presentation.inspector)
8601
+ || presentation.inspector.length !== 1
8602
+ || presentation.inspector[0] !== 'summary'
8603
+ || !projection
8604
+ || projection.type !== 'incremental')
8605
+ return false;
8606
+ const labelIds = uniqueProjectionIds(presentation.hierarchy.labelIds);
8607
+ const metadataIds = uniqueProjectionIds(projection.syncMetadataIds);
8608
+ return labelIds.length > 0
8609
+ && labelIds.length === metadataIds.length
8610
+ && labelIds.every(id => metadataIds.includes(id))
8611
+ && uniqueProjectionIds(projection.syncTransformIds).length === 0
8612
+ && uniqueProjectionIds(projection.reprojectIds).length === 0
8613
+ && uniqueProjectionIds(projection.createdNodeIds).length === 0
8614
+ && uniqueProjectionIds(projection.deletedNodeIds).length === 0;
8615
+ }
7371
8616
  function applyProjectionImpactToDocument(state, options, input) {
7372
8617
  if (!input.impact || input.impact.type === 'rebuild')
7373
8618
  return false;
@@ -7380,12 +8625,13 @@ function applyProjectionImpactToDocument(state, options, input) {
7380
8625
  projectNodeIds: input.impact.createdNodeIds,
7381
8626
  removeNodeIds: input.impact.deletedNodeIds,
7382
8627
  reason: input.reason,
8628
+ syncWorld: input.syncWorld,
7383
8629
  });
7384
8630
  }
7385
8631
  function rebuildProjection(state, options, result) {
7386
8632
  rebuildProjectionFromDocument(state, options, result.workingDocument, result.selection);
7387
8633
  }
7388
- function applyIncrementalHistoryProjectionImpact(state, options, result, operation, impact) {
8634
+ function applyIncrementalHistoryProjectionImpact(state, options, result, operation, impact, syncWorld) {
7389
8635
  const projectNodeIds = operation === 'redo'
7390
8636
  ? uniqueProjectionIds(impact.createdNodeIds)
7391
8637
  : uniqueProjectionIds(impact.deletedNodeIds);
@@ -7401,6 +8647,7 @@ function applyIncrementalHistoryProjectionImpact(state, options, result, operati
7401
8647
  projectNodeIds,
7402
8648
  removeNodeIds,
7403
8649
  reason: 'history-impact',
8650
+ syncWorld,
7404
8651
  });
7405
8652
  }
7406
8653
  function applyIncrementalProjectionImpactToDocument(state, options, input) {
@@ -7489,14 +8736,16 @@ function applyIncrementalProjectionImpactToDocument(state, options, input) {
7489
8736
  applyPreviewVisibilityStateToProjection(state);
7490
8737
  const sanitized = sanitizeSelection(state, options, input.document, input.selection);
7491
8738
  syncSelectionToProjection(state, options, sanitized ?? input.selection);
7492
- syncEditorWorldAppearanceFromDocument(state, options, input.document, `world-appearance-${input.reason}`);
7493
- if (syncMetadataNodes.length > 0) {
7494
- syncEditorWorldRenderingFromDocument(state, options, input.document, `world-rendering-${input.reason}`, {
7495
- staticProjectedMetadataChanged: true,
7496
- });
7497
- }
7498
- else {
7499
- syncEditorWorldRenderingFromDocument(state, options, input.document, `world-rendering-${input.reason}`, true);
8739
+ if (input.syncWorld !== false) {
8740
+ syncEditorWorldAppearanceFromDocument(state, options, input.document, `world-appearance-${input.reason}`);
8741
+ if (syncMetadataNodes.length > 0) {
8742
+ syncEditorWorldRenderingFromDocument(state, options, input.document, `world-rendering-${input.reason}`, {
8743
+ staticProjectedMetadataChanged: true,
8744
+ });
8745
+ }
8746
+ else {
8747
+ syncEditorWorldRenderingFromDocument(state, options, input.document, `world-rendering-${input.reason}`, true);
8748
+ }
7500
8749
  }
7501
8750
  invalidateEditorScene(state, `projection-${input.reason}`, options);
7502
8751
  return true;
@@ -7688,7 +8937,7 @@ function syncProjectionMetadataForChangedIds(state, options, document, changedId
7688
8937
  }
7689
8938
  invalidateEditorScene(state, 'projection-sync-metadata-ids');
7690
8939
  }
7691
- function reprojectProjectionForChangedIds(state, options, document, changedIds) {
8940
+ function reprojectProjectionForChangedIds(state, options, document, changedIds, syncOptions = {}) {
7692
8941
  if (state.prefabStage) {
7693
8942
  rebuildProjectionFromDocument(state, options, document, EMPTY_EDITOR_SELECTION);
7694
8943
  return;
@@ -7697,8 +8946,18 @@ function reprojectProjectionForChangedIds(state, options, document, changedIds)
7697
8946
  const projectedNodes = resolveProjectionNodesForTarget(options, document, changedId);
7698
8947
  if (projectedNodes) {
7699
8948
  removeSceneProjectionTarget(state, changedId);
7700
- for (const projectedNode of projectedNodes)
8949
+ for (const projectedNode of projectedNodes) {
7701
8950
  state.projection?.projectNode(projectedNode);
8951
+ if (syncOptions.refreshInspector === false) {
8952
+ const batch = state.projection?.getLastProjectionBatch();
8953
+ if (batch) {
8954
+ suppressProjectionInspectorRefreshForBatch(state, batch.batchId, projectedNode.id);
8955
+ void batch.settled.then(() => {
8956
+ releaseProjectionInspectorRefreshSuppression(state, batch.batchId);
8957
+ });
8958
+ }
8959
+ }
8960
+ }
7702
8961
  }
7703
8962
  }
7704
8963
  applyPreviewVisibilityStateToProjection(state);
@@ -7707,6 +8966,24 @@ function reprojectProjectionForChangedIds(state, options, document, changedIds)
7707
8966
  syncEditorWorldRenderingFromDocument(state, options, document, 'world-rendering-reproject-changed-ids', true);
7708
8967
  invalidateEditorScene(state, 'projection-reproject-changed-ids', options);
7709
8968
  }
8969
+ function suppressProjectionInspectorRefreshForBatch(state, batchId, nodeId) {
8970
+ state.suppressedProjectionInspectorRefreshBatchIds.add(batchId);
8971
+ const batches = state.suppressedProjectionInspectorRefreshNodeBatches.get(nodeId) ?? new Set();
8972
+ batches.add(batchId);
8973
+ state.suppressedProjectionInspectorRefreshNodeBatches.set(nodeId, batches);
8974
+ }
8975
+ function isProjectionInspectorRefreshSuppressed(state, nodeId, batchId) {
8976
+ return (batchId !== undefined && state.suppressedProjectionInspectorRefreshBatchIds.has(batchId))
8977
+ || state.suppressedProjectionInspectorRefreshNodeBatches.has(nodeId);
8978
+ }
8979
+ function releaseProjectionInspectorRefreshSuppression(state, batchId) {
8980
+ state.suppressedProjectionInspectorRefreshBatchIds.delete(batchId);
8981
+ for (const [nodeId, batches] of state.suppressedProjectionInspectorRefreshNodeBatches) {
8982
+ batches.delete(batchId);
8983
+ if (batches.size === 0)
8984
+ state.suppressedProjectionInspectorRefreshNodeBatches.delete(nodeId);
8985
+ }
8986
+ }
7710
8987
  function removeLocalEditorMaterialProfileDiagnostics(state, projectionNodeId) {
7711
8988
  state.materialProfileDiagnostics = state.materialProfileDiagnostics.filter(diagnostic => diagnostic.locator?.objectId !== projectionNodeId);
7712
8989
  }
@@ -7817,8 +9094,7 @@ function syncViewportMeasurementState(state) {
7817
9094
  if (measurement)
7818
9095
  state.viewportMeasurement = measurement;
7819
9096
  }
7820
- function hasSceneCameraPreviewRig(state, options) {
7821
- const document = state.session?.getState().workingDocument ?? null;
9097
+ function hasSceneCameraPreviewRig(options, document) {
7822
9098
  return !!document && !!options.documentAdapter.getSceneCameraPreviewRig?.(document);
7823
9099
  }
7824
9100
  function applyActiveTransformPreviewToInspectorObject(state, options, document, inspectorObject) {
@@ -8044,7 +9320,7 @@ function tryFreezeHierarchyContributionDocument(document) {
8044
9320
  return null;
8045
9321
  }
8046
9322
  }
8047
- export function createLocalEditorSceneHierarchyScopeAdapter(state, options) {
9323
+ export function createLocalEditorSceneHierarchyScopeAdapter(state, options, applyRenamePresentation) {
8048
9324
  const clipboard = new Map();
8049
9325
  return {
8050
9326
  id: 'fps.editor.product.scene-hierarchy',
@@ -8052,7 +9328,7 @@ export function createLocalEditorSceneHierarchyScopeAdapter(state, options) {
8052
9328
  canProvide: () => !state.prefabStage,
8053
9329
  getTree(cache) {
8054
9330
  const sessionState = state.session?.getState({ cloneDocuments: false });
8055
- const structureKey = `scene:${String(sessionState?.documentStructureRevision ?? 0)}:${String(state.markerGraphVisibilityRevision)}`;
9331
+ const structureKey = `scene:${String(sessionState?.documentStructureRevision ?? 0)}:${String(state.markerGraphVisibilityRevision)}:${String(state.hierarchyPresentationFallbackRevision)}`;
8056
9332
  const revision = resolveLocalEditorHierarchyRevision(state);
8057
9333
  if (cache?.structureKey === structureKey && cache.snapshot.revision === revision)
8058
9334
  return cache;
@@ -8154,7 +9430,8 @@ export function createLocalEditorSceneHierarchyScopeAdapter(state, options) {
8154
9430
  : []),
8155
9431
  ];
8156
9432
  },
8157
- async executeOperation({ snapshot, invocation, operation, render, getSnapshot }) {
9433
+ async executeOperation({ snapshot, invocation, operation, render, getSnapshot, state: operationState }) {
9434
+ const state = operationState;
8158
9435
  const resolve = (rowId) => this.resolveTarget(snapshot, rowId);
8159
9436
  if (invocation.operationId === 'hierarchy.node.focus') {
8160
9437
  const target = invocation.contextNodeId ? resolve(invocation.contextNodeId) : null;
@@ -8230,7 +9507,7 @@ export function createLocalEditorSceneHierarchyScopeAdapter(state, options) {
8230
9507
  if (!targetId || !name || snapshot.readonly)
8231
9508
  return createHarnessHierarchyOperationResult(false, false, snapshot.revision, 'hierarchy.rename.invalid', 'Rename target or name is invalid.');
8232
9509
  const outcome = renameSceneGraphNode(state, options, { id: resolve(targetId)?.authoredId ?? targetId, name });
8233
- if (outcome === 'changed')
9510
+ if (outcome === 'changed' && !applyRenamePresentation?.({ id: targetId, name }))
8234
9511
  render();
8235
9512
  return outcome === 'changed'
8236
9513
  ? createHarnessHierarchyOperationResult(true, true, getSnapshot().revision)
@@ -8398,7 +9675,8 @@ export function createLocalEditorPrefabHierarchyScopeAdapter(state, options) {
8398
9675
  : []),
8399
9676
  ].flat();
8400
9677
  },
8401
- async executeOperation({ snapshot, invocation, operation, render, getSnapshot, executorStates }) {
9678
+ async executeOperation({ snapshot, invocation, operation, render, getSnapshot, executorStates, state: operationState }) {
9679
+ const state = operationState;
8402
9680
  const resolve = (rowId) => this.resolveTarget(snapshot, rowId);
8403
9681
  if (invocation.operationId === 'hierarchy.node.focus') {
8404
9682
  const target = invocation.contextNodeId ? resolve(invocation.contextNodeId) : null;
@@ -8670,6 +9948,10 @@ export function createLocalEditorHarnessHierarchyScopeProvider(state, options, r
8670
9948
  applySelection: applyHierarchySelection,
8671
9949
  listOperations,
8672
9950
  async executeOperation(invocation) {
9951
+ const serializedAccess = getSerializedHierarchyInvocationAccess(invocation);
9952
+ const serializedOperationState = serializedAccess === undefined
9953
+ ? state
9954
+ : createSerializedHierarchyOperationState(state, serializedAccess);
8673
9955
  const validated = validateContext(invocation);
8674
9956
  if ('ok' in validated)
8675
9957
  return validated;
@@ -8689,13 +9971,16 @@ export function createLocalEditorHarnessHierarchyScopeProvider(state, options, r
8689
9971
  ? invocation.input.visibleIds.filter((id) => typeof id === 'string')
8690
9972
  : [...validated.nodeById.keys()];
8691
9973
  const selectableIds = requestedIds.filter(id => validated.nodeById.get(id)?.selectable === true);
8692
- return applyHierarchySelection({
9974
+ const apply = () => applyHierarchySelection({
8693
9975
  ...invocation,
8694
9976
  selectedIds: selectableIds,
8695
9977
  activeId: selectableIds.includes(invocation.activeId ?? '')
8696
9978
  ? invocation.activeId
8697
9979
  : selectableIds[selectableIds.length - 1] ?? null,
8698
9980
  });
9981
+ return serializedAccess === undefined
9982
+ ? apply()
9983
+ : callWithEditorAuthoringSerializedAccess(serializedAccess, apply);
8699
9984
  }
8700
9985
  const contextNodeId = invocation.contextNodeId;
8701
9986
  const contextNode = contextNodeId ? validated.nodeById.get(contextNodeId) : null;
@@ -8719,11 +10004,14 @@ export function createLocalEditorHarnessHierarchyScopeProvider(state, options, r
8719
10004
  selectedIds = descendants;
8720
10005
  }
8721
10006
  const selectableIds = selectedIds.filter(id => validated.nodeById.get(id)?.selectable === true);
8722
- return applyHierarchySelection({
10007
+ const apply = () => applyHierarchySelection({
8723
10008
  ...invocation,
8724
10009
  selectedIds: selectableIds,
8725
10010
  activeId: selectableIds[0] ?? null,
8726
10011
  });
10012
+ return serializedAccess === undefined
10013
+ ? apply()
10014
+ : callWithEditorAuthoringSerializedAccess(serializedAccess, apply);
8727
10015
  }
8728
10016
  const contribution = (options.hierarchy?.operations ?? []).find(operation => operation.id === invocation.operationId);
8729
10017
  if (contribution) {
@@ -8733,36 +10021,48 @@ export function createLocalEditorHarnessHierarchyScopeProvider(state, options, r
8733
10021
  const beforeRevision = validated.revision;
8734
10022
  try {
8735
10023
  return await runExclusiveResult(state, render, async () => {
8736
- const preparedSnapshot = validateContext(invocation);
8737
- if ('ok' in preparedSnapshot)
8738
- return preparedSnapshot;
8739
- const visibleContext = createOperationContributionContext(preparedSnapshot, invocation, invocation.input);
8740
- if (!visibleContext || contribution.visible?.(visibleContext) === false) {
8741
- return createHarnessHierarchyOperationResult(false, false, preparedSnapshot.revision, 'hierarchy.operation.unsupported', `Unsupported Hierarchy operation: ${invocation.operationId}`);
8742
- }
8743
- const disabledContext = createOperationContributionContext(preparedSnapshot, invocation, invocation.input);
8744
- const disabled = disabledContext ? contribution.disabled?.(disabledContext) : true;
8745
- if (disabled === true || typeof disabled === 'string') {
8746
- return createHarnessHierarchyOperationResult(false, false, preparedSnapshot.revision, 'hierarchy.operation.disabled', typeof disabled === 'string' ? disabled : 'Hierarchy operation is disabled.');
8747
- }
8748
- const runContext = createOperationContributionContext(preparedSnapshot, invocation, invocation.input, 'isolated');
8749
- if (!runContext) {
8750
- return createHarnessHierarchyOperationResult(false, false, preparedSnapshot.revision, 'hierarchy.operation.unsupported', `Unsupported Hierarchy operation: ${invocation.operationId}`);
8751
- }
8752
- const contributionResult = await contribution.run(runContext);
8753
- const commitSnapshot = validateContext(invocation);
8754
- if ('ok' in commitSnapshot) {
8755
- return createHarnessHierarchyOperationResult(false, false, commitSnapshot.revision, 'hierarchy.operation.stale-before-commit', 'Hierarchy scope changed while the operation was being prepared; no patch was applied.');
8756
- }
8757
- const handled = applyHierarchyOperationContributionResult(state, options, contributionResult, contribution.label);
8758
- if (handled)
8759
- render();
8760
- const current = getSnapshot();
8761
- const changed = current.revision > beforeRevision;
8762
- if (handled && (contribution.effect !== 'authoring' || changed)) {
8763
- return createHarnessHierarchyOperationResult(true, changed, current.revision);
8764
- }
8765
- return createHarnessHierarchyOperationResult(false, changed, current.revision, 'hierarchy.operation.rejected', `${contribution.label} was rejected.`);
10024
+ const executeContribution = async (operationState = state) => {
10025
+ const preparedSnapshot = validateContext(invocation);
10026
+ if ('ok' in preparedSnapshot)
10027
+ return preparedSnapshot;
10028
+ const visibleContext = createOperationContributionContext(preparedSnapshot, invocation, invocation.input);
10029
+ if (!visibleContext || contribution.visible?.(visibleContext) === false) {
10030
+ return createHarnessHierarchyOperationResult(false, false, preparedSnapshot.revision, 'hierarchy.operation.unsupported', `Unsupported Hierarchy operation: ${invocation.operationId}`);
10031
+ }
10032
+ const disabledContext = createOperationContributionContext(preparedSnapshot, invocation, invocation.input);
10033
+ const disabled = disabledContext ? contribution.disabled?.(disabledContext) : true;
10034
+ if (disabled === true || typeof disabled === 'string') {
10035
+ return createHarnessHierarchyOperationResult(false, false, preparedSnapshot.revision, 'hierarchy.operation.disabled', typeof disabled === 'string' ? disabled : 'Hierarchy operation is disabled.');
10036
+ }
10037
+ const runContext = createOperationContributionContext(preparedSnapshot, invocation, invocation.input, 'isolated');
10038
+ if (!runContext) {
10039
+ return createHarnessHierarchyOperationResult(false, false, preparedSnapshot.revision, 'hierarchy.operation.unsupported', `Unsupported Hierarchy operation: ${invocation.operationId}`);
10040
+ }
10041
+ const contributionResult = await contribution.run(runContext);
10042
+ const commitSnapshot = validateContext(invocation);
10043
+ if ('ok' in commitSnapshot) {
10044
+ return createHarnessHierarchyOperationResult(false, false, commitSnapshot.revision, 'hierarchy.operation.stale-before-commit', 'Hierarchy scope changed while the operation was being prepared; no patch was applied.');
10045
+ }
10046
+ if (isLocalEditorHarnessPatchResult(contributionResult)
10047
+ && contribution.effect !== undefined
10048
+ && contribution.effect !== 'authoring') {
10049
+ return createHarnessHierarchyOperationResult(false, false, commitSnapshot.revision, 'hierarchy.operation.effect-mismatch', `${contribution.label} declared effect '${contribution.effect}' and cannot return an authoring patch.`);
10050
+ }
10051
+ const handled = applyHierarchyOperationContributionResult(operationState, options, contributionResult, contribution.label);
10052
+ if (handled)
10053
+ render();
10054
+ const current = getSnapshot();
10055
+ const changed = current.revision > beforeRevision;
10056
+ if (handled && (contribution.effect !== 'authoring' || changed)) {
10057
+ return createHarnessHierarchyOperationResult(true, changed, current.revision);
10058
+ }
10059
+ return createHarnessHierarchyOperationResult(false, changed, current.revision, 'hierarchy.operation.rejected', `${contribution.label} was rejected.`);
10060
+ };
10061
+ return contribution.effect === 'view'
10062
+ || contribution.effect === 'selection'
10063
+ || serializedAccess !== undefined
10064
+ ? executeContribution(serializedOperationState)
10065
+ : state.runBrowserAuthoringMutation(invocation.operationId, JSON.stringify([invocation, validated.scopeKey, validated.revision]), executeContribution);
8766
10066
  }, executorStates);
8767
10067
  }
8768
10068
  catch (error) {
@@ -8776,21 +10076,29 @@ export function createLocalEditorHarnessHierarchyScopeProvider(state, options, r
8776
10076
  const beforeRevision = validated.revision;
8777
10077
  try {
8778
10078
  return await runExclusiveResult(state, render, async () => {
8779
- const preparedSnapshot = validateContext(invocation);
8780
- if ('ok' in preparedSnapshot)
8781
- return preparedSnapshot;
8782
- return adapter.executeOperation({
8783
- snapshot: preparedSnapshot,
8784
- context: invocation,
8785
- invocation,
8786
- operation: listedOperation,
8787
- state,
8788
- options,
8789
- render,
8790
- getSnapshot,
8791
- executorStates,
8792
- });
8793
- }, executorStates);
10079
+ const executeAdapter = async (operationState = state) => {
10080
+ const preparedSnapshot = validateContext(invocation);
10081
+ if ('ok' in preparedSnapshot)
10082
+ return preparedSnapshot;
10083
+ return adapter.executeOperation({
10084
+ snapshot: preparedSnapshot,
10085
+ context: invocation,
10086
+ invocation,
10087
+ operation: listedOperation,
10088
+ state: operationState,
10089
+ options,
10090
+ render,
10091
+ getSnapshot,
10092
+ executorStates,
10093
+ });
10094
+ };
10095
+ return listedOperation.effect === 'authoring' && serializedAccess === undefined
10096
+ ? state.runBrowserAuthoringMutation(invocation.operationId, JSON.stringify([invocation, validated.scopeKey, validated.revision]), executeAdapter)
10097
+ : executeAdapter(serializedOperationState);
10098
+ }, executorStates, {
10099
+ renderBoundary: !(adapter.id === 'fps.editor.product.scene-hierarchy'
10100
+ && invocation.operationId === 'hierarchy.node.rename'),
10101
+ });
8794
10102
  }
8795
10103
  catch (error) {
8796
10104
  const current = getSnapshot();
@@ -8799,6 +10107,28 @@ export function createLocalEditorHarnessHierarchyScopeProvider(state, options, r
8799
10107
  },
8800
10108
  };
8801
10109
  }
10110
+ function getSerializedHierarchyInvocationAccess(invocation) {
10111
+ return invocation[SERIALIZED_HIERARCHY_INVOCATION];
10112
+ }
10113
+ function createSerializedHierarchyOperationState(state, serializedAccess) {
10114
+ const session = state.session;
10115
+ if (!session)
10116
+ return state;
10117
+ const authorizedSession = createEditorAuthoringSerializedSessionView(session, serializedAccess);
10118
+ return new Proxy(state, {
10119
+ get(target, property, receiver) {
10120
+ if (property === 'session')
10121
+ return authorizedSession;
10122
+ return Reflect.get(target, property, receiver);
10123
+ },
10124
+ set(target, property, value, receiver) {
10125
+ if (property === 'session') {
10126
+ throw new Error('Serialized Hierarchy operations cannot replace the active Session.');
10127
+ }
10128
+ return Reflect.set(target, property, value, receiver);
10129
+ },
10130
+ });
10131
+ }
8802
10132
  const BUILT_IN_HIERARCHY_OPERATION_IDS = new Set([
8803
10133
  'hierarchy.node.focus',
8804
10134
  'hierarchy.node.rename',
@@ -8848,6 +10178,13 @@ function createHarnessHierarchyOperationResult(ok, changed, revision, code, mess
8848
10178
  : Object.freeze([]),
8849
10179
  });
8850
10180
  }
10181
+ function reportBrowserAuthoringFailure(state, render, error) {
10182
+ state.status = 'Editor command failed';
10183
+ state.statusTone = 'error';
10184
+ state.statusToneStatus = state.status;
10185
+ state.statusDetails = error instanceof Error ? error.message : String(error);
10186
+ render();
10187
+ }
8851
10188
  function sameHierarchySelection(left, right) {
8852
10189
  return left.length === right.length && left.every((id, index) => id === right[index]);
8853
10190
  }
@@ -8875,6 +10212,32 @@ function getCachedLocalEditorHierarchyItems(state, options, document) {
8875
10212
  }
8876
10213
  return state.hierarchyItemsCache;
8877
10214
  }
10215
+ function resolveAuthoritativeHierarchyLabels(state, options, document, ids) {
10216
+ const cachedItems = getCachedLocalEditorHierarchyItems(state, options, document);
10217
+ const cachedById = new Map(cachedItems.map(item => [item.id, item]));
10218
+ const labels = {};
10219
+ let changed = false;
10220
+ const nextItems = [...cachedItems];
10221
+ for (const id of ids) {
10222
+ const cached = cachedById.get(id);
10223
+ const projectedName = options.documentAdapter.getProjectionNode(document, id)?.name;
10224
+ const label = typeof projectedName === 'string' && projectedName.trim()
10225
+ ? projectedName
10226
+ : cached?.label;
10227
+ if (!label)
10228
+ continue;
10229
+ labels[id] = label;
10230
+ if (cached && cached.label !== label) {
10231
+ const index = nextItems.findIndex(item => item.id === id);
10232
+ if (index >= 0)
10233
+ nextItems[index] = Object.freeze({ ...cached, label, name: label });
10234
+ changed = true;
10235
+ }
10236
+ }
10237
+ if (changed)
10238
+ state.hierarchyItemsCache = Object.freeze(nextItems);
10239
+ return labels;
10240
+ }
8878
10241
  function getLocalEditorDiagnosticContext(state) {
8879
10242
  return {
8880
10243
  scopeId: state.prefabStage
@@ -9140,6 +10503,23 @@ function toBrowserStatusDiagnostic(diagnostic, context) {
9140
10503
  ...(diagnostic.details ? { details: normalizeEditorDiagnosticDetails(diagnostic.details) } : {}),
9141
10504
  };
9142
10505
  }
10506
+ function createUiSessionState(state) {
10507
+ const sessionState = state.session?.getState({ cloneDocuments: false });
10508
+ const projectSnapshot = state.prefabStage ? null : state.projectAuthoringSnapshot;
10509
+ return sessionState
10510
+ ? {
10511
+ source: sessionState.source,
10512
+ dirty: state.prefabStage?.transaction.snapshot().documentDirty
10513
+ ?? projectSnapshot?.dirty
10514
+ ?? sessionState.dirty,
10515
+ canUndo: projectSnapshot?.canUndo ?? sessionState.canUndo,
10516
+ canRedo: projectSnapshot?.canRedo ?? sessionState.canRedo,
10517
+ history: projectSnapshot
10518
+ ? { entries: projectSnapshot.history.entries.map(entry => ({ ...entry })) }
10519
+ : sessionState.history,
10520
+ }
10521
+ : null;
10522
+ }
9143
10523
  function createUiState(state, options, hierarchySnapshot, toolManager) {
9144
10524
  const sessionState = state.session?.getState({ cloneDocuments: false });
9145
10525
  const document = sessionState?.workingDocument ?? null;
@@ -9179,7 +10559,6 @@ function createUiState(state, options, hierarchySnapshot, toolManager) {
9179
10559
  const uiState = {
9180
10560
  mode: state.mode,
9181
10561
  busy: state.busy,
9182
- agentBridge: state.agentBridgeStatus,
9183
10562
  status: state.status,
9184
10563
  statusTone: state.statusToneStatus === state.status ? state.statusTone : 'default',
9185
10564
  statusDetails: state.statusToneStatus === state.status ? state.statusDetails : '',
@@ -9198,6 +10577,7 @@ function createUiState(state, options, hierarchySnapshot, toolManager) {
9198
10577
  inspectorObject: previewInspectorObject,
9199
10578
  inspectorMultiObject: previewInspectorMultiObject,
9200
10579
  inspectorPending: false,
10580
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
9201
10581
  renderingPanel: document
9202
10582
  ? options.documentAdapter.getRenderingPanelState?.(document, {
9203
10583
  scene: state.world?.scene ?? null,
@@ -9242,22 +10622,14 @@ function createUiState(state, options, hierarchySnapshot, toolManager) {
9242
10622
  performanceStats: cloneLocalEditorPerformanceStats(state.performanceStats),
9243
10623
  sceneCameraPreview: {
9244
10624
  enabled: state.sceneCameraPreviewEnabled,
9245
- available: hasSceneCameraPreviewRig(state, options),
10625
+ available: hasSceneCameraPreviewRig(options, document),
9246
10626
  },
9247
10627
  prefabStage: createBrowserPrefabStageState(state, options, document),
9248
10628
  grid: {
9249
10629
  visible: state.gridVisible,
9250
10630
  available: !!state.grid,
9251
10631
  },
9252
- session: sessionState
9253
- ? {
9254
- source: sessionState.source,
9255
- dirty: state.prefabStage?.transaction.snapshot().documentDirty ?? sessionState.dirty,
9256
- canUndo: sessionState.canUndo,
9257
- canRedo: sessionState.canRedo,
9258
- history: sessionState.history,
9259
- }
9260
- : null,
10632
+ session: createUiSessionState(state),
9261
10633
  };
9262
10634
  uiState.documentRevision = sessionState?.documentRevision ?? 0;
9263
10635
  const diagnosticContext = getLocalEditorDiagnosticContext(state);
@@ -9333,25 +10705,25 @@ function createBrowserPrefabStageState(state, options, document, includeInspecto
9333
10705
  previewNodeId: descriptor.previewNodeId,
9334
10706
  };
9335
10707
  }
9336
- function summarizeAgentBridgePrefabStage(state, options) {
10708
+ function summarizeEditorCommandPrefabStage(state, options) {
9337
10709
  const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
9338
10710
  const stage = createBrowserPrefabStageState(state, options, document);
9339
10711
  if (!stage)
9340
10712
  return null;
9341
- return createAgentBridgePrefabStageState(stage);
10713
+ return createEditorCommandPrefabStageState(stage);
9342
10714
  }
9343
- function summarizeAgentBridgePrefabStageDetails(state, options) {
10715
+ function summarizeEditorCommandPrefabStageDetails(state, options) {
9344
10716
  const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
9345
10717
  const stage = createBrowserPrefabStageState(state, options, document);
9346
10718
  if (!stage)
9347
10719
  return null;
9348
10720
  return {
9349
- stage: createAgentBridgePrefabStageState(stage),
9350
- nodeDetails: createAgentBridgePrefabNodeDetails(stage.structureItems),
10721
+ stage: createEditorCommandPrefabStageState(stage),
10722
+ nodeDetails: createEditorCommandPrefabNodeDetails(stage.structureItems),
9351
10723
  inspectorObject: stage.inspectorObject ?? null,
9352
10724
  };
9353
10725
  }
9354
- function createAgentBridgePrefabNodeDetails(items) {
10726
+ function createEditorCommandPrefabNodeDetails(items) {
9355
10727
  const details = [];
9356
10728
  const stack = [...items].reverse();
9357
10729
  while (stack.length > 0) {
@@ -9380,7 +10752,7 @@ function createAgentBridgePrefabNodeDetails(items) {
9380
10752
  }
9381
10753
  return details;
9382
10754
  }
9383
- function createAgentBridgePrefabStageState(stage) {
10755
+ function createEditorCommandPrefabStageState(stage) {
9384
10756
  return {
9385
10757
  assetId: stage.assetId,
9386
10758
  ...(stage.browserAssetId ? { browserAssetId: stage.browserAssetId } : {}),
@@ -9396,7 +10768,7 @@ function createAgentBridgePrefabStageState(stage) {
9396
10768
  canDiscard: stage.canDiscard,
9397
10769
  };
9398
10770
  }
9399
- function createAgentBridgePrefabSummaryFromStage(stage) {
10771
+ function createEditorCommandPrefabSummaryFromStage(stage) {
9400
10772
  return {
9401
10773
  assetId: stage.assetId,
9402
10774
  ...(stage.browserAssetId ? { browserAssetId: stage.browserAssetId } : {}),
@@ -9407,7 +10779,7 @@ function createAgentBridgePrefabSummaryFromStage(stage) {
9407
10779
  status: 'ready',
9408
10780
  };
9409
10781
  }
9410
- function isSameAgentBridgePrefabStage(left, right) {
10782
+ function isSameEditorCommandPrefabStage(left, right) {
9411
10783
  if (!left || !right)
9412
10784
  return false;
9413
10785
  return left.assetId === right.assetId
@@ -9574,10 +10946,10 @@ function createLocalEditorEditingContextProviders(state, options) {
9574
10946
  return focusProjectionNode(state, activeId);
9575
10947
  },
9576
10948
  commitTransform: event => commitSceneGizmoTransform(state, options, event),
9577
- beginDuplicateDrag: input => beginDuplicateDrag(state, options, input),
10949
+ beginDuplicateDrag: (input, session) => beginDuplicateDrag(state, options, input, session),
9578
10950
  getInspectorObject: (document, targetId) => createSceneEditingContextInspectorObject(state, options, document, targetId),
9579
10951
  getInspectorMultiObject: (document, targetIds, activeId) => createSceneEditingContextInspectorMultiObject(state, options, document, targetIds, activeId),
9580
- patchInspectorProperty: input => patchSceneSerializedProperty(state, options, input),
10952
+ patchInspectorProperty: (input, onCommitted) => patchSceneSerializedProperty(state, options, input, onCommitted),
9581
10953
  resolveInspectorPreviewTransform(document, targetId, transform, preview) {
9582
10954
  const createInspectorPreview = options.documentAdapter.createTransformInspectorPreview;
9583
10955
  if (!document || !createInspectorPreview)
@@ -9790,6 +11162,7 @@ function createUiToolPresentationPreviewState(state, snapshot) {
9790
11162
  };
9791
11163
  }
9792
11164
  function publishLocalEditorSelectionPresentation(state, options, renderPreviewUi, reason) {
11165
+ cancelInspectorPresentationPreview(state);
9793
11166
  syncViewportSpatialOverlay(state, options);
9794
11167
  renderPreviewUi(createUiSelectionPresentationPreviewState(state, options));
9795
11168
  requestEditorSceneFrame(state, reason);
@@ -9802,6 +11175,7 @@ function createUiSelectionPresentationPreviewState(state, options) {
9802
11175
  const transformSelectionIsLarge = isLargeSelection(selectedIds);
9803
11176
  const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
9804
11177
  return {
11178
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
9805
11179
  selectedIds,
9806
11180
  activeId,
9807
11181
  selectionSummary: {
@@ -9828,6 +11202,7 @@ function createUiSelectionInspectorPreviewState(state, options) {
9828
11202
  const document = state.session?.getState({ cloneDocuments: false }).workingDocument ?? null;
9829
11203
  if (!document) {
9830
11204
  return {
11205
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
9831
11206
  inspectorObject: null,
9832
11207
  inspectorMultiObject: null,
9833
11208
  inspectorPending: false,
@@ -9837,6 +11212,7 @@ function createUiSelectionInspectorPreviewState(state, options) {
9837
11212
  if (state.prefabStage) {
9838
11213
  const prefabStage = createBrowserPrefabStageState(state, options, document);
9839
11214
  return {
11215
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
9840
11216
  prefabStage,
9841
11217
  inspectorObject: prefabStage?.inspectorObject ?? null,
9842
11218
  inspectorMultiObject: null,
@@ -9845,6 +11221,7 @@ function createUiSelectionInspectorPreviewState(state, options) {
9845
11221
  }
9846
11222
  const editingContext = getLocalEditorEditingContext(state);
9847
11223
  return {
11224
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
9848
11225
  inspectorObject: editingContext.getInspectorObject(document),
9849
11226
  inspectorMultiObject: editingContext.getInspectorMultiObject(document),
9850
11227
  inspectorPending: false,
@@ -9852,10 +11229,6 @@ function createUiSelectionInspectorPreviewState(state, options) {
9852
11229
  }
9853
11230
  function cancelScheduledSelectionInspectorRefresh(state) {
9854
11231
  state.selectionInspectorRefreshGeneration += 1;
9855
- if (state.selectionInspectorRefreshFrame !== null) {
9856
- globalThis.cancelAnimationFrame?.(state.selectionInspectorRefreshFrame);
9857
- state.selectionInspectorRefreshFrame = null;
9858
- }
9859
11232
  if (state.selectionInspectorRefreshTimeout !== null) {
9860
11233
  globalThis.clearTimeout(state.selectionInspectorRefreshTimeout);
9861
11234
  state.selectionInspectorRefreshTimeout = null;
@@ -9883,18 +11256,7 @@ function scheduleSelectionInspectorRefresh(state, options, renderPreviewUi) {
9883
11256
  });
9884
11257
  }
9885
11258
  };
9886
- const deferUntilAfterFrame = () => {
9887
- state.selectionInspectorRefreshFrame = null;
9888
- if (generation !== state.selectionInspectorRefreshGeneration || !state.world)
9889
- return;
9890
- state.selectionInspectorRefreshTimeout = globalThis.setTimeout(publish, 0);
9891
- };
9892
- if (typeof globalThis.requestAnimationFrame === 'function') {
9893
- state.selectionInspectorRefreshFrame = globalThis.requestAnimationFrame(deferUntilAfterFrame);
9894
- }
9895
- else {
9896
- state.selectionInspectorRefreshTimeout = globalThis.setTimeout(publish, 0);
9897
- }
11259
+ state.selectionInspectorRefreshTimeout = globalThis.setTimeout(publish, 0);
9898
11260
  }
9899
11261
  function isLocalEditorSelectionDebugEnabled() {
9900
11262
  return typeof globalThis.location?.search === 'string'
@@ -9926,6 +11288,7 @@ function createUiPreviewState(state, options) {
9926
11288
  ? applyActiveTransformPreviewToInspectorObject(state, options, document, withRuntimeInspectorSections(state, options, document, inspectorObjectBase))
9927
11289
  : null;
9928
11290
  return {
11291
+ inspectorPresentationGeneration: state.inspectorPresentationGeneration,
9929
11292
  status: state.status,
9930
11293
  statusTone: state.statusToneStatus === state.status ? state.statusTone : 'default',
9931
11294
  statusDetails: state.statusToneStatus === state.status ? state.statusDetails : '',