@vgai/editor 0.2.0 → 0.4.0-canary.20260715.0
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.
- package/README.md +24 -0
- package/dist/assets/axe-C7YBtOuM.js +30 -0
- package/dist/assets/browserAll-DDtGGE48.js +1 -0
- package/dist/assets/create-runtime-DbTlBlKG.js +1 -0
- package/dist/assets/{game-BI111o5f.js → game-BE0r7DMI.js} +3 -3
- package/dist/assets/game-BdTHR2_X.js +1 -0
- package/dist/assets/{game-pt_1lQLv.js → game-C3iQGSqo.js} +1 -1
- package/dist/assets/game-CcHfYxjP.js +1 -0
- package/dist/assets/game-Cqzj_lpD.js +1 -0
- package/dist/assets/game-DSZdeCHu.js +1 -0
- package/dist/assets/game-Dch9sAPc.js +1 -0
- package/dist/assets/{game-xsOho_wg.js → game-SAFn90pA.js} +3 -3
- package/dist/assets/game-loop-DMIgSMV-.js +1 -0
- package/dist/assets/{game-source-CvidN7AB.js → game-source-Dk83w26t.js} +1 -1
- package/dist/assets/{index-Bp5cecD6.js → index-4idIsHHJ.js} +2 -2
- package/dist/assets/{index-DL7RcQ0n.js → index-C-LhOTBN.js} +1 -1
- package/dist/assets/{index-Cs8xwv3e.js → index-CDkxceqE.js} +1 -1
- package/dist/assets/index-CQEfi217.js +15412 -0
- package/dist/assets/index-Dvi-V0NE.css +1 -0
- package/dist/assets/ingest-siblings-s0P5I1Ub.js +1 -0
- package/dist/assets/mount-manifest-DXMOlF79.js +1 -0
- package/dist/assets/react-18-C9eHn8x1.js +1 -0
- package/dist/assets/webworkerAll-Fn0e-ouF.js +1 -0
- package/dist/assets/world-documents-GM0a9Kv7.js +1 -0
- package/dist/index.html +15 -13
- package/dist/ingest/racing-game/vgai.game.json +5 -4
- package/dist/ingest/simcity/vgai.game.json +5 -4
- package/dist/ingest/tanks/vgai.game.json +5 -4
- package/dist/project-scripts.bundle.js +3917 -0
- package/dist/scenes/untitled.vscn.json +2 -0
- package/dist-server/packaged.mjs +7697 -3435
- package/package.json +31 -4
- package/scripts/probe-reporter.ts +349 -0
- package/scripts/run-probe.ts +2260 -0
- package/server/asset-catalog-audit.ts +268 -0
- package/server/asset-catalog-v2.ts +146 -0
- package/server/asset-library-routes.ts +276 -58
- package/server/canonical-path.ts +1 -1
- package/server/dev.ts +148 -44
- package/server/editor-server.ts +888 -61
- package/server/editor-sse.ts +115 -4
- package/server/harness-chat-service.ts +796 -0
- package/server/local-asset-catalog.ts +157 -22
- package/server/packaged.ts +51 -21
- package/server/process-shutdown.ts +136 -0
- package/server/prod.ts +9 -6
- package/server/project-hmr-files.ts +41 -0
- package/server/project-operations.ts +343 -0
- package/server/project-optimize-deps-entries.ts +4 -4
- package/server/project-output-writer.ts +156 -0
- package/server/project-validation.ts +140 -0
- package/server/project-view.ts +8 -50
- package/server/server-utils.ts +75 -10
- package/server/session-registry.ts +12 -0
- package/src/EditorContext.tsx +107 -3
- package/src/action-registry.ts +115 -17
- package/src/adapter-resolver.ts +213 -478
- package/src/asset-events.ts +64 -1
- package/src/asset-preview.ts +906 -0
- package/src/asset-selection.ts +121 -0
- package/src/asset-workflow/asset-capabilities.ts +259 -0
- package/src/asset-workflow/asset-editor-errors.ts +46 -0
- package/src/asset-workflow/asset-import-pipeline.ts +176 -0
- package/src/asset-workflow/asset-library-query.ts +107 -0
- package/src/asset-workflow/asset-types.ts +192 -0
- package/src/asset-workflow/asset-workflow-quality.ts +65 -0
- package/src/asset-workflow/import-contract.ts +113 -0
- package/src/asset-workflow/model-conversion.ts +126 -0
- package/src/asset-workflow/model-inspection.ts +185 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +153 -0
- package/src/asset-workflow/project-asset-operations.ts +119 -0
- package/src/asset-workflow/thumbnail-system.ts +172 -0
- package/src/authoring/active-systems.ts +15 -0
- package/src/authoring/boundary-authoring-adapter.ts +16 -5
- package/src/authoring/composite-authoring-adapter.ts +305 -124
- package/src/authoring/design-time-layers.ts +300 -117
- package/src/authoring/edit-mode-authoring.ts +278 -293
- package/src/authoring/embed-only-adapter.ts +4 -2
- package/src/authoring/first-party-hierarchy-menu.ts +7 -2
- package/src/authoring/first-party-inspector/AddSectionMenu.tsx +5 -12
- package/src/authoring/first-party-inspector/EnvironmentSection.tsx +53 -126
- package/src/authoring/first-party-inspector/HeaderSection.tsx +54 -65
- package/src/authoring/first-party-inspector/is-first-party-selection.ts +30 -11
- package/src/authoring/first-party-inspector/register.tsx +13 -2
- package/src/authoring/ingest-authoring-adapter.ts +142 -45
- package/src/authoring/mount-failure-report.ts +5 -5
- package/src/authoring/provenance.ts +41 -0
- package/src/authoring/react-dom-authoring-adapter.ts +92 -92
- package/src/authoring/react-inspector-section.tsx +489 -51
- package/src/authoring/react-world-authoring-adapter.ts +541 -306
- package/src/authoring/story-overlay.ts +1 -1
- package/src/authoring/story-types.ts +11 -0
- package/src/authoring/vgai-scene-authoring-adapter.ts +54 -25
- package/src/authoring/viewport-tool-context.ts +78 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +186 -0
- package/src/authoring/world-pan-state.ts +33 -17
- package/src/authoring/world-session-state.ts +1 -1
- package/src/authoring/world2d-authoring-adapter.ts +109 -52
- package/src/availability-tick.ts +56 -0
- package/src/browser-play-entry.ts +5 -5
- package/src/browser-project-scripts.ts +1 -0
- package/src/build-identity.ts +15 -0
- package/src/command-listener.ts +893 -19
- package/src/components/AlignToolbar.tsx +74 -63
- package/src/components/AppRoot.tsx +193 -26
- package/src/components/ApplicationMenus.tsx +272 -0
- package/src/components/AssetBrowser.tsx +1450 -293
- package/src/components/AssetEditorShell.tsx +141 -0
- package/src/components/AssetImportDetails.tsx +218 -0
- package/src/components/AssetLibraryPanel.tsx +14 -0
- package/src/components/CameraInfo.tsx +11 -20
- package/src/components/CenterDocuments.tsx +585 -0
- package/src/components/CommandPalette.tsx +75 -30
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +57 -112
- package/src/components/DebugConsolePanel.tsx +461 -0
- package/src/components/DebuggerPanel.tsx +165 -0
- package/src/components/DefaultEditorLayout.tsx +167 -231
- package/src/components/GameHierarchy.tsx +873 -290
- package/src/components/GamePerformanceOverlay.tsx +46 -0
- package/src/components/HarnessChatPanel.tsx +2352 -0
- package/src/components/HistoryPanel.tsx +226 -0
- package/src/components/Inspector.tsx +153 -99
- package/src/components/InspectorToolSection.tsx +6 -4
- package/src/components/MountFailureBanner.tsx +31 -48
- package/src/components/NetworkSection.tsx +25 -14
- package/src/components/OnlineAssetBrowser.tsx +794 -343
- package/src/components/OverlayReportBanner.tsx +38 -64
- package/src/components/PerformancePanel.tsx +206 -0
- package/src/components/PlayBar.tsx +93 -263
- package/src/components/PrefabSaveDialog.tsx +55 -127
- package/src/components/ProjectHeader.css +60 -0
- package/src/components/ProjectHeader.tsx +170 -105
- package/src/components/ProjectScreen.tsx +246 -184
- package/src/components/ReactCanvasControls.tsx +185 -0
- package/src/components/ResolutionPicker.tsx +85 -0
- package/src/components/RootActivateDialog.tsx +39 -68
- package/src/components/SaveDialog.tsx +55 -127
- package/src/components/SaveStatus.tsx +11 -29
- package/src/components/StartupLoadingScreen.tsx +96 -0
- package/src/components/StateWatchPanel.tsx +302 -0
- package/src/components/StatsOverlay.tsx +12 -5
- package/src/components/StatusBar.tsx +64 -0
- package/src/components/ThemeManagerDialog.css +89 -0
- package/src/components/ThemeManagerDialog.tsx +371 -0
- package/src/components/ToolHost.tsx +26 -15
- package/src/components/Toolbar.tsx +117 -214
- package/src/components/VgaiVoxelLogo.tsx +89 -0
- package/src/components/ViewportOverlay.tsx +97 -172
- package/src/components/ViewportPanel.tsx +130 -31
- package/src/components/WorkspaceDock.tsx +891 -0
- package/src/components/WorldSelectionOverlay.tsx +51 -63
- package/src/components/WorldTextEditor.tsx +9 -5
- package/src/components/asset-documents.tsx +390 -0
- package/src/components/asset-editor-persistence.ts +44 -0
- package/src/components/asset-selection-section.tsx +338 -0
- package/src/components/asset-viewers/AudioViewer.tsx +73 -21
- package/src/components/asset-viewers/GenericJsonViewer.tsx +26 -11
- package/src/components/asset-viewers/ImageViewer.tsx +43 -11
- package/src/components/asset-viewers/InputMapViewer.tsx +512 -134
- package/src/components/asset-viewers/MaterialAssetEditor.tsx +540 -0
- package/src/components/asset-viewers/ModelViewer.tsx +805 -121
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +177 -60
- package/src/components/asset-viewers/SourceAssetViewer.tsx +121 -0
- package/src/components/asset-workflow.css +506 -0
- package/src/components/build-documents.tsx +696 -0
- package/src/components/core-utilities.tsx +75 -0
- package/src/components/data-documents.tsx +364 -0
- package/src/components/{DataPanel.tsx → data-editor.tsx} +138 -288
- package/src/components/debugger-panel-state.ts +57 -0
- package/src/components/inspector-widgets/AlignmentGrid.tsx +8 -14
- package/src/components/inspector-widgets/BorderEditor.tsx +41 -33
- package/src/components/inspector-widgets/ColorPicker.tsx +39 -39
- package/src/components/inspector-widgets/FontPicker.tsx +13 -21
- package/src/components/inspector-widgets/GradientEditor.tsx +11 -19
- package/src/components/inspector-widgets/ScrubbableInput.tsx +6 -3
- package/src/components/inspector-widgets/ShadowEditor.tsx +20 -33
- package/src/components/inspector-widgets/shared.tsx +90 -49
- package/src/components/inspectors/AnimationSection.tsx +39 -40
- package/src/components/inspectors/AudioSection.tsx +28 -39
- package/src/components/inspectors/BoneAttachmentSection.tsx +19 -24
- package/src/components/inspectors/CameraSection.tsx +14 -23
- package/src/components/inspectors/ComponentsSection.tsx +39 -43
- package/src/components/inspectors/JointsSection.tsx +34 -43
- package/src/components/inspectors/LightSection.tsx +90 -35
- package/src/components/inspectors/MaterialSection.tsx +137 -174
- package/src/components/inspectors/MeshSection.tsx +9 -17
- package/src/components/inspectors/NavigationSection.tsx +8 -15
- package/src/components/inspectors/ParticleSection.tsx +91 -76
- package/src/components/inspectors/PhysicsSection.tsx +42 -46
- package/src/components/inspectors/PostProcessingSection.tsx +28 -36
- package/src/components/inspectors/RenderingSection.tsx +12 -20
- package/src/components/inspectors/ShadowSection.tsx +7 -8
- package/src/components/inspectors/SplineSection.tsx +31 -42
- package/src/components/inspectors/TransformSection.tsx +14 -22
- package/src/components/patterns/Dialog.tsx +95 -0
- package/src/components/patterns/Fields.tsx +44 -0
- package/src/components/patterns/List.tsx +25 -0
- package/src/components/patterns/StateSurface.tsx +40 -0
- package/src/components/patterns/Surfaces.tsx +115 -0
- package/src/components/patterns/Tabs.tsx +80 -0
- package/src/components/patterns/Toolbar.tsx +51 -0
- package/src/components/patterns/Tree.tsx +72 -0
- package/src/components/primitives/Button.tsx +46 -0
- package/src/components/primitives/ColorInput.tsx +11 -47
- package/src/components/primitives/EditorIcon.tsx +99 -0
- package/src/components/primitives/FormControls.tsx +71 -0
- package/src/components/primitives/JsonInput.tsx +15 -2
- package/src/components/primitives/Layout.tsx +100 -0
- package/src/components/primitives/Menu.tsx +105 -0
- package/src/components/primitives/NumberInput.tsx +8 -35
- package/src/components/primitives/Panel.tsx +49 -44
- package/src/components/primitives/SectionHeader.tsx +10 -28
- package/src/components/primitives/Text.tsx +46 -0
- package/src/components/primitives/Tooltip.tsx +20 -12
- package/src/components/primitives/Vec3Input.tsx +3 -0
- package/src/components/primitives/banner-tones.ts +33 -0
- package/src/components/primitives/editor-icons.ts +102 -0
- package/src/components/primitives/panel-header-styles.ts +30 -0
- package/src/components/project-operation-documents.tsx +226 -0
- package/src/components/status-contributions.tsx +175 -0
- package/src/components/story-documents-register.ts +15 -0
- package/src/components/story-documents.tsx +1185 -0
- package/src/components/tool-documents.tsx +110 -0
- package/src/components/workspace-dock.css +293 -0
- package/src/components/workspace-history.ts +33 -0
- package/src/components/world-documents.tsx +145 -0
- package/src/components/xstate-documents.tsx +209 -0
- package/src/composite-screenshot.ts +248 -0
- package/src/design-system/index.ts +70 -0
- package/src/design-system-stories/Foundation.stories.tsx +183 -0
- package/src/design-system-stories/Patterns.stories.tsx +251 -0
- package/src/design-system-stories/Workspace.stories.tsx +538 -0
- package/src/doctor/report.ts +57 -13
- package/src/editor-api.ts +295 -31
- package/src/editor-compatibility.ts +200 -0
- package/src/editor-console.ts +35 -17
- package/src/editor-hotkeys.ts +85 -33
- package/src/editor-store.ts +538 -233
- package/src/editor-viewport.ts +160 -34
- package/src/entity-factory.ts +14 -3
- package/src/gizmo-registry.ts +21 -5
- package/src/harness-chat-editor-context.ts +37 -0
- package/src/harness-chat-indicator.ts +68 -0
- package/src/harness-chat-layout.ts +53 -0
- package/src/harness-chat-lifecycle.ts +170 -0
- package/src/harness-chat-reconnect.ts +85 -0
- package/src/harness-chat-types.ts +409 -0
- package/src/hierarchy-drop.ts +50 -0
- package/src/hierarchy-expansion-state.ts +100 -0
- package/src/hierarchy-menu-registry.ts +1 -1
- package/src/hierarchy-projection.ts +76 -0
- package/src/history/editor-session.ts +21 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-service.ts +904 -0
- package/src/history/json-history-resource.ts +165 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +266 -0
- package/src/history/project-root-history-backends.ts +53 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +108 -0
- package/src/history/source-history-backend.ts +374 -0
- package/src/history/types.ts +100 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hosted-example.ts +12 -2
- package/src/hotkeys.ts +89 -18
- package/src/ingest/discovery-react.ts +9 -10
- package/src/ingest/discovery.ts +4 -4
- package/src/ingest/discovery2d.ts +5 -5
- package/src/ingest/games/bloom-composer/vgai.game.json +3 -3
- package/src/ingest/games/embed-bundle/vgai.game.json +3 -3
- package/src/ingest/games/games-fps/vgai.game.json +3 -3
- package/src/ingest/games/iframe-reachable/vgai.game.json +3 -3
- package/src/ingest/games/interactive-cubes/vgai.game.json +3 -3
- package/src/ingest/games/mismatched-three/vgai.game.json +3 -3
- package/src/ingest/games/own-three-bundled/vgai.game.json +3 -3
- package/src/ingest/games/pointerlock-maze/vgai.game.json +7 -4
- package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +3 -3
- package/src/ingest/games-2d/bunnymark/vgai.game.json +3 -3
- package/src/ingest/games-2d/flappy/vgai.game.json +3 -3
- package/src/ingest/games-2d/flappy-pixi/vgai.game.json +3 -3
- package/src/ingest/games-2d/puzzling-potions/vgai.game.json +3 -3
- package/src/ingest/games-2d/tilemap-camera/vgai.game.json +3 -3
- package/src/ingest/games-react/react-rpg/vgai.game.json +3 -3
- package/src/ingest/types.ts +1 -1
- package/src/ingest-mode.ts +47 -52
- package/src/ingest-siblings.ts +23 -33
- package/src/initial-scene.ts +1 -2
- package/src/main.tsx +16 -8
- package/src/manifest-project.ts +10 -12
- package/src/model-thumbnail.ts +261 -26
- package/src/module-mode.ts +44 -50
- package/src/play-log-events.ts +26 -0
- package/src/play-mode.ts +495 -401
- package/src/play-scene-adoption.ts +23 -0
- package/src/playground/main.ts +68 -24
- package/src/playwright-shim.ts +473 -0
- package/src/project-manager.ts +90 -10
- package/src/project-operations.ts +112 -0
- package/src/project-story-discovery.ts +25 -0
- package/src/project-tool-discovery.ts +43 -0
- package/src/scene-serializer.ts +0 -6
- package/src/scene-sync.ts +7 -2
- package/src/script-loader.ts +3 -3
- package/src/skeleton-helper.ts +57 -0
- package/src/storage/seed.ts +68 -8
- package/src/stories/StoryPreviewMount.tsx +265 -0
- package/src/stories/action-stories.fixture.tsx +44 -0
- package/src/stories/button-stories.fixture.tsx +50 -0
- package/src/stories/compose-project-stories.ts +182 -0
- package/src/stories/loader-stories.fixture.tsx +53 -0
- package/src/stories/story-discovery.ts +130 -0
- package/src/stories/story-registry.ts +146 -0
- package/src/theme-css.ts +1049 -0
- package/src/theme-library.ts +238 -0
- package/src/theme-preference.ts +130 -0
- package/src/theme.ts +527 -0
- package/src/tool-loader.ts +80 -24
- package/src/ui-source/inspect.ts +27 -4
- package/src/ui-source/source-write-backend.ts +83 -22
- package/src/widgets/index.ts +9 -18
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-dock-controller.ts +64 -0
- package/src/workspace-document-ids.ts +5 -0
- package/src/workspace-document-registry.ts +367 -0
- package/src/workspace-state-persistence.ts +455 -0
- package/src/workspace-status-registry.ts +110 -0
- package/src/workspace-utility-commands.ts +49 -0
- package/src/workspace-utility-registry.ts +161 -0
- package/src/world-document-routing.ts +16 -0
- package/src/xstate-inspect/XStateMachineInspector.tsx +544 -0
- package/src/xstate-inspect/character-animation-machine.fixture.ts +74 -0
- package/src/xstate-inspect/use-live-actor-state.ts +39 -0
- package/src/xstate-inspect/xstate-graph.ts +265 -0
- package/src/xstate-inspect/xstate-layout.ts +76 -0
- package/src/z-index.ts +26 -0
- package/template/.claude/skills/editor/SKILL.md +129 -90
- package/template/AGENTS.md +1110 -0
- package/template/CLAUDE.md +1 -512
- package/template/IDIOMS.md +50 -0
- package/template/check-idioms.ts +706 -0
- package/template/manifest-entry-modules-plugin.ts +53 -0
- package/template/package.json +13 -4
- package/template/public/scenes/default.scn2d.json +6 -0
- package/template/public/scenes/default.vscn.json +7 -1
- package/template/public/scenes/untitled.vscn.json +10 -0
- package/template/scripts/playtest.ts +40 -0
- package/template/server/loopback.ts +75 -0
- package/template/server/rooms/arena-room.ts +69 -1
- package/template/server/rooms/game-room.ts +68 -1
- package/template/src/data/README.md +9 -4
- package/template/src/data/data-ref.ts +35 -0
- package/template/src/data/tuning.schema.ts +1 -1
- package/template/src/main.ts +41 -62
- package/template/src/manifest-entry-modules.d.ts +3 -0
- package/template/src/operations/README.md +88 -0
- package/template/src/runtime/pixi-adapter.ts +24 -0
- package/template/src/scripts/components/data-spinner.ts +43 -2
- package/template/src/scripts/components/spin-lap-math.ts +27 -0
- package/template/src/tools/README.md +5 -3
- package/template/src/tools/example.tool.tsx +13 -7
- package/template/src/ui/Button.stories.tsx +66 -0
- package/template/src/ui/RebindPanel.tsx +2 -6
- package/template/src/ui/game.tsx +17 -0
- package/template/tests/acceptance/example.spec.ts +64 -0
- package/template/tests/logic/example.test.ts +31 -0
- package/template/tests/logic/room.test.ts +100 -0
- package/template/tests/tsconfig.json +30 -0
- package/template/validate-manifest.ts +5 -5
- package/template/validate-scenes.ts +50 -18
- package/template/vgai.game.json +20 -13
- package/template/vite.config.ts +77 -16
- package/vite-plugin-ui-oid.ts +261 -17
- package/dist/assets/CCDIKSolver-Dz-ysxZF.js +0 -1
- package/dist/assets/SelectionBox-BXsv_6aH.js +0 -1
- package/dist/assets/browser-project-scripts-DOru4L1x.js +0 -2
- package/dist/assets/browserAll-CEkWYlFk.js +0 -1
- package/dist/assets/create-runtime-DYIWr3va.js +0 -1
- package/dist/assets/data-asset-Bb9sIM7i.js +0 -5
- package/dist/assets/game-8SDZPPgH.js +0 -1
- package/dist/assets/game-CevorxyV.js +0 -1
- package/dist/assets/game-Di7XlywD.js +0 -1
- package/dist/assets/game-DjnCaw8R.js +0 -1
- package/dist/assets/game-Q9A0aXSV.js +0 -1
- package/dist/assets/index-CPVV6pjw.js +0 -1
- package/dist/assets/index-CpOnYyeD.js +0 -213
- package/dist/assets/index-Dr8H_6Rl.js +0 -1
- package/dist/assets/index-_bCaipUk.js +0 -13650
- package/dist/assets/ingest-siblings-Dz8eEqrV.js +0 -1
- package/dist/assets/mount-manifest-Bhk0ohsl.js +0 -1
- package/dist/assets/scene-query-BivAHhJu.js +0 -1
- package/dist/assets/webworkerAll-BLrH0F6F.js +0 -1
- package/dist/assets/xstate-animation-binding-1NGLmw6y.js +0 -1
- package/dist/assets/xstate.esm-BgUD33nl.js +0 -3
- package/src/authoring/scene-ui-layer.ts +0 -485
- package/src/authoring/ui-authoring-adapter.ts +0 -325
- package/src/authoring/ui-hierarchy-menu.ts +0 -40
- package/src/authoring/ui-inspector-sections.tsx +0 -156
- package/src/authoring/undo-timeline.ts +0 -145
- package/src/components/BottomPanel.tsx +0 -326
- package/src/components/BuildPanel.tsx +0 -455
- package/src/components/FolderTree.tsx +0 -179
- package/src/components/RightPanel.tsx +0 -166
- package/src/components/WorldContextMenu.tsx +0 -257
- package/src/components/asset-viewers/AssetViewer.tsx +0 -38
- package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +0 -129
- package/src/scene-ui-mode/active-scene-ui.ts +0 -58
- package/src/scene-ui-mode/scene-ui-palette-panel.tsx +0 -152
- package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +0 -29
- package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +0 -74
- package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +0 -49
- package/src/scene-ui-mode/ui-prefab-io.ts +0 -76
- package/src/ui-editor/inspector.tsx +0 -563
- package/src/ui-editor/node-ops.ts +0 -266
- package/src/ui-editor/overlay.tsx +0 -380
- package/src/ui-editor/palette.tsx +0 -114
- package/src/ui-editor/react-store.ts +0 -78
- package/src/ui-editor/timeline-panel.tsx +0 -443
- package/src/ui-editor/ui-edit-store.ts +0 -552
- package/src/ui-editor/ui-prefab.ts +0 -95
- package/template/project.json +0 -9
- package/template/src/scripts/main.ts +0 -94
- package/template/src/ui/DefaultHud.tsx +0 -40
- package/template/src/ui/game-state.tsx +0 -37
- package/template/src/ui/mount-default-hud.tsx +0 -19
- package/template/src/ui/mount-ui.ts +0 -15
- package/vite-plugin-react-world-provider.ts +0 -81
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-world drop validity for the hierarchy shell (spec 29 §3,
|
|
3
|
+
* `docs/unified-world-editor/29-hierarchy-philosophy.md`): edge semantics
|
|
4
|
+
* belong to the kind, so `CompositeAuthoringAdapter`'s structure provider
|
|
5
|
+
* REFUSES cross-world reparents (loud warn + no-op) and cross-world reorder
|
|
6
|
+
* anchors. A drop the adapter will refuse must never LOOK valid in the panel —
|
|
7
|
+
* chrome advertising an operation that will be refused is a false claim — so
|
|
8
|
+
* `GameHierarchy`'s dragover path gates the drop indicator on this predicate
|
|
9
|
+
* instead of letting the drop fall through to the adapter's refusal.
|
|
10
|
+
*
|
|
11
|
+
* Rule zero: roots are resolved by ASKING the composite (`groupNodeId`/
|
|
12
|
+
* `ownerOf`), never by decoding adapter-minted id strings here.
|
|
13
|
+
*/
|
|
14
|
+
import type { AuthoringAdapter } from '@engine/adapter';
|
|
15
|
+
import { CompositeAuthoringAdapter } from './authoring/composite-authoring-adapter';
|
|
16
|
+
|
|
17
|
+
/** The world that owns `nodeId` for drop purposes: the owning child's
|
|
18
|
+
* `worldId` for an ordinary row, the world itself for its synthetic
|
|
19
|
+
* `world:<id>` group row (dropping INTO a world's own group row is
|
|
20
|
+
* "become a root of my world" — valid), `null` for an organizational or
|
|
21
|
+
* unrecognized id
|
|
22
|
+
* no child recognizes. */
|
|
23
|
+
function dropWorldOf(composite: CompositeAuthoringAdapter, nodeId: string): string | null {
|
|
24
|
+
for (const child of composite.childAdapters()) {
|
|
25
|
+
if (composite.groupNodeId(child.worldId) === nodeId) return child.worldId;
|
|
26
|
+
}
|
|
27
|
+
return composite.ownerOf(nodeId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* True when reparenting/reordering `dragIds` at row `targetId` will be
|
|
32
|
+
* accepted by the active adapter's structure provider: the adapter is not a
|
|
33
|
+
* composite (a bare adapter is single-world by construction), or EVERY
|
|
34
|
+
* dragged id and the target row live in the same world. A mixed-world
|
|
35
|
+
* multi-select fails as a whole — the alternative is a drop that half-applies
|
|
36
|
+
* (same-world ids move, foreign ids warn), which is worse than refusing the
|
|
37
|
+
* affordance outright. Group-row / organizational drag ids fail the same way
|
|
38
|
+
* (`ownerOf` → null): roots are reordered through their zOrder, not by
|
|
39
|
+
* dragging one into another's subtree.
|
|
40
|
+
*/
|
|
41
|
+
export function isSameWorldDrop(
|
|
42
|
+
adapter: AuthoringAdapter,
|
|
43
|
+
dragIds: string[],
|
|
44
|
+
targetId: string,
|
|
45
|
+
): boolean {
|
|
46
|
+
if (!(adapter instanceof CompositeAuthoringAdapter)) return true;
|
|
47
|
+
const targetWorld = dropWorldOf(adapter, targetId);
|
|
48
|
+
if (targetWorld === null) return false;
|
|
49
|
+
return dragIds.every((id) => adapter.ownerOf(id) === targetWorld);
|
|
50
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-scoped hierarchy expansion preferences.
|
|
3
|
+
*
|
|
4
|
+
* Expansion belongs to an authored node's stable adapter id, not to its
|
|
5
|
+
* current row index. That lets the same preference survive an edit/live
|
|
6
|
+
* adapter replacement (Play/Stop) and ordinary React remounts. The project
|
|
7
|
+
* scope prevents common ids such as `game` or `root` leaking between games.
|
|
8
|
+
*
|
|
9
|
+
* Only explicit user choices are stored. A node with no entry follows the
|
|
10
|
+
* hierarchy's current shallow-open default, so changing the projection does
|
|
11
|
+
* not require a migration of a fully materialized tree state.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const STORAGE_KEY = 'vgai:hierarchy-expansion:v1';
|
|
15
|
+
|
|
16
|
+
type ProjectPreferences = Map<string, boolean>;
|
|
17
|
+
|
|
18
|
+
const preferences = new Map<string, ProjectPreferences>();
|
|
19
|
+
let hydrated = false;
|
|
20
|
+
|
|
21
|
+
function browserStorage(): Storage | null {
|
|
22
|
+
try {
|
|
23
|
+
return typeof window === 'undefined' ? null : window.localStorage;
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hydrate(): void {
|
|
30
|
+
if (hydrated) return;
|
|
31
|
+
hydrated = true;
|
|
32
|
+
const storage = browserStorage();
|
|
33
|
+
if (!storage) return;
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(storage.getItem(STORAGE_KEY) ?? '{}') as Record<
|
|
36
|
+
string,
|
|
37
|
+
Record<string, boolean>
|
|
38
|
+
>;
|
|
39
|
+
for (const [projectId, nodes] of Object.entries(parsed)) {
|
|
40
|
+
preferences.set(projectId, new Map(Object.entries(nodes)));
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// A corrupt/stale preference must never prevent the editor from opening.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function persist(): void {
|
|
48
|
+
const storage = browserStorage();
|
|
49
|
+
if (!storage) return;
|
|
50
|
+
try {
|
|
51
|
+
const serialized: Record<string, Record<string, boolean>> = {};
|
|
52
|
+
for (const [projectId, nodes] of preferences) {
|
|
53
|
+
serialized[projectId] = Object.fromEntries(nodes);
|
|
54
|
+
}
|
|
55
|
+
storage.setItem(STORAGE_KEY, JSON.stringify(serialized));
|
|
56
|
+
} catch {
|
|
57
|
+
// Expansion is convenience state; storage denial/quota is non-fatal.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function hierarchyExpansionPreference(
|
|
62
|
+
projectId: string,
|
|
63
|
+
nodeId: string,
|
|
64
|
+
): boolean | undefined {
|
|
65
|
+
hydrate();
|
|
66
|
+
return preferences.get(projectId)?.get(nodeId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Apply a whole branch/view operation with one storage write. */
|
|
70
|
+
export function setHierarchyExpansionPreferences(
|
|
71
|
+
projectId: string,
|
|
72
|
+
entries: Iterable<readonly [nodeId: string, expanded: boolean]>,
|
|
73
|
+
): void {
|
|
74
|
+
hydrate();
|
|
75
|
+
let project = preferences.get(projectId);
|
|
76
|
+
if (!project) {
|
|
77
|
+
project = new Map();
|
|
78
|
+
preferences.set(projectId, project);
|
|
79
|
+
}
|
|
80
|
+
for (const [nodeId, expanded] of entries) project.set(nodeId, expanded);
|
|
81
|
+
persist();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Return every node in one project to the shallow first-open policy. */
|
|
85
|
+
export function clearHierarchyExpansionPreferences(projectId: string): void {
|
|
86
|
+
hydrate();
|
|
87
|
+
preferences.delete(projectId);
|
|
88
|
+
persist();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Test-only reset for this process and its jsdom localStorage. */
|
|
92
|
+
export function _resetHierarchyExpansionPreferencesForTest(): void {
|
|
93
|
+
preferences.clear();
|
|
94
|
+
hydrated = true;
|
|
95
|
+
try {
|
|
96
|
+
browserStorage()?.removeItem(STORAGE_KEY);
|
|
97
|
+
} catch {
|
|
98
|
+
// no-op
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -64,7 +64,7 @@ export function getHierarchyMenuItems(ctx: HierarchyMenuContext): HierarchyMenuI
|
|
|
64
64
|
return registrations.filter((r) => r.match(ctx)).flatMap((r) => r.items(ctx));
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
/** Test-only reset
|
|
67
|
+
/** Test-only reset for module-level menu registrations. */
|
|
68
68
|
export function __resetHierarchyMenuRegistryForTest(): void {
|
|
69
69
|
registrations.length = 0;
|
|
70
70
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-authored hierarchy projection (D20).
|
|
3
|
+
*
|
|
4
|
+
* This is editor metadata, not runtime composition. `vgai.game.json.roots`
|
|
5
|
+
* declares adapter mounts; `vgai.game.json.authoring.hierarchy` only
|
|
6
|
+
* chooses how those roots are labelled and grouped in the authoring tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface HierarchyProjectionGroup {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly label: string;
|
|
12
|
+
readonly roots: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface HierarchyProjection {
|
|
16
|
+
readonly rootLabels?: Readonly<Record<string, string>>;
|
|
17
|
+
readonly groups?: readonly HierarchyProjectionGroup[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function record(value: unknown): Record<string, unknown> | null {
|
|
21
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
22
|
+
? (value as Record<string, unknown>)
|
|
23
|
+
: null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Leniently read authoring metadata. Invalid entries are omitted so a typo in
|
|
28
|
+
* an optional projection can never make the game itself unopenable.
|
|
29
|
+
*/
|
|
30
|
+
export function parseHierarchyProjection(value: unknown): HierarchyProjection | undefined {
|
|
31
|
+
const source = record(value);
|
|
32
|
+
if (!source) return undefined;
|
|
33
|
+
|
|
34
|
+
const labelsSource = record(source['rootLabels']);
|
|
35
|
+
const labelEntries = labelsSource
|
|
36
|
+
? Object.entries(labelsSource).flatMap(([id, label]): Array<[string, string]> => {
|
|
37
|
+
const normalizedId = id.trim();
|
|
38
|
+
const normalizedLabel = typeof label === 'string' ? label.trim() : '';
|
|
39
|
+
return normalizedId && normalizedLabel ? [[normalizedId, normalizedLabel]] : [];
|
|
40
|
+
})
|
|
41
|
+
: [];
|
|
42
|
+
const rootLabels = labelEntries.length > 0 ? Object.fromEntries(labelEntries) : undefined;
|
|
43
|
+
|
|
44
|
+
const groupIds = new Set<string>();
|
|
45
|
+
const groupEntries = Array.isArray(source['groups'])
|
|
46
|
+
? source['groups'].flatMap((candidate): HierarchyProjectionGroup[] => {
|
|
47
|
+
const group = record(candidate);
|
|
48
|
+
const id = typeof group?.['id'] === 'string' ? group['id'].trim() : '';
|
|
49
|
+
const label = typeof group?.['label'] === 'string' ? group['label'].trim() : '';
|
|
50
|
+
const roots = Array.isArray(group?.['roots'])
|
|
51
|
+
? group['roots'].flatMap((root): string[] => {
|
|
52
|
+
const normalized = typeof root === 'string' ? root.trim() : '';
|
|
53
|
+
return normalized ? [normalized] : [];
|
|
54
|
+
})
|
|
55
|
+
: [];
|
|
56
|
+
if (!id || !label || roots.length === 0 || groupIds.has(id)) return [];
|
|
57
|
+
groupIds.add(id);
|
|
58
|
+
return [{ id, label, roots: [...new Set(roots)] }];
|
|
59
|
+
})
|
|
60
|
+
: [];
|
|
61
|
+
const groups = groupEntries.length > 0 ? groupEntries : undefined;
|
|
62
|
+
|
|
63
|
+
if (!rootLabels && !groups) return undefined;
|
|
64
|
+
return {
|
|
65
|
+
...(rootLabels ? { rootLabels } : {}),
|
|
66
|
+
...(groups ? { groups } : {}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Read the projection from a raw `vgai.game.json` config object. */
|
|
71
|
+
export function hierarchyProjectionFromProjectConfig(
|
|
72
|
+
config: unknown,
|
|
73
|
+
): HierarchyProjection | undefined {
|
|
74
|
+
const authoring = record(record(config)?.['authoring']);
|
|
75
|
+
return parseHierarchyProjection(authoring?.['hierarchy']);
|
|
76
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HistoryCommands } from './history-commands';
|
|
2
|
+
import { HistoryService, type HistoryServiceOptions } from './history-service';
|
|
3
|
+
|
|
4
|
+
/** Owns project-lifetime editor services; disposed when EditorProvider unmounts. */
|
|
5
|
+
export class EditorSession {
|
|
6
|
+
readonly history: HistoryService;
|
|
7
|
+
readonly historyCommands: HistoryCommands;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly projectIdentity: string,
|
|
11
|
+
historyOptions: HistoryServiceOptions = {},
|
|
12
|
+
) {
|
|
13
|
+
this.history = new HistoryService(historyOptions);
|
|
14
|
+
this.historyCommands = new HistoryCommands(this.history);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
dispose(): void {
|
|
18
|
+
this.historyCommands.dispose();
|
|
19
|
+
this.history.dispose();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { HistoryService } from './history-service';
|
|
2
|
+
|
|
3
|
+
export interface HistoryCommandSnapshot {
|
|
4
|
+
readonly version: number;
|
|
5
|
+
readonly busy: boolean;
|
|
6
|
+
readonly canUndo: boolean;
|
|
7
|
+
readonly canRedo: boolean;
|
|
8
|
+
readonly undoLabel: string | null;
|
|
9
|
+
readonly redoLabel: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Shell command surface for the one project HistoryService timeline. */
|
|
13
|
+
export class HistoryCommands {
|
|
14
|
+
private tail: Promise<void> = Promise.resolve();
|
|
15
|
+
private readonly listeners = new Set<() => void>();
|
|
16
|
+
private pending = 0;
|
|
17
|
+
private version = 0;
|
|
18
|
+
private disposed = false;
|
|
19
|
+
private readonly idleWaiters = new Set<{
|
|
20
|
+
unsubscribe: () => void;
|
|
21
|
+
reject: (error: Error) => void;
|
|
22
|
+
}>();
|
|
23
|
+
private readonly unsubscribeHistory: () => void;
|
|
24
|
+
private snapshot: HistoryCommandSnapshot;
|
|
25
|
+
|
|
26
|
+
constructor(private readonly history: HistoryService) {
|
|
27
|
+
this.snapshot = this.buildSnapshot();
|
|
28
|
+
this.unsubscribeHistory = history.subscribe(this.notify);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
subscribe = (listener: () => void): (() => void) => {
|
|
32
|
+
if (this.disposed) return () => undefined;
|
|
33
|
+
this.listeners.add(listener);
|
|
34
|
+
return () => this.listeners.delete(listener);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
getSnapshot = (): HistoryCommandSnapshot => this.snapshot;
|
|
38
|
+
|
|
39
|
+
undo(): Promise<boolean> {
|
|
40
|
+
return this.enqueue(async () => {
|
|
41
|
+
await this.waitForServiceIdle();
|
|
42
|
+
this.assertNotDisposed();
|
|
43
|
+
return this.history.undo();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
redo(): Promise<boolean> {
|
|
48
|
+
return this.enqueue(async () => {
|
|
49
|
+
await this.waitForServiceIdle();
|
|
50
|
+
this.assertNotDisposed();
|
|
51
|
+
return this.history.redo();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
jumpTo(cursor: number): Promise<boolean> {
|
|
56
|
+
return this.enqueue(async () => {
|
|
57
|
+
await this.waitForServiceIdle();
|
|
58
|
+
this.assertNotDisposed();
|
|
59
|
+
return this.history.jumpTo(cursor);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get canUndo(): boolean {
|
|
64
|
+
return this.snapshot.canUndo;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get canRedo(): boolean {
|
|
68
|
+
return this.snapshot.canRedo;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
dispose(): void {
|
|
72
|
+
if (this.disposed) return;
|
|
73
|
+
this.disposed = true;
|
|
74
|
+
this.unsubscribeHistory();
|
|
75
|
+
const error = new Error('History commands are disposed.');
|
|
76
|
+
for (const waiter of this.idleWaiters) {
|
|
77
|
+
waiter.unsubscribe();
|
|
78
|
+
waiter.reject(error);
|
|
79
|
+
}
|
|
80
|
+
this.idleWaiters.clear();
|
|
81
|
+
this.listeners.clear();
|
|
82
|
+
this.notify();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private enqueue(operation: () => Promise<boolean>): Promise<boolean> {
|
|
86
|
+
if (this.disposed) return Promise.reject(new Error('History commands are disposed.'));
|
|
87
|
+
this.pending++;
|
|
88
|
+
this.notify();
|
|
89
|
+
const run = () => {
|
|
90
|
+
if (this.disposed) throw new Error('History commands are disposed.');
|
|
91
|
+
return operation();
|
|
92
|
+
};
|
|
93
|
+
const result = this.tail.then(run, run);
|
|
94
|
+
this.tail = result.then(
|
|
95
|
+
() => undefined,
|
|
96
|
+
() => undefined,
|
|
97
|
+
);
|
|
98
|
+
return result.finally(() => {
|
|
99
|
+
this.pending--;
|
|
100
|
+
this.notify();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private assertNotDisposed(): void {
|
|
105
|
+
if (this.disposed) throw new Error('History commands are disposed.');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private waitForServiceIdle(): Promise<void> {
|
|
109
|
+
if (this.disposed) return Promise.reject(new Error('History commands are disposed.'));
|
|
110
|
+
if (!this.history.getSnapshot().busy) return Promise.resolve();
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const waiter: {
|
|
113
|
+
unsubscribe: () => void;
|
|
114
|
+
reject: (error: Error) => void;
|
|
115
|
+
} = { unsubscribe: () => undefined, reject };
|
|
116
|
+
const finish = () => {
|
|
117
|
+
waiter.unsubscribe();
|
|
118
|
+
this.idleWaiters.delete(waiter);
|
|
119
|
+
};
|
|
120
|
+
waiter.unsubscribe = this.history.subscribe(() => {
|
|
121
|
+
if (this.history.getSnapshot().busy) return;
|
|
122
|
+
finish();
|
|
123
|
+
resolve();
|
|
124
|
+
});
|
|
125
|
+
this.idleWaiters.add(waiter);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private notify = (): void => {
|
|
130
|
+
this.version++;
|
|
131
|
+
this.snapshot = this.buildSnapshot();
|
|
132
|
+
for (const listener of this.listeners) listener();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
private buildSnapshot(): HistoryCommandSnapshot {
|
|
136
|
+
const current = this.history.getSnapshot();
|
|
137
|
+
const busy = this.pending > 0 || current.busy;
|
|
138
|
+
return {
|
|
139
|
+
version: this.version,
|
|
140
|
+
busy,
|
|
141
|
+
canUndo: !this.disposed && !busy && current.canUndo,
|
|
142
|
+
canRedo: !this.disposed && !busy && current.canRedo,
|
|
143
|
+
undoLabel: current.undoLabel,
|
|
144
|
+
redoLabel: current.redoLabel,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|