@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
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { faXmark } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
-
import { useEditorStore } from '../EditorContext';
|
|
4
|
-
import type { AssetTab } from '../editor-store';
|
|
5
|
-
import { AssetViewer } from './asset-viewers/AssetViewer';
|
|
6
|
-
import { Inspector } from './Inspector';
|
|
7
|
-
|
|
8
|
-
export function RightPanel() {
|
|
9
|
-
const store = useEditorStore();
|
|
10
|
-
const activeKey = store.activeTabKey;
|
|
11
|
-
const tabs = store.assetTabs;
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<div
|
|
15
|
-
style={{
|
|
16
|
-
width: 280,
|
|
17
|
-
borderLeft: '1px solid #333',
|
|
18
|
-
display: 'flex',
|
|
19
|
-
flexDirection: 'column',
|
|
20
|
-
background: '#242424',
|
|
21
|
-
pointerEvents: 'auto',
|
|
22
|
-
}}
|
|
23
|
-
>
|
|
24
|
-
{/* Only show tab bar when asset tabs are open */}
|
|
25
|
-
{tabs.length > 0 && (
|
|
26
|
-
<TabBar
|
|
27
|
-
activeKey={activeKey}
|
|
28
|
-
assetTabs={tabs}
|
|
29
|
-
onSelectTab={(key) => store.setActiveTab(key)}
|
|
30
|
-
onCloseTab={(key) => store.closeAssetTab(key)}
|
|
31
|
-
/>
|
|
32
|
-
)}
|
|
33
|
-
<div style={{ flex: 1, overflowY: 'auto', scrollbarWidth: 'none', minHeight: 0 }}>
|
|
34
|
-
{activeKey === '__inspector__' ? (
|
|
35
|
-
// C2 — the ONE inspector shell: `Inspector` itself resolves matched
|
|
36
|
-
// registered sections per selected node (see
|
|
37
|
-
// `inspector-section-registry.ts`); this shell no longer branches
|
|
38
|
-
// between two panels (the A3 dispatch seam is deleted).
|
|
39
|
-
<Inspector />
|
|
40
|
-
) : (
|
|
41
|
-
(() => {
|
|
42
|
-
const tab = tabs.find((t) => t.key === activeKey);
|
|
43
|
-
return tab ? <AssetViewer tab={tab} /> : null;
|
|
44
|
-
})()
|
|
45
|
-
)}
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function TabBar({
|
|
52
|
-
activeKey,
|
|
53
|
-
assetTabs,
|
|
54
|
-
onSelectTab,
|
|
55
|
-
onCloseTab,
|
|
56
|
-
}: {
|
|
57
|
-
activeKey: string;
|
|
58
|
-
assetTabs: readonly AssetTab[];
|
|
59
|
-
onSelectTab: (key: string) => void;
|
|
60
|
-
onCloseTab: (key: string) => void;
|
|
61
|
-
}) {
|
|
62
|
-
return (
|
|
63
|
-
<div
|
|
64
|
-
style={{
|
|
65
|
-
display: 'flex',
|
|
66
|
-
borderBottom: '1px solid #333',
|
|
67
|
-
background: '#2c2c2c',
|
|
68
|
-
overflowX: 'auto',
|
|
69
|
-
scrollbarWidth: 'none',
|
|
70
|
-
flexShrink: 0,
|
|
71
|
-
}}
|
|
72
|
-
>
|
|
73
|
-
<TabButton
|
|
74
|
-
label="Inspector"
|
|
75
|
-
active={activeKey === '__inspector__'}
|
|
76
|
-
closeable={false}
|
|
77
|
-
onClick={() => onSelectTab('__inspector__')}
|
|
78
|
-
/>
|
|
79
|
-
{assetTabs.map((tab) => (
|
|
80
|
-
<TabButton
|
|
81
|
-
key={tab.key}
|
|
82
|
-
label={tab.label}
|
|
83
|
-
active={activeKey === tab.key}
|
|
84
|
-
closeable
|
|
85
|
-
onClick={() => onSelectTab(tab.key)}
|
|
86
|
-
onClose={() => onCloseTab(tab.key)}
|
|
87
|
-
/>
|
|
88
|
-
))}
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function TabButton({
|
|
94
|
-
label,
|
|
95
|
-
active,
|
|
96
|
-
closeable,
|
|
97
|
-
onClick,
|
|
98
|
-
onClose,
|
|
99
|
-
}: {
|
|
100
|
-
label: string;
|
|
101
|
-
active: boolean;
|
|
102
|
-
closeable: boolean;
|
|
103
|
-
onClick: () => void;
|
|
104
|
-
onClose?: () => void;
|
|
105
|
-
}) {
|
|
106
|
-
return (
|
|
107
|
-
<div
|
|
108
|
-
role="button"
|
|
109
|
-
tabIndex={0}
|
|
110
|
-
onClick={onClick}
|
|
111
|
-
onKeyDown={(e) => {
|
|
112
|
-
if (e.key === 'Enter') onClick();
|
|
113
|
-
}}
|
|
114
|
-
onMouseDown={(e) => {
|
|
115
|
-
// Middle-click to close
|
|
116
|
-
if (e.button === 1 && closeable) {
|
|
117
|
-
e.preventDefault();
|
|
118
|
-
onClose?.();
|
|
119
|
-
}
|
|
120
|
-
}}
|
|
121
|
-
style={{
|
|
122
|
-
display: 'flex',
|
|
123
|
-
alignItems: 'center',
|
|
124
|
-
gap: 4,
|
|
125
|
-
padding: '4px 8px',
|
|
126
|
-
fontSize: 11,
|
|
127
|
-
color: active ? '#c5c8ce' : '#8c8c8c',
|
|
128
|
-
background: active ? '#242424' : 'transparent',
|
|
129
|
-
borderBottom: active ? '2px solid #579EFF' : '2px solid transparent',
|
|
130
|
-
cursor: 'pointer',
|
|
131
|
-
userSelect: 'none',
|
|
132
|
-
whiteSpace: 'nowrap',
|
|
133
|
-
maxWidth: 120,
|
|
134
|
-
flexShrink: 0,
|
|
135
|
-
}}
|
|
136
|
-
>
|
|
137
|
-
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis' }} title={label}>
|
|
138
|
-
{label}
|
|
139
|
-
</span>
|
|
140
|
-
{closeable && (
|
|
141
|
-
<span
|
|
142
|
-
role="button"
|
|
143
|
-
tabIndex={0}
|
|
144
|
-
onClick={(e) => {
|
|
145
|
-
e.stopPropagation();
|
|
146
|
-
onClose?.();
|
|
147
|
-
}}
|
|
148
|
-
onKeyDown={(e) => {
|
|
149
|
-
if (e.key === 'Enter') {
|
|
150
|
-
e.stopPropagation();
|
|
151
|
-
onClose?.();
|
|
152
|
-
}
|
|
153
|
-
}}
|
|
154
|
-
style={{
|
|
155
|
-
fontSize: 9,
|
|
156
|
-
opacity: 0.6,
|
|
157
|
-
cursor: 'pointer',
|
|
158
|
-
padding: '0 2px',
|
|
159
|
-
}}
|
|
160
|
-
>
|
|
161
|
-
<FontAwesomeIcon icon={faXmark} />
|
|
162
|
-
</span>
|
|
163
|
-
)}
|
|
164
|
-
</div>
|
|
165
|
-
);
|
|
166
|
-
}
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WorldContextMenu — spec 27 §6 D3.a (docs/unified-world-editor/
|
|
3
|
-
* 27-visual-react-editing.md) right-click canvas context menu: Duplicate /
|
|
4
|
-
* Wrap / Unwrap / Delete / Select-Parent, plus an Insert-child ▸ submenu
|
|
5
|
-
* (D3.e) when the owning adapter reports `structure.creatableKinds`. Styled
|
|
6
|
-
* after (but a SEPARATE component from) `GameHierarchy.tsx`'s hierarchy-row
|
|
7
|
-
* `ContextMenu` — that one opens from a right-click on a HIERARCHY ROW; this
|
|
8
|
-
* one opens from a right-click on the CANVAS overlay, resolving its target
|
|
9
|
-
* node via `adapter.pickable` (see `WorldSelectionOverlay`'s `onContextMenu`
|
|
10
|
-
* handler) rather than a row's own known id. Both ultimately drive the SAME
|
|
11
|
-
* `AuthoringAdapter.structure` contract, so the two menus intentionally look
|
|
12
|
-
* alike.
|
|
13
|
-
*
|
|
14
|
-
* Rule zero: this file talks ONLY to the `AuthoringAdapter` contract (via the
|
|
15
|
-
* owner-routing helpers in `world-overlay-gestures.ts` — `structureForId`,
|
|
16
|
-
* not a concrete adapter cast) + `hierarchy`/`selection`, which ARE
|
|
17
|
-
* merged/forwarded on `CompositeAuthoringAdapter` (unlike `rects`/`boxEdit`/
|
|
18
|
-
* `text`/`structure`'s OWNER-specific reads here). No `UIEditStore`/
|
|
19
|
-
* `SceneEntity`/`THREE.`/`elementFromPoint`.
|
|
20
|
-
*/
|
|
21
|
-
import type { AuthoringAdapter } from '@engine/adapter';
|
|
22
|
-
import { useEffect, useRef, useState } from 'react';
|
|
23
|
-
import { createPortal } from 'react-dom';
|
|
24
|
-
import { structureForId } from './world-overlay-gestures';
|
|
25
|
-
|
|
26
|
-
export interface WorldContextMenuState {
|
|
27
|
-
x: number;
|
|
28
|
-
y: number;
|
|
29
|
-
nodeId: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface WorldContextMenuProps {
|
|
33
|
-
adapter: AuthoringAdapter;
|
|
34
|
-
state: WorldContextMenuState;
|
|
35
|
-
onClose: () => void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const MENU_BG = '#2c2c2c';
|
|
39
|
-
const MENU_BORDER = '#444';
|
|
40
|
-
const ITEM_HOVER = '#3a3a3a';
|
|
41
|
-
|
|
42
|
-
function menuItemStyle(color?: string): React.CSSProperties {
|
|
43
|
-
return { padding: '5px 12px', cursor: 'pointer', color: color ?? '#c5c8ce' };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function hoverHandlers(): {
|
|
47
|
-
onMouseEnter: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
48
|
-
onMouseLeave: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
49
|
-
} {
|
|
50
|
-
return {
|
|
51
|
-
onMouseEnter: (e) => {
|
|
52
|
-
(e.currentTarget as HTMLDivElement).style.background = ITEM_HOVER;
|
|
53
|
-
},
|
|
54
|
-
onMouseLeave: (e) => {
|
|
55
|
-
(e.currentTarget as HTMLDivElement).style.background = 'transparent';
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** The canvas right-click menu (D3.a) — a pickable node's Duplicate/Wrap/
|
|
61
|
-
* Unwrap/Delete/Select-Parent, capability-gated on the owning adapter's
|
|
62
|
-
* `structure` provider (absent for an ingested `react-dom` world — no
|
|
63
|
-
* structural items render at all, only Select-Parent, which needs only
|
|
64
|
-
* `hierarchy`/`selection`). */
|
|
65
|
-
export function WorldContextMenu({
|
|
66
|
-
adapter,
|
|
67
|
-
state,
|
|
68
|
-
onClose,
|
|
69
|
-
}: WorldContextMenuProps): React.ReactNode {
|
|
70
|
-
const menuRef = useRef<HTMLDivElement>(null);
|
|
71
|
-
const [insertOpen, setInsertOpen] = useState(false);
|
|
72
|
-
|
|
73
|
-
useEffect(() => {
|
|
74
|
-
const handler = (e: MouseEvent): void => {
|
|
75
|
-
if (menuRef.current && !menuRef.current.contains(e.target as Node)) onClose();
|
|
76
|
-
};
|
|
77
|
-
const keyHandler = (e: KeyboardEvent): void => {
|
|
78
|
-
if (e.key === 'Escape') onClose();
|
|
79
|
-
};
|
|
80
|
-
document.addEventListener('mousedown', handler);
|
|
81
|
-
document.addEventListener('keydown', keyHandler);
|
|
82
|
-
return () => {
|
|
83
|
-
document.removeEventListener('mousedown', handler);
|
|
84
|
-
document.removeEventListener('keydown', keyHandler);
|
|
85
|
-
};
|
|
86
|
-
}, [onClose]);
|
|
87
|
-
|
|
88
|
-
const { nodeId } = state;
|
|
89
|
-
const node = adapter.hierarchy.node(nodeId);
|
|
90
|
-
if (!node) return null;
|
|
91
|
-
|
|
92
|
-
const structure = structureForId(adapter, nodeId);
|
|
93
|
-
const creatableKinds = structure?.creatableKinds?.(nodeId) ?? [];
|
|
94
|
-
const parentId = node.parentId;
|
|
95
|
-
|
|
96
|
-
const items: { testId: string; label: string; action: () => void; color?: string }[] = [];
|
|
97
|
-
if (parentId !== null) {
|
|
98
|
-
items.push({
|
|
99
|
-
testId: 'world-context-menu-select-parent',
|
|
100
|
-
label: 'Select Parent',
|
|
101
|
-
action: () => {
|
|
102
|
-
adapter.selection?.set([parentId]);
|
|
103
|
-
onClose();
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
if (structure) {
|
|
108
|
-
items.push({
|
|
109
|
-
testId: 'world-context-menu-duplicate',
|
|
110
|
-
label: 'Duplicate',
|
|
111
|
-
action: () => {
|
|
112
|
-
structure.duplicate(nodeId);
|
|
113
|
-
onClose();
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
if (structure.wrap) {
|
|
117
|
-
items.push({
|
|
118
|
-
testId: 'world-context-menu-wrap',
|
|
119
|
-
label: 'Wrap',
|
|
120
|
-
action: () => {
|
|
121
|
-
structure.wrap!(nodeId);
|
|
122
|
-
onClose();
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
if (structure.unwrap) {
|
|
127
|
-
items.push({
|
|
128
|
-
testId: 'world-context-menu-unwrap',
|
|
129
|
-
label: 'Unwrap',
|
|
130
|
-
action: () => {
|
|
131
|
-
structure.unwrap!(nodeId);
|
|
132
|
-
onClose();
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Portaled straight to `document.body` (spec-27 §8 pan-seam fix): this
|
|
139
|
-
// component renders as a DOM descendant of `WorldSelectionOverlay`'s outer
|
|
140
|
-
// wrapper, which space-pan gives a live `transform` when pan≠0. A non-`none`
|
|
141
|
-
// transform on an ancestor becomes the CSS containing block for a
|
|
142
|
-
// `position: fixed` descendant, so — un-portaled — this menu's `left`/`top`
|
|
143
|
-
// (raw `clientX`/`clientY` from the triggering right-click, see
|
|
144
|
-
// `WorldSelectionOverlay`'s `onContextMenu`) would resolve against the
|
|
145
|
-
// transformed wrapper instead of the viewport once panned, displacing the
|
|
146
|
-
// menu away from the cursor. Portaling to `document.body` — which never
|
|
147
|
-
// carries that transform — restores `position: fixed`'s normal
|
|
148
|
-
// viewport-relative meaning regardless of pan. `menuRef` still points at
|
|
149
|
-
// the REAL DOM node either way (a portal only changes WHERE React inserts
|
|
150
|
-
// the subtree, not the node itself), so the outside-click/Escape-to-close
|
|
151
|
-
// handlers below — native `document` listeners doing DOM `.contains()`
|
|
152
|
-
// checks — are unaffected by the portal.
|
|
153
|
-
return createPortal(
|
|
154
|
-
<div
|
|
155
|
-
ref={menuRef}
|
|
156
|
-
data-testid="world-context-menu"
|
|
157
|
-
style={{
|
|
158
|
-
position: 'fixed',
|
|
159
|
-
left: state.x,
|
|
160
|
-
top: state.y,
|
|
161
|
-
background: MENU_BG,
|
|
162
|
-
border: `1px solid ${MENU_BORDER}`,
|
|
163
|
-
borderRadius: 4,
|
|
164
|
-
padding: '4px 0',
|
|
165
|
-
zIndex: 1000,
|
|
166
|
-
minWidth: 150,
|
|
167
|
-
maxWidth: 260,
|
|
168
|
-
boxShadow: '0 4px 12px rgba(0,0,0,0.5)',
|
|
169
|
-
fontSize: 12,
|
|
170
|
-
color: '#c5c8ce',
|
|
171
|
-
}}
|
|
172
|
-
>
|
|
173
|
-
{items.map((item) => (
|
|
174
|
-
<div
|
|
175
|
-
key={item.testId}
|
|
176
|
-
data-testid={item.testId}
|
|
177
|
-
role="menuitem"
|
|
178
|
-
tabIndex={0}
|
|
179
|
-
onClick={item.action}
|
|
180
|
-
onKeyDown={(e) => {
|
|
181
|
-
if (e.key === 'Enter') item.action();
|
|
182
|
-
}}
|
|
183
|
-
style={menuItemStyle(item.color)}
|
|
184
|
-
{...hoverHandlers()}
|
|
185
|
-
>
|
|
186
|
-
{item.label}
|
|
187
|
-
</div>
|
|
188
|
-
))}
|
|
189
|
-
{/* D3.e — Insert-child submenu, gated on the owning adapter's
|
|
190
|
-
`structure.creatableKinds` (react-world only today; the ingested
|
|
191
|
-
react-dom adapter has no `structure` at all, so `structure` is
|
|
192
|
-
`null` here and this whole block is skipped). */}
|
|
193
|
-
{structure && creatableKinds.length > 0 && (
|
|
194
|
-
<div>
|
|
195
|
-
<div
|
|
196
|
-
data-testid="world-context-menu-insert-child"
|
|
197
|
-
role="menuitem"
|
|
198
|
-
tabIndex={0}
|
|
199
|
-
onClick={() => setInsertOpen((v) => !v)}
|
|
200
|
-
onKeyDown={(e) => {
|
|
201
|
-
if (e.key === 'Enter') setInsertOpen((v) => !v);
|
|
202
|
-
}}
|
|
203
|
-
style={menuItemStyle()}
|
|
204
|
-
{...hoverHandlers()}
|
|
205
|
-
>
|
|
206
|
-
Insert child ▸
|
|
207
|
-
</div>
|
|
208
|
-
{insertOpen &&
|
|
209
|
-
creatableKinds.map((k) => (
|
|
210
|
-
<div
|
|
211
|
-
key={k.kind}
|
|
212
|
-
data-testid={`world-context-menu-insert-child-${k.kind}`}
|
|
213
|
-
role="menuitem"
|
|
214
|
-
tabIndex={0}
|
|
215
|
-
onClick={() => {
|
|
216
|
-
structure.create(k.kind, nodeId);
|
|
217
|
-
onClose();
|
|
218
|
-
}}
|
|
219
|
-
onKeyDown={(e) => {
|
|
220
|
-
if (e.key === 'Enter') {
|
|
221
|
-
structure.create(k.kind, nodeId);
|
|
222
|
-
onClose();
|
|
223
|
-
}
|
|
224
|
-
}}
|
|
225
|
-
style={{ padding: '5px 12px 5px 24px', cursor: 'pointer' }}
|
|
226
|
-
{...hoverHandlers()}
|
|
227
|
-
>
|
|
228
|
-
{k.label}
|
|
229
|
-
</div>
|
|
230
|
-
))}
|
|
231
|
-
</div>
|
|
232
|
-
)}
|
|
233
|
-
{structure && (
|
|
234
|
-
<div
|
|
235
|
-
data-testid="world-context-menu-delete"
|
|
236
|
-
role="menuitem"
|
|
237
|
-
tabIndex={0}
|
|
238
|
-
onClick={() => {
|
|
239
|
-
structure.remove(nodeId);
|
|
240
|
-
onClose();
|
|
241
|
-
}}
|
|
242
|
-
onKeyDown={(e) => {
|
|
243
|
-
if (e.key === 'Enter') {
|
|
244
|
-
structure.remove(nodeId);
|
|
245
|
-
onClose();
|
|
246
|
-
}
|
|
247
|
-
}}
|
|
248
|
-
style={menuItemStyle('#ff6b6b')}
|
|
249
|
-
{...hoverHandlers()}
|
|
250
|
-
>
|
|
251
|
-
Delete
|
|
252
|
-
</div>
|
|
253
|
-
)}
|
|
254
|
-
</div>,
|
|
255
|
-
document.body,
|
|
256
|
-
);
|
|
257
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { AssetTab } from '../../editor-store';
|
|
2
|
-
import { AudioViewer } from './AudioViewer';
|
|
3
|
-
import { GenericJsonViewer } from './GenericJsonViewer';
|
|
4
|
-
import { ImageViewer } from './ImageViewer';
|
|
5
|
-
import { InputMapViewer } from './InputMapViewer';
|
|
6
|
-
import { ModelViewer } from './ModelViewer';
|
|
7
|
-
import { OnlineAssetDetail } from './OnlineAssetDetail';
|
|
8
|
-
|
|
9
|
-
interface AssetViewerProps {
|
|
10
|
-
tab: AssetTab;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function AssetViewer({ tab }: AssetViewerProps) {
|
|
14
|
-
// Online asset that hasn't been downloaded yet
|
|
15
|
-
if (tab.online) {
|
|
16
|
-
return <OnlineAssetDetail tabKey={tab.key} online={tab.online} />;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
switch (tab.kind) {
|
|
20
|
-
case 'model':
|
|
21
|
-
return <ModelViewer assetPath={tab.assetPath} />;
|
|
22
|
-
case 'image':
|
|
23
|
-
return <ImageViewer assetPath={tab.assetPath} />;
|
|
24
|
-
case 'audio':
|
|
25
|
-
return <AudioViewer assetPath={tab.assetPath} />;
|
|
26
|
-
case 'json':
|
|
27
|
-
if (tab.assetPath.endsWith('.inputmap.json')) {
|
|
28
|
-
return <InputMapViewer assetPath={tab.assetPath} />;
|
|
29
|
-
}
|
|
30
|
-
return <GenericJsonViewer assetPath={tab.assetPath} />;
|
|
31
|
-
default:
|
|
32
|
-
return (
|
|
33
|
-
<div style={{ padding: 16, color: '#8c8c8c', fontSize: 12 }}>
|
|
34
|
-
No viewer available for this asset type.
|
|
35
|
-
</div>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Track N, N2 — verbatim copy of the template's `GameProvider` seam
|
|
3
|
-
* (`packages/editor/template/src/ui/game-state.tsx`), present here
|
|
4
|
-
* ONLY because `adapter-resolver.ts`'s `loadProjectGameProvider` (shared by
|
|
5
|
-
* `default-react` and `ingest-react`, T6.2/Track N) hard-requires
|
|
6
|
-
* `src/ui/game-state.tsx` under whatever `projectRoot` an
|
|
7
|
-
* `ingest-react` world resolves against — see
|
|
8
|
-
* `vite-plugin-react-world-provider.ts`'s literal `/src/ui/
|
|
9
|
-
* game-state.tsx` path. This folder (`games-react/react-rpg/`) IS that
|
|
10
|
-
* world's `projectRoot` (its `vgai.game.json`'s `entry` — `../entry.tsx` —
|
|
11
|
-
* resolves relative to it too), so it needs its own copy, exactly like every
|
|
12
|
-
* scaffolded project gets one (`create-vgai-project`'s `scaffoldProject`).
|
|
13
|
-
*
|
|
14
|
-
* The vendored react-rpg game itself never reads `useGameState`/`useGame` —
|
|
15
|
-
* D-N2's host shim (`../../entry.tsx`) only composes the vendored game's OWN
|
|
16
|
-
* `<Provider store><PersistGate persistor><App/></PersistGate></Provider>`,
|
|
17
|
-
* with `<GameProvider>` wrapped around that AUTOMATICALLY by the resolver
|
|
18
|
-
* (context-only, harmless to a foreign tree, per D-N2). This file is
|
|
19
|
-
* therefore present purely to satisfy the resolver's lookup, not because the
|
|
20
|
-
* ingested game consumes it — kept byte-identical to the template's copy so
|
|
21
|
-
* a future react-ingest game that DOES want the state bridge (e.g. an
|
|
22
|
-
* ingest-authoring follow-on, D-N8) gets it for free.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import type { WorldStateObserver } from '@engine/adapter';
|
|
26
|
-
import {
|
|
27
|
-
createFrameSelectorCache,
|
|
28
|
-
type Equals,
|
|
29
|
-
shallow,
|
|
30
|
-
} from '@engine/runtime/frame-selector-cache';
|
|
31
|
-
import type { Game } from '@engine/runtime/game';
|
|
32
|
-
import { createContext, type ReactNode, useContext, useRef, useSyncExternalStore } from 'react';
|
|
33
|
-
|
|
34
|
-
/** Re-exported for convenience — the opt-in equality for selectors that
|
|
35
|
-
* return a fresh object/array/tuple every call (default is `Object.is`). */
|
|
36
|
-
export { shallow };
|
|
37
|
-
|
|
38
|
-
const GameContext = createContext<Game | null>(null);
|
|
39
|
-
|
|
40
|
-
/** Provide the `Game` to `useGameState`/`useGame` for everything mounted
|
|
41
|
-
* beneath it. Does not replace or wrap `mountUI` — compose it around the
|
|
42
|
-
* element passed to `mountUI` (see the module doc comment above). */
|
|
43
|
-
export function GameProvider({ game, children }: { game: Game; children: ReactNode }) {
|
|
44
|
-
return <GameContext.Provider value={game}>{children}</GameContext.Provider>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Read the `Game` provided by the nearest `GameProvider`. Throws
|
|
48
|
-
* descriptively when called outside one — matching the repo's loud-failure
|
|
49
|
-
* habit rather than silently returning `null`. */
|
|
50
|
-
export function useGame(): Game {
|
|
51
|
-
const game = useContext(GameContext);
|
|
52
|
-
if (!game) {
|
|
53
|
-
throw new Error(
|
|
54
|
-
'useGame: no Game in context — wrap this component in <GameProvider game={ctx.game!}>.',
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
return game;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Subscribe to a selected slice of game state (`docs/REACT-STATE-BRIDGE.md`
|
|
62
|
-
* §3). Re-renders only when the selected value changes: the selector re-runs
|
|
63
|
-
* at most once per completed frame (`game.state.frameVersion`), and
|
|
64
|
-
* `equals` (default `Object.is`; pass {@link shallow} for tuples/objects)
|
|
65
|
-
* gates whether the fresh result actually counts as a change.
|
|
66
|
-
*/
|
|
67
|
-
export function useGameState<T>(selector: (game: Game) => T, equals: Equals<T> = Object.is): T {
|
|
68
|
-
const game = useGame();
|
|
69
|
-
const cacheRef = useRef<ReturnType<typeof createFrameSelectorCache<T>> | null>(null);
|
|
70
|
-
if (cacheRef.current === null) {
|
|
71
|
-
cacheRef.current = createFrameSelectorCache<T>(equals);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return useSyncExternalStore(
|
|
75
|
-
(onStoreChange) => game.state.subscribe(onStoreChange),
|
|
76
|
-
() => cacheRef.current!.get(game.state.frameVersion, () => selector(game)),
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Pure, react-free lookup for the `useWorldObservation` hook below — see the
|
|
82
|
-
* template's copy of this file for the full doc comment (byte-identical
|
|
83
|
-
* logic, kept here only so this folder's `GameProvider` lookup resolves).
|
|
84
|
-
*/
|
|
85
|
-
export function requireWorldObserver(game: Game, worldId: string): WorldStateObserver {
|
|
86
|
-
const world = game.world(worldId);
|
|
87
|
-
if (!world) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
`useWorldObservation: no world registered with id "${worldId}" — check game.worlds for the ` +
|
|
90
|
-
'ids actually registered.',
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
const observer = world.mounted.observe;
|
|
94
|
-
if (!observer) {
|
|
95
|
-
throw new Error(
|
|
96
|
-
`useWorldObservation: world "${worldId}" (kind: ${world.kind}, adapter: "${world.adapter.id}") ` +
|
|
97
|
-
'has no state bridge — its mount has no `observe` (WorldStateObserver). This world cannot ' +
|
|
98
|
-
'be observed from React (docs/REACT-STATE-BRIDGE.md §4).',
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
return observer;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Subscribe to a selected slice of a FOREIGN (non-first-party) world's
|
|
106
|
-
* observed state — see the template's copy for the full doc comment.
|
|
107
|
-
*/
|
|
108
|
-
export function useWorldObservation<T>(
|
|
109
|
-
worldId: string,
|
|
110
|
-
selector: (snapshot: unknown) => T,
|
|
111
|
-
equals: Equals<T> = Object.is,
|
|
112
|
-
): T {
|
|
113
|
-
const game = useGame();
|
|
114
|
-
const observer = requireWorldObserver(game, worldId);
|
|
115
|
-
const cacheRef = useRef<ReturnType<typeof createFrameSelectorCache<T>> | null>(null);
|
|
116
|
-
if (cacheRef.current === null) {
|
|
117
|
-
cacheRef.current = createFrameSelectorCache<T>(equals);
|
|
118
|
-
}
|
|
119
|
-
const versionRef = useRef(0);
|
|
120
|
-
|
|
121
|
-
return useSyncExternalStore(
|
|
122
|
-
(onStoreChange) =>
|
|
123
|
-
observer.subscribe(() => {
|
|
124
|
-
versionRef.current++;
|
|
125
|
-
onStoreChange();
|
|
126
|
-
}),
|
|
127
|
-
() => cacheRef.current!.get(versionRef.current, () => selector(observer.snapshot())),
|
|
128
|
-
);
|
|
129
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scene-UI-mode chrome (E1.a/b/c, spec-27 §7 E1 — the remaining half of "Absorb
|
|
3
|
-
* scene-UI as a mode, not a separate app": palette, keyframe timeline, prefabs).
|
|
4
|
-
*
|
|
5
|
-
* Files under THIS folder are the §10 item-7 grep-ban exemption's home
|
|
6
|
-
* ("outside the migrated scene-UI-mode files"): they may import `UIEditStore`
|
|
7
|
-
* and its neighbours (`ui-editor/*`) freely, because they exist SPECIFICALLY to
|
|
8
|
-
* author a `.vscn` `ui` tree. The generic editor shell (`components/
|
|
9
|
-
* DefaultEditorLayout.tsx`, `components/GameHierarchy.tsx`, `components/
|
|
10
|
-
* BottomPanel.tsx`, …) may compose a `scene-ui-mode/*` component/hook by
|
|
11
|
-
* IMPORTING it (exactly like it already composes `GameHierarchy`/`RightPanel`),
|
|
12
|
-
* but must never import `UIEditStore` (or `SceneEntity`/`THREE.`) itself — that
|
|
13
|
-
* boundary is what keeps `rg "UIEditStore" src/components` a meaningful,
|
|
14
|
-
* zero-hit grep gate outside this folder.
|
|
15
|
-
*
|
|
16
|
-
* This module resolves WHICH `UIAuthoringAdapter` (if any) is the open
|
|
17
|
-
* project's live scene-UI child, so every other file in this folder has one
|
|
18
|
-
* place to ask "is scene-UI authoring live right now?" instead of re-deriving
|
|
19
|
-
* the composite-child lookup.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { useSyncExternalStore } from 'react';
|
|
23
|
-
import { getAuthoringOverride } from '../authoring/active-adapter';
|
|
24
|
-
import { CompositeAuthoringAdapter } from '../authoring/composite-authoring-adapter';
|
|
25
|
-
import { UIAuthoringAdapter } from '../authoring/ui-authoring-adapter';
|
|
26
|
-
import { useEditorStore } from '../EditorContext';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The active `UIAuthoringAdapter`, whether it is installed directly as the
|
|
30
|
-
* override (the standalone harness's pre-C3 shape, `ui-editor/harness.tsx`) or
|
|
31
|
-
* nested as the edit-mode `CompositeAuthoringAdapter`'s `kind: 'scene-ui'`
|
|
32
|
-
* child (C3, the unified editor's real shape — at most one such child exists
|
|
33
|
-
* per open scene, `edit-mode-authoring.ts`'s `buildUIChild`). `null` when
|
|
34
|
-
* neither applies: no override installed, a bare non-UI override (ingest/
|
|
35
|
-
* play), or a composite with no scene-UI child yet (the open scene has no
|
|
36
|
-
* `ui` roots — §3.1's install gate).
|
|
37
|
-
*/
|
|
38
|
-
export function resolveActiveSceneUIAdapter(): UIAuthoringAdapter | null {
|
|
39
|
-
const active = getAuthoringOverride();
|
|
40
|
-
if (active instanceof UIAuthoringAdapter) return active;
|
|
41
|
-
if (active instanceof CompositeAuthoringAdapter) {
|
|
42
|
-
const child = active.childAdapters().find((c) => c.kind === 'scene-ui');
|
|
43
|
-
return child?.adapter instanceof UIAuthoringAdapter ? child.adapter : null;
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* React-hook form of {@link resolveActiveSceneUIAdapter} — re-resolves on
|
|
50
|
-
* every `EditorStore` notify (edit-mode composite install/teardown, scene
|
|
51
|
-
* switch, undo/redo of the whole document all fire one), which is exactly the
|
|
52
|
-
* signal that can flip whether a scene-UI child exists at all.
|
|
53
|
-
*/
|
|
54
|
-
export function useActiveSceneUIAdapter(): UIAuthoringAdapter | null {
|
|
55
|
-
const store = useEditorStore();
|
|
56
|
-
useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
57
|
-
return resolveActiveSceneUIAdapter();
|
|
58
|
-
}
|