@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
|
@@ -6,31 +6,21 @@ import {
|
|
|
6
6
|
faEye,
|
|
7
7
|
faEyeSlash,
|
|
8
8
|
} from '@fortawesome/free-solid-svg-icons';
|
|
9
|
-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
10
9
|
import { useEffect, useRef, useState } from 'react';
|
|
10
|
+
import {
|
|
11
|
+
Button,
|
|
12
|
+
EditorIcon,
|
|
13
|
+
FloatingToolbar,
|
|
14
|
+
IconButton,
|
|
15
|
+
Menu,
|
|
16
|
+
MenuItem,
|
|
17
|
+
MenuSeparator,
|
|
18
|
+
SplitButtonGroup,
|
|
19
|
+
Text,
|
|
20
|
+
Tooltip,
|
|
21
|
+
} from '../design-system';
|
|
11
22
|
import { useEditorStore } from '../EditorContext';
|
|
12
23
|
import type { EditorStore, ShadingMode } from '../editor-store';
|
|
13
|
-
import { Tooltip } from './primitives/Tooltip';
|
|
14
|
-
|
|
15
|
-
const iconBtn: React.CSSProperties = {
|
|
16
|
-
background: '#333',
|
|
17
|
-
color: '#c5c8ce',
|
|
18
|
-
border: '1px solid #444',
|
|
19
|
-
borderRadius: 3,
|
|
20
|
-
padding: '4px 7px',
|
|
21
|
-
cursor: 'pointer',
|
|
22
|
-
fontSize: 12,
|
|
23
|
-
lineHeight: '18px',
|
|
24
|
-
display: 'flex',
|
|
25
|
-
alignItems: 'center',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const activeIconBtn: React.CSSProperties = {
|
|
29
|
-
...iconBtn,
|
|
30
|
-
background: '#579EFF',
|
|
31
|
-
border: '1px solid #6AADFF',
|
|
32
|
-
color: '#fff',
|
|
33
|
-
};
|
|
34
24
|
|
|
35
25
|
const shadingLabels: Record<ShadingMode, string> = {
|
|
36
26
|
solid: 'Solid',
|
|
@@ -40,66 +30,54 @@ const shadingLabels: Record<ShadingMode, string> = {
|
|
|
40
30
|
|
|
41
31
|
const shadingOrder: ShadingMode[] = ['solid', 'wireframe', 'unlit'];
|
|
42
32
|
|
|
43
|
-
|
|
33
|
+
/** Viewport-level rendering controls. Three-specific controls hide when no 3D world is active. */
|
|
34
|
+
export function ViewportOverlay({ statsOnly = false }: { statsOnly?: boolean }) {
|
|
44
35
|
const store = useEditorStore();
|
|
45
36
|
return (
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
top: 8,
|
|
50
|
-
right: 8,
|
|
51
|
-
display: 'flex',
|
|
52
|
-
alignItems: 'center',
|
|
53
|
-
gap: 4,
|
|
54
|
-
padding: '4px 6px',
|
|
55
|
-
background: 'rgba(36, 36, 36, 0.9)',
|
|
56
|
-
border: '1px solid #444',
|
|
57
|
-
borderRadius: 6,
|
|
58
|
-
pointerEvents: 'auto',
|
|
59
|
-
backdropFilter: 'blur(8px)',
|
|
60
|
-
}}
|
|
37
|
+
<FloatingToolbar
|
|
38
|
+
label="Viewport display"
|
|
39
|
+
className="vgai-viewport-toolbar vgai-viewport-toolbar-right"
|
|
61
40
|
>
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
style={store.showStats ? activeIconBtn : iconBtn}
|
|
41
|
+
{!statsOnly && (
|
|
42
|
+
<>
|
|
43
|
+
<Tooltip text={`Grid: ${store.showGrid ? 'On' : 'Off'}`}>
|
|
44
|
+
<IconButton
|
|
45
|
+
aria-label="Toggle grid"
|
|
46
|
+
aria-pressed={store.showGrid}
|
|
47
|
+
size="comfortable"
|
|
48
|
+
onClick={() => store.toggleGrid()}
|
|
49
|
+
>
|
|
50
|
+
<EditorIcon icon={faBorderAll} size="md" />
|
|
51
|
+
</IconButton>
|
|
52
|
+
</Tooltip>
|
|
53
|
+
<HelpersButton store={store} />
|
|
54
|
+
<Tooltip text={`Shading: ${shadingLabels[store.shadingMode]}`}>
|
|
55
|
+
<Button
|
|
56
|
+
variant="ghost"
|
|
57
|
+
aria-label={`Shading: ${shadingLabels[store.shadingMode]}`}
|
|
58
|
+
aria-pressed={store.shadingMode !== 'solid'}
|
|
59
|
+
size="comfortable"
|
|
60
|
+
onClick={() => {
|
|
61
|
+
const index = shadingOrder.indexOf(store.shadingMode);
|
|
62
|
+
store.setShadingMode(shadingOrder[(index + 1) % shadingOrder.length]!);
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<Text variant="label">{shadingLabels[store.shadingMode]}</Text>
|
|
66
|
+
</Button>
|
|
67
|
+
</Tooltip>
|
|
68
|
+
</>
|
|
69
|
+
)}
|
|
70
|
+
<Tooltip text={`Viewport stats: ${store.showStats ? 'On' : 'Off'}`}>
|
|
71
|
+
<IconButton
|
|
72
|
+
aria-label="Toggle viewport stats"
|
|
73
|
+
aria-pressed={store.showStats}
|
|
74
|
+
size="comfortable"
|
|
97
75
|
onClick={() => store.toggleStats()}
|
|
98
76
|
>
|
|
99
|
-
<
|
|
100
|
-
</
|
|
77
|
+
<EditorIcon icon={faChartSimple} size="md" />
|
|
78
|
+
</IconButton>
|
|
101
79
|
</Tooltip>
|
|
102
|
-
</
|
|
80
|
+
</FloatingToolbar>
|
|
103
81
|
);
|
|
104
82
|
}
|
|
105
83
|
|
|
@@ -109,8 +87,8 @@ function HelpersButton({ store }: { store: EditorStore }) {
|
|
|
109
87
|
|
|
110
88
|
useEffect(() => {
|
|
111
89
|
if (!open) return;
|
|
112
|
-
const handler = (
|
|
113
|
-
if (ref.current && !ref.current.contains(
|
|
90
|
+
const handler = (event: MouseEvent) => {
|
|
91
|
+
if (ref.current && !ref.current.contains(event.target as Node)) setOpen(false);
|
|
114
92
|
};
|
|
115
93
|
document.addEventListener('mousedown', handler);
|
|
116
94
|
return () => document.removeEventListener('mousedown', handler);
|
|
@@ -123,111 +101,58 @@ function HelpersButton({ store }: { store: EditorStore }) {
|
|
|
123
101
|
{ key: 'audio' as const, label: 'Audio' },
|
|
124
102
|
{ key: 'splines' as const, label: 'Splines' },
|
|
125
103
|
{ key: 'navmesh' as const, label: 'NavMesh' },
|
|
104
|
+
{ key: 'skeletons' as const, label: 'Skeletons' },
|
|
126
105
|
];
|
|
127
106
|
|
|
128
107
|
return (
|
|
129
|
-
<div ref={ref}
|
|
130
|
-
<
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
108
|
+
<div ref={ref} className="vgai-viewport-popover-anchor">
|
|
109
|
+
<SplitButtonGroup>
|
|
110
|
+
<Tooltip text={`Helpers: ${store.showHelpers ? 'On' : 'Off'}`}>
|
|
111
|
+
<IconButton
|
|
112
|
+
aria-label="Toggle helpers"
|
|
113
|
+
aria-pressed={store.showHelpers}
|
|
114
|
+
size="comfortable"
|
|
115
|
+
onClick={() => store.toggleHelpers()}
|
|
116
|
+
>
|
|
117
|
+
<EditorIcon icon={store.showHelpers ? faEye : faEyeSlash} size="md" />
|
|
118
|
+
</IconButton>
|
|
119
|
+
</Tooltip>
|
|
120
|
+
<IconButton
|
|
121
|
+
aria-label="Choose helpers"
|
|
122
|
+
aria-expanded={open}
|
|
123
|
+
size="comfortable"
|
|
124
|
+
onClick={() => setOpen(!open)}
|
|
135
125
|
>
|
|
136
|
-
<
|
|
137
|
-
</
|
|
138
|
-
</
|
|
139
|
-
<button
|
|
140
|
-
type="button"
|
|
141
|
-
onClick={() => setOpen(!open)}
|
|
142
|
-
style={{
|
|
143
|
-
...iconBtn,
|
|
144
|
-
padding: '4px 3px',
|
|
145
|
-
fontSize: 8,
|
|
146
|
-
borderLeft: 'none',
|
|
147
|
-
borderTopLeftRadius: 0,
|
|
148
|
-
borderBottomLeftRadius: 0,
|
|
149
|
-
marginLeft: -1,
|
|
150
|
-
}}
|
|
151
|
-
>
|
|
152
|
-
<FontAwesomeIcon icon={faCaretDown} />
|
|
153
|
-
</button>
|
|
126
|
+
<EditorIcon icon={faCaretDown} size="xs" />
|
|
127
|
+
</IconButton>
|
|
128
|
+
</SplitButtonGroup>
|
|
154
129
|
{open && (
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
marginTop: 4,
|
|
161
|
-
background: '#2c2c2c',
|
|
162
|
-
border: '1px solid #444',
|
|
163
|
-
borderRadius: 4,
|
|
164
|
-
padding: '4px 0',
|
|
165
|
-
zIndex: 1000,
|
|
166
|
-
minWidth: 130,
|
|
167
|
-
boxShadow: '0 4px 12px rgba(0,0,0,0.5)',
|
|
168
|
-
}}
|
|
169
|
-
>
|
|
170
|
-
<div
|
|
171
|
-
role="menuitem"
|
|
172
|
-
tabIndex={0}
|
|
173
|
-
onClick={() => store.toggleHelpers()}
|
|
174
|
-
onKeyDown={(e) => {
|
|
175
|
-
if (e.key === 'Enter') store.toggleHelpers();
|
|
176
|
-
}}
|
|
177
|
-
style={{
|
|
178
|
-
padding: '5px 12px',
|
|
179
|
-
cursor: 'pointer',
|
|
180
|
-
fontSize: 12,
|
|
181
|
-
color: '#c5c8ce',
|
|
182
|
-
display: 'flex',
|
|
183
|
-
alignItems: 'center',
|
|
184
|
-
gap: 6,
|
|
185
|
-
}}
|
|
186
|
-
onMouseEnter={(e) => {
|
|
187
|
-
(e.currentTarget as HTMLDivElement).style.background = '#3a3a3a';
|
|
188
|
-
}}
|
|
189
|
-
onMouseLeave={(e) => {
|
|
190
|
-
(e.currentTarget as HTMLDivElement).style.background = 'transparent';
|
|
191
|
-
}}
|
|
130
|
+
<Menu className="vgai-helpers-menu" onDismiss={() => setOpen(false)}>
|
|
131
|
+
<MenuItem
|
|
132
|
+
role="menuitemcheckbox"
|
|
133
|
+
aria-checked={store.showHelpers}
|
|
134
|
+
onSelect={() => store.toggleHelpers()}
|
|
192
135
|
>
|
|
193
|
-
<span
|
|
194
|
-
<
|
|
136
|
+
<span className="vgai-menu-check">
|
|
137
|
+
{store.showHelpers && <EditorIcon icon={faCheck} size="xs" />}
|
|
195
138
|
</span>
|
|
196
139
|
All
|
|
197
|
-
</
|
|
198
|
-
<
|
|
199
|
-
{helperTypes.map((
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
onKeyDown={(e) => {
|
|
206
|
-
if (e.key === 'Enter') store.toggleHelperType(h.key);
|
|
207
|
-
}}
|
|
208
|
-
style={{
|
|
209
|
-
padding: '5px 12px',
|
|
210
|
-
cursor: 'pointer',
|
|
211
|
-
fontSize: 12,
|
|
212
|
-
color: '#c5c8ce',
|
|
213
|
-
display: 'flex',
|
|
214
|
-
alignItems: 'center',
|
|
215
|
-
gap: 6,
|
|
216
|
-
}}
|
|
217
|
-
onMouseEnter={(e) => {
|
|
218
|
-
(e.currentTarget as HTMLDivElement).style.background = '#3a3a3a';
|
|
219
|
-
}}
|
|
220
|
-
onMouseLeave={(e) => {
|
|
221
|
-
(e.currentTarget as HTMLDivElement).style.background = 'transparent';
|
|
222
|
-
}}
|
|
140
|
+
</MenuItem>
|
|
141
|
+
<MenuSeparator />
|
|
142
|
+
{helperTypes.map((helper) => (
|
|
143
|
+
<MenuItem
|
|
144
|
+
key={helper.key}
|
|
145
|
+
role="menuitemcheckbox"
|
|
146
|
+
aria-checked={store.helperVisibility[helper.key]}
|
|
147
|
+
onSelect={() => store.toggleHelperType(helper.key)}
|
|
223
148
|
>
|
|
224
|
-
<span
|
|
225
|
-
<
|
|
149
|
+
<span className="vgai-menu-check">
|
|
150
|
+
{store.helperVisibility[helper.key] && <EditorIcon icon={faCheck} size="xs" />}
|
|
226
151
|
</span>
|
|
227
|
-
{
|
|
228
|
-
</
|
|
152
|
+
{helper.label}
|
|
153
|
+
</MenuItem>
|
|
229
154
|
))}
|
|
230
|
-
</
|
|
155
|
+
</Menu>
|
|
231
156
|
)}
|
|
232
157
|
</div>
|
|
233
158
|
);
|
|
@@ -3,30 +3,43 @@ import { applyRendererSettings, applyScenePostProcessing } from '@engine/setup/s
|
|
|
3
3
|
import { EffectComposer } from 'postprocessing';
|
|
4
4
|
import { useEffect, useRef, useSyncExternalStore } from 'react';
|
|
5
5
|
import * as THREE from 'three';
|
|
6
|
+
import { getActiveAuthoring } from '../authoring/active-adapter';
|
|
6
7
|
import type { CompositeAuthoringAdapter } from '../authoring/composite-authoring-adapter';
|
|
7
|
-
import { mountDesignTimeLayers } from '../authoring/design-time-layers';
|
|
8
8
|
import {
|
|
9
9
|
EDIT_MODE_REBUILD_EVENT,
|
|
10
10
|
exitEditModeAuthoring,
|
|
11
11
|
installEditModeAuthoringForProject,
|
|
12
12
|
} from '../authoring/edit-mode-authoring';
|
|
13
|
+
import {
|
|
14
|
+
isViewportToolContextVisible,
|
|
15
|
+
resolveViewportToolContext,
|
|
16
|
+
} from '../authoring/viewport-tool-context';
|
|
17
|
+
import {
|
|
18
|
+
isThreejsSurfaceVisible,
|
|
19
|
+
resolveFocusedViewportWorldId,
|
|
20
|
+
} from '../authoring/world-hidden-viewport';
|
|
21
|
+
import { isWorldHidden } from '../authoring/world-session-state';
|
|
13
22
|
import { collectState } from '../command-listener';
|
|
14
|
-
import {
|
|
23
|
+
import { themeVars } from '../design-system';
|
|
24
|
+
import {
|
|
25
|
+
useEditorStats,
|
|
26
|
+
useEditorStore,
|
|
27
|
+
useHistoryCommands,
|
|
28
|
+
useHistoryService,
|
|
29
|
+
} from '../EditorContext';
|
|
15
30
|
import { reportEditorState } from '../editor-api';
|
|
16
31
|
import { connectServerLogs, editorConsole } from '../editor-console';
|
|
17
32
|
import { registerEditorHotkeys } from '../editor-hotkeys';
|
|
18
33
|
import { getEditorMode } from '../editor-mode';
|
|
19
34
|
import type { EditorStore } from '../editor-store';
|
|
20
35
|
import { EditorViewport } from '../editor-viewport';
|
|
36
|
+
import { getProjectFileHistory } from '../history/project-file-history';
|
|
21
37
|
import { autoLaunchIngestFromURL, bindIngestMode } from '../ingest-mode';
|
|
22
38
|
import { loadInitialScene } from '../initial-scene';
|
|
23
39
|
import { setupNavMeshHandlers } from '../navmesh-handler';
|
|
24
40
|
import { bindPlayMode } from '../play-mode';
|
|
25
41
|
import { resolvePreviewBoneAttachments } from '../scene-sync';
|
|
26
42
|
import { CameraInfo } from './CameraInfo';
|
|
27
|
-
import { CommandPalette } from './CommandPalette';
|
|
28
|
-
import { NetworkSection } from './NetworkSection';
|
|
29
|
-
import { PlayBar } from './PlayBar';
|
|
30
43
|
import { StatsOverlay } from './StatsOverlay';
|
|
31
44
|
import { ToolStrip } from './Toolbar';
|
|
32
45
|
import { ViewportOverlay } from './ViewportOverlay';
|
|
@@ -51,9 +64,22 @@ function buildEntityTagMap(store: EditorStore): Map<string, string[]> {
|
|
|
51
64
|
export function ViewportPanel() {
|
|
52
65
|
const store = useEditorStore();
|
|
53
66
|
const stats = useEditorStats();
|
|
67
|
+
const history = useHistoryCommands();
|
|
68
|
+
const historyService = useHistoryService();
|
|
54
69
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
55
70
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
56
71
|
|
|
72
|
+
// Referenced materials are part of the rendered scene even though their
|
|
73
|
+
// bytes live in a separate project resource. Observe the authoritative
|
|
74
|
+
// history stream so writes, undo, and redo all refresh the WYSIWYG preview.
|
|
75
|
+
useEffect(
|
|
76
|
+
() =>
|
|
77
|
+
getProjectFileHistory(historyService).subscribeAll((path) => {
|
|
78
|
+
if (path.split(/[?#]/, 1)[0]!.endsWith('.mat.json')) store.refreshMaterialAssets();
|
|
79
|
+
}),
|
|
80
|
+
[historyService, store],
|
|
81
|
+
);
|
|
82
|
+
|
|
57
83
|
useEffect(() => {
|
|
58
84
|
const canvas = canvasRef.current!;
|
|
59
85
|
const container = containerRef.current!;
|
|
@@ -82,7 +108,9 @@ export function ViewportPanel() {
|
|
|
82
108
|
store.bindScene(scene, renderer);
|
|
83
109
|
|
|
84
110
|
// --- Viewport ---
|
|
85
|
-
|
|
111
|
+
// Bind navigation to the whole authoring surface. A DOM selection layer
|
|
112
|
+
// above the WebGL canvas must not disable right-drag orbit/fly controls.
|
|
113
|
+
const viewport = new EditorViewport(canvas, scene, store, container);
|
|
86
114
|
// Bind the REAL viewport camera + orbit target so store.cameraPose (the
|
|
87
115
|
// `editor.viewport.camera.get` facet, see command-listener.ts's
|
|
88
116
|
// collectState) and the thumbnail-capture path read live data instead of
|
|
@@ -106,12 +134,19 @@ export function ViewportPanel() {
|
|
|
106
134
|
store.environment?.rendering as RenderScope | undefined,
|
|
107
135
|
window.devicePixelRatio,
|
|
108
136
|
);
|
|
137
|
+
// World-hidden eye: while the focused threejs world is hidden, its
|
|
138
|
+
// authored post chain (bloom/vignette/…) must not render either — pass
|
|
139
|
+
// no environment so the composer builds bare. `editor-viewport.ts`
|
|
140
|
+
// bumps `composerVersion` (via `store.reapplyEnvironment()`) on both
|
|
141
|
+
// hide/show edges, which is what re-runs this rebuild.
|
|
142
|
+
const hiddenWorldId = resolveFocusedViewportWorldId(store);
|
|
143
|
+
const worldHidden = hiddenWorldId !== null && isWorldHidden(hiddenWorldId);
|
|
109
144
|
applyScenePostProcessing(
|
|
110
145
|
composer,
|
|
111
146
|
renderer,
|
|
112
147
|
store.scene ?? scene,
|
|
113
148
|
viewport.camera,
|
|
114
|
-
store.environment,
|
|
149
|
+
worldHidden ? undefined : store.environment,
|
|
115
150
|
store.objectMap,
|
|
116
151
|
buildEntityTagMap(store),
|
|
117
152
|
);
|
|
@@ -163,7 +198,7 @@ export function ViewportPanel() {
|
|
|
163
198
|
});
|
|
164
199
|
|
|
165
200
|
// --- Hotkeys ---
|
|
166
|
-
const unregisterHotkeys = registerEditorHotkeys(store, viewport, canvas);
|
|
201
|
+
const unregisterHotkeys = registerEditorHotkeys(store, viewport, canvas, history);
|
|
167
202
|
|
|
168
203
|
// --- NavMesh ---
|
|
169
204
|
const disposeNavMesh = setupNavMeshHandlers(store, viewport, scene);
|
|
@@ -246,13 +281,13 @@ export function ViewportPanel() {
|
|
|
246
281
|
// override behind).
|
|
247
282
|
let disposed = false;
|
|
248
283
|
let editModeComposite: CompositeAuthoringAdapter | undefined;
|
|
249
|
-
let
|
|
284
|
+
let disposeWorldDocuments: (() => void) | undefined;
|
|
250
285
|
|
|
251
286
|
/**
|
|
252
287
|
* (A1) fetch `vgai.game.json` and install the edit-mode composite over
|
|
253
|
-
* every declared world, then
|
|
254
|
-
*
|
|
255
|
-
*
|
|
288
|
+
* every declared world, then register a distinct center document for
|
|
289
|
+
* every non-Three authoring surface. This component keeps the native
|
|
290
|
+
* Three renderer; only Game composes roots. Callable more than once: the
|
|
256
291
|
* initial mount (below) AND (C3) the `'editor:edit-mode-rebuild'`
|
|
257
292
|
* listener — e.g. after the "Add UI Canvas" hierarchy-menu action seeds
|
|
258
293
|
* the scene's first `ui` root, the composite needs rebuilding so its new
|
|
@@ -260,8 +295,8 @@ export function ViewportPanel() {
|
|
|
260
295
|
* first, so a rebuild never leaks the old composite/layers.
|
|
261
296
|
*/
|
|
262
297
|
async function installAll(): Promise<void> {
|
|
263
|
-
|
|
264
|
-
|
|
298
|
+
disposeWorldDocuments?.();
|
|
299
|
+
disposeWorldDocuments = undefined;
|
|
265
300
|
if (editModeComposite) {
|
|
266
301
|
exitEditModeAuthoring(editModeComposite);
|
|
267
302
|
editModeComposite = undefined;
|
|
@@ -273,7 +308,15 @@ export function ViewportPanel() {
|
|
|
273
308
|
editModeComposite = undefined;
|
|
274
309
|
return;
|
|
275
310
|
}
|
|
276
|
-
|
|
311
|
+
const { installWorldDocuments } = await import('./world-documents');
|
|
312
|
+
if (disposed || editModeComposite !== composite) {
|
|
313
|
+
if (editModeComposite === composite) {
|
|
314
|
+
exitEditModeAuthoring(composite);
|
|
315
|
+
editModeComposite = undefined;
|
|
316
|
+
}
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
disposeWorldDocuments = installWorldDocuments(store, composite);
|
|
277
320
|
}
|
|
278
321
|
|
|
279
322
|
function onEditModeRebuild(): void {
|
|
@@ -313,7 +356,7 @@ export function ViewportPanel() {
|
|
|
313
356
|
unregisterHotkeys();
|
|
314
357
|
disposeNavMesh();
|
|
315
358
|
window.removeEventListener(EDIT_MODE_REBUILD_EVENT, onEditModeRebuild);
|
|
316
|
-
|
|
359
|
+
disposeWorldDocuments?.();
|
|
317
360
|
exitEditModeAuthoring(editModeComposite);
|
|
318
361
|
window.removeEventListener('error', onError);
|
|
319
362
|
window.removeEventListener('unhandledrejection', onUnhandledRejection);
|
|
@@ -323,15 +366,36 @@ export function ViewportPanel() {
|
|
|
323
366
|
// render targets on unmount (incl. React StrictMode's mount/unmount/remount).
|
|
324
367
|
composer.dispose();
|
|
325
368
|
renderer.dispose();
|
|
369
|
+
// `dispose()` clears Three's GPU resources but intentionally keeps the
|
|
370
|
+
// browser WebGL context alive. Fast Refresh can remount this panel many
|
|
371
|
+
// times in one tab; explicitly release the old context so a later mount
|
|
372
|
+
// cannot fail with "Error creating WebGL context" after the browser's
|
|
373
|
+
// per-process context budget is exhausted.
|
|
374
|
+
renderer.forceContextLoss();
|
|
326
375
|
};
|
|
327
376
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps -- runs once on mount
|
|
328
377
|
|
|
329
378
|
// Subscribe to store for overlay visibility
|
|
330
379
|
useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
331
380
|
|
|
381
|
+
// Spec 28 — figma mode's backdrop is the STANDARD transparency
|
|
382
|
+
// checkerboard, not a flat color: with no threejs surface showing, the
|
|
383
|
+
// area behind the DOM roots isn't "a gray scene", it's NOTHING, and the
|
|
384
|
+
// checkerboard is the universal signal for that. Achieved by fading the
|
|
385
|
+
// WebGL canvas to opacity 0 (keeps layout AND pointer flow identical —
|
|
386
|
+
// the layered-pick path still runs) so the container's own checkerboard
|
|
387
|
+
// shows through behind the DOM world layers appended above it.
|
|
388
|
+
const threejsSurface = isThreejsSurfaceVisible(store);
|
|
389
|
+
const toolContext = resolveViewportToolContext(
|
|
390
|
+
getActiveAuthoring(store),
|
|
391
|
+
store.selectedEntityIds,
|
|
392
|
+
);
|
|
393
|
+
const toolContextVisible = isViewportToolContextVisible(store, toolContext);
|
|
394
|
+
const showThreejsTools = threejsSurface && toolContextVisible && toolContext?.kind === 'threejs';
|
|
332
395
|
return (
|
|
333
396
|
<div
|
|
334
397
|
ref={containerRef}
|
|
398
|
+
data-testid="viewport-panel"
|
|
335
399
|
style={{
|
|
336
400
|
position: 'absolute',
|
|
337
401
|
top: 0,
|
|
@@ -340,6 +404,23 @@ export function ViewportPanel() {
|
|
|
340
404
|
height: '100%',
|
|
341
405
|
overflow: 'hidden',
|
|
342
406
|
pointerEvents: 'auto',
|
|
407
|
+
...(threejsSurface
|
|
408
|
+
? {}
|
|
409
|
+
: {
|
|
410
|
+
// Dark-UI transparency checkerboard (VS Code image-preview
|
|
411
|
+
// style — the light Figma checker glares in a dark editor and
|
|
412
|
+
// washes out light-on-transparent HUD content). V-20 — the
|
|
413
|
+
// PATTERN itself is a deliberate, documented design choice
|
|
414
|
+
// (left alone); `themeVars.surface.raised` is an exact-value token match for the
|
|
415
|
+
// base tone, so swapped in. The gradient's `#444649` has no
|
|
416
|
+
// exact token in the current set, so it stays a literal per
|
|
417
|
+
// the audit's own "only swap exact matches" guidance.
|
|
418
|
+
backgroundColor: themeVars.surface.raised,
|
|
419
|
+
backgroundImage:
|
|
420
|
+
'linear-gradient(45deg, #444649 25%, transparent 25%, transparent 75%, #444649 75%), linear-gradient(45deg, #444649 25%, transparent 25%, transparent 75%, #444649 75%)',
|
|
421
|
+
backgroundPosition: '0 0, 8px 8px',
|
|
422
|
+
backgroundSize: '16px 16px',
|
|
423
|
+
}),
|
|
343
424
|
}}
|
|
344
425
|
>
|
|
345
426
|
<canvas
|
|
@@ -347,23 +428,41 @@ export function ViewportPanel() {
|
|
|
347
428
|
data-testid="editor-canvas"
|
|
348
429
|
aria-hidden="true"
|
|
349
430
|
tabIndex={-1}
|
|
350
|
-
style={{
|
|
431
|
+
style={{
|
|
432
|
+
width: '100%',
|
|
433
|
+
height: '100%',
|
|
434
|
+
display: 'block',
|
|
435
|
+
pointerEvents: 'auto',
|
|
436
|
+
opacity: threejsSurface ? 1 : 0,
|
|
437
|
+
}}
|
|
351
438
|
/>
|
|
352
|
-
{/*
|
|
353
|
-
|
|
354
|
-
world's own `position:absolute; inset:0` layer into, so `RectProvider.rect(id)`'s
|
|
355
|
-
host-relative geometry lines up with this overlay's own coordinate space with no
|
|
356
|
-
correction (see WorldSelectionOverlay.tsx's own doc comment). Self-gates to a
|
|
357
|
-
no-op when the active composite has no rect-capable (DOM) child, so a 3D-only
|
|
358
|
-
project renders nothing extra here. */}
|
|
439
|
+
{/* Three-scene selection overlay. React/Pixi documents mount their own
|
|
440
|
+
co-located overlay beside the isolated world host. */}
|
|
359
441
|
<WorldSelectionOverlay />
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
{
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
442
|
+
{/* W4 (inventory row V4): the PlayBar copy that floated here moved to
|
|
443
|
+
the global command header (`ProjectHeader.tsx`) — transport is now
|
|
444
|
+
document-independent. */}
|
|
445
|
+
{/* Spec 28 — the 3D cockpit (transform toolstrip, grid/helpers/shading
|
|
446
|
+
controls, camera Pos/Target readout) gates on a threejs surface
|
|
447
|
+
actually SHOWING, exactly as WorldSelectionOverlay above self-gates
|
|
448
|
+
on a DOM child existing. With every 3D world hidden the viewport is
|
|
449
|
+
a DOM authoring surface and presents as one. Re-evaluated on every
|
|
450
|
+
notify via this component's useSyncExternalStore subscription. */}
|
|
451
|
+
{showThreejsTools ? (
|
|
452
|
+
<>
|
|
453
|
+
<ToolStrip />
|
|
454
|
+
<ViewportOverlay />
|
|
455
|
+
<CameraInfo />
|
|
456
|
+
</>
|
|
457
|
+
) : threejsSurface ? (
|
|
458
|
+
<ViewportOverlay statsOnly />
|
|
459
|
+
) : null}
|
|
460
|
+
{threejsSurface && store.showStats && <StatsOverlay />}
|
|
461
|
+
{/* W4 (inventory row V9): the duplicated play-time NetworkSection
|
|
462
|
+
overlay is gone from the scene document — compact connection state
|
|
463
|
+
lives in the status bar (`status-contributions.tsx`); the detailed
|
|
464
|
+
overlay stays contextual in the Game document (`CenterDocuments`'s
|
|
465
|
+
GamePanel), where play actually renders. */}
|
|
367
466
|
</div>
|
|
368
467
|
);
|
|
369
468
|
}
|