@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
package/src/editor-viewport.ts
CHANGED
|
@@ -9,6 +9,18 @@ import { BatchedRenderer } from 'three.quarks';
|
|
|
9
9
|
import { getActiveAuthoring } from './authoring/active-adapter';
|
|
10
10
|
import { pickTopmost } from './authoring/layered-pick';
|
|
11
11
|
import { setViewportPickContext } from './authoring/viewport-pick-context';
|
|
12
|
+
import {
|
|
13
|
+
isViewportToolContextVisible,
|
|
14
|
+
resolveViewportToolContext,
|
|
15
|
+
} from './authoring/viewport-tool-context';
|
|
16
|
+
import {
|
|
17
|
+
applyWorldHiddenVisibility,
|
|
18
|
+
isThreejsSurfaceVisible,
|
|
19
|
+
resolveFocusedViewportWorldId,
|
|
20
|
+
suppressWorldEnvironment,
|
|
21
|
+
} from './authoring/world-hidden-viewport';
|
|
22
|
+
import { isWorldHidden } from './authoring/world-session-state';
|
|
23
|
+
import { themeVars, zIndex } from './design-system';
|
|
12
24
|
import { downloadOnlineAsset, getDownloadedAssetPath, getOnlineAssetFiles } from './editor-api';
|
|
13
25
|
import { EDITOR_LAYER } from './editor-layers';
|
|
14
26
|
import type { EditorStore } from './editor-store';
|
|
@@ -37,6 +49,23 @@ const VC_DIRS: THREE.Vector3[] = [
|
|
|
37
49
|
/* 5 -Z */ new THREE.Vector3(0, 0, -1),
|
|
38
50
|
];
|
|
39
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Godot axis color RGB triples (X/Y/Z) — EDITOR-STYLE-AUDIT.md V-13:
|
|
54
|
+
* previously defined independently, from scratch, in BOTH
|
|
55
|
+
* `_initOrientationGizmo` (the view-cube) and `_patchGizmo` (the transform
|
|
56
|
+
* gizmo), each with its own identical "Godot axis colors" comment. Hoisted
|
|
57
|
+
* to one module-level constant so a future retouch of one can't silently
|
|
58
|
+
* drift from the other. Kept as plain `[r,g,b]` triples rather than shared
|
|
59
|
+
* `THREE.Color` instances — call sites construct their own `new
|
|
60
|
+
* THREE.Color(...)` from these, so nothing here can be mutated in place by
|
|
61
|
+
* one call site (materials, sprite canvases) and leak into the other.
|
|
62
|
+
*/
|
|
63
|
+
const GODOT_AXIS_COLOR_RGB: readonly [number, number, number][] = [
|
|
64
|
+
[0.96, 0.2, 0.32], // X
|
|
65
|
+
[0.53, 0.84, 0.01], // Y
|
|
66
|
+
[0.16, 0.55, 0.96], // Z
|
|
67
|
+
];
|
|
68
|
+
|
|
40
69
|
export class EditorViewport {
|
|
41
70
|
readonly camera: THREE.PerspectiveCamera;
|
|
42
71
|
readonly orbitControls: OrbitControls;
|
|
@@ -58,6 +87,9 @@ export class EditorViewport {
|
|
|
58
87
|
private _store: EditorStore;
|
|
59
88
|
private _objectMap = new Map<string, THREE.Object3D>();
|
|
60
89
|
private _canvas: HTMLCanvasElement;
|
|
90
|
+
/** Camera input belongs to the whole viewport surface, including authoring
|
|
91
|
+
* overlays rendered above the WebGL canvas. */
|
|
92
|
+
private _interactionElement: HTMLElement;
|
|
61
93
|
private _pointerDownPos = new THREE.Vector2();
|
|
62
94
|
private _skipNextSync = false;
|
|
63
95
|
|
|
@@ -83,6 +115,15 @@ export class EditorViewport {
|
|
|
83
115
|
* during a transform drag, which notifies per frame but changes none of them). */
|
|
84
116
|
private _lastGizmoObjectMap: Map<string, THREE.Object3D> | null = null;
|
|
85
117
|
private _lastGizmoSig = '';
|
|
118
|
+
/** Previous world-hidden eye state — edge detection for environment suppress/restore. */
|
|
119
|
+
private _lastWorldHidden = false;
|
|
120
|
+
/**
|
|
121
|
+
* Spec 28 — recomputed from surface visibility AND selection ownership on every
|
|
122
|
+
* `syncFromStore`; read by the per-frame render hooks (`renderViewCube`,
|
|
123
|
+
* `renderCameraPreview`) and the view-cube click path, which run between
|
|
124
|
+
* notifies and must not re-walk the composite 60×/s.
|
|
125
|
+
*/
|
|
126
|
+
private _threejsToolContextActive = false;
|
|
86
127
|
private _vcRaycaster = new THREE.Raycaster();
|
|
87
128
|
|
|
88
129
|
// -- Asset drop --
|
|
@@ -147,8 +188,14 @@ export class EditorViewport {
|
|
|
147
188
|
private _flyEuler = new THREE.Euler(0, 0, 0, 'YXZ');
|
|
148
189
|
private _rightMouseDown = false;
|
|
149
190
|
|
|
150
|
-
constructor(
|
|
191
|
+
constructor(
|
|
192
|
+
canvas: HTMLCanvasElement,
|
|
193
|
+
scene: THREE.Scene,
|
|
194
|
+
store: EditorStore,
|
|
195
|
+
interactionElement: HTMLElement = canvas,
|
|
196
|
+
) {
|
|
151
197
|
this._canvas = canvas;
|
|
198
|
+
this._interactionElement = interactionElement;
|
|
152
199
|
this._scene = scene;
|
|
153
200
|
this._store = store;
|
|
154
201
|
|
|
@@ -183,7 +230,7 @@ export class EditorViewport {
|
|
|
183
230
|
scene.add(this.batchedRenderer);
|
|
184
231
|
|
|
185
232
|
// OrbitControls – Unity-style: right-drag = orbit, middle-drag = pan, scroll = zoom
|
|
186
|
-
this.orbitControls = new OrbitControls(this.camera,
|
|
233
|
+
this.orbitControls = new OrbitControls(this.camera, interactionElement);
|
|
187
234
|
this.orbitControls.enableDamping = true;
|
|
188
235
|
this.orbitControls.dampingFactor = 0.1;
|
|
189
236
|
this.orbitControls.mouseButtons = {
|
|
@@ -361,10 +408,10 @@ export class EditorViewport {
|
|
|
361
408
|
// -- Fly camera input (right-click + WASD) --
|
|
362
409
|
window.addEventListener('keydown', this._onFlyKeyDown);
|
|
363
410
|
window.addEventListener('keyup', this._onFlyKeyUp);
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
411
|
+
interactionElement.addEventListener('pointerdown', this._onFlyPointerDown);
|
|
412
|
+
interactionElement.addEventListener('pointerup', this._onFlyPointerUp);
|
|
413
|
+
interactionElement.addEventListener('pointermove', this._onFlyPointerMove);
|
|
414
|
+
interactionElement.addEventListener('wheel', this._onFlyWheel, { passive: false });
|
|
368
415
|
|
|
369
416
|
// Alt+Left-drag = orbit (Unity-style), via capture phase so it fires before OrbitControls
|
|
370
417
|
canvas.addEventListener(
|
|
@@ -527,8 +574,22 @@ export class EditorViewport {
|
|
|
527
574
|
this.transformControls.setRotationSnap(snap ? THREE.MathUtils.degToRad(vals.rotate) : null);
|
|
528
575
|
this.transformControls.setScaleSnap(snap ? vals.scale : null);
|
|
529
576
|
|
|
530
|
-
//
|
|
531
|
-
|
|
577
|
+
// Spec 28 step 2 — visibility says a Three.js surface is painted;
|
|
578
|
+
// selection ownership says it is the native world the user is editing.
|
|
579
|
+
// The grid, view cube, camera preview, and transform gizmo require BOTH.
|
|
580
|
+
// Empty/organizational/cross-world selections deliberately leave only
|
|
581
|
+
// shell chrome rather than advertising an arbitrary coordinate system.
|
|
582
|
+
const toolContext = resolveViewportToolContext(
|
|
583
|
+
getActiveAuthoring(this._store),
|
|
584
|
+
this._store.selectedEntityIds,
|
|
585
|
+
);
|
|
586
|
+
this._threejsToolContextActive =
|
|
587
|
+
isThreejsSurfaceVisible(this._store) &&
|
|
588
|
+
isViewportToolContextVisible(this._store, toolContext) &&
|
|
589
|
+
toolContext?.kind === 'threejs';
|
|
590
|
+
|
|
591
|
+
// Grid visibility — the user's toggle, AND'd with the surface actually showing
|
|
592
|
+
this.grid.visible = this._store.showGrid && this._threejsToolContextActive;
|
|
532
593
|
|
|
533
594
|
// The two passes below (apply gizmos + per-type helper/icon visibility) are
|
|
534
595
|
// idempotent and O(total scene nodes). Their only inputs are the objectMap
|
|
@@ -536,11 +597,49 @@ export class EditorViewport {
|
|
|
536
597
|
// transform drag/scrub (which still fires syncFromStore every frame). Gate
|
|
537
598
|
// them on a cheap signature so a drag doesn't re-walk the whole graph 60×/s.
|
|
538
599
|
const vis = this._store.helperVisibility;
|
|
539
|
-
|
|
600
|
+
// World-hidden eye (D9) folded into the SAME cheap signature/gate as the
|
|
601
|
+
// gizmo/helper passes below — see `world-hidden-viewport.ts`'s doc
|
|
602
|
+
// comment for why this must be recomputed from scratch on every rebuild
|
|
603
|
+
// (never a one-shot flip) and why folding it in here (rather than a
|
|
604
|
+
// separate always-on pass) is safe: the toggle itself
|
|
605
|
+
// (`GameHierarchy.tsx`'s `toggleWorldHidden` + `store.notifyIngestEdit()`)
|
|
606
|
+
// changes `hiddenWorldId`'s hidden state, which changes this signature,
|
|
607
|
+
// so it re-applies on the very next `syncFromStore()` call — exactly the
|
|
608
|
+
// same notify path that already re-triggers this whole method.
|
|
609
|
+
const hiddenWorldId = resolveFocusedViewportWorldId(this._store);
|
|
610
|
+
const hidden = hiddenWorldId !== null && isWorldHidden(hiddenWorldId);
|
|
611
|
+
// While hidden, re-apply on EVERY notify, not just signature changes: a
|
|
612
|
+
// SINGLE-entity rebuild (scene-sync `updateEntityPreview`) mutates the
|
|
613
|
+
// existing objectMap in place — same instance, same size, so the gate
|
|
614
|
+
// below never re-fires — while re-stamping the rebuilt object visible
|
|
615
|
+
// from its descriptor. Cost is one map walk per notify only while a
|
|
616
|
+
// world is actually hidden; the gated call below still handles the
|
|
617
|
+
// hide→show transition (restoring per-entity visibility).
|
|
618
|
+
if (hidden) applyWorldHiddenVisibility(this._objectMap, hiddenWorldId);
|
|
619
|
+
// Scene-LEVEL environment (background/skybox/fog/IBL/ambient — none of it
|
|
620
|
+
// in the objectMap) + the post-processing chain. Edge: both directions
|
|
621
|
+
// re-apply the authored environment from `_sceneMeta` truth and bump
|
|
622
|
+
// `composerVersion` (ViewportPanel's rebuild strips scene effects while
|
|
623
|
+
// hidden). While hidden: suppress on EVERY notify — same rationale as the
|
|
624
|
+
// per-notify `applyWorldHiddenVisibility` above, because an inspector
|
|
625
|
+
// environment edit mid-hide re-paints the authored values.
|
|
626
|
+
if (hidden !== this._lastWorldHidden) {
|
|
627
|
+
this._lastWorldHidden = hidden;
|
|
628
|
+
this._store.reapplyEnvironment();
|
|
629
|
+
}
|
|
630
|
+
if (hidden) suppressWorldEnvironment(this._scene);
|
|
631
|
+
const gizmoSig = `${this._objectMap.size}|${this._store.showHelpers}|${JSON.stringify(vis)}|${hiddenWorldId ?? ''}|${hidden}`;
|
|
540
632
|
if (this._objectMap !== this._lastGizmoObjectMap || gizmoSig !== this._lastGizmoSig) {
|
|
541
633
|
this._lastGizmoObjectMap = this._objectMap;
|
|
542
634
|
this._lastGizmoSig = gizmoSig;
|
|
543
635
|
|
|
636
|
+
// Threejs roots have no DOM layer to `display:none` (unlike react/pixi
|
|
637
|
+
// — `design-time-layers.ts`'s `applySessionStyle`), so this is what
|
|
638
|
+
// actually makes a hidden threejs world's group-row eye hide its
|
|
639
|
+
// objects in THIS viewport. ABOVE the per-entity `visible` flag (ANDed
|
|
640
|
+
// in, never overwritten) — see `world-hidden-viewport.ts`.
|
|
641
|
+
applyWorldHiddenVisibility(this._objectMap, hiddenWorldId);
|
|
642
|
+
|
|
544
643
|
// Ensure gizmos (icon billboards + wireframe helpers) exist on all objects.
|
|
545
644
|
// Idempotent — needed for game scene objects created by the runtime without gizmos.
|
|
546
645
|
for (const obj of this._objectMap.values()) {
|
|
@@ -557,6 +656,10 @@ export class EditorViewport {
|
|
|
557
656
|
}
|
|
558
657
|
if (!getUserData(child, 'editorHelper')) return;
|
|
559
658
|
const type = getUserData(child, 'editorHelperType') as string | undefined;
|
|
659
|
+
if (type === 'skeletons') {
|
|
660
|
+
child.visible = vis.skeletons || Boolean(getUserData(child, 'skeletonEnabled'));
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
560
663
|
if (type && type in vis) {
|
|
561
664
|
child.visible = vis[type as keyof typeof vis];
|
|
562
665
|
} else {
|
|
@@ -570,8 +673,11 @@ export class EditorViewport {
|
|
|
570
673
|
}
|
|
571
674
|
}
|
|
572
675
|
|
|
573
|
-
// Attach gizmo based on pivot mode
|
|
574
|
-
|
|
676
|
+
// Attach gizmo based on pivot mode. Spec 28: no gizmo without a visible
|
|
677
|
+
// threejs surface — this whole block re-derives per notify, so detaching
|
|
678
|
+
// here is self-healing (the un-hide notify re-attaches to the same
|
|
679
|
+
// selection with no extra bookkeeping).
|
|
680
|
+
const selectedId = this._threejsToolContextActive ? this._store.selectedEntityId : null;
|
|
575
681
|
if (selectedId) {
|
|
576
682
|
if (!this.transformControls.dragging) {
|
|
577
683
|
if (this._store.pivotMode === 'median-point' && this._store.selectedEntityIds.size > 1) {
|
|
@@ -803,6 +909,7 @@ export class EditorViewport {
|
|
|
803
909
|
|
|
804
910
|
/** Render the orientation gizmo overlaid in the top-right corner. */
|
|
805
911
|
renderViewCube(renderer: THREE.WebGLRenderer): void {
|
|
912
|
+
if (!this._threejsToolContextActive) return; // spec 28 — no selected 3D context, no compass
|
|
806
913
|
const w = renderer.domElement.clientWidth;
|
|
807
914
|
const h = renderer.domElement.clientHeight;
|
|
808
915
|
const size = this._vcSize;
|
|
@@ -833,6 +940,7 @@ export class EditorViewport {
|
|
|
833
940
|
|
|
834
941
|
/** Render a small camera preview in the bottom-right corner if a camera entity is selected. */
|
|
835
942
|
renderCameraPreview(renderer: THREE.WebGLRenderer): void {
|
|
943
|
+
if (!this._threejsToolContextActive) return; // spec 28 — no selected 3D context, no preview
|
|
836
944
|
const selectedEntity = this._store.selectedEntity;
|
|
837
945
|
if (!selectedEntity?.camera) return;
|
|
838
946
|
|
|
@@ -904,10 +1012,10 @@ export class EditorViewport {
|
|
|
904
1012
|
setViewportPickContext(null);
|
|
905
1013
|
window.removeEventListener('keydown', this._onFlyKeyDown);
|
|
906
1014
|
window.removeEventListener('keyup', this._onFlyKeyUp);
|
|
907
|
-
this.
|
|
908
|
-
this.
|
|
909
|
-
this.
|
|
910
|
-
this.
|
|
1015
|
+
this._interactionElement.removeEventListener('pointerdown', this._onFlyPointerDown);
|
|
1016
|
+
this._interactionElement.removeEventListener('pointerup', this._onFlyPointerUp);
|
|
1017
|
+
this._interactionElement.removeEventListener('pointermove', this._onFlyPointerMove);
|
|
1018
|
+
this._interactionElement.removeEventListener('wheel', this._onFlyWheel);
|
|
911
1019
|
this._canvas.removeEventListener('pointerdown', this._onPointerDown);
|
|
912
1020
|
this._canvas.removeEventListener('pointermove', this._onPointerMove);
|
|
913
1021
|
this._canvas.removeEventListener('pointerup', this._onPointerUp);
|
|
@@ -939,12 +1047,8 @@ export class EditorViewport {
|
|
|
939
1047
|
light.position.set(1, 2, 3);
|
|
940
1048
|
this._vcScene.add(light);
|
|
941
1049
|
|
|
942
|
-
// Godot axis colors
|
|
943
|
-
const colors = [
|
|
944
|
-
new THREE.Color(0.96, 0.2, 0.32), // X
|
|
945
|
-
new THREE.Color(0.53, 0.84, 0.01), // Y
|
|
946
|
-
new THREE.Color(0.16, 0.55, 0.96), // Z
|
|
947
|
-
];
|
|
1050
|
+
// Godot axis colors (V-13 — see module-level `GODOT_AXIS_COLOR_RGB`)
|
|
1051
|
+
const colors = GODOT_AXIS_COLOR_RGB.map(([r, g, b]) => new THREE.Color(r, g, b));
|
|
948
1052
|
const axes = [
|
|
949
1053
|
new THREE.Vector3(1, 0, 0),
|
|
950
1054
|
new THREE.Vector3(0, 1, 0),
|
|
@@ -1283,10 +1387,11 @@ export class EditorViewport {
|
|
|
1283
1387
|
|
|
1284
1388
|
/** Recolor gizmo handles to Godot axis colors & shift plane geometry to meet at center. */
|
|
1285
1389
|
private _patchGizmo(gizmoHelper: THREE.Object3D): void {
|
|
1286
|
-
// Godot axis colors
|
|
1287
|
-
const
|
|
1288
|
-
const
|
|
1289
|
-
const
|
|
1390
|
+
// Godot axis colors (V-13 — see module-level `GODOT_AXIS_COLOR_RGB`)
|
|
1391
|
+
const [axisRgbX, axisRgbY, axisRgbZ] = GODOT_AXIS_COLOR_RGB;
|
|
1392
|
+
const axisX = new THREE.Color(...axisRgbX!);
|
|
1393
|
+
const axisY = new THREE.Color(...axisRgbY!);
|
|
1394
|
+
const axisZ = new THREE.Color(...axisRgbZ!);
|
|
1290
1395
|
|
|
1291
1396
|
// Handle color: axis handles use axis color, plane handles use normal-axis color
|
|
1292
1397
|
const colorMap: Record<string, THREE.Color> = {
|
|
@@ -1591,12 +1696,16 @@ export class EditorViewport {
|
|
|
1591
1696
|
|
|
1592
1697
|
if (!this._marqueeDiv) {
|
|
1593
1698
|
this._marqueeDiv = document.createElement('div');
|
|
1699
|
+
// V-12 — was the string `'999'` (a stray string literal in an
|
|
1700
|
+
// otherwise-numeric z-index scale); now the canonical `zIndex.sticky`
|
|
1701
|
+
// token (numeric `1000`, same absorbed tier as the old `999`/`1000`
|
|
1702
|
+
// pair per the audit's own z-index reconciliation).
|
|
1594
1703
|
Object.assign(this._marqueeDiv.style, {
|
|
1595
1704
|
position: 'fixed',
|
|
1596
|
-
border:
|
|
1597
|
-
background:
|
|
1705
|
+
border: `1px solid ${themeVars.accent.default}`,
|
|
1706
|
+
background: themeVars.accent.muted,
|
|
1598
1707
|
pointerEvents: 'none',
|
|
1599
|
-
zIndex:
|
|
1708
|
+
zIndex: zIndex.sticky,
|
|
1600
1709
|
});
|
|
1601
1710
|
document.body.appendChild(this._marqueeDiv);
|
|
1602
1711
|
}
|
|
@@ -1653,6 +1762,16 @@ export class EditorViewport {
|
|
|
1653
1762
|
for (const [id, obj] of this._objectMap) {
|
|
1654
1763
|
// Skip locked entities in marquee selection
|
|
1655
1764
|
if (this._store.isEntityLocked(id)) continue;
|
|
1765
|
+
// Skip invisible entities — mirrors `raycastPick`'s single-click
|
|
1766
|
+
// behavior for free (THREE.Raycaster's own `intersectObject` already
|
|
1767
|
+
// stops descending into an `obj.visible === false` subtree, so a
|
|
1768
|
+
// single click can never land on one). Marquee did its own screen-
|
|
1769
|
+
// space rect test with no such check, so a world hidden via the
|
|
1770
|
+
// group-row eye (`world-hidden-viewport.ts` — forces `obj.visible =
|
|
1771
|
+
// false` for the whole world while hidden) stayed marquee-selectable
|
|
1772
|
+
// even though it was invisible and unclickable. Also correctly skips
|
|
1773
|
+
// an entity hidden via its OWN eye, for the same reason.
|
|
1774
|
+
if (!obj.visible) continue;
|
|
1656
1775
|
const screen = this._projectToScreen(obj);
|
|
1657
1776
|
if (screen.x >= left && screen.x <= right && screen.y >= top && screen.y <= bottom) {
|
|
1658
1777
|
hitIds.push(id);
|
|
@@ -1680,8 +1799,9 @@ export class EditorViewport {
|
|
|
1680
1799
|
// Don't interfere with gizmo clicks
|
|
1681
1800
|
if (this.transformControls.dragging) return;
|
|
1682
1801
|
|
|
1683
|
-
// Check orientation gizmo click first
|
|
1684
|
-
|
|
1802
|
+
// Check orientation gizmo click first (spec 28 — the cube isn't rendered
|
|
1803
|
+
// without a visible threejs surface, so it can't be clicked either)
|
|
1804
|
+
if (this._threejsToolContextActive && this._handleViewCubeClick(e)) return;
|
|
1685
1805
|
|
|
1686
1806
|
// D12 (B4) — topmost-first layered pick: the composite's non-threejs
|
|
1687
1807
|
// children (react/pixi design-time layers) are tried topmost-first before
|
|
@@ -1720,13 +1840,19 @@ export class EditorViewport {
|
|
|
1720
1840
|
private _showDropOverlay(): void {
|
|
1721
1841
|
if (this._dropOverlay) return;
|
|
1722
1842
|
const overlay = document.createElement('div');
|
|
1843
|
+
// V-12 — the stray string `'5'` (below every named tier in the z-index
|
|
1844
|
+
// scale) becomes the numeric `zIndex.base`, the lowest defined tier,
|
|
1845
|
+
// preserving its relative order (still below the marquee's `zIndex.
|
|
1846
|
+
// sticky` and every dropdown/menu). The semantic accent tokens reconcile this
|
|
1847
|
+
// block's one-off `#579EFF`/`rgba(87,158,255,0.08)` onto the canonical
|
|
1848
|
+
// accent tint per the audit's own §3 absorption list.
|
|
1723
1849
|
Object.assign(overlay.style, {
|
|
1724
1850
|
position: 'fixed',
|
|
1725
1851
|
inset: '0',
|
|
1726
1852
|
pointerEvents: 'none',
|
|
1727
|
-
border:
|
|
1728
|
-
background:
|
|
1729
|
-
zIndex:
|
|
1853
|
+
border: `2px dashed ${themeVars.accent.default}`,
|
|
1854
|
+
background: themeVars.accent.muted,
|
|
1855
|
+
zIndex: zIndex.base,
|
|
1730
1856
|
});
|
|
1731
1857
|
document.body.appendChild(overlay);
|
|
1732
1858
|
this._dropOverlay = overlay;
|
|
@@ -1787,7 +1913,7 @@ export class EditorViewport {
|
|
|
1787
1913
|
const baseName = online.name.replace(/\.[^.]+$/, '');
|
|
1788
1914
|
|
|
1789
1915
|
// Already downloaded? Create entity instantly, no placeholder needed.
|
|
1790
|
-
const cachedPath = getDownloadedAssetPath(online.source, online.
|
|
1916
|
+
const cachedPath = getDownloadedAssetPath(online.source, online.id);
|
|
1791
1917
|
if (cachedPath) {
|
|
1792
1918
|
this._store.addEntity(null, {
|
|
1793
1919
|
id: crypto.randomUUID(),
|
package/src/entity-factory.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { buildClipMap } from '@engine/animation/clip-map';
|
|
|
4
4
|
// disposal-safe clone (own materials + `__sharedGeometry` tags) — the same
|
|
5
5
|
// clone-safety contract the runtime relies on.
|
|
6
6
|
import { loadGLTF, resolveGltfNode } from '@engine/scene/asset-loaders';
|
|
7
|
+
import { applyImportCorrection, getAssetMeta, loadRegistry } from '@engine/scene/asset-registry';
|
|
7
8
|
import { DEFAULTS } from '@engine/scene/defaults';
|
|
8
9
|
import { deleteUserData, getUserData, setUserData } from '@engine/scene/user-data';
|
|
9
10
|
import '@engine/scene/geometries';
|
|
@@ -20,6 +21,7 @@ import '@engine/scene/materials';
|
|
|
20
21
|
import { createParticleSystemFromData } from '@engine/scene/particles-factory';
|
|
21
22
|
import type { SceneEntity } from '@engine/scene/scene-types';
|
|
22
23
|
import * as THREE from 'three';
|
|
24
|
+
import { ensureSkeletonHelper } from './skeleton-helper';
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* Load a GLTF and return a disposal-safe clone + its animation clips for the
|
|
@@ -40,9 +42,10 @@ function setupAnimation(
|
|
|
40
42
|
animations: THREE.AnimationClip[],
|
|
41
43
|
autoplay?: string,
|
|
42
44
|
loop?: boolean,
|
|
45
|
+
clipAliases?: Record<string, string>,
|
|
43
46
|
): void {
|
|
44
47
|
if (animations.length === 0) return;
|
|
45
|
-
const clipMap = buildClipMap(animations);
|
|
48
|
+
const clipMap = buildClipMap(animations, clipAliases);
|
|
46
49
|
|
|
47
50
|
// Expose available clip names for the inspector dropdown
|
|
48
51
|
setUserData(group, '_availableClips', [...clipMap.keys()]);
|
|
@@ -95,10 +98,16 @@ export function createEntityObject(entity: SceneEntity): THREE.Object3D {
|
|
|
95
98
|
const group = new THREE.Group();
|
|
96
99
|
const src = entity.mesh.src;
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
// Runtime scene loading awaits this same registry before constructing a
|
|
102
|
+
// model. Await it alongside the GLTF so editor preview and Play apply the
|
|
103
|
+
// exact same visual-only scale/facing correction.
|
|
104
|
+
const gltfPromise = Promise.all([loadGltfWithClips(src), loadRegistry()]).then(
|
|
105
|
+
([gltf]) => gltf,
|
|
106
|
+
);
|
|
99
107
|
|
|
100
108
|
const autoplay = entity.animation?.autoplay;
|
|
101
109
|
const loop = entity.animation?.loop;
|
|
110
|
+
const clipAliases = entity.animation?.clipAliases;
|
|
102
111
|
|
|
103
112
|
const nodeName = entity.mesh.node;
|
|
104
113
|
const lod = entity.mesh.lod;
|
|
@@ -128,6 +137,7 @@ export function createEntityObject(entity: SceneEntity): THREE.Object3D {
|
|
|
128
137
|
content.rotation.set(0, 0, 0);
|
|
129
138
|
content.scale.set(1, 1, 1);
|
|
130
139
|
}
|
|
140
|
+
applyImportCorrection(content, getAssetMeta(src)?.importCorrection);
|
|
131
141
|
group.add(content);
|
|
132
142
|
// The shared loadGLTF already gave the clone its own materials and tagged
|
|
133
143
|
// every mesh `__sharedGeometry` (so editor disposal in scene-sync never
|
|
@@ -136,7 +146,8 @@ export function createEntityObject(entity: SceneEntity): THREE.Object3D {
|
|
|
136
146
|
content.traverse((n) => {
|
|
137
147
|
setUserData(n, '__sharedGeometry', true);
|
|
138
148
|
});
|
|
139
|
-
setupAnimation(group, clone, animations, autoplay, loop);
|
|
149
|
+
setupAnimation(group, clone, animations, autoplay, loop, clipAliases);
|
|
150
|
+
ensureSkeletonHelper(group);
|
|
140
151
|
});
|
|
141
152
|
obj = group;
|
|
142
153
|
} else {
|
package/src/gizmo-registry.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
import { getUserData, setUserData } from '@engine/scene/user-data';
|
|
25
25
|
import * as THREE from 'three';
|
|
26
26
|
import { EDITOR_LAYER } from './editor-layers';
|
|
27
|
+
import { ensureSkeletonHelper } from './skeleton-helper';
|
|
27
28
|
|
|
28
29
|
// ---------------------------------------------------------------------------
|
|
29
30
|
// Registry types
|
|
@@ -361,7 +362,7 @@ const audioGizmo: GizmoEntry = {
|
|
|
361
362
|
* `dims` already has the entity's composed world scale (self × ancestors)
|
|
362
363
|
* applied, so this function itself must NOT apply any further scale.
|
|
363
364
|
*/
|
|
364
|
-
function createColliderHelper(
|
|
365
|
+
export function createColliderHelper(
|
|
365
366
|
collider: SceneCollider,
|
|
366
367
|
dims: ColliderWorldDimensions,
|
|
367
368
|
): THREE.Object3D | null {
|
|
@@ -424,7 +425,9 @@ function createColliderHelper(
|
|
|
424
425
|
return null;
|
|
425
426
|
}
|
|
426
427
|
|
|
427
|
-
|
|
428
|
+
if (group.children.length === 0) return null;
|
|
429
|
+
if (collider.offset) group.position.fromArray(collider.offset);
|
|
430
|
+
return group;
|
|
428
431
|
}
|
|
429
432
|
|
|
430
433
|
const colliderGizmo: GizmoEntry = {
|
|
@@ -566,11 +569,23 @@ const GIZMO_REGISTRY: GizmoEntry[] = [
|
|
|
566
569
|
*/
|
|
567
570
|
export function applyEntityGizmos(obj: THREE.Object3D): void {
|
|
568
571
|
const entity = getUserData(obj, 'entity') as SceneEntity | undefined;
|
|
569
|
-
if (!entity)
|
|
572
|
+
if (!entity) {
|
|
573
|
+
ensureSkeletonHelper(obj);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
570
576
|
|
|
571
|
-
//
|
|
572
|
-
|
|
577
|
+
// Skeletons are created independently from entity gizmos and must not make
|
|
578
|
+
// collider/light/etc. setup look complete.
|
|
579
|
+
const hasEntityGizmos = obj.children.some(
|
|
580
|
+
(child) =>
|
|
581
|
+
getUserData(child, 'editorIcon') ||
|
|
582
|
+
(getUserData(child, 'editorHelper') &&
|
|
583
|
+
getUserData(child, 'editorHelperType') !== 'skeletons'),
|
|
584
|
+
);
|
|
585
|
+
if (hasEntityGizmos) {
|
|
586
|
+
ensureSkeletonHelper(obj);
|
|
573
587
|
return;
|
|
588
|
+
}
|
|
574
589
|
|
|
575
590
|
let added = false;
|
|
576
591
|
for (const entry of GIZMO_REGISTRY) {
|
|
@@ -605,4 +620,5 @@ export function applyEntityGizmos(obj: THREE.Object3D): void {
|
|
|
605
620
|
|
|
606
621
|
// Force matrix computation so helpers render at the correct position immediately
|
|
607
622
|
if (added) obj.updateMatrixWorld(true);
|
|
623
|
+
ensureSkeletonHelper(obj);
|
|
608
624
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Lightweight bridge from the editor shell into the coding-agent panel.
|
|
2
|
+
* Kept free of EditorContext's engine import graph so the panel remains
|
|
3
|
+
* independently testable and the Supercode-facing UI stays framework-thin. */
|
|
4
|
+
export interface HarnessChatEditorStore {
|
|
5
|
+
subscribe(listener: () => void): () => void;
|
|
6
|
+
getSnapshot(): number;
|
|
7
|
+
readonly selectedEntityId: string | null;
|
|
8
|
+
readonly selectedEntity: {
|
|
9
|
+
id?: string | undefined;
|
|
10
|
+
name?: string | undefined;
|
|
11
|
+
} | null;
|
|
12
|
+
readonly playState: 'stopped' | 'playing' | 'paused';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let current: HarnessChatEditorStore | null = null;
|
|
16
|
+
let version = 0;
|
|
17
|
+
const listeners = new Set<() => void>();
|
|
18
|
+
|
|
19
|
+
export function setHarnessChatEditorStore(store: HarnessChatEditorStore | null): void {
|
|
20
|
+
if (current === store) return;
|
|
21
|
+
current = store;
|
|
22
|
+
version++;
|
|
23
|
+
for (const listener of listeners) listener();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function harnessChatEditorStore(): HarnessChatEditorStore | null {
|
|
27
|
+
return current;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function subscribeHarnessChatEditorStore(listener: () => void): () => void {
|
|
31
|
+
listeners.add(listener);
|
|
32
|
+
return () => listeners.delete(listener);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function harnessChatEditorStoreVersion(): number {
|
|
36
|
+
return version;
|
|
37
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { HarnessChatSnapshot } from './harness-chat-types';
|
|
2
|
+
|
|
3
|
+
export interface HarnessChatIndicator {
|
|
4
|
+
/** This editor owns the selected runtime. This is deliberately a state,
|
|
5
|
+
* not a fabricated multi-agent count. */
|
|
6
|
+
controlled: boolean;
|
|
7
|
+
working: boolean;
|
|
8
|
+
needsInput: boolean;
|
|
9
|
+
following: boolean;
|
|
10
|
+
unavailable: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let current: HarnessChatIndicator = {
|
|
14
|
+
controlled: false,
|
|
15
|
+
working: false,
|
|
16
|
+
needsInput: false,
|
|
17
|
+
following: false,
|
|
18
|
+
unavailable: false,
|
|
19
|
+
};
|
|
20
|
+
let version = 0;
|
|
21
|
+
const listeners = new Set<() => void>();
|
|
22
|
+
|
|
23
|
+
export function updateHarnessChatIndicator(snapshot: HarnessChatSnapshot): void {
|
|
24
|
+
const next: HarnessChatIndicator = {
|
|
25
|
+
controlled: snapshot.connection.ownsRuntime,
|
|
26
|
+
working: snapshot.turn.state !== 'idle',
|
|
27
|
+
needsInput: snapshot.requests.some((request) => request.status === 'pending'),
|
|
28
|
+
following: snapshot.connection.follow !== 'inactive',
|
|
29
|
+
unavailable: snapshot.status === 'unavailable',
|
|
30
|
+
};
|
|
31
|
+
if (
|
|
32
|
+
next.controlled === current.controlled &&
|
|
33
|
+
next.working === current.working &&
|
|
34
|
+
next.needsInput === current.needsInput &&
|
|
35
|
+
next.following === current.following &&
|
|
36
|
+
next.unavailable === current.unavailable
|
|
37
|
+
) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
current = next;
|
|
41
|
+
version++;
|
|
42
|
+
for (const listener of listeners) listener();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function harnessChatIndicator(): HarnessChatIndicator {
|
|
46
|
+
return current;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function harnessChatIndicatorVersion(): number {
|
|
50
|
+
return version;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function subscribeHarnessChatIndicator(listener: () => void): () => void {
|
|
54
|
+
listeners.add(listener);
|
|
55
|
+
return () => listeners.delete(listener);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function __resetHarnessChatIndicatorForTest(): void {
|
|
59
|
+
current = {
|
|
60
|
+
controlled: false,
|
|
61
|
+
working: false,
|
|
62
|
+
needsInput: false,
|
|
63
|
+
following: false,
|
|
64
|
+
unavailable: false,
|
|
65
|
+
};
|
|
66
|
+
version++;
|
|
67
|
+
for (const listener of listeners) listener();
|
|
68
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Presentation state for the permanent coding-agent surface.
|
|
2
|
+
*
|
|
3
|
+
* Chat is a Dockview panel, so Dockview owns its position and size. This tiny
|
|
4
|
+
* store owns only whether the optional panel is present. Supercode's server
|
|
5
|
+
* controller remains independent of either surface, so closing/moving the
|
|
6
|
+
* panel never detaches or hands off a controlled harness session.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface HarnessChatLayoutState {
|
|
10
|
+
readonly collapsed: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let state: HarnessChatLayoutState = { collapsed: false };
|
|
14
|
+
let version = 0;
|
|
15
|
+
const listeners = new Set<() => void>();
|
|
16
|
+
|
|
17
|
+
function publish(next: HarnessChatLayoutState): void {
|
|
18
|
+
if (next.collapsed === state.collapsed) return;
|
|
19
|
+
state = next;
|
|
20
|
+
version += 1;
|
|
21
|
+
for (const listener of listeners) listener();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function subscribeHarnessChatLayout(listener: () => void): () => void {
|
|
25
|
+
listeners.add(listener);
|
|
26
|
+
return () => listeners.delete(listener);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function harnessChatLayoutVersion(): number {
|
|
30
|
+
return version;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function harnessChat(): HarnessChatLayoutState {
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function setHarnessChatCollapsed(collapsed: boolean): void {
|
|
38
|
+
publish({ ...state, collapsed });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function toggleHarnessChatCollapsed(): void {
|
|
42
|
+
setHarnessChatCollapsed(!state.collapsed);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function hydrateHarnessChatLayout(next: Partial<HarnessChatLayoutState>): void {
|
|
46
|
+
publish({ collapsed: next.collapsed ?? state.collapsed });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function __resetHarnessChatLayoutForTest(): void {
|
|
50
|
+
state = { collapsed: false };
|
|
51
|
+
version = 0;
|
|
52
|
+
listeners.clear();
|
|
53
|
+
}
|