@volter/editor-core 0.5.57

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 (719) hide show
  1. package/BUNDLED_NOTICES +1527 -0
  2. package/LICENSE +686 -0
  3. package/LICENSE-APACHE +202 -0
  4. package/NOTICE +18 -0
  5. package/README.md +24 -0
  6. package/dist/build/chunk-JS4D4XZ3.js +175 -0
  7. package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
  8. package/dist/build/vite-plugin-product-contributions.js +100 -0
  9. package/dist/build/vite-plugin-product-contributions.js.map +7 -0
  10. package/dist/build/vite-plugin-shared-react.js +25 -0
  11. package/dist/build/vite-plugin-shared-react.js.map +7 -0
  12. package/dist/build/vite-plugin-shared-three.js +86 -0
  13. package/dist/build/vite-plugin-shared-three.js.map +7 -0
  14. package/dist/server/chunk-KMJC7AGO.js +98 -0
  15. package/dist/server/chunk-KMJC7AGO.js.map +7 -0
  16. package/dist/server/chunk-PSILUMGS.js +46 -0
  17. package/dist/server/chunk-PSILUMGS.js.map +7 -0
  18. package/dist/server/frame-proxy.js +255 -0
  19. package/dist/server/frame-proxy.js.map +7 -0
  20. package/dist/server/open-browser.js +53 -0
  21. package/dist/server/open-browser.js.map +7 -0
  22. package/dist/server/process-shutdown.js +127 -0
  23. package/dist/server/process-shutdown.js.map +7 -0
  24. package/dist/server/session-registry.js +141 -0
  25. package/dist/server/session-registry.js.map +7 -0
  26. package/dist/server/spawn-opener.js +11 -0
  27. package/dist/server/spawn-opener.js.map +7 -0
  28. package/dist/server/worktree-identity.js +11 -0
  29. package/dist/server/worktree-identity.js.map +7 -0
  30. package/dist-server/packaged.mjs +88816 -0
  31. package/package.json +118 -0
  32. package/scripts/build-plugins.mjs +14 -0
  33. package/scripts/build-server.mjs +26 -0
  34. package/scripts/build-session.mjs +9 -0
  35. package/server/account-credentials.ts +60 -0
  36. package/server/account-service.ts +1434 -0
  37. package/server/adapter-region-includes.ts +47 -0
  38. package/server/asset-catalog-v2.ts +175 -0
  39. package/server/asset-history-snapshots.ts +196 -0
  40. package/server/asset-ledger-store.ts +195 -0
  41. package/server/asset-library-routes.ts +1595 -0
  42. package/server/blender-wasm-artifact.ts +430 -0
  43. package/server/boot-timings.ts +106 -0
  44. package/server/canonical-path.ts +50 -0
  45. package/server/checkout-workspace-preflight.ts +349 -0
  46. package/server/cloud-asset-catalog.ts +158 -0
  47. package/server/coding-inference-launch.ts +237 -0
  48. package/server/collaboration-account-client.ts +202 -0
  49. package/server/collaboration-attribution.ts +122 -0
  50. package/server/collaboration-session.ts +934 -0
  51. package/server/comfyui-bridge.ts +248 -0
  52. package/server/console-ledger.ts +499 -0
  53. package/server/creation-site-transform.ts +304 -0
  54. package/server/creation-site-write.ts +648 -0
  55. package/server/data-file-serialize.ts +158 -0
  56. package/server/editor-brand-html.ts +72 -0
  57. package/server/editor-control-socket.ts +366 -0
  58. package/server/editor-server-options.ts +190 -0
  59. package/server/editor-server.ts +1483 -0
  60. package/server/editor-sse.ts +352 -0
  61. package/server/engine-provenance.ts +169 -0
  62. package/server/engine-source-restart.ts +117 -0
  63. package/server/frame-bridge.ts +115 -0
  64. package/server/frame-proxy.ts +490 -0
  65. package/server/frame-workbench.ts +259 -0
  66. package/server/frontend-handoff.ts +229 -0
  67. package/server/game-globals-shadow.ts +113 -0
  68. package/server/gameplay-session-retention.ts +149 -0
  69. package/server/gameplay-sessions.ts +123 -0
  70. package/server/generation-jobs.ts +201 -0
  71. package/server/generation-reconciler.ts +137 -0
  72. package/server/generative-execution-context.ts +59 -0
  73. package/server/git-workflow.ts +612 -0
  74. package/server/harness-chat-caller.ts +36 -0
  75. package/server/harness-chat-service.ts +1681 -0
  76. package/server/idle-shutdown.ts +170 -0
  77. package/server/js-profiling-policy.ts +52 -0
  78. package/server/launcher-settings.ts +84 -0
  79. package/server/local-asset-catalog.ts +410 -0
  80. package/server/managed-account-defaults.ts +22 -0
  81. package/server/mock-control-plane.ts +540 -0
  82. package/server/model-import-conversion.ts +345 -0
  83. package/server/native-credential-store.ts +162 -0
  84. package/server/open-browser.ts +118 -0
  85. package/server/packaged.ts +1192 -0
  86. package/server/play-stall.ts +126 -0
  87. package/server/process-shutdown.ts +218 -0
  88. package/server/product-presets.ts +55 -0
  89. package/server/project-build-artifact.ts +95 -0
  90. package/server/project-components.ts +100 -0
  91. package/server/project-dependency-invalidation.ts +114 -0
  92. package/server/project-file-scan.ts +235 -0
  93. package/server/project-hmr-files.ts +215 -0
  94. package/server/project-install-roots.ts +210 -0
  95. package/server/project-kinds.ts +71 -0
  96. package/server/project-mcp-servers.ts +82 -0
  97. package/server/project-module-freshness.ts +109 -0
  98. package/server/project-module-instance.ts +375 -0
  99. package/server/project-optimize-deps-entries.ts +827 -0
  100. package/server/project-output-writer.ts +679 -0
  101. package/server/project-package-origin.ts +63 -0
  102. package/server/project-root-surface.ts +831 -0
  103. package/server/project-scratch-path.ts +47 -0
  104. package/server/project-script-hmr.ts +619 -0
  105. package/server/project-serving-plugins.ts +236 -0
  106. package/server/project-tools.ts +653 -0
  107. package/server/project-validation.ts +250 -0
  108. package/server/project-verbs.ts +127 -0
  109. package/server/project-view.ts +52 -0
  110. package/server/project-watch.ts +1134 -0
  111. package/server/project-work-coordinator.ts +288 -0
  112. package/server/provider-credentials.ts +331 -0
  113. package/server/recent-projects-store.ts +98 -0
  114. package/server/redact-secrets.ts +71 -0
  115. package/server/repository-presence.ts +267 -0
  116. package/server/routes/account.ts +357 -0
  117. package/server/routes/agents.ts +60 -0
  118. package/server/routes/assets.ts +154 -0
  119. package/server/routes/build.ts +13 -0
  120. package/server/routes/collaboration.ts +595 -0
  121. package/server/routes/configurations.ts +419 -0
  122. package/server/routes/context.ts +264 -0
  123. package/server/routes/control-plane.ts +1811 -0
  124. package/server/routes/logs.ts +272 -0
  125. package/server/routes/project-identity.ts +302 -0
  126. package/server/routes/project-open.ts +429 -0
  127. package/server/routes/project-source.ts +686 -0
  128. package/server/routes/project-state.ts +383 -0
  129. package/server/routes/relay.ts +1029 -0
  130. package/server/routes/route-helpers.ts +29 -0
  131. package/server/routes/served-modules.ts +138 -0
  132. package/server/routes/session-tabs.ts +196 -0
  133. package/server/routes/settings.ts +121 -0
  134. package/server/routes/share-control.ts +486 -0
  135. package/server/routes/themes.ts +116 -0
  136. package/server/routes/tools.ts +230 -0
  137. package/server/routes/worktrees.ts +595 -0
  138. package/server/scoped-game-css.ts +461 -0
  139. package/server/server-utils.ts +1194 -0
  140. package/server/session-product.ts +112 -0
  141. package/server/session-registry.ts +230 -0
  142. package/server/share-claims.ts +138 -0
  143. package/server/share-host.ts +526 -0
  144. package/server/share-session-gateway.ts +1362 -0
  145. package/server/share-tunnel.ts +123 -0
  146. package/server/spawn-opener.ts +74 -0
  147. package/server/support/play/log-format.ts +76 -0
  148. package/server/support/play/session-record.ts +199 -0
  149. package/server/support/project/build-discipline.ts +718 -0
  150. package/server/support/project/inspection-node.ts +119 -0
  151. package/server/support/project/log-naming.ts +54 -0
  152. package/server/support/project/provenance.ts +290 -0
  153. package/server/support/project/run-name.ts +18 -0
  154. package/server/support/project/session-journal.ts +830 -0
  155. package/server/support/project/shared.ts +327 -0
  156. package/server/tab-bootstrap.ts +62 -0
  157. package/server/tab-heartbeat.ts +477 -0
  158. package/server/tab-lifecycle.ts +550 -0
  159. package/server/tab-presence.ts +1508 -0
  160. package/server/team-agent-mirror.ts +95 -0
  161. package/server/twin-auth.ts +138 -0
  162. package/server/vendored-lock-recorder.ts +968 -0
  163. package/server/worktree-identity.ts +121 -0
  164. package/server/worktree-management.ts +398 -0
  165. package/server/worktree-retention.d.mts +13 -0
  166. package/server/worktree-retention.mjs +205 -0
  167. package/src/EditorContext.tsx +169 -0
  168. package/src/account.ts +333 -0
  169. package/src/action-registry.ts +532 -0
  170. package/src/active-product.ts +74 -0
  171. package/src/active-project.ts +155 -0
  172. package/src/adapter-editor-config.ts +25 -0
  173. package/src/adapter-observation.ts +49 -0
  174. package/src/animation/stage-transport.ts +379 -0
  175. package/src/animation/three-clips-subject.ts +172 -0
  176. package/src/api/asset-library-wire.ts +45 -0
  177. package/src/api/assets.ts +365 -0
  178. package/src/api/base.ts +10 -0
  179. package/src/api/build.ts +99 -0
  180. package/src/api/git-wire.ts +56 -0
  181. package/src/api/logs.ts +92 -0
  182. package/src/api/project-identity.ts +74 -0
  183. package/src/api/project-open.ts +355 -0
  184. package/src/api/project-source.ts +162 -0
  185. package/src/api/project-state.ts +107 -0
  186. package/src/api/relay.ts +268 -0
  187. package/src/api/settings.ts +36 -0
  188. package/src/api/themes.ts +45 -0
  189. package/src/api/worktrees.ts +257 -0
  190. package/src/asset-compare-core.ts +171 -0
  191. package/src/asset-compare.ts +294 -0
  192. package/src/asset-editor-context.tsx +100 -0
  193. package/src/asset-events.ts +97 -0
  194. package/src/asset-inspector-actions.ts +87 -0
  195. package/src/asset-preview-framing.ts +357 -0
  196. package/src/asset-preview.ts +2802 -0
  197. package/src/asset-selection-viewer-registry.ts +113 -0
  198. package/src/asset-selection.ts +133 -0
  199. package/src/asset-workflow/asset-capabilities.ts +344 -0
  200. package/src/asset-workflow/asset-import-jobs.ts +106 -0
  201. package/src/asset-workflow/asset-ledger-backend.ts +126 -0
  202. package/src/asset-workflow/asset-ledger.ts +156 -0
  203. package/src/asset-workflow/asset-materialization-report.ts +140 -0
  204. package/src/asset-workflow/asset-pack-manifest.ts +320 -0
  205. package/src/asset-workflow/asset-types.ts +142 -0
  206. package/src/asset-workflow/asset-workflow-quality.ts +61 -0
  207. package/src/asset-workflow/audio-preview-player.ts +193 -0
  208. package/src/asset-workflow/audio-waveform.ts +22 -0
  209. package/src/asset-workflow/cloud-asset-client.ts +263 -0
  210. package/src/asset-workflow/folder-preview.ts +345 -0
  211. package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
  212. package/src/asset-workflow/image-view-scale.ts +32 -0
  213. package/src/asset-workflow/import-contract.ts +124 -0
  214. package/src/asset-workflow/ledger-write-lock.ts +244 -0
  215. package/src/asset-workflow/model-inspection.ts +818 -0
  216. package/src/asset-workflow/pixi-spritesheet.ts +197 -0
  217. package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
  218. package/src/asset-workflow/project-asset-commands.ts +23 -0
  219. package/src/asset-workflow/project-asset-health.ts +139 -0
  220. package/src/asset-workflow/project-asset-operations.ts +154 -0
  221. package/src/asset-workflow/project-asset-roots.ts +68 -0
  222. package/src/asset-workflow/project-content.ts +288 -0
  223. package/src/asset-workflow/project-source-index.ts +550 -0
  224. package/src/asset-workflow/thumbnail-system.ts +256 -0
  225. package/src/authoring/active-adapter.ts +199 -0
  226. package/src/authoring/active-systems.ts +422 -0
  227. package/src/authoring/adapter-key.ts +18 -0
  228. package/src/authoring/authoring-asset-url.ts +27 -0
  229. package/src/authoring/bootstrap-state.ts +49 -0
  230. package/src/authoring/boundary-authoring-adapter.ts +184 -0
  231. package/src/authoring/breakpoint-state.ts +43 -0
  232. package/src/authoring/canvas-scene-guides.ts +76 -0
  233. package/src/authoring/component-instance-root.ts +171 -0
  234. package/src/authoring/composite-authoring-adapter.ts +2110 -0
  235. package/src/authoring/consumer-actions.ts +520 -0
  236. package/src/authoring/css-numeric-style.ts +97 -0
  237. package/src/authoring/design-time-layers.ts +849 -0
  238. package/src/authoring/design-time-mount-registry.ts +235 -0
  239. package/src/authoring/design-time-settle.ts +343 -0
  240. package/src/authoring/edit-mode-authoring.ts +619 -0
  241. package/src/authoring/eyedropper-session.ts +60 -0
  242. package/src/authoring/instance-source-menu-register.ts +13 -0
  243. package/src/authoring/instance-source-menu.ts +135 -0
  244. package/src/authoring/layered-pick.ts +183 -0
  245. package/src/authoring/live-gesture-lock.ts +50 -0
  246. package/src/authoring/live-object-transform.ts +62 -0
  247. package/src/authoring/mount-failure-report.ts +154 -0
  248. package/src/authoring/mounted-root-subjects.ts +144 -0
  249. package/src/authoring/no-authoring-adapter.ts +55 -0
  250. package/src/authoring/null-inspection-subjects.tsx +75 -0
  251. package/src/authoring/object3d-document-persistence.ts +106 -0
  252. package/src/authoring/object3d-document-session-registry.ts +120 -0
  253. package/src/authoring/object3d-document-session.ts +1326 -0
  254. package/src/authoring/object3d-gesture-controller.ts +113 -0
  255. package/src/authoring/panel-authoring.ts +121 -0
  256. package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
  257. package/src/authoring/prefab-instance-section-model.ts +55 -0
  258. package/src/authoring/project-authoring-session.ts +105 -0
  259. package/src/authoring/provenance.ts +99 -0
  260. package/src/authoring/quarks-particle-systems.ts +19 -0
  261. package/src/authoring/react-canvas-navigation.ts +255 -0
  262. package/src/authoring/react-design-canvas-style.ts +20 -0
  263. package/src/authoring/react-story-board.ts +937 -0
  264. package/src/authoring/selection-scope.ts +195 -0
  265. package/src/authoring/shell-document-ops.ts +169 -0
  266. package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
  267. package/src/authoring/shell-viewport-policy.ts +48 -0
  268. package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
  269. package/src/authoring/stories-scope.ts +35 -0
  270. package/src/authoring/story-board-chrome-fit.ts +107 -0
  271. package/src/authoring/story-board-presentation.ts +111 -0
  272. package/src/authoring/three-projection-core.ts +226 -0
  273. package/src/authoring/viewport-pick-context.ts +40 -0
  274. package/src/authoring/viewport-raycast.ts +240 -0
  275. package/src/authoring/viewport-tool-context.ts +73 -0
  276. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  277. package/src/authoring/world-hidden-viewport.ts +152 -0
  278. package/src/authoring/world-pan-state.ts +198 -0
  279. package/src/authoring/world-session-state.ts +101 -0
  280. package/src/authoring/write-pipe.ts +173 -0
  281. package/src/availability-tick.ts +66 -0
  282. package/src/bitmap-label.ts +120 -0
  283. package/src/blender-tab-metrics.ts +161 -0
  284. package/src/board-open-actions.ts +20 -0
  285. package/src/boot-routing.ts +391 -0
  286. package/src/build-identity.ts +15 -0
  287. package/src/bytes-codec.ts +62 -0
  288. package/src/camera-authoring.ts +175 -0
  289. package/src/cancellation-reason.ts +58 -0
  290. package/src/canvas-preview-frames.ts +482 -0
  291. package/src/capture-camera-pose.ts +77 -0
  292. package/src/chrome-registry.ts +159 -0
  293. package/src/chrome-slot-registry.ts +91 -0
  294. package/src/collaboration-client.ts +264 -0
  295. package/src/collaboration-presence.ts +41 -0
  296. package/src/command-dispatch.ts +19 -0
  297. package/src/command-listener.ts +2743 -0
  298. package/src/command-registry.ts +70 -0
  299. package/src/component-board-registry.ts +205 -0
  300. package/src/component-states-registry.ts +200 -0
  301. package/src/components/AgentPresentationNotice.tsx +75 -0
  302. package/src/components/AlignToolbar.tsx +204 -0
  303. package/src/components/AppRoot.tsx +394 -0
  304. package/src/components/ApplicationMenus.tsx +415 -0
  305. package/src/components/AssetBrowser.tsx +2843 -0
  306. package/src/components/AssetEditorShell.tsx +216 -0
  307. package/src/components/AssetInspectorToolSection.tsx +124 -0
  308. package/src/components/BoardRulers.tsx +354 -0
  309. package/src/components/CameraInfo.tsx +81 -0
  310. package/src/components/CanvasSceneViewport.tsx +556 -0
  311. package/src/components/CapabilityCoverageSection.tsx +185 -0
  312. package/src/components/CenterDocuments.tsx +22 -0
  313. package/src/components/ChromeSlot.tsx +20 -0
  314. package/src/components/CodeView.tsx +470 -0
  315. package/src/components/CollaborationHeaderControl.css +74 -0
  316. package/src/components/CompactInspectorCard.tsx +190 -0
  317. package/src/components/CompactInspectorShell.tsx +39 -0
  318. package/src/components/ConsolePanel.css +55 -0
  319. package/src/components/ConsolePanel.tsx +270 -0
  320. package/src/components/DefaultEditorLayout.tsx +106 -0
  321. package/src/components/DocumentHeaderStrip.tsx +96 -0
  322. package/src/components/DocumentShelfRail.tsx +45 -0
  323. package/src/components/DocumentThumbnail.tsx +345 -0
  324. package/src/components/EditorLeaseGuard.tsx +372 -0
  325. package/src/components/ErrorBanner.tsx +123 -0
  326. package/src/components/FolderPreviewTile.tsx +159 -0
  327. package/src/components/GameHierarchy.tsx +3842 -0
  328. package/src/components/GameplaySessionTimeline.tsx +295 -0
  329. package/src/components/InspectionProjection.tsx +968 -0
  330. package/src/components/Inspector.tsx +233 -0
  331. package/src/components/InspectorCanvasPreview.tsx +35 -0
  332. package/src/components/InspectorFieldsSection.tsx +290 -0
  333. package/src/components/InspectorObjectPreview.tsx +57 -0
  334. package/src/components/InspectorStoriesSection.tsx +92 -0
  335. package/src/components/InspectorToolSection.tsx +96 -0
  336. package/src/components/InspectorTransformSection.tsx +245 -0
  337. package/src/components/LightExplorerPanel.tsx +433 -0
  338. package/src/components/MediaProperties.tsx +145 -0
  339. package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
  340. package/src/components/Object3DDocumentToolbar.css +100 -0
  341. package/src/components/Object3DDocumentToolbar.tsx +454 -0
  342. package/src/components/Object3DDocumentViewport.tsx +58 -0
  343. package/src/components/ProjectHeader.css +617 -0
  344. package/src/components/ProjectHeader.tsx +328 -0
  345. package/src/components/ProjectLayout.tsx +249 -0
  346. package/src/components/ReactCanvasControls.tsx +284 -0
  347. package/src/components/RootSelectionOverlay.tsx +3162 -0
  348. package/src/components/RootTextEditor.tsx +79 -0
  349. package/src/components/SaveStatus.tsx +70 -0
  350. package/src/components/StageHost.tsx +1954 -0
  351. package/src/components/StageOverlays.tsx +21 -0
  352. package/src/components/StartupErrorScreen.tsx +76 -0
  353. package/src/components/StartupLoadingScreen.tsx +65 -0
  354. package/src/components/StatsOverlay.tsx +78 -0
  355. package/src/components/SurfaceStateOverlay.tsx +24 -0
  356. package/src/components/ToolContributionSurfaces.tsx +65 -0
  357. package/src/components/ToolHost.tsx +370 -0
  358. package/src/components/ToolObject3DPreview.tsx +39 -0
  359. package/src/components/Toolbar.tsx +595 -0
  360. package/src/components/TransientHint.tsx +44 -0
  361. package/src/components/TransportStrip.tsx +174 -0
  362. package/src/components/VersionControlSection.tsx +470 -0
  363. package/src/components/VgaiLogo.css +83 -0
  364. package/src/components/VgaiLogo.tsx +35 -0
  365. package/src/components/ViewportControlsHint.tsx +60 -0
  366. package/src/components/ViewportFurniture.tsx +401 -0
  367. package/src/components/ViewportOverlay.tsx +145 -0
  368. package/src/components/ViewportOverlaysMenu.tsx +153 -0
  369. package/src/components/ViewportShadingMenu.tsx +300 -0
  370. package/src/components/ViewportViewMenu.tsx +101 -0
  371. package/src/components/WorkspaceDocumentSurface.tsx +204 -0
  372. package/src/components/WorkspaceUtilitySurface.tsx +22 -0
  373. package/src/components/WorktreeSwitcher.css +239 -0
  374. package/src/components/WorktreeSwitcher.tsx +890 -0
  375. package/src/components/account-documents.tsx +1162 -0
  376. package/src/components/asset-documents.tsx +812 -0
  377. package/src/components/asset-editor-persistence.ts +216 -0
  378. package/src/components/asset-selection-section.tsx +535 -0
  379. package/src/components/asset-thumbnails.tsx +312 -0
  380. package/src/components/asset-viewers/AudioViewer.tsx +201 -0
  381. package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
  382. package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
  383. package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  384. package/src/components/asset-viewers/ImageViewer.tsx +300 -0
  385. package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
  386. package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
  387. package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
  388. package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
  389. package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
  390. package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
  391. package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
  392. package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
  393. package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
  394. package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
  395. package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  396. package/src/components/asset-viewers/VideoViewer.tsx +101 -0
  397. package/src/components/asset-viewers/shader-source.ts +144 -0
  398. package/src/components/asset-workflow.css +731 -0
  399. package/src/components/board-guides.ts +150 -0
  400. package/src/components/compact-inspector.css +539 -0
  401. package/src/components/core-utilities.tsx +90 -0
  402. package/src/components/editor-notifications.css +40 -0
  403. package/src/components/engine-workspace.css +274 -0
  404. package/src/components/inspector-preview-section.tsx +238 -0
  405. package/src/components/inspector-property-grouping.ts +64 -0
  406. package/src/components/inspector-revert-label.ts +20 -0
  407. package/src/components/inspector-selection.ts +42 -0
  408. package/src/components/inspector-stories-gating.ts +171 -0
  409. package/src/components/inspector-transform-subject.ts +11 -0
  410. package/src/components/inspector-transform.ts +75 -0
  411. package/src/components/kind-documents.tsx +500 -0
  412. package/src/components/palette-action-publisher.tsx +140 -0
  413. package/src/components/primitives/DraftColorInput.tsx +74 -0
  414. package/src/components/product-shell.css +1829 -0
  415. package/src/components/project-tool-documents.tsx +410 -0
  416. package/src/components/scene-documents.tsx +223 -0
  417. package/src/components/stage-keyboard.tsx +37 -0
  418. package/src/components/stage-overlay-set.tsx +107 -0
  419. package/src/components/stage-presence-markers.ts +478 -0
  420. package/src/components/standard-viewport-dressing.ts +417 -0
  421. package/src/components/status-contributions.tsx +403 -0
  422. package/src/components/tool-documents.tsx +309 -0
  423. package/src/components/tool-schema-form.tsx +262 -0
  424. package/src/components/use-after-paint.ts +41 -0
  425. package/src/components/use-project-image-assets.ts +86 -0
  426. package/src/components/viewport-header-controls.css +90 -0
  427. package/src/components/viewport-surface-status.tsx +55 -0
  428. package/src/components/workspace-history.ts +32 -0
  429. package/src/components/workspace-static-panel-registry.tsx +152 -0
  430. package/src/components/workspace-surfaces.css +621 -0
  431. package/src/components/world-documents.tsx +586 -0
  432. package/src/components/world-overlay-gestures.ts +1694 -0
  433. package/src/composite-screenshot.ts +1641 -0
  434. package/src/console-sync.ts +131 -0
  435. package/src/constraint-helper.ts +338 -0
  436. package/src/content-entry-source-registry.ts +184 -0
  437. package/src/coverage/authoring-seam-evidence.ts +300 -0
  438. package/src/coverage/canvas-reveal.ts +192 -0
  439. package/src/coverage/design-time-surfaces.ts +101 -0
  440. package/src/coverage/live-seam-evidence.ts +11 -0
  441. package/src/coverage/ontology-invariants.ts +466 -0
  442. package/src/coverage/session-vitals.ts +501 -0
  443. package/src/coverage/system-seam-evidence.ts +72 -0
  444. package/src/crash-null-boundary.ts +36 -0
  445. package/src/creation-site-edit.ts +1479 -0
  446. package/src/creation-site-registry.ts +160 -0
  447. package/src/delegate-harness-registry.ts +143 -0
  448. package/src/document-context-registry.ts +177 -0
  449. package/src/document-open-registry.ts +200 -0
  450. package/src/document-preview-source.ts +20 -0
  451. package/src/document-renderer-session.ts +138 -0
  452. package/src/editor-api.ts +46 -0
  453. package/src/editor-chrome-capture.ts +139 -0
  454. package/src/editor-commands.ts +164 -0
  455. package/src/editor-console.ts +563 -0
  456. package/src/editor-current-view.ts +82 -0
  457. package/src/editor-document-probe.ts +881 -0
  458. package/src/editor-git-client.ts +115 -0
  459. package/src/editor-host-door.ts +462 -0
  460. package/src/editor-hotkeys.ts +842 -0
  461. package/src/editor-lease-view.ts +39 -0
  462. package/src/editor-lease.ts +415 -0
  463. package/src/editor-mode.ts +19 -0
  464. package/src/editor-notifications.ts +140 -0
  465. package/src/editor-presence.ts +563 -0
  466. package/src/editor-presentation-activity.ts +50 -0
  467. package/src/editor-presentation-notice.ts +42 -0
  468. package/src/editor-runtime.tsx +145 -0
  469. package/src/editor-server-response.ts +86 -0
  470. package/src/editor-session-attribution.ts +75 -0
  471. package/src/editor-session-mode.ts +54 -0
  472. package/src/editor-shell-store.ts +1304 -0
  473. package/src/editor-state-facets.ts +74 -0
  474. package/src/editor-styles.css +33 -0
  475. package/src/editor-view-presentation.ts +810 -0
  476. package/src/editor-viewport.ts +5302 -0
  477. package/src/entity-lod.ts +31 -0
  478. package/src/entity-object.ts +91 -0
  479. package/src/files/file-provider.ts +62 -0
  480. package/src/files/project-files.ts +264 -0
  481. package/src/finders/index.ts +136 -0
  482. package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
  483. package/src/frame/bridge.tsx +1408 -0
  484. package/src/frame/product.ts +77 -0
  485. package/src/gameplay-dom-recording.ts +319 -0
  486. package/src/gameplay-export-state.ts +14 -0
  487. package/src/gameplay-replay.ts +417 -0
  488. package/src/gameplay-session-time.ts +9 -0
  489. package/src/gameplay-sessions.ts +204 -0
  490. package/src/harness-chat-types.ts +253 -0
  491. package/src/hierarchy-component-marks.ts +298 -0
  492. package/src/hierarchy-drop.ts +91 -0
  493. package/src/hierarchy-expansion-state.ts +80 -0
  494. package/src/hierarchy-header-slot.ts +52 -0
  495. package/src/hierarchy-internals.ts +197 -0
  496. package/src/hierarchy-kind-icon.ts +217 -0
  497. package/src/hierarchy-mark-reader.ts +73 -0
  498. package/src/hierarchy-menu-registry.ts +67 -0
  499. package/src/hierarchy-node-rows.ts +307 -0
  500. package/src/hierarchy-panel-view.ts +280 -0
  501. package/src/hierarchy-projection.ts +76 -0
  502. package/src/hierarchy-row-cache.ts +243 -0
  503. package/src/hierarchy-row-model.ts +308 -0
  504. package/src/hierarchy-rows.ts +11 -0
  505. package/src/hierarchy-walk.ts +86 -0
  506. package/src/history/editor-session.ts +25 -0
  507. package/src/history/history-commands.ts +147 -0
  508. package/src/history/history-delegate.ts +163 -0
  509. package/src/history/history-limit-notices.ts +43 -0
  510. package/src/history/history-service.ts +1173 -0
  511. package/src/history/persistence-coordinator.ts +35 -0
  512. package/src/history/project-file-history.ts +386 -0
  513. package/src/history/project-root-history-backends.ts +139 -0
  514. package/src/history/resource-registry.ts +209 -0
  515. package/src/history/snapshot-store.ts +103 -0
  516. package/src/history/source-history-backend.ts +546 -0
  517. package/src/history/types.ts +124 -0
  518. package/src/hmr-registration-group.ts +67 -0
  519. package/src/hmr-stable-react-context.ts +23 -0
  520. package/src/hotkeys.ts +188 -0
  521. package/src/inference-diagnostics.ts +69 -0
  522. package/src/initial-project.ts +80 -0
  523. package/src/inspection/active-subject.ts +578 -0
  524. package/src/inspection/active-surface.ts +142 -0
  525. package/src/inspection/compose.ts +1064 -0
  526. package/src/inspection/display.ts +170 -0
  527. package/src/inspection/document-subject.ts +109 -0
  528. package/src/inspection/game-subject.ts +85 -0
  529. package/src/inspection/model.ts +542 -0
  530. package/src/inspection/null-subject.ts +115 -0
  531. package/src/inspection/serialize.ts +357 -0
  532. package/src/inspection/use-active-inspection.ts +180 -0
  533. package/src/inspector-presentation.ts +201 -0
  534. package/src/inspector-section-registry.ts +221 -0
  535. package/src/instance-source-actions.ts +163 -0
  536. package/src/instanced-presentation.ts +164 -0
  537. package/src/js-heap.ts +71 -0
  538. package/src/key-actions.ts +91 -0
  539. package/src/keymap-presets.ts +401 -0
  540. package/src/layout-policy.ts +31 -0
  541. package/src/learn-links.ts +73 -0
  542. package/src/light-explorer-model.ts +134 -0
  543. package/src/live-canvas-frame.ts +55 -0
  544. package/src/live-document.ts +279 -0
  545. package/src/live-module-source.ts +230 -0
  546. package/src/live-session-registry.ts +220 -0
  547. package/src/live-transition.ts +633 -0
  548. package/src/manifest-project.ts +107 -0
  549. package/src/model-thumbnail.ts +523 -0
  550. package/src/native-selection-style.ts +202 -0
  551. package/src/object3d-document-write-policy.ts +137 -0
  552. package/src/packaged-runtime.ts +108 -0
  553. package/src/palettes/maya.palette.json +57 -0
  554. package/src/palettes/substance.palette.json +57 -0
  555. package/src/pasteboard-module.ts +81 -0
  556. package/src/performance-profiler.ts +367 -0
  557. package/src/performance-sources.ts +69 -0
  558. package/src/play-boot-phase.ts +145 -0
  559. package/src/presentation-surface.ts +248 -0
  560. package/src/project-adapter.ts +1143 -0
  561. package/src/project-asset-refresh.ts +26 -0
  562. package/src/project-declaration-refresh.ts +31 -0
  563. package/src/project-local-state.ts +118 -0
  564. package/src/project-manager.ts +243 -0
  565. package/src/project-module-changes.ts +163 -0
  566. package/src/project-module-split.ts +266 -0
  567. package/src/project-provenance.ts +115 -0
  568. package/src/project-ready.ts +42 -0
  569. package/src/project-session-reset.ts +67 -0
  570. package/src/project-shape.ts +68 -0
  571. package/src/project-tool-discovery.ts +66 -0
  572. package/src/project-tools.ts +107 -0
  573. package/src/project-work-types.ts +149 -0
  574. package/src/projection/three.ts +898 -0
  575. package/src/projection/types.ts +44 -0
  576. package/src/readiness.ts +113 -0
  577. package/src/reflection-probe-helper.ts +142 -0
  578. package/src/reported-play-state.ts +90 -0
  579. package/src/resolve-relative-specifier.ts +33 -0
  580. package/src/scene-document-plan.ts +315 -0
  581. package/src/scene-framing.ts +315 -0
  582. package/src/scene-live-open.ts +210 -0
  583. package/src/scene-view-fog.ts +89 -0
  584. package/src/scoped-game-css.ts +152 -0
  585. package/src/session-orphan-record.ts +193 -0
  586. package/src/session-tombstone.ts +126 -0
  587. package/src/settings/settings-provider.ts +82 -0
  588. package/src/settings-store.ts +345 -0
  589. package/src/shared-view-restore.ts +42 -0
  590. package/src/shell-store-door.ts +45 -0
  591. package/src/source-conflict.ts +122 -0
  592. package/src/spatial-handle-visuals.ts +332 -0
  593. package/src/stage-context.ts +341 -0
  594. package/src/stage-store-registry.ts +63 -0
  595. package/src/stale-chunk-recovery.ts +34 -0
  596. package/src/state-report-deferral.ts +73 -0
  597. package/src/storage/host-files-storage.ts +97 -0
  598. package/src/storage/http-storage.ts +174 -0
  599. package/src/storage/index.ts +75 -0
  600. package/src/storage/mem-storage.ts +149 -0
  601. package/src/storage/path-lock.ts +44 -0
  602. package/src/storage/paths.ts +26 -0
  603. package/src/storage/types.ts +116 -0
  604. package/src/stories/StoryComponentThumbnail.tsx +184 -0
  605. package/src/stories/StoryPreviewMount.tsx +306 -0
  606. package/src/stories/component-content-source.tsx +106 -0
  607. package/src/stories/component-states-source.ts +78 -0
  608. package/src/stories/compose-project-stories.ts +255 -0
  609. package/src/stories/pixi-story-model.ts +30 -0
  610. package/src/stories/prefabs-finder.ts +54 -0
  611. package/src/stories/prefabs-from-stories.ts +182 -0
  612. package/src/stories/project-story-discovery.ts +78 -0
  613. package/src/stories/project-story-regions.ts +24 -0
  614. package/src/stories/story-actions.ts +54 -0
  615. package/src/stories/story-capture-command.ts +124 -0
  616. package/src/stories/story-capture.ts +584 -0
  617. package/src/stories/story-declared-medium.ts +126 -0
  618. package/src/stories/story-discovery.ts +176 -0
  619. package/src/stories/story-document-openers.ts +36 -0
  620. package/src/stories/story-dom-runtime.ts +78 -0
  621. package/src/stories/story-grouping.ts +111 -0
  622. package/src/stories/story-lane.ts +88 -0
  623. package/src/stories/story-mount-turn.ts +27 -0
  624. package/src/stories/story-opener.ts +260 -0
  625. package/src/stories/story-pixi-preview.ts +408 -0
  626. package/src/stories/story-presentation.ts +215 -0
  627. package/src/stories/story-registry.ts +517 -0
  628. package/src/stories/story-three-preview.ts +807 -0
  629. package/src/stories/three-story-model.ts +96 -0
  630. package/src/story-three-preview-runtime.ts +56 -0
  631. package/src/surface-keyboard.ts +112 -0
  632. package/src/surface-state.ts +124 -0
  633. package/src/tab-bootstrap.js +628 -0
  634. package/src/tab-census.ts +198 -0
  635. package/src/tab-lifecycle-client.ts +196 -0
  636. package/src/theme-library.ts +844 -0
  637. package/src/theme-preference.ts +378 -0
  638. package/src/theme.css +3437 -0
  639. package/src/three-viewport/bone-selection-highlight.ts +119 -0
  640. package/src/three-viewport/camera-fit.ts +41 -0
  641. package/src/three-viewport/interactive-renderer.ts +132 -0
  642. package/src/three-viewport/selection-brackets.ts +310 -0
  643. package/src/three-viewport/selection-outline.ts +183 -0
  644. package/src/three-viewport/skeleton-helper.ts +61 -0
  645. package/src/three-viewport/source-color.ts +167 -0
  646. package/src/three-viewport/studio-environment.ts +96 -0
  647. package/src/three-viewport-presentation.ts +23 -0
  648. package/src/tool-contribution-play.ts +74 -0
  649. package/src/tool-loader.ts +1798 -0
  650. package/src/transform-mode-request.ts +57 -0
  651. package/src/transient-hint.ts +78 -0
  652. package/src/trigger-volume-helper.ts +116 -0
  653. package/src/ui-source/adapter-region-includes.ts +241 -0
  654. package/src/ui-source/ensure-import.ts +132 -0
  655. package/src/ui-source/file-region-resolver.ts +302 -0
  656. package/src/ui-source/inspect.ts +775 -0
  657. package/src/ui-source/oid-transform.ts +1845 -0
  658. package/src/ui-source/plan-csf-story.ts +196 -0
  659. package/src/ui-source/plan-extract-component.ts +421 -0
  660. package/src/ui-source/plan-fork-component.ts +621 -0
  661. package/src/ui-source/plan-named-style.ts +95 -0
  662. package/src/ui-source/plan-source-edit.ts +353 -0
  663. package/src/ui-source/r3f-contract-resolver.ts +327 -0
  664. package/src/ui-source/r3f-diagnostic-index.ts +165 -0
  665. package/src/ui-source/r3f-environment-binding.ts +133 -0
  666. package/src/ui-source/r3f-joint-binding.ts +251 -0
  667. package/src/ui-source/r3f-lod-binding.ts +91 -0
  668. package/src/ui-source/r3f-particle-binding.ts +235 -0
  669. package/src/ui-source/r3f-physics-binding.ts +483 -0
  670. package/src/ui-source/r3f-project-contracts.ts +444 -0
  671. package/src/ui-source/relative-import-specifier.ts +34 -0
  672. package/src/ui-source/reparent-guard.ts +544 -0
  673. package/src/ui-source/source-edit-request.ts +97 -0
  674. package/src/ui-source/source-write-backend.ts +618 -0
  675. package/src/ui-source/syntactic-prop-specs.ts +296 -0
  676. package/src/ui-source/tier-source-write-backend.ts +279 -0
  677. package/src/ui-source/ts-ast.ts +171 -0
  678. package/src/ui-source/utility-class-support.ts +169 -0
  679. package/src/ui-source/write-component-default.ts +133 -0
  680. package/src/ui-source/writer.ts +1989 -0
  681. package/src/viewport-activation-timings.ts +840 -0
  682. package/src/viewport-authoring-policy.ts +186 -0
  683. package/src/viewport-controls-hint.ts +57 -0
  684. package/src/viewport-door.ts +237 -0
  685. package/src/viewport-shading-boundary.ts +12 -0
  686. package/src/vite-error-surface.ts +141 -0
  687. package/src/wait-until.ts +37 -0
  688. package/src/workspace-areas.ts +156 -0
  689. package/src/workspace-aux-commands.ts +11 -0
  690. package/src/workspace-available-documents.ts +127 -0
  691. package/src/workspace-core-utilities.ts +31 -0
  692. package/src/workspace-document-ids.ts +59 -0
  693. package/src/workspace-document-registry.ts +612 -0
  694. package/src/workspace-document-restore.ts +145 -0
  695. package/src/workspace-host-commands.ts +141 -0
  696. package/src/workspace-persistence-gate.ts +40 -0
  697. package/src/workspace-play-utilities.ts +44 -0
  698. package/src/workspace-presets.ts +425 -0
  699. package/src/workspace-regions.ts +294 -0
  700. package/src/workspace-state-persistence.ts +536 -0
  701. package/src/workspace-static-panels.ts +73 -0
  702. package/src/workspace-status-registry.ts +121 -0
  703. package/src/workspace-style.ts +239 -0
  704. package/src/workspace-utility-commands.ts +74 -0
  705. package/src/workspace-utility-registry.ts +263 -0
  706. package/src/workspace-viewport-rect.ts +97 -0
  707. package/src/world-adoption.ts +115 -0
  708. package/src/world-document-routing.ts +104 -0
  709. package/vite-plugin-creation-site-write.ts +184 -0
  710. package/vite-plugin-creation-site.ts +80 -0
  711. package/vite-plugin-game-static.ts +303 -0
  712. package/vite-plugin-module-doorways.ts +336 -0
  713. package/vite-plugin-product-contributions.ts +197 -0
  714. package/vite-plugin-project-game-static.ts +125 -0
  715. package/vite-plugin-project-jsx-js.ts +65 -0
  716. package/vite-plugin-project-root-absolute-assets.ts +359 -0
  717. package/vite-plugin-shared-react.ts +420 -0
  718. package/vite-plugin-shared-three.ts +203 -0
  719. package/vite-plugin-ui-oid.ts +2106 -0
@@ -0,0 +1,401 @@
1
+ import type { EditorKeyActionId, KeyChord, KeymapContribution } from '@volter/editor-sdk/looks';
2
+ import { editorConsole } from './editor-console';
3
+ import {
4
+ adapterSettings,
5
+ projectSettings,
6
+ subscribeSettings,
7
+ updatePreferenceSettings,
8
+ updateProjectSettings,
9
+ userSettings,
10
+ } from './settings-store';
11
+
12
+ export type { EditorKeyActionId, KeyChord } from '@volter/editor-sdk/looks';
13
+ /**
14
+ * KEYMAPS — the binding table behind every editor keyboard action.
15
+ *
16
+ * The ruling (docs/ARCHITECTURE-CORE.md §Editor chrome, the "Workspaces are
17
+ * task-named layout memories" bullet, final sentence): *"Keymaps are
18
+ * orthogonal to workspaces: a `keymap` setting selects the binding table
19
+ * (`vgai` default; `blender` — G/R/S, A, Alt+A, `.` frame) through one
20
+ * indirection at the action-registry/hotkey seam."*
21
+ *
22
+ * ONE INDIRECTION means exactly this: nothing in the editor spells a literal
23
+ * key for a keyboard action any more. `editor-hotkeys.ts` builds its
24
+ * `HotkeyBinding`s from {@link keyChordsFor}, and every place that PRINTS a
25
+ * shortcut — the command palette (via `action-registry.ts`), the viewport
26
+ * toolstrip tooltips, the camera-controls hint, the snap transient hint —
27
+ * renders {@link shortcutFor} over the same table. Switch the keymap and the
28
+ * chrome tells the truth on the next paint, with no reload.
29
+ *
30
+ * The two axes this module is deliberately NOT: it is not a workspace (that is
31
+ * `workspace-presets.ts` — layout, keyed per project) and not an appearance
32
+ * preference (`theme-preference.ts`). A keymap is a per-user input preference,
33
+ * persisted the way that module persists palette/material: one settings
34
+ * key, lazily read, written on change, broadcast to `useSyncExternalStore`
35
+ * subscribers, and simply falling back to the default when unreadable —
36
+ * nothing a user authored is at stake in a stored preference.
37
+ *
38
+ * WHAT THIS DOES NOT GOVERN — the boundary, stated once: this table is the
39
+ * EDITOR's own chrome bindings, consumed by `hotkeys.ts`'s single `keydown`
40
+ * dispatcher on the editor's window. Play-mode input isolation is a different
41
+ * mechanism entirely and is untouched by a keymap switch: the engine's
42
+ * `InputManager.setEnabled` gate plus `gated-globals.ts`'s lexical
43
+ * `window`/`document` shadow over project modules decide whether GAME code
44
+ * hears a key. A game never reads this table, and no keymap entry can widen or
45
+ * narrow what a running game receives.
46
+ */
47
+
48
+ /** Any registered keymap's id: the editor's own `vgai`, or one a package
49
+ * contributes (`@volter/editor-sdk/looks`, `KeymapContribution`). */
50
+ export type EditorKeymapId = string;
51
+
52
+ export interface EditorKeymapDescriptor {
53
+ readonly id: EditorKeymapId;
54
+ readonly title: string;
55
+ readonly description: string;
56
+ }
57
+
58
+ /** The editor's OWN keymap, the one every project has. Every other keymap is
59
+ * a package's contribution (Blender's ships with `@volter/editor-blender`). */
60
+ const BUILT_IN_KEYMAPS: readonly EditorKeymapDescriptor[] = Object.freeze([
61
+ {
62
+ id: 'vgai',
63
+ title: 'vgai',
64
+ description: "The editor's own bindings: W/E/R gizmo modes, Ctrl+A select all, F frames.",
65
+ },
66
+ ] satisfies readonly EditorKeymapDescriptor[]);
67
+
68
+ interface ContributedKeymap {
69
+ readonly descriptor: EditorKeymapDescriptor;
70
+ readonly table: EditorKeymapTable;
71
+ }
72
+ const contributedKeymaps = new Map<string, ContributedKeymap>();
73
+ let registryVersion = 0;
74
+
75
+ /** Built-ins first, then contributions in registration order — the switch
76
+ * surfaces (View menu, palette) enumerate this. */
77
+ export function editorKeymaps(): readonly EditorKeymapDescriptor[] {
78
+ return [
79
+ ...BUILT_IN_KEYMAPS,
80
+ ...[...contributedKeymaps.values()].map((entry) => entry.descriptor),
81
+ ];
82
+ }
83
+
84
+ export function editorKeymapsVersion(): number {
85
+ return registryVersion;
86
+ }
87
+
88
+ /**
89
+ * Register a package's keymap (`workspace.keymap` contribution). The table is
90
+ * the editor's own bindings with the contribution's chords over them, so a
91
+ * keymap declares only where it differs. Returns the unregister. A duplicate
92
+ * id throws — ids are the `keymap` setting's values.
93
+ */
94
+ export function registerContributedKeymap(contribution: KeymapContribution): () => void {
95
+ if (
96
+ BUILT_IN_KEYMAPS.some((entry) => entry.id === contribution.id) ||
97
+ contributedKeymaps.has(contribution.id)
98
+ )
99
+ throw new Error(
100
+ `registerContributedKeymap: keymap "${contribution.id}" is already registered.`,
101
+ );
102
+ const entry: ContributedKeymap = {
103
+ descriptor: {
104
+ id: contribution.id,
105
+ title: contribution.title,
106
+ description: contribution.description,
107
+ },
108
+ table: Object.freeze({ ...VGAI_KEYMAP, ...contribution.bindings }) as EditorKeymapTable,
109
+ };
110
+ contributedKeymaps.set(contribution.id, entry);
111
+ registryVersion++;
112
+ // A stored preference this contribution satisfies applies now, not on the
113
+ // next reload: the cache re-reads the setting against the wider registry.
114
+ cachedKeymap = null;
115
+ emit();
116
+ return () => {
117
+ if (contributedKeymaps.get(contribution.id) !== entry) return;
118
+ contributedKeymaps.delete(contribution.id);
119
+ registryVersion++;
120
+ cachedKeymap = null;
121
+ emit();
122
+ };
123
+ }
124
+
125
+ export function isEditorKeymapId(value: unknown): value is EditorKeymapId {
126
+ return (
127
+ typeof value === 'string' &&
128
+ (BUILT_IN_KEYMAPS.some((entry) => entry.id === value) || contributedKeymaps.has(value))
129
+ );
130
+ }
131
+
132
+ export type EditorKeymapTable = Readonly<Record<EditorKeyActionId, readonly KeyChord[]>>;
133
+
134
+ /**
135
+ * The vgai table reproduces the bindings the editor shipped before keymaps
136
+ * existed, chord for chord. It is the regression bar: any change here is a
137
+ * change to the default editor, not to a keymap.
138
+ */
139
+ const VGAI_KEYMAP: EditorKeymapTable = Object.freeze({
140
+ 'edit.undo': [{ key: 'z', mod: true }],
141
+ // Ctrl+Y mirrors Ctrl+Shift+Z (Windows convention).
142
+ 'edit.redo': [
143
+ { key: 'z', mod: true, shift: true },
144
+ { key: 'y', mod: true },
145
+ ],
146
+ 'edit.copy': [{ key: 'c', mod: true }],
147
+ 'edit.cut': [{ key: 'x', mod: true }],
148
+ 'edit.paste': [{ key: 'v', mod: true }],
149
+ 'edit.duplicate': [{ key: 'd', mod: true }],
150
+ 'edit.group': [{ key: 'g', mod: true }],
151
+ 'edit.wrap': [{ key: 'g', mod: true, alt: true }],
152
+ 'edit.unwrap': [{ key: 'g', mod: true, shift: true }],
153
+ 'edit.selectAll': [{ key: 'a', mod: true }],
154
+ // No dedicated chord: Escape is the vgai deselect, and it carries the
155
+ // scope-exit semantics too (`edit.exitScopeOrDeselect`). An empty chord list
156
+ // registers no binding; the printed hint falls back to Escape's.
157
+ 'edit.deselectAll': [],
158
+ 'edit.save': [{ key: 's', mod: true }],
159
+ 'edit.delete': [{ key: 'delete' }, { key: 'backspace' }],
160
+ 'edit.enterScope': [{ key: 'enter' }],
161
+ 'edit.exitScopeOrDeselect': [{ key: 'escape' }],
162
+ 'edit.nudgeUp': [{ key: 'arrowup' }],
163
+ 'edit.nudgeUpCoarse': [{ key: 'arrowup', shift: true }],
164
+ 'edit.nudgeDown': [{ key: 'arrowdown' }],
165
+ 'edit.nudgeDownCoarse': [{ key: 'arrowdown', shift: true }],
166
+ 'edit.nudgeLeft': [{ key: 'arrowleft' }],
167
+ 'edit.nudgeLeftCoarse': [{ key: 'arrowleft', shift: true }],
168
+ 'edit.nudgeRight': [{ key: 'arrowright' }],
169
+ 'edit.nudgeRightCoarse': [{ key: 'arrowright', shift: true }],
170
+ 'view.resetPan': [{ key: '0', mod: true }],
171
+ 'view.commandPalette': [{ key: 'k', mod: true }],
172
+ 'view.toggleConsole': [{ key: '`' }],
173
+ 'view.focusMode': [{ key: 'f', mod: true, shift: true }],
174
+ // Blender's own workspace cycle keys, and free in this registry.
175
+ 'workspace.cycleNext': [{ key: 'pagedown', mod: true }],
176
+ 'workspace.cyclePrevious': [{ key: 'pageup', mod: true }],
177
+ // UNBOUND HERE, DELIBERATELY: this editor's own four transform tools already
178
+ // hold T/W/E/R, and the Select tool arrived with the Blender look (whose
179
+ // keymap puts it on Blender's own `W`). An empty list is the table's way of
180
+ // saying a keymap binds nothing to an action, and the strip's button is the
181
+ // tool's other door.
182
+ 'transform.select': [],
183
+ 'transform.combined': [{ key: 't' }],
184
+ 'transform.translate': [{ key: 'w' }],
185
+ 'transform.rotate': [{ key: 'e' }],
186
+ 'transform.scale': [{ key: 'r' }],
187
+ 'viewport.toggleSnap': [{ key: 's', shift: true }],
188
+ 'viewport.frameSelection': [{ key: 'f' }],
189
+ 'viewport.cyclePivot': [{ key: '.' }],
190
+ 'viewport.vertexSnapHold': [{ key: 'v' }],
191
+ 'viewport.snapToFloor': [{ key: '', code: 'PageDown' }],
192
+ 'view.top': [{ key: '', code: 'Numpad7' }],
193
+ 'view.front': [{ key: '', code: 'Numpad1' }],
194
+ 'view.right': [{ key: '', code: 'Numpad3' }],
195
+ 'view.perspective': [{ key: '', code: 'Numpad5' }],
196
+ } satisfies EditorKeymapTable);
197
+
198
+ // ---------------------------------------------------------------------------
199
+ // The setting
200
+ // ---------------------------------------------------------------------------
201
+
202
+ export const DEFAULT_EDITOR_KEYMAP: EditorKeymapId = 'vgai';
203
+
204
+ let cachedKeymap: EditorKeymapId | null = null;
205
+ let settingsSyncInstalled = false;
206
+ const listeners = new Set<() => void>();
207
+
208
+ function emit(): void {
209
+ for (const listener of listeners) listener();
210
+ }
211
+
212
+ /** The editor's own keymap ids — the ones that exist in every project. */
213
+ function isBuiltInKeymapId(value: unknown): boolean {
214
+ return typeof value === 'string' && BUILT_IN_KEYMAPS.some((entry) => entry.id === value);
215
+ }
216
+
217
+ /** What the PROJECT selects: its adapter's declaration, its own settings over it. */
218
+ function projectScopedKeymap(): unknown {
219
+ return projectSettings().keymap ?? adapterSettings().keymap;
220
+ }
221
+
222
+ /**
223
+ * A keymap a PACKAGE contributes is project-scoped: it exists only where that
224
+ * package is declared, so only the project may select it — its adapter
225
+ * (`editor: { keymap: blenderKeymap }`) or its own `.vgai/settings.json`. The
226
+ * USER layer chooses among the editor's own, because a cross-project default
227
+ * naming a skew's bindings is how a models project's G/R/S reached a game
228
+ * project that merely happens to declare the same package.
229
+ */
230
+ function readStoredKeymap(): EditorKeymapId {
231
+ const scoped = projectScopedKeymap();
232
+ if (isEditorKeymapId(scoped)) return scoped;
233
+ const preferred = userSettings().keymap;
234
+ return isBuiltInKeymapId(preferred) ? (preferred as EditorKeymapId) : DEFAULT_EDITOR_KEYMAP;
235
+ }
236
+
237
+ const saidUnavailable = new Set<string>();
238
+ /**
239
+ * Say, once per id, that the STORED keymap is one nothing in this project
240
+ * contributes, so a models project opened without its Blender package
241
+ * explains the W/E/R it is showing. Called by the loader AFTER a contribution
242
+ * pass has registered what the project's packages ship — asked at boot it
243
+ * would warn about every keymap a package is about to contribute (measured
244
+ * 2026-09-17: "blender is not available" on a project whose mesh package
245
+ * registered it a moment later).
246
+ */
247
+ export function reportUnavailableKeymap(): void {
248
+ const stored = projectScopedKeymap();
249
+ if (typeof stored !== 'string' || stored === DEFAULT_EDITOR_KEYMAP) return;
250
+ if (isEditorKeymapId(stored) || saidUnavailable.has(stored)) return;
251
+ saidUnavailable.add(stored);
252
+ editorConsole.warn(
253
+ `Keymap "${stored}" is not available in this project: no declared package contributes it ` +
254
+ `(a package ships one as a \`workspace.keymap\` contribution). Using "${DEFAULT_EDITOR_KEYMAP}".`,
255
+ 'editor',
256
+ );
257
+ }
258
+
259
+ /** The setting is `keymap` in the settings layers (`settings-store.ts`); a
260
+ * load finishing or a project's own override becoming active must not leave
261
+ * this module's cache lying. Installed on first read so the module has no
262
+ * load-time side effect. */
263
+ function ensureSettingsSync(): void {
264
+ if (settingsSyncInstalled) return;
265
+ settingsSyncInstalled = true;
266
+ subscribeSettings(() => {
267
+ const next = readStoredKeymap();
268
+ if (next === cachedKeymap) return;
269
+ cachedKeymap = next;
270
+ emit();
271
+ });
272
+ }
273
+
274
+ /** Current keymap id (`useSyncExternalStore`-shaped snapshot). */
275
+ export function activeEditorKeymap(): EditorKeymapId {
276
+ ensureSettingsSync();
277
+ cachedKeymap ??= readStoredKeymap();
278
+ return cachedKeymap;
279
+ }
280
+
281
+ /**
282
+ * Switch keymaps. Live: every binding registration re-derives from the new
283
+ * table on this call (`editor-hotkeys.ts`) and every printed hint re-renders,
284
+ * so there is no reload and no restart. Choosing one of the editor's OWN
285
+ * keymaps writes where the key is declared; choosing a package's writes the
286
+ * PROJECT layer, because that is the only layer a contributed keymap is read
287
+ * from (see {@link readStoredKeymap}) — a gesture must land somewhere it wins.
288
+ */
289
+ export function setEditorKeymapPreference(id: EditorKeymapId): void {
290
+ if (activeEditorKeymap() === id) return;
291
+ cachedKeymap = id;
292
+ if (isBuiltInKeymapId(id)) updatePreferenceSettings({ keymap: id });
293
+ else updateProjectSettings({ keymap: id });
294
+ emit();
295
+ }
296
+
297
+ export function subscribeEditorKeymap(listener: () => void): () => void {
298
+ listeners.add(listener);
299
+ return () => listeners.delete(listener);
300
+ }
301
+
302
+ export function __resetEditorKeymapForTest(): void {
303
+ cachedKeymap = null;
304
+ listeners.clear();
305
+ }
306
+
307
+ // ---------------------------------------------------------------------------
308
+ // The one lookup
309
+ // ---------------------------------------------------------------------------
310
+
311
+ /** The active table's chords for one action. Empty means deliberately unbound. */
312
+ export function keyChordsFor(action: EditorKeyActionId): readonly KeyChord[] {
313
+ return keymapTable(activeEditorKeymap())[action];
314
+ }
315
+
316
+ /** A named table, for a surface that must show a keymap it is not running.
317
+ * An unregistered id answers the editor's own table. */
318
+ export function keymapTable(id: EditorKeymapId): EditorKeymapTable {
319
+ return contributedKeymaps.get(id)?.table ?? VGAI_KEYMAP;
320
+ }
321
+
322
+ // ---------------------------------------------------------------------------
323
+ // Display
324
+ // ---------------------------------------------------------------------------
325
+
326
+ function isMacPlatform(): boolean {
327
+ return typeof navigator !== 'undefined' && navigator.platform.includes('Mac');
328
+ }
329
+
330
+ /** Named keys whose label is neither the raw `key` nor its uppercase form. */
331
+ const KEY_LABELS: Readonly<Record<string, string>> = {
332
+ delete: 'Del',
333
+ backspace: 'Backspace',
334
+ escape: 'Esc',
335
+ enter: 'Enter',
336
+ pagedown: 'PgDn',
337
+ pageup: 'PgUp',
338
+ arrowup: '↑',
339
+ arrowdown: '↓',
340
+ arrowleft: '←',
341
+ arrowright: '→',
342
+ ' ': 'Space',
343
+ tab: 'Tab',
344
+ };
345
+
346
+ const CODE_LABELS: Readonly<Record<string, string>> = {
347
+ Numpad0: 'Num0',
348
+ Numpad1: 'Num1',
349
+ Numpad2: 'Num2',
350
+ Numpad3: 'Num3',
351
+ Numpad4: 'Num4',
352
+ Numpad5: 'Num5',
353
+ Numpad6: 'Num6',
354
+ Numpad7: 'Num7',
355
+ Numpad8: 'Num8',
356
+ Numpad9: 'Num9',
357
+ NumpadDecimal: 'Num.',
358
+ PageDown: 'PgDn',
359
+ PageUp: 'PgUp',
360
+ End: 'End',
361
+ KeyG: 'G',
362
+ KeyH: 'H',
363
+ KeyJ: 'J',
364
+ KeyK: 'K',
365
+ };
366
+
367
+ function keyLabel(chord: KeyChord): string {
368
+ if (chord.code) return CODE_LABELS[chord.code] ?? chord.code;
369
+ return KEY_LABELS[chord.key] ?? (chord.key.length === 1 ? chord.key.toUpperCase() : chord.key);
370
+ }
371
+
372
+ /**
373
+ * Render one chord the way the editor's chrome has always rendered them —
374
+ * BOTH existing conventions preserved verbatim, because changing a printed
375
+ * string is a visible regression: a mod-prefixed chord reads `⌘⇧Z` / `Ctrl+⇧Z`
376
+ * (the command palette's shape), while a modless chord spells its modifiers
377
+ * out, `Shift+S` (the toolstrip's shape).
378
+ */
379
+ export function formatChord(chord: KeyChord): string {
380
+ const label = keyLabel(chord);
381
+ if (chord.mod) {
382
+ const mod = isMacPlatform() ? '⌘' : 'Ctrl+';
383
+ return `${mod}${chord.alt ? '⌥' : ''}${chord.shift ? '⇧' : ''}${label}`;
384
+ }
385
+ const parts: string[] = [];
386
+ if (chord.alt) parts.push('Alt');
387
+ if (chord.shift) parts.push('Shift');
388
+ parts.push(label);
389
+ return parts.join('+');
390
+ }
391
+
392
+ /**
393
+ * The printed hint for an action under the ACTIVE keymap — the first chord,
394
+ * which every table lists in "the one to teach" order. `undefined` when the
395
+ * action is deliberately unbound, so a caller can fall back or omit the hint
396
+ * rather than print a lie.
397
+ */
398
+ export function shortcutFor(action: EditorKeyActionId): string | undefined {
399
+ const chord = keyChordsFor(action)[0];
400
+ return chord ? formatChord(chord) : undefined;
401
+ }
@@ -0,0 +1,31 @@
1
+ /** Presentation chosen by mounted layout code. No game or website names live here. */
2
+ import type { WorkspaceArrangement } from '@volter/editor-sdk/layout-arrangements';
3
+ import { activeProjectKey } from './active-project';
4
+ export interface LayoutPolicy {
5
+ readonly immersivePlay?: boolean;
6
+ readonly playUtilities?: readonly string[];
7
+ readonly arrangement?: WorkspaceArrangement;
8
+ }
9
+ let owner: string | null = null;
10
+ let policy: LayoutPolicy | null = null;
11
+ const listeners = new Set<() => void>();
12
+ export function layoutPolicy(): LayoutPolicy | null {
13
+ return owner === activeProjectKey() ? policy : null;
14
+ }
15
+ export function subscribeLayoutPolicy(listener: () => void): () => void {
16
+ listeners.add(listener);
17
+ return () => {
18
+ listeners.delete(listener);
19
+ };
20
+ }
21
+ export function installLayoutPolicy(next: LayoutPolicy): () => void {
22
+ owner = activeProjectKey();
23
+ policy = next;
24
+ for (const listener of listeners) listener();
25
+ return () => {
26
+ if (policy !== next) return;
27
+ policy = null;
28
+ owner = null;
29
+ for (const listener of listeners) listener();
30
+ };
31
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Editor → Learn-site linkage (G6).
3
+ *
4
+ * The whole editor→site half of the FTUE deep-link contract lives here:
5
+ * the Help/Learn menu's destinations (`ApplicationMenus.tsx`) and the
6
+ * read-only example viewer's lesson affordance (`status-contributions.tsx`)
7
+ * both consume these helpers, so the URL shapes are stated exactly once.
8
+ *
9
+ * Reference links are VERSION-PINNED: the zero-base platform-vertical plan
10
+ * serves immutable per-minor snapshots at `/reference/<major>.<minor>/` with
11
+ * `/reference/latest/` as an explicit 302 alias — so a project pinned to
12
+ * engine 0.5.x links `/reference/0.5/` and keeps meaning that engine forever.
13
+ * The pin is derived from the project's `engine.version` manifest field (an
14
+ * identity pin, not a range — @volter/editor-project/manifest/schema). When the version is
15
+ * missing or unparseable (or the `0.0.x` dev placeholder), we fall back to
16
+ * the unpinned reference root rather than fabricating a snapshot that can
17
+ * never exist.
18
+ */
19
+
20
+ /** Learn-site origin (site/astro.config.mjs `site`). */
21
+ export const LEARN_SITE_URL = 'https://vgai-learn.pages.dev/';
22
+
23
+ /** Quick-starts landing (site/src/content/x). */
24
+ export const LEARN_QUICK_STARTS_URL = `${LEARN_SITE_URL}quick-starts/`;
25
+
26
+ /** Manual landing (site/src/content/x). */
27
+ export const LEARN_MANUAL_URL = `${LEARN_SITE_URL}manual/`;
28
+
29
+ /** Unpinned reference root — the fallback when no engine version is known. */
30
+ export const LEARN_REFERENCE_ROOT_URL = `${LEARN_SITE_URL}reference/`;
31
+
32
+ /**
33
+ * The `<major>.<minor>` reference-snapshot pin for an engine version, or null
34
+ * when the version cannot honestly name a snapshot: missing, unparseable, or
35
+ * the `0.0.x` never-released dev placeholder. Prerelease/build suffixes
36
+ * (`0.5.0-rc.1`) still pin their minor — the snapshot contract is per-minor.
37
+ */
38
+ export function referenceVersionPin(engineVersion: string | null | undefined): string | null {
39
+ const match = /^(\d+)\.(\d+)(?:[.+-]|$)/.exec(engineVersion?.trim() ?? '');
40
+ if (!match) return null;
41
+ const pin = `${Number(match[1])}.${Number(match[2])}`;
42
+ return pin === '0.0' ? null : pin;
43
+ }
44
+
45
+ /**
46
+ * Version-pinned Reference URL (`/reference/<major>.<minor>/`) for the given
47
+ * engine version; the unpinned reference root when no pin can be derived.
48
+ */
49
+ export function learnReferenceUrl(engineVersion: string | null | undefined): string {
50
+ const pin = referenceVersionPin(engineVersion);
51
+ return pin === null ? LEARN_REFERENCE_ROOT_URL : `${LEARN_REFERENCE_ROOT_URL}${pin}/`;
52
+ }
53
+
54
+ /**
55
+ * A lesson URL from example `learn` metadata (FT-5), validated to an http(s)
56
+ * absolute URL — manifests are project-authored content, so anything else
57
+ * (relative paths, other schemes) renders no link rather than a broken or
58
+ * unsafe one. Returns null when absent or invalid.
59
+ */
60
+ export function safeLessonUrl(lesson: string | null | undefined): string | null {
61
+ if (!lesson) return null;
62
+ try {
63
+ const url = new URL(lesson);
64
+ return url.protocol === 'https:' || url.protocol === 'http:' ? url.href : null;
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ /** Open a Learn-site destination in a new tab (§6: all Help links open out). */
71
+ export function openLearnLink(url: string): void {
72
+ window.open(url, '_blank', 'noopener,noreferrer');
73
+ }
@@ -0,0 +1,134 @@
1
+ import type { AuthoringAdapter, EditorNode, PropertyDescriptor } from '@volter/editor-project/adapter';
2
+ import { setAuthoringInspectorField } from './authoring/consumer-actions';
3
+ import { forEachHierarchyNode } from './hierarchy-walk';
4
+
5
+ export const LIGHT_EXPLORER_PATHS = {
6
+ enabled: 'visible',
7
+ color: 'light.color',
8
+ intensity: 'light.intensity',
9
+ range: 'light.distance',
10
+ shadows: 'shadow.cast',
11
+ } as const;
12
+
13
+ export type LightExplorerField = keyof typeof LIGHT_EXPLORER_PATHS;
14
+
15
+ export interface LightExplorerCell<T> {
16
+ readonly supported: boolean;
17
+ readonly writable: boolean;
18
+ readonly value: T | null;
19
+ }
20
+
21
+ export interface LightExplorerRow {
22
+ readonly id: string;
23
+ readonly name: string;
24
+ readonly type: string;
25
+ readonly enabled: LightExplorerCell<boolean>;
26
+ readonly color: LightExplorerCell<string>;
27
+ readonly intensity: LightExplorerCell<number>;
28
+ readonly range: LightExplorerCell<number>;
29
+ readonly shadows: LightExplorerCell<boolean>;
30
+ }
31
+
32
+ interface HierarchyWithInternals {
33
+ /** Optional editor-side hierarchy projection used by component-owning
34
+ * adapters. These are still real adapter nodes; they are merely folded out
35
+ * of the ordinary tree until a person asks to reveal implementation parts. */
36
+ internalChildren?(id: string): EditorNode[] | undefined;
37
+ }
38
+
39
+ function lightNodes(adapter: AuthoringAdapter): EditorNode[] {
40
+ const result: EditorNode[] = [];
41
+ const hierarchyWithInternals = adapter as AuthoringAdapter & HierarchyWithInternals;
42
+ forEachHierarchyNode(
43
+ adapter.hierarchy,
44
+ (node) => {
45
+ if (node.kind === 'light') result.push(node);
46
+ },
47
+ { extraChildren: (id) => hierarchyWithInternals.internalChildren?.(id) },
48
+ );
49
+ return result;
50
+ }
51
+
52
+ export function activeLightCount(adapter: AuthoringAdapter): number {
53
+ return lightNodes(adapter).length;
54
+ }
55
+
56
+ function descriptorFor(
57
+ descriptors: readonly PropertyDescriptor[],
58
+ field: LightExplorerField,
59
+ ): PropertyDescriptor | null {
60
+ return descriptors.find((descriptor) => descriptor.path === LIGHT_EXPLORER_PATHS[field]) ?? null;
61
+ }
62
+
63
+ function cell<T>(
64
+ adapter: AuthoringAdapter,
65
+ id: string,
66
+ descriptors: readonly PropertyDescriptor[],
67
+ field: LightExplorerField,
68
+ accept: (value: unknown) => value is T,
69
+ ): LightExplorerCell<T> {
70
+ const descriptor = descriptorFor(descriptors, field);
71
+ if (!descriptor || !adapter.inspector) {
72
+ return { supported: false, writable: false, value: null };
73
+ }
74
+ let value: unknown;
75
+ try {
76
+ value = adapter.inspector.get(id, descriptor.path);
77
+ } catch {
78
+ value = undefined;
79
+ }
80
+ return {
81
+ supported: true,
82
+ writable: descriptor.readonly !== true,
83
+ value: accept(value) ? value : null,
84
+ };
85
+ }
86
+
87
+ const isBoolean = (value: unknown): value is boolean => typeof value === 'boolean';
88
+ const isString = (value: unknown): value is string => typeof value === 'string';
89
+ const isNumber = (value: unknown): value is number =>
90
+ typeof value === 'number' && Number.isFinite(value);
91
+
92
+ export function lightExplorerRows(adapter: AuthoringAdapter): LightExplorerRow[] {
93
+ return lightNodes(adapter).map((node) => {
94
+ let descriptors: readonly PropertyDescriptor[] = [];
95
+ try {
96
+ descriptors = adapter.inspector?.properties(node.id) ?? [];
97
+ } catch {
98
+ // A broken per-node inspector must not take the scene-wide inventory down.
99
+ }
100
+ const nativeType = adapter.hierarchy.object3D?.(node.id)?.type;
101
+ return {
102
+ id: node.id,
103
+ name: node.label,
104
+ type: node.typeLabel ?? nativeType ?? 'Light',
105
+ enabled: cell(adapter, node.id, descriptors, 'enabled', isBoolean),
106
+ color: cell(adapter, node.id, descriptors, 'color', isString),
107
+ intensity: cell(adapter, node.id, descriptors, 'intensity', isNumber),
108
+ range: cell(adapter, node.id, descriptors, 'range', isNumber),
109
+ shadows: cell(adapter, node.id, descriptors, 'shadows', isBoolean),
110
+ };
111
+ });
112
+ }
113
+
114
+ export function setLightExplorerField(
115
+ adapter: AuthoringAdapter,
116
+ ids: readonly string[],
117
+ field: LightExplorerField,
118
+ value: unknown,
119
+ ): number {
120
+ if (!adapter.inspector) return 0;
121
+ let changed = 0;
122
+ for (const id of ids) {
123
+ let descriptor: PropertyDescriptor | null = null;
124
+ try {
125
+ descriptor = descriptorFor(adapter.inspector.properties(id), field);
126
+ } catch {
127
+ continue;
128
+ }
129
+ if (!descriptor || descriptor.readonly) continue;
130
+ setAuthoringInspectorField(adapter, id, descriptor.path, value);
131
+ changed++;
132
+ }
133
+ return changed;
134
+ }