@volter/editor-game 0.5.66 → 0.5.68

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 (239) hide show
  1. package/contributions/audio-unlock.service.ts +2 -2
  2. package/contributions/autoplay.service.ts +1 -1
  3. package/contributions/bridge.command.ts +3 -3
  4. package/contributions/build-player.document.tsx +95 -0
  5. package/contributions/canvas/component-board.service.ts +16 -0
  6. package/contributions/canvas/design-time-mount.service.ts +45 -0
  7. package/contributions/canvas-story-capture.service.ts +12 -0
  8. package/contributions/edit-mode-audio.service.ts +2 -2
  9. package/contributions/edit-mode-networking.service.ts +1 -1
  10. package/contributions/gameplay.command.ts +4 -4
  11. package/contributions/generation.service.ts +1 -1
  12. package/contributions/godot.style.ts +26 -6
  13. package/contributions/godot.view.ts +6 -0
  14. package/contributions/ingest.service.ts +2 -2
  15. package/contributions/instances.command.ts +1 -1
  16. package/contributions/navmesh.menu.ts +1 -1
  17. package/contributions/network-observer.service.ts +14 -0
  18. package/contributions/play.command.ts +10 -4
  19. package/contributions/react/component-board.service.ts +1 -1
  20. package/contributions/react/design-time-mount.service.ts +1 -1
  21. package/contributions/scene-document.service.ts +3 -3
  22. package/contributions/state-watch.menu.ts +1 -1
  23. package/contributions/state-watch.utility.tsx +1 -1
  24. package/contributions/team-playtest.service.ts +4 -4
  25. package/contributions/three/component-board.service.ts +1 -1
  26. package/contributions/three/component-verbs.command.ts +6 -6
  27. package/contributions/three/three-authoring.service.ts +8 -5
  28. package/contributions/three-story-capture.service.ts +12 -0
  29. package/contributions/unity.style.ts +17 -7
  30. package/contributions/unity.view.ts +6 -0
  31. package/contributions/unreal.style.ts +10 -2
  32. package/contributions/unreal.view.ts +5 -0
  33. package/package.json +21 -10
  34. package/src/asset-budget/AssetBudgetPanel.tsx +1 -1
  35. package/src/asset-budget/asset-budget-model.ts +1 -1
  36. package/src/audio/AudioDebuggerPanel.tsx +1 -1
  37. package/src/bridge/dispatch.ts +14 -14
  38. package/src/bridge/live-frames.ts +1 -1
  39. package/src/bridge/screenshot.ts +3 -3
  40. package/src/build/BuildProfilesPanel.tsx +14 -3
  41. package/src/build/build-session.ts +35 -0
  42. package/src/canvas/canvas-board/CanvasBoardDocument.tsx +749 -0
  43. package/src/canvas/canvas-board/canvas-board-model.ts +407 -0
  44. package/src/canvas/canvas-board/canvas-component-board.ts +56 -0
  45. package/src/canvas/canvas-design-mount.ts +524 -0
  46. package/src/canvas/design-time-canvas-mount.ts +79 -0
  47. package/src/coverage/live-authoring-surface.ts +5 -5
  48. package/src/coverage/live-project-verbs.ts +1 -1
  49. package/src/coverage/native-system-coverage.ts +5 -5
  50. package/src/coverage/root-coverage.ts +1 -1
  51. package/src/coverage/session-coverage.ts +3 -3
  52. package/src/design-system-stories/ApplicationChrome.stories.tsx +5 -5
  53. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +7 -7
  54. package/src/edit-mode/edit-mode-audio.ts +4 -4
  55. package/src/edit-mode/edit-mode-networking.ts +2 -2
  56. package/src/game-document/GameCaptureFrameButton.tsx +1 -1
  57. package/src/game-document/GameDocument.tsx +2 -2
  58. package/src/game-document/GamePanel.tsx +4 -4
  59. package/src/game-document/InstanceInspectorPicker.tsx +2 -2
  60. package/src/game-document/crowd-debug.ts +1 -1
  61. package/src/game-document/device-preview.ts +10 -11
  62. package/src/game-document/physics-debug.ts +1 -1
  63. package/src/generation/GenerationActivity.tsx +3 -3
  64. package/src/generation/generation-documents.tsx +5 -5
  65. package/src/generation/generation-jobs.ts +1 -1
  66. package/src/host/adapter-runtime-bindings.ts +96 -5
  67. package/src/host/authoring/babylon-authoring-adapter.ts +6 -6
  68. package/src/host/authoring/gesture-persist.ts +1 -1
  69. package/src/host/authoring/ingest-data-writer.ts +1 -1
  70. package/src/host/authoring/ingest-source-persistence.ts +4 -4
  71. package/src/host/authoring/mounted-authoring.ts +4 -4
  72. package/src/host/authoring/phaser-live-authoring-adapter.ts +4 -4
  73. package/src/host/authoring/pixi-authoring-adapter.ts +178 -31
  74. package/src/host/authoring/pixi-creatable-kinds.ts +62 -0
  75. package/src/host/authoring/pixi-creation-site-write-target.ts +2 -2
  76. package/src/host/authoring/pixi-live-write-target.ts +4 -4
  77. package/src/host/authoring/pixi-source-identity.ts +3 -3
  78. package/src/host/authoring/pixi-source-write-target.ts +1709 -0
  79. package/src/host/authoring/pixi-still-presentation.ts +1 -1
  80. package/src/host/authoring/pixi-structure-history.ts +2 -2
  81. package/src/host/authoring/pixi-transform-channels.ts +16 -14
  82. package/src/host/authoring/source-persistence-backend.ts +3 -3
  83. package/src/host/authoring/struct-write-pipe.ts +1 -1
  84. package/src/host/binding-resolver.ts +8 -9
  85. package/src/host/browser-transpile.ts +1 -1
  86. package/src/host/canvas-entry-runtime.ts +58 -47
  87. package/src/host/canvas-preview-frames.ts +482 -0
  88. package/src/host/components/CameraAuthoringOverlay.tsx +1 -1
  89. package/src/host/components/HeaderTelemetry.tsx +4 -4
  90. package/src/host/components/PixiIsolationSceneContent.tsx +11 -11
  91. package/src/host/components/ThreeIsolationSceneContent.tsx +3 -3
  92. package/src/host/components/frame-debugger-model.ts +2 -2
  93. package/src/host/components/header-telemetry-model.ts +2 -2
  94. package/src/host/components/scene-document.tsx +14 -14
  95. package/src/host/components/utility-view-state.ts +1 -1
  96. package/src/host/components/world-root-stage-binding.tsx +12 -12
  97. package/src/host/components/world-root-stage.ts +70 -49
  98. package/src/host/coverage/system-adapter-coverage.ts +3 -4
  99. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +9 -11
  100. package/src/host/document-preview-three.ts +1 -1
  101. package/src/host/entry-adjudication.ts +6 -6
  102. package/src/host/game-css-scope-transform.ts +4 -0
  103. package/src/host/game-realm-page.ts +1 -1
  104. package/src/host/gameplay-export.ts +25 -14
  105. package/src/host/gameplay-recording.ts +5 -5
  106. package/src/host/gated-globals.ts +2 -2
  107. package/src/host/history/json-history-resource.ts +1 -1
  108. package/src/host/projection/pixi.ts +24 -2
  109. package/src/host/r3f-entry-runtime.ts +65 -34
  110. package/src/host/react-mount-runtime.ts +7 -48
  111. package/src/host/realm-services.ts +1 -1
  112. package/src/host/roots/canvas-root.tsx +373 -0
  113. package/src/host/roots/r3f-root.tsx +473 -0
  114. package/src/host/roots/react-root.ts +9 -43
  115. package/src/host/served-bundle-runtime-modules.ts +3 -19
  116. package/src/host/server-log-bridge.ts +2 -2
  117. package/src/host/stories/mounted-story-viewport-source.ts +1 -1
  118. package/src/host/stories/pixi-story-model.ts +30 -0
  119. package/src/host/stories/story-media-captures.ts +46 -0
  120. package/src/host/stories/story-media-presence.ts +3 -3
  121. package/src/host/stories/story-pixi-preview.ts +408 -0
  122. package/src/host/stories/story-three-preview.ts +806 -0
  123. package/src/host/stories/three-story-captures.ts +35 -0
  124. package/src/host/story-three-preview-runtime.ts +56 -0
  125. package/src/host/use-active-performance-source.ts +2 -2
  126. package/src/host/viewport-pose-memory.ts +1 -1
  127. package/src/host/viewport-root-presentation.ts +6 -5
  128. package/src/ingest/active-ingest.ts +1 -1
  129. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +4 -4
  130. package/src/ingest/authoring/ingest-root-adapter.ts +8 -8
  131. package/src/ingest/deferred-ingest-play.ts +6 -6
  132. package/src/ingest/discovery-public-ingest.ts +2 -2
  133. package/src/ingest/ingest-boot-viewport.ts +2 -2
  134. package/src/ingest/ingest-canvas-scene-document.tsx +9 -9
  135. package/src/ingest/ingest-canvas-scene.ts +3 -3
  136. package/src/ingest/ingest-evidence-hook.ts +1 -1
  137. package/src/ingest/ingest-frame-snapshot.ts +1 -1
  138. package/src/ingest/ingest-play-control.ts +1 -1
  139. package/src/ingest/ingest-render-debug.ts +10 -10
  140. package/src/ingest/ingest-siblings.ts +13 -25
  141. package/src/ingest/module-mode.ts +14 -14
  142. package/src/ingest/mount-canvas-ingest-root.ts +21 -21
  143. package/src/ingest/mount-coverage.ts +2 -2
  144. package/src/ingest/mount-dom-ingest-root.ts +11 -11
  145. package/src/ingest/mount-ingest-root.ts +8 -8
  146. package/src/ingest/mount-three-ingest-root.ts +8 -8
  147. package/src/ingest/resolve-canvas.ts +1 -1
  148. package/src/ingest/served-html-boot.ts +1 -1
  149. package/src/ingest/surface-canvas.ts +1 -1
  150. package/src/ingest/unmount-ingest-root.ts +5 -5
  151. package/src/navmesh/navmesh-handler.ts +24 -16
  152. package/src/network/NetworkInspectorPanel.tsx +939 -37
  153. package/src/network/network-inspector-model.ts +20 -2
  154. package/src/play/play-log-events.ts +1 -1
  155. package/src/play/play-mode.ts +76 -133
  156. package/src/play/play-recording.ts +1 -1
  157. package/src/play/react-play-live-authoring.ts +3 -3
  158. package/src/play/run-selection.ts +93 -0
  159. package/src/play-bar/PlayBar.tsx +20 -39
  160. package/src/profiler/FrameDebuggerPanel.tsx +1 -1
  161. package/src/profiler/PerformancePanel.tsx +3 -3
  162. package/src/react/design-time-react-mount.ts +23 -65
  163. package/src/react/dom-authoring-adapter.ts +9 -9
  164. package/src/react/react-inspector-section.tsx +5 -5
  165. package/src/react/react-world-authoring-adapter.ts +11 -11
  166. package/src/react/story-documents/story-documents.tsx +9 -9
  167. package/src/react/ui-board-document.tsx +7 -7
  168. package/src/react/ui-component-board.ts +2 -2
  169. package/src/runtime/adapter/audio-meter.ts +21 -0
  170. package/src/runtime/adapter/first-party-audio-system.ts +230 -0
  171. package/src/runtime/adapter/ingest/contract-debug-adapter.ts +114 -0
  172. package/src/runtime/adapter/ingest/contract-system-adapters.ts +256 -0
  173. package/src/runtime/adapter/ingest/merge-debug-adapters.ts +197 -0
  174. package/src/runtime/adapter/ingest/observation-debug-adapter.ts +162 -0
  175. package/src/runtime/adapter/ingest/upstream-pin.ts +51 -0
  176. package/src/runtime/adapter/native-debug-module.ts +498 -0
  177. package/src/runtime/audio/bus-mixer.ts +161 -0
  178. package/src/runtime/audio/pose-guard.ts +80 -0
  179. package/src/runtime/core/frame-pacing.ts +126 -0
  180. package/src/runtime/core/game-loop.ts +225 -0
  181. package/src/runtime/core/game-scoped-slot.ts +28 -0
  182. package/src/runtime/core/seeded-random.ts +162 -0
  183. package/src/runtime/core/sim-clock.ts +391 -0
  184. package/src/runtime/core/system-runner.ts +269 -0
  185. package/src/runtime/core/types.ts +104 -0
  186. package/src/runtime/create-runtime.ts +1128 -0
  187. package/src/runtime/debug-bridge.ts +570 -0
  188. package/src/runtime/debug-registry.ts +899 -0
  189. package/src/runtime/dev/chrome-trace.ts +153 -0
  190. package/src/runtime/dev/instruments.ts +403 -0
  191. package/src/runtime/dev/logger.ts +119 -0
  192. package/src/runtime/dev/performance-profiler.ts +367 -0
  193. package/src/runtime/dev/register-render-vitals.ts +276 -0
  194. package/src/runtime/dev/render-census.ts +354 -0
  195. package/src/runtime/dev/render-debug-adapter.ts +218 -0
  196. package/src/runtime/dev/render-memory.ts +226 -0
  197. package/src/runtime/dev/render-vitals.ts +338 -0
  198. package/src/runtime/dev/static-batch-advisor.ts +188 -0
  199. package/src/runtime/dev/webgl-frame-capture.ts +366 -0
  200. package/src/runtime/dev/webgl-gpu-timer.ts +53 -0
  201. package/src/runtime/dev-build.ts +47 -0
  202. package/src/runtime/game.ts +1636 -0
  203. package/src/runtime/gameplay-rng-trap.ts +135 -0
  204. package/src/runtime/host-context.ts +64 -0
  205. package/src/runtime/input-router.ts +182 -0
  206. package/src/runtime/mount-manifest.ts +480 -0
  207. package/src/runtime/pixi/authoring.ts +706 -0
  208. package/src/runtime/pixi/ingest.ts +116 -0
  209. package/src/runtime/pixi/physics-registry.ts +49 -0
  210. package/src/runtime/pixi/render-pass-bracket.ts +117 -0
  211. package/src/runtime/pixi/scene-capture.ts +179 -0
  212. package/src/runtime/pixi/system-adapters.ts +69 -0
  213. package/src/runtime/playtest.ts +22 -0
  214. package/src/runtime/presentation.ts +141 -0
  215. package/src/runtime/render-control.ts +642 -0
  216. package/src/runtime/render-seed.ts +77 -0
  217. package/src/runtime/run-ticks-settled.ts +73 -0
  218. package/src/runtime/setup/setup-audio.ts +72 -0
  219. package/src/services/audio-pose-guard.ts +2 -2
  220. package/src/services/game-audio.ts +152 -0
  221. package/src/services/game-network.ts +767 -0
  222. package/src/services/game-physics.ts +334 -0
  223. package/src/state-watch/StateWatchPanel.tsx +1 -1
  224. package/src/three/authoring/camera-runtime-inspector-section.tsx +3 -2
  225. package/src/three/authoring/constraint-inspector-section.tsx +6 -5
  226. package/src/three/authoring/model-asset-inspector-section.tsx +7 -6
  227. package/src/three/authoring/oid-source-persistence.ts +7 -7
  228. package/src/three/authoring/r3f-design-session.ts +58 -54
  229. package/src/three/authoring/r3f-source-authoring-adapter.ts +95 -91
  230. package/src/three/authoring/reflection-probe-inspector-section.tsx +3 -2
  231. package/src/three/authoring/three-authoring-adapter.ts +29 -29
  232. package/src/three/component-verbs/extract-menu.ts +7 -6
  233. package/src/three/component-verbs/fork-menu.ts +7 -6
  234. package/src/three/component-verbs/internals-menu.ts +2 -2
  235. package/src/three/story-documents/three-story-documents.tsx +13 -13
  236. package/src/three/three-board/ThreeBoardDocument.tsx +13 -12
  237. package/src/three/three-board/board-scene.ts +6 -6
  238. package/src/three/three-board/three-component-board.ts +2 -2
  239. package/src/services/game-audio-unlock.ts +0 -48
@@ -34,14 +34,14 @@ import {
34
34
  isOccurrenceId,
35
35
  ownOidOf,
36
36
  rendersSameSourceElement,
37
- } from '@volter/editor-core/authoring/component-instance-root';
37
+ } from '@volter/editor-threejs/kit/authoring/component-instance-root';
38
38
  import { beginLiveGesture, endLiveGesture } from '@volter/editor-sdk/kit/live-gesture-lock';
39
39
  import { createStructWritePipe, type StructOpOptions } from '../../host/authoring/struct-write-pipe';
40
40
  import {
41
41
  CollapsedHierarchyView,
42
42
  readLocalTransform,
43
43
  StoreSelectionAdoption,
44
- } from '@volter/editor-core/authoring/three-projection-core';
44
+ } from '@volter/editor-threejs/kit/authoring/three-projection-core';
45
45
  import {
46
46
  clipboardOutcome,
47
47
  LIVE_ONLY_ACK,
@@ -51,15 +51,15 @@ import {
51
51
  type WriteAck,
52
52
  type WriteResolution,
53
53
  } from '@volter/editor-sdk/kit/write-pipe';
54
- import { componentStatesProvider } from '@volter/editor-core/component-states-registry';
55
- import { openProjectToolDocument } from '@volter/editor-core/components/project-tool-documents';
54
+ import { componentStatesProvider } from '@volter/editor-sdk/kit/component-states-registry';
55
+ import { openProjectToolDocument } from '@volter/editor-sdk/kit/components/project-tool-documents';
56
56
  import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
57
- import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
57
+ import type { EditorShellStore } from '@volter/editor-threejs/kit/editor-shell-store';
58
58
  import {
59
59
  replaceProjectSource,
60
60
  withProjectSourceHistory,
61
- } from '@volter/editor-core/history/source-history-backend';
62
- import { warnGuessedFromText } from '@volter/editor-core/inference-diagnostics';
61
+ } from '@volter/editor-sdk/kit/history/source-history-backend';
62
+ import { warnGuessedFromText } from '@volter/editor-sdk/kit/inference-diagnostics';
63
63
  import {
64
64
  extractedHint,
65
65
  extractNoBackendHint,
@@ -79,8 +79,8 @@ import {
79
79
  type SourceOidIdentity,
80
80
  sourceOidIdentity,
81
81
  ThreeProjector,
82
- } from '@volter/editor-core/projection/three';
83
- import { getStorageBackend } from '@volter/editor-core/storage/index';
82
+ } from '@volter/editor-threejs/kit/projection/three';
83
+ import { getStorageBackend } from '@volter/editor-sdk/kit/storage/index';
84
84
  import { showTransientHint } from '@volter/editor-sdk/kit/transient-hint';
85
85
  import {
86
86
  type ComponentPropSpec,
@@ -100,7 +100,7 @@ import type { ReparentChannel, ReparentRebase } from '@volter/editor-react/sourc
100
100
  import type {
101
101
  SourceWriteBackend,
102
102
  StructReparentContext,
103
- } from '@volter/editor-core/ui-source/source-write-backend';
103
+ } from '@volter/editor-sdk/kit/ui-source/source-write-backend';
104
104
  import {
105
105
  analyzeJsxAttributes,
106
106
  type DuplicateRewrite,
@@ -598,7 +598,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
598
598
  // session adopts this scene and `syncAdoptedObjectMap` keeps that index in
599
599
  // step — so picking reads the map the viewport itself draws from.
600
600
  this.projector = new ThreeProjector(this.identity, { pickScope: 'store-object-map' });
601
- this.writeBackend = withProjectSourceHistory(options.writeBackend, store.projectHistory);
601
+ this.writeBackend = withProjectSourceHistory(options.writeBackend, store.shell.projectHistory);
602
602
  this.capabilities = {
603
603
  transform: true,
604
604
  inspectorFields: true,
@@ -613,7 +613,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
613
613
  save: async () => undefined,
614
614
  destination: options.entryPath,
615
615
  lastError: () => {
616
- const error = store.projectHistory?.getSnapshot().lastError;
616
+ const error = store.shell.projectHistory?.getSnapshot().lastError;
617
617
  if (!error) return null;
618
618
  return error.code === 'apply-failed' ||
619
619
  error.code === 'compensation-failed' ||
@@ -624,7 +624,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
624
624
  };
625
625
  }
626
626
  this.selectionState = new StoreSelectionAdoption({
627
- store,
627
+ store: store.shell,
628
628
  owns: (id) => this.byId.has(id),
629
629
  initial: [this.documentNodeId],
630
630
  });
@@ -638,7 +638,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
638
638
  documentNodeId: this.documentNodeId,
639
639
  rootIds: this.definitionRootIds,
640
640
  });
641
- this.stories = componentStatesProvider('three', store, (id) => this.storyComponent(id));
641
+ this.stories = componentStatesProvider('three', store.shell, (id) => this.storyComponent(id));
642
642
  void this.refreshSourceState();
643
643
  }
644
644
 
@@ -772,7 +772,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
772
772
  // child subscriptions when `replaceChild` swaps this adapter in (it used
773
773
  // to bind them once at subscribe time, which is why this line carried a
774
774
  // note about not being able to rely on the seam).
775
- this.store.notifyIngestEdit();
775
+ this.store.shell.notifyIngestEdit();
776
776
  });
777
777
  }
778
778
 
@@ -790,9 +790,9 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
790
790
  // Keep selection inside the same authoritative index the hierarchy,
791
791
  // picker, and gizmo now consume; otherwise TransformControls can remain
792
792
  // attached to a ghost id after the object has disappeared from every row.
793
- const retainedSelection = [...this.store.selectedEntityIds].filter((id) => map.has(id));
794
- if (retainedSelection.length !== this.store.selectedEntityIds.size) {
795
- this.store.selectMultiple(retainedSelection);
793
+ const retainedSelection = [...this.store.shell.selectedEntityIds].filter((id) => map.has(id));
794
+ if (retainedSelection.length !== this.store.shell.selectedEntityIds.size) {
795
+ this.store.shell.selectMultiple(retainedSelection);
796
796
  }
797
797
  }
798
798
 
@@ -888,7 +888,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
888
888
  this.pendingCreatedSelection = {
889
889
  parentId,
890
890
  before: new Set(this.hierarchy.node(parentId)?.childIds ?? []),
891
- selectionAtWrite: new Set(this.store.selectedEntityIds),
891
+ selectionAtWrite: new Set(this.store.shell.selectedEntityIds),
892
892
  ...(afterId ? { afterId } : {}),
893
893
  };
894
894
  }
@@ -897,7 +897,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
897
897
  const pending = this.pendingCreatedSelection;
898
898
  this.pendingCreatedSelection = null;
899
899
  if (!pending) return;
900
- const current = this.store.selectedEntityIds;
900
+ const current = this.store.shell.selectedEntityIds;
901
901
  const unchanged =
902
902
  current.size === pending.selectionAtWrite.size &&
903
903
  [...current].every((id) => pending.selectionAtWrite.has(id));
@@ -905,11 +905,11 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
905
905
  const children = this.hierarchy.node(pending.parentId)?.childIds ?? [];
906
906
  const copy = pending.afterId ? this.childWrittenAfter(children, pending.afterId) : null;
907
907
  if (copy) {
908
- this.store.selectMultiple([copy]);
908
+ this.store.shell.selectMultiple([copy]);
909
909
  return;
910
910
  }
911
911
  const fresh = children.filter((id) => !pending.before.has(id));
912
- if (fresh.length > 0) this.store.selectMultiple(fresh);
912
+ if (fresh.length > 0) this.store.shell.selectMultiple(fresh);
913
913
  }
914
914
 
915
915
  /** Among `children`, the one whose callsite is the FIRST after `afterId`'s
@@ -969,7 +969,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
969
969
  this.oidIndex = nextIndex;
970
970
  this.sources = next;
971
971
  this.reflectionProbeAvailable = reflectionProbeAvailable;
972
- this.store.notifyIngestEdit();
972
+ this.store.shell.notifyIngestEdit();
973
973
  } catch {
974
974
  // Honest degradation: nodes stay live-projected (read-only) if the
975
975
  // index/source can't be fetched.
@@ -1107,7 +1107,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
1107
1107
  const tag = callsite?.tag ?? 'component';
1108
1108
  if (!oid || !definitionOid || !callsite) return forkUnavailableHint(tag);
1109
1109
  const backend = this.writeBackend;
1110
- const history = this.store.projectHistory;
1110
+ const history = this.store.shell.projectHistory;
1111
1111
  if (!backend?.forkComponent || !backend.readSource || !backend.applySource || !history) {
1112
1112
  return forkNoBackendHint(tag);
1113
1113
  }
@@ -1169,7 +1169,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
1169
1169
  const tag = callsite?.tag ?? 'element';
1170
1170
  if (!oid || !callsite) return extractUnavailableHint(tag);
1171
1171
  const backend = this.writeBackend;
1172
- const history = this.store.projectHistory;
1172
+ const history = this.store.shell.projectHistory;
1173
1173
  if (!backend?.extractComponent || !backend.readSource || !backend.applySource || !history) {
1174
1174
  return extractNoBackendHint(tag);
1175
1175
  }
@@ -1587,7 +1587,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
1587
1587
  object3D: (id) => {
1588
1588
  return this.transformObject(id);
1589
1589
  },
1590
- idForObject3D: (object) => this.idByObject.get(object) ?? null,
1590
+ idForObject3D: (object: THREE.Object3D) => this.idByObject.get(object) ?? null,
1591
1591
  };
1592
1592
 
1593
1593
  /** The same OID source address every guarded JSX write uses, exposed for
@@ -2130,7 +2130,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2130
2130
  private pipedSourceTokenWrite(write: () => Promise<boolean>): Promise<WriteAck> {
2131
2131
  return runWritePipe({
2132
2132
  resolve: (): WriteResolution =>
2133
- this.writeBackend && this.store.projectHistory
2133
+ this.writeBackend && this.store.shell.projectHistory
2134
2134
  ? {
2135
2135
  reaches: 'writer',
2136
2136
  anchorKind: 'construction-literal',
@@ -2386,7 +2386,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2386
2386
  if (channel === 'position') object.position.fromArray(edit.position);
2387
2387
  else if (channel === 'rotation') object.quaternion.fromArray(edit.quaternion);
2388
2388
  else object.scale.fromArray(edit.scale);
2389
- this.store.notifyIngestEdit();
2389
+ this.store.shell.notifyIngestEdit();
2390
2390
  };
2391
2391
 
2392
2392
  const backend = selectedBackend ?? this.writeBackend;
@@ -2467,7 +2467,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2467
2467
  } else {
2468
2468
  await run(backend);
2469
2469
  }
2470
- this.store.notifyIngestEdit();
2470
+ this.store.shell.notifyIngestEdit();
2471
2471
  return persisted;
2472
2472
  }
2473
2473
 
@@ -2689,35 +2689,31 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2689
2689
  * A mixed explicit+automatic body therefore degrades instead of binding a
2690
2690
  * source tag to the wrong native shape. */
2691
2691
  /**
2692
- * The physics adapter ONLY while a world is actually stepping.
2692
+ * A body's live colliders or joints, read for the Inspector.
2693
2693
  *
2694
- * The engine's slot refuses by name when no `<RapierPhysicsBridge>` is
2695
- * live, and that is right for its declared members: they are gesture-rate
2696
- * ACTIONS, so a fabricated empty would be a lie about a sim you just tried
2697
- * to edit (`world3d-react/rapier-physics-bridge.tsx`). The two binding
2698
- * readers below break that premise — they run from `properties()`, which
2699
- * the Inspector calls on EVERY RENDER — so selecting a physics object in
2700
- * edit mode threw the refusal up through React and took the whole editor
2701
- * surface down with it, which then swallowed the edits the human was
2702
- * making (runhuman pass 96: added jump pads "didn't add", a delete "doesn't
2703
- * delete", both actually present after a reload).
2704
- *
2705
- * So the presence question is asked POSITIVELY, before the call. A binding
2706
- * ties a source tag to a LIVE native handle; with nothing stepping there
2707
- * are no handles, and none is the true answer rather than a refusal. Every
2708
- * gesture-rate call keeps going straight at the slot and stays loud.
2694
+ * These run from `properties()`, which the Inspector calls on EVERY RENDER,
2695
+ * so a physics adapter that refuses a read (no world live yet, a game's own
2696
+ * adapter that throws) must yield no rows rather than take the editor surface
2697
+ * down with it (runhuman pass 96: a throw here swallowed the edits the human
2698
+ * was making). The design world's own `<Physics>` holds real colliders in
2699
+ * Edit even though it never steps, so the read is not gated on Play, the way
2700
+ * a selected body shows its collider in Unity's and Godot's editors.
2709
2701
  */
2710
- private steppingPhysics(): PhysicsAdapter | null {
2711
- if (this.store.playState === 'stopped') return null;
2712
- return this.options.physics?.() ?? null;
2702
+ private physicsRead<T>(read: (physics: PhysicsAdapter) => readonly T[] | undefined): T[] {
2703
+ const physics = this.options.physics?.();
2704
+ if (!physics) return [];
2705
+ try {
2706
+ return [...(read(physics) ?? [])];
2707
+ } catch {
2708
+ return [];
2709
+ }
2713
2710
  }
2714
2711
 
2715
2712
  private colliderBindingsOf(id: string): ColliderSourceBinding[] {
2716
2713
  const rigidBodyOid = this.rigidBodyOidOf(id);
2717
- const physics = this.steppingPhysics();
2718
- if (!rigidBodyOid || !physics?.colliders) return [];
2714
+ if (!rigidBodyOid) return [];
2719
2715
  const sourceOids = this.explicitColliderOids(rigidBodyOid);
2720
- const snapshots = [...physics.colliders(id)];
2716
+ const snapshots = this.physicsRead((physics) => physics.colliders?.(id));
2721
2717
  if (sourceOids.length === 0 || sourceOids.length !== snapshots.length) return [];
2722
2718
  const bindings: ColliderSourceBinding[] = [];
2723
2719
  for (let index = 0; index < sourceOids.length; index += 1) {
@@ -2769,12 +2765,21 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2769
2765
  : binding.sourceTag === 'CapsuleCollider'
2770
2766
  ? ['Half height', 'Radius']
2771
2767
  : ['Radius'];
2768
+ const args = this.attrsOfOid(binding.sourceOid)?.find((attr) => attr.name === 'args');
2769
+ const readonlyReason = binding.writable
2770
+ ? null
2771
+ : !this.writeBackend?.writeProp
2772
+ ? 'Source writes are unavailable in this session.'
2773
+ : !args?.isLiteral
2774
+ ? `\`<${binding.sourceTag} args>\` is an expression in source, not a number list; edit it there.`
2775
+ : 'This size is computed while the game runs; edit it in source.';
2772
2776
  return labels.map((label, index) => ({
2773
2777
  path: `${COLLIDER_ARG_PATH_PREFIX}${encodeURIComponent(binding.sourceOid)}.arg.${index}`,
2774
2778
  label,
2775
2779
  type: 'number' as const,
2776
2780
  group: humanizeIdentifier(binding.sourceTag),
2777
2781
  readonly: !binding.writable,
2782
+ ...(readonlyReason ? { readonlyReason } : {}),
2778
2783
  }));
2779
2784
  }
2780
2785
 
@@ -2784,9 +2789,8 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2784
2789
  private jointBindingsOf(id: string): JointSourceBinding[] {
2785
2790
  const rigidBodyOid = this.rigidBodyOidOf(id);
2786
2791
  const entry = rigidBodyOid ? this.oidIndex.get(rigidBodyOid) : undefined;
2787
- const physics = this.steppingPhysics();
2788
- if (!rigidBodyOid || !entry?.jointBindings || !physics?.joints) return [];
2789
- const snapshots = [...physics.joints(id)];
2792
+ if (!rigidBodyOid || !entry?.jointBindings) return [];
2793
+ const snapshots = this.physicsRead((physics) => physics.joints?.(id));
2790
2794
  if (entry.jointBindings.length !== snapshots.length) return [];
2791
2795
  const result: JointSourceBinding[] = [];
2792
2796
  for (let index = 0; index < entry.jointBindings.length; index += 1) {
@@ -2803,7 +2807,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2803
2807
  !!source.paramRanges &&
2804
2808
  !!this.writeBackend?.readSource &&
2805
2809
  !!this.writeBackend.applySource &&
2806
- !!this.store.projectHistory,
2810
+ !!this.store.shell.projectHistory,
2807
2811
  });
2808
2812
  }
2809
2813
  return result;
@@ -2976,7 +2980,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
2976
2980
  () =>
2977
2981
  !!this.writeBackend?.readSource &&
2978
2982
  !!this.writeBackend.applySource &&
2979
- !!this.store.projectHistory,
2983
+ !!this.store.shell.projectHistory,
2980
2984
  ),
2981
2985
  ),
2982
2986
  });
@@ -3059,7 +3063,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3059
3063
  rawValue: number,
3060
3064
  ): Promise<boolean> {
3061
3065
  const backend = this.writeBackend;
3062
- const history = this.store.projectHistory;
3066
+ const history = this.store.shell.projectHistory;
3063
3067
  const token = binding.source.fields[field];
3064
3068
  const source = this.sources.get(binding.sourceFile);
3065
3069
  if (
@@ -3077,7 +3081,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3077
3081
  const value = normalizeParticleField(field, rawValue);
3078
3082
  const previous = (binding.shape as unknown as Record<string, unknown>)[field];
3079
3083
  previewParticleEdit({ binding, field, value });
3080
- this.store.notifyIngestEdit();
3084
+ this.store.shell.notifyIngestEdit();
3081
3085
  const next = `${source.slice(0, token.start)}${fmt(value)}${source.slice(token.end)}`;
3082
3086
  try {
3083
3087
  await replaceProjectSource(backend, history, {
@@ -3090,7 +3094,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3090
3094
  return true;
3091
3095
  } catch (error) {
3092
3096
  (binding.shape as unknown as Record<string, unknown>)[field] = previous;
3093
- this.store.notifyIngestEdit();
3097
+ this.store.shell.notifyIngestEdit();
3094
3098
  throw error;
3095
3099
  }
3096
3100
  }
@@ -3108,7 +3112,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3108
3112
  const canWrite =
3109
3113
  !!this.writeBackend?.readSource &&
3110
3114
  !!this.writeBackend.applySource &&
3111
- !!this.store.projectHistory;
3115
+ !!this.store.shell.projectHistory;
3112
3116
  return lods.map((lod, index) => {
3113
3117
  const sourceOid = ownOidOf(lod) ?? authoringOidOf(lod);
3114
3118
  const entry = sourceOid ? this.oidIndex.get(sourceOid) : undefined;
@@ -3234,7 +3238,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3234
3238
  rollback: () => void,
3235
3239
  ): Promise<boolean> {
3236
3240
  const backend = this.writeBackend;
3237
- const history = this.store.projectHistory;
3241
+ const history = this.store.shell.projectHistory;
3238
3242
  const file = binding.sourceFile;
3239
3243
  const source = file ? this.sources.get(file) : undefined;
3240
3244
  if (
@@ -3249,7 +3253,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3249
3253
  return false;
3250
3254
  }
3251
3255
  preview();
3252
- this.store.notifyIngestEdit();
3256
+ this.store.shell.notifyIngestEdit();
3253
3257
  const next = `${source.slice(0, token.start)}${fmt(value)}${source.slice(token.end)}`;
3254
3258
  try {
3255
3259
  await replaceProjectSource(backend, history, { file, source: next, label });
@@ -3258,7 +3262,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3258
3262
  return true;
3259
3263
  } catch (error) {
3260
3264
  rollback();
3261
- this.store.notifyIngestEdit();
3265
+ this.store.shell.notifyIngestEdit();
3262
3266
  throw error;
3263
3267
  }
3264
3268
  }
@@ -3311,7 +3315,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3311
3315
  params: readonly R3fJointLiteral[],
3312
3316
  ): Promise<boolean> {
3313
3317
  const backend = this.writeBackend;
3314
- const history = this.store.projectHistory;
3318
+ const history = this.store.shell.projectHistory;
3315
3319
  const source = this.sources.get(binding.sourceFile);
3316
3320
  const before = binding.source.params;
3317
3321
  const ranges = binding.source.paramRanges;
@@ -3490,7 +3494,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3490
3494
  !token ||
3491
3495
  !this.writeBackend?.readSource ||
3492
3496
  !this.writeBackend.applySource ||
3493
- !this.store.projectHistory
3497
+ !this.store.shell.projectHistory
3494
3498
  ) {
3495
3499
  return false;
3496
3500
  }
@@ -3797,7 +3801,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3797
3801
  rollback: () => void,
3798
3802
  ): Promise<boolean> {
3799
3803
  const backend = this.writeBackend;
3800
- const history = this.store.projectHistory;
3804
+ const history = this.store.shell.projectHistory;
3801
3805
  const text = this.sources.get(source.file);
3802
3806
  if (
3803
3807
  !backend ||
@@ -3817,7 +3821,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3817
3821
  replacement = fmt(value);
3818
3822
  }
3819
3823
  preview();
3820
- this.store.notifyIngestEdit();
3824
+ this.store.shell.notifyIngestEdit();
3821
3825
  const next = `${text.slice(0, token.start)}${replacement}${text.slice(token.end)}`;
3822
3826
  try {
3823
3827
  await replaceProjectSource(backend, history, { file: source.file, source: next, label });
@@ -3826,7 +3830,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3826
3830
  return true;
3827
3831
  } catch (error) {
3828
3832
  rollback();
3829
- this.store.notifyIngestEdit();
3833
+ this.store.shell.notifyIngestEdit();
3830
3834
  throw error;
3831
3835
  }
3832
3836
  }
@@ -3900,7 +3904,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3900
3904
  const echoKey = this.echoKey(id, 'visible');
3901
3905
  object.visible = value;
3902
3906
  this.valueEcho.set(echoKey, value);
3903
- this.store.notifyIngestEdit();
3907
+ this.store.shell.notifyIngestEdit();
3904
3908
  try {
3905
3909
  const result = await backend.writeProp(oid, 'visible', this.serializeValue(value), {
3906
3910
  addIfMissing: true,
@@ -3909,7 +3913,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3909
3913
  if (result.dynamic) this.dynamicPaths.add(echoKey);
3910
3914
  object.visible = previous;
3911
3915
  this.valueEcho.delete(echoKey);
3912
- this.store.notifyIngestEdit();
3916
+ this.store.shell.notifyIngestEdit();
3913
3917
  console.warn(
3914
3918
  `[R3fSourceAuthoringAdapter] visibility write refused for oid "${oid}": ` +
3915
3919
  `${result.dynamic ? 'dynamic expression (guarded)' : (result.error ?? 'no change')} — reverting.`,
@@ -3918,7 +3922,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3918
3922
  } catch (error) {
3919
3923
  object.visible = previous;
3920
3924
  this.valueEcho.delete(echoKey);
3921
- this.store.notifyIngestEdit();
3925
+ this.store.shell.notifyIngestEdit();
3922
3926
  console.warn(
3923
3927
  `[R3fSourceAuthoringAdapter] visibility write failed for oid "${oid}": ${String(error)} — reverting.`,
3924
3928
  );
@@ -3942,7 +3946,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
3942
3946
  );
3943
3947
  if (!field || field.type === 'asset') return;
3944
3948
  applyTypedField(object, firstMaterial(object), field, value);
3945
- this.store.notifyIngestEdit();
3949
+ this.store.shell.notifyIngestEdit();
3946
3950
  },
3947
3951
  properties: (id): PropertyDescriptor[] => {
3948
3952
  if (id === this.documentNodeId) {
@@ -4147,7 +4151,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4147
4151
  if (path === 'locked') {
4148
4152
  if (value) this.lockedIds.add(id);
4149
4153
  else this.lockedIds.delete(id);
4150
- this.store.notifyIngestEdit();
4154
+ this.store.shell.notifyIngestEdit();
4151
4155
  return;
4152
4156
  }
4153
4157
  const typedField = typedFieldForPath(
@@ -4395,7 +4399,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4395
4399
  this.valueEcho.delete(this.echoKey(id, path));
4396
4400
  const res = await this.writeBackend.removeProp(oid, prop);
4397
4401
  if (!res.changed) {
4398
- this.store.notifyIngestEdit();
4402
+ this.store.shell.notifyIngestEdit();
4399
4403
  console.warn(
4400
4404
  `[R3fSourceAuthoringAdapter] revert refused/no-op for oid "${oid}" prop "${prop}": ` +
4401
4405
  `${res.dynamic ? 'dynamic expression (guarded)' : (res.error ?? 'no change')}`,
@@ -4427,7 +4431,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4427
4431
  }
4428
4432
  const echoKey = this.echoKey(id, path);
4429
4433
  this.valueEcho.set(echoKey, value);
4430
- this.store.notifyIngestEdit();
4434
+ this.store.shell.notifyIngestEdit();
4431
4435
  let res: Awaited<ReturnType<NonNullable<SourceWriteBackend['writeProp']>>>;
4432
4436
  try {
4433
4437
  res = await this.writeBackend.writeProp(oid, prop, this.serializeValue(value), {
@@ -4435,7 +4439,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4435
4439
  });
4436
4440
  } catch (error) {
4437
4441
  this.valueEcho.delete(echoKey);
4438
- this.store.notifyIngestEdit();
4442
+ this.store.shell.notifyIngestEdit();
4439
4443
  console.warn(
4440
4444
  `[R3fSourceAuthoringAdapter] prop write failed for oid "${oid}" prop "${prop}": ${String(error)}`,
4441
4445
  );
@@ -4444,7 +4448,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4444
4448
  if (!res.changed) {
4445
4449
  this.valueEcho.delete(echoKey);
4446
4450
  if (res.dynamic) this.dynamicPaths.add(echoKey);
4447
- this.store.notifyIngestEdit();
4451
+ this.store.shell.notifyIngestEdit();
4448
4452
  console.warn(
4449
4453
  `[R3fSourceAuthoringAdapter] prop write refused/no-op for oid "${oid}" prop "${prop}": ` +
4450
4454
  `${res.dynamic ? 'dynamic expression (guarded)' : (res.error ?? 'no change')}`,
@@ -4470,7 +4474,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4470
4474
  }
4471
4475
  const echoKey = `${id}|${path}`;
4472
4476
  this.valueEcho.set(echoKey, value);
4473
- this.store.notifyIngestEdit();
4477
+ this.store.shell.notifyIngestEdit();
4474
4478
  let res: Awaited<ReturnType<NonNullable<SourceWriteBackend['writeProp']>>>;
4475
4479
  try {
4476
4480
  res = await this.writeBackend.writeProp(oid, prop, this.serializeValue(value), {
@@ -4488,7 +4492,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4488
4492
  });
4489
4493
  } catch (error) {
4490
4494
  this.valueEcho.delete(echoKey);
4491
- this.store.notifyIngestEdit();
4495
+ this.store.shell.notifyIngestEdit();
4492
4496
  console.warn(
4493
4497
  `[R3fSourceAuthoringAdapter] prop write failed for oid "${oid}" prop "${prop}": ${String(error)}`,
4494
4498
  );
@@ -4497,7 +4501,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4497
4501
  if (!res.changed) {
4498
4502
  this.valueEcho.delete(echoKey);
4499
4503
  if (res.dynamic) this.dynamicPaths.add(echoKey);
4500
- this.store.notifyIngestEdit();
4504
+ this.store.shell.notifyIngestEdit();
4501
4505
  console.warn(
4502
4506
  `[R3fSourceAuthoringAdapter] prop write refused/no-op for oid "${oid}" prop "${prop}": ` +
4503
4507
  `${res.dynamic ? 'dynamic expression (guarded)' : (res.error ?? 'no change')}`,
@@ -4620,7 +4624,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4620
4624
  const applied = applyTypedField(object, material, field, value);
4621
4625
  if (applied !== null) {
4622
4626
  this.valueEcho.set(`${id}|${field.path}`, readTypedField(object, material, field));
4623
- this.store.notifyIngestEdit();
4627
+ this.store.shell.notifyIngestEdit();
4624
4628
  }
4625
4629
  return runWritePipe({
4626
4630
  resolve: (): WriteResolution =>
@@ -4656,7 +4660,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4656
4660
  const before = readTypedField(object, material, field);
4657
4661
  const applied = applyTypedField(object, material, field, value);
4658
4662
  if (applied === null) return false;
4659
- this.store.notifyIngestEdit();
4663
+ this.store.shell.notifyIngestEdit();
4660
4664
  const wrote = await this.writeJsxProp(
4661
4665
  id,
4662
4666
  `${JSX_PATH_PREFIX}${routedProp}`,
@@ -4665,7 +4669,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4665
4669
  );
4666
4670
  if (!wrote && before !== null && before !== undefined) {
4667
4671
  applyTypedField(object, material, field, before);
4668
- this.store.notifyIngestEdit();
4672
+ this.store.shell.notifyIngestEdit();
4669
4673
  }
4670
4674
  return wrote;
4671
4675
  }
@@ -4683,7 +4687,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4683
4687
  if (applied === null) return false;
4684
4688
  const echoKey = `${id}|${field.path}`;
4685
4689
  this.valueEcho.set(echoKey, readTypedField(object, material, field));
4686
- this.store.notifyIngestEdit();
4690
+ this.store.shell.notifyIngestEdit();
4687
4691
  let res: Awaited<ReturnType<NonNullable<SourceWriteBackend['writeProp']>>>;
4688
4692
  try {
4689
4693
  res = await this.writeBackend.writeProp(oid, field.prop, this.serializeValue(applied), {
@@ -4692,7 +4696,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4692
4696
  } catch (error) {
4693
4697
  this.valueEcho.delete(echoKey);
4694
4698
  await this.refreshSourceState();
4695
- this.store.notifyIngestEdit();
4699
+ this.store.shell.notifyIngestEdit();
4696
4700
  console.warn(
4697
4701
  `[R3fSourceAuthoringAdapter] typed "${field.prop}" write failed for oid "${oid}": ${String(error)}`,
4698
4702
  );
@@ -4723,7 +4727,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
4723
4727
  // next remount disagreed — runhuman pass 41). The narration goes to the
4724
4728
  // EDITOR console: a raw console.warn is invisible in the product.
4725
4729
  if (before !== null && before !== undefined) applyTypedField(object, material, field, before);
4726
- this.store.notifyIngestEdit();
4730
+ this.store.shell.notifyIngestEdit();
4727
4731
  editorConsole.warn(
4728
4732
  `“${field.prop}” on “${this.hierarchy.node(id)?.label ?? id}” is ${
4729
4733
  res.dynamic
@@ -5786,7 +5790,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
5786
5790
  return false;
5787
5791
  }
5788
5792
  if (res.warning) showTransientHint(res.warning);
5789
- this.store.notifyIngestEdit();
5793
+ this.store.shell.notifyIngestEdit();
5790
5794
  return true;
5791
5795
  },
5792
5796
  'reparent',
@@ -5808,7 +5812,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
5808
5812
  report: (message) => console.warn(`[R3fSourceAuthoringAdapter] ${message}`),
5809
5813
  noWriterReason: NO_SOURCE_WRITER_REASON,
5810
5814
  backend: () => this.writeBackend,
5811
- onChanged: () => this.store.notifyIngestEdit(),
5815
+ onChanged: () => this.store.shell.notifyIngestEdit(),
5812
5816
  });
5813
5817
 
5814
5818
  /**
@@ -5894,8 +5898,8 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
5894
5898
  ack: Promise<WriteAck>,
5895
5899
  ): Promise<WriteAck> {
5896
5900
  const removed = new Set(ids);
5897
- const wasSelected = [...this.store.selectedEntityIds].some((id) => removed.has(id));
5898
- if (wasSelected) this.store.selectMultiple([]);
5901
+ const wasSelected = [...this.store.shell.selectedEntityIds].some((id) => removed.has(id));
5902
+ if (wasSelected) this.store.shell.selectMultiple([]);
5899
5903
  return ack;
5900
5904
  }
5901
5905
 
@@ -5923,7 +5927,7 @@ export class R3fSourceAuthoringAdapter implements AuthoringAdapter {
5923
5927
  }
5924
5928
 
5925
5929
  subscribe(listener: () => void): () => void {
5926
- return this.store.subscribe(listener);
5930
+ return this.store.shell.subscribe(listener);
5927
5931
  }
5928
5932
 
5929
5933
  get documentId(): string {
@@ -1,9 +1,10 @@
1
- import { useThreeEditorStore } from '@volter/editor-core/editor-runtime';
1
+ import { threeObject } from '@volter/editor-threejs/adapter/three-contract';
2
2
  import type { InspectorSectionProps } from '@volter/editor-sdk/kit/inspector-section-registry';
3
3
  import type { AuthoringAdapter, EditorNode } from '@volter/editor-project/adapter';
4
4
  import { type ReflectionProbeSnapshot, reflectionProbeOf } from '@volter/threejs-runtime/adapter/reflection-probe';
5
5
  import { Button, EditorBanner, FieldGroup, FieldRow, Text } from '@volter/editor-sdk/widgets';
6
6
  import { useSyncExternalStore } from 'react';
7
+ import { useThreeEditorStore } from '@volter/editor-threejs/kit/three-state';
7
8
 
8
9
  export function matches(node: EditorNode | null, adapter: AuthoringAdapter): boolean {
9
10
  void adapter;
@@ -22,7 +23,7 @@ const EMPTY_SNAPSHOT: ReflectionProbeSnapshot = { status: 'idle', lastCapturedAt
22
23
  export function ReflectionProbeCaptureSection({ adapter, nodeId }: InspectorSectionProps) {
23
24
  const store = useThreeEditorStore();
24
25
  const object = nodeId
25
- ? (store.objectMap.get(nodeId) ?? adapter.hierarchy.object3D?.(nodeId))
26
+ ? (store.objectMap.get(nodeId) ?? threeObject(adapter.hierarchy, nodeId))
26
27
  : null;
27
28
  const probe = reflectionProbeOf(object);
28
29
  const snapshot = useSyncExternalStore(