@vgai/editor 0.2.0 → 0.4.0-canary.20260715.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/assets/axe-C7YBtOuM.js +30 -0
- package/dist/assets/browserAll-DDtGGE48.js +1 -0
- package/dist/assets/create-runtime-DbTlBlKG.js +1 -0
- package/dist/assets/{game-BI111o5f.js → game-BE0r7DMI.js} +3 -3
- package/dist/assets/game-BdTHR2_X.js +1 -0
- package/dist/assets/{game-pt_1lQLv.js → game-C3iQGSqo.js} +1 -1
- package/dist/assets/game-CcHfYxjP.js +1 -0
- package/dist/assets/game-Cqzj_lpD.js +1 -0
- package/dist/assets/game-DSZdeCHu.js +1 -0
- package/dist/assets/game-Dch9sAPc.js +1 -0
- package/dist/assets/{game-xsOho_wg.js → game-SAFn90pA.js} +3 -3
- package/dist/assets/game-loop-DMIgSMV-.js +1 -0
- package/dist/assets/{game-source-CvidN7AB.js → game-source-Dk83w26t.js} +1 -1
- package/dist/assets/{index-Bp5cecD6.js → index-4idIsHHJ.js} +2 -2
- package/dist/assets/{index-DL7RcQ0n.js → index-C-LhOTBN.js} +1 -1
- package/dist/assets/{index-Cs8xwv3e.js → index-CDkxceqE.js} +1 -1
- package/dist/assets/index-CQEfi217.js +15412 -0
- package/dist/assets/index-Dvi-V0NE.css +1 -0
- package/dist/assets/ingest-siblings-s0P5I1Ub.js +1 -0
- package/dist/assets/mount-manifest-DXMOlF79.js +1 -0
- package/dist/assets/react-18-C9eHn8x1.js +1 -0
- package/dist/assets/webworkerAll-Fn0e-ouF.js +1 -0
- package/dist/assets/world-documents-GM0a9Kv7.js +1 -0
- package/dist/index.html +15 -13
- package/dist/ingest/racing-game/vgai.game.json +5 -4
- package/dist/ingest/simcity/vgai.game.json +5 -4
- package/dist/ingest/tanks/vgai.game.json +5 -4
- package/dist/project-scripts.bundle.js +3917 -0
- package/dist/scenes/untitled.vscn.json +2 -0
- package/dist-server/packaged.mjs +7697 -3435
- package/package.json +31 -4
- package/scripts/probe-reporter.ts +349 -0
- package/scripts/run-probe.ts +2260 -0
- package/server/asset-catalog-audit.ts +268 -0
- package/server/asset-catalog-v2.ts +146 -0
- package/server/asset-library-routes.ts +276 -58
- package/server/canonical-path.ts +1 -1
- package/server/dev.ts +148 -44
- package/server/editor-server.ts +888 -61
- package/server/editor-sse.ts +115 -4
- package/server/harness-chat-service.ts +796 -0
- package/server/local-asset-catalog.ts +157 -22
- package/server/packaged.ts +51 -21
- package/server/process-shutdown.ts +136 -0
- package/server/prod.ts +9 -6
- package/server/project-hmr-files.ts +41 -0
- package/server/project-operations.ts +343 -0
- package/server/project-optimize-deps-entries.ts +4 -4
- package/server/project-output-writer.ts +156 -0
- package/server/project-validation.ts +140 -0
- package/server/project-view.ts +8 -50
- package/server/server-utils.ts +75 -10
- package/server/session-registry.ts +12 -0
- package/src/EditorContext.tsx +107 -3
- package/src/action-registry.ts +115 -17
- package/src/adapter-resolver.ts +213 -478
- package/src/asset-events.ts +64 -1
- package/src/asset-preview.ts +906 -0
- package/src/asset-selection.ts +121 -0
- package/src/asset-workflow/asset-capabilities.ts +259 -0
- package/src/asset-workflow/asset-editor-errors.ts +46 -0
- package/src/asset-workflow/asset-import-pipeline.ts +176 -0
- package/src/asset-workflow/asset-library-query.ts +107 -0
- package/src/asset-workflow/asset-types.ts +192 -0
- package/src/asset-workflow/asset-workflow-quality.ts +65 -0
- package/src/asset-workflow/import-contract.ts +113 -0
- package/src/asset-workflow/model-conversion.ts +126 -0
- package/src/asset-workflow/model-inspection.ts +185 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +153 -0
- package/src/asset-workflow/project-asset-operations.ts +119 -0
- package/src/asset-workflow/thumbnail-system.ts +172 -0
- package/src/authoring/active-systems.ts +15 -0
- package/src/authoring/boundary-authoring-adapter.ts +16 -5
- package/src/authoring/composite-authoring-adapter.ts +305 -124
- package/src/authoring/design-time-layers.ts +300 -117
- package/src/authoring/edit-mode-authoring.ts +278 -293
- package/src/authoring/embed-only-adapter.ts +4 -2
- package/src/authoring/first-party-hierarchy-menu.ts +7 -2
- package/src/authoring/first-party-inspector/AddSectionMenu.tsx +5 -12
- package/src/authoring/first-party-inspector/EnvironmentSection.tsx +53 -126
- package/src/authoring/first-party-inspector/HeaderSection.tsx +54 -65
- package/src/authoring/first-party-inspector/is-first-party-selection.ts +30 -11
- package/src/authoring/first-party-inspector/register.tsx +13 -2
- package/src/authoring/ingest-authoring-adapter.ts +142 -45
- package/src/authoring/mount-failure-report.ts +5 -5
- package/src/authoring/provenance.ts +41 -0
- package/src/authoring/react-dom-authoring-adapter.ts +92 -92
- package/src/authoring/react-inspector-section.tsx +489 -51
- package/src/authoring/react-world-authoring-adapter.ts +541 -306
- package/src/authoring/story-overlay.ts +1 -1
- package/src/authoring/story-types.ts +11 -0
- package/src/authoring/vgai-scene-authoring-adapter.ts +54 -25
- package/src/authoring/viewport-tool-context.ts +78 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +186 -0
- package/src/authoring/world-pan-state.ts +33 -17
- package/src/authoring/world-session-state.ts +1 -1
- package/src/authoring/world2d-authoring-adapter.ts +109 -52
- package/src/availability-tick.ts +56 -0
- package/src/browser-play-entry.ts +5 -5
- package/src/browser-project-scripts.ts +1 -0
- package/src/build-identity.ts +15 -0
- package/src/command-listener.ts +893 -19
- package/src/components/AlignToolbar.tsx +74 -63
- package/src/components/AppRoot.tsx +193 -26
- package/src/components/ApplicationMenus.tsx +272 -0
- package/src/components/AssetBrowser.tsx +1450 -293
- package/src/components/AssetEditorShell.tsx +141 -0
- package/src/components/AssetImportDetails.tsx +218 -0
- package/src/components/AssetLibraryPanel.tsx +14 -0
- package/src/components/CameraInfo.tsx +11 -20
- package/src/components/CenterDocuments.tsx +585 -0
- package/src/components/CommandPalette.tsx +75 -30
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +57 -112
- package/src/components/DebugConsolePanel.tsx +461 -0
- package/src/components/DebuggerPanel.tsx +165 -0
- package/src/components/DefaultEditorLayout.tsx +167 -231
- package/src/components/GameHierarchy.tsx +873 -290
- package/src/components/GamePerformanceOverlay.tsx +46 -0
- package/src/components/HarnessChatPanel.tsx +2352 -0
- package/src/components/HistoryPanel.tsx +226 -0
- package/src/components/Inspector.tsx +153 -99
- package/src/components/InspectorToolSection.tsx +6 -4
- package/src/components/MountFailureBanner.tsx +31 -48
- package/src/components/NetworkSection.tsx +25 -14
- package/src/components/OnlineAssetBrowser.tsx +794 -343
- package/src/components/OverlayReportBanner.tsx +38 -64
- package/src/components/PerformancePanel.tsx +206 -0
- package/src/components/PlayBar.tsx +93 -263
- package/src/components/PrefabSaveDialog.tsx +55 -127
- package/src/components/ProjectHeader.css +60 -0
- package/src/components/ProjectHeader.tsx +170 -105
- package/src/components/ProjectScreen.tsx +246 -184
- package/src/components/ReactCanvasControls.tsx +185 -0
- package/src/components/ResolutionPicker.tsx +85 -0
- package/src/components/RootActivateDialog.tsx +39 -68
- package/src/components/SaveDialog.tsx +55 -127
- package/src/components/SaveStatus.tsx +11 -29
- package/src/components/StartupLoadingScreen.tsx +96 -0
- package/src/components/StateWatchPanel.tsx +302 -0
- package/src/components/StatsOverlay.tsx +12 -5
- package/src/components/StatusBar.tsx +64 -0
- package/src/components/ThemeManagerDialog.css +89 -0
- package/src/components/ThemeManagerDialog.tsx +371 -0
- package/src/components/ToolHost.tsx +26 -15
- package/src/components/Toolbar.tsx +117 -214
- package/src/components/VgaiVoxelLogo.tsx +89 -0
- package/src/components/ViewportOverlay.tsx +97 -172
- package/src/components/ViewportPanel.tsx +130 -31
- package/src/components/WorkspaceDock.tsx +891 -0
- package/src/components/WorldSelectionOverlay.tsx +51 -63
- package/src/components/WorldTextEditor.tsx +9 -5
- package/src/components/asset-documents.tsx +390 -0
- package/src/components/asset-editor-persistence.ts +44 -0
- package/src/components/asset-selection-section.tsx +338 -0
- package/src/components/asset-viewers/AudioViewer.tsx +73 -21
- package/src/components/asset-viewers/GenericJsonViewer.tsx +26 -11
- package/src/components/asset-viewers/ImageViewer.tsx +43 -11
- package/src/components/asset-viewers/InputMapViewer.tsx +512 -134
- package/src/components/asset-viewers/MaterialAssetEditor.tsx +540 -0
- package/src/components/asset-viewers/ModelViewer.tsx +805 -121
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +177 -60
- package/src/components/asset-viewers/SourceAssetViewer.tsx +121 -0
- package/src/components/asset-workflow.css +506 -0
- package/src/components/build-documents.tsx +696 -0
- package/src/components/core-utilities.tsx +75 -0
- package/src/components/data-documents.tsx +364 -0
- package/src/components/{DataPanel.tsx → data-editor.tsx} +138 -288
- package/src/components/debugger-panel-state.ts +57 -0
- package/src/components/inspector-widgets/AlignmentGrid.tsx +8 -14
- package/src/components/inspector-widgets/BorderEditor.tsx +41 -33
- package/src/components/inspector-widgets/ColorPicker.tsx +39 -39
- package/src/components/inspector-widgets/FontPicker.tsx +13 -21
- package/src/components/inspector-widgets/GradientEditor.tsx +11 -19
- package/src/components/inspector-widgets/ScrubbableInput.tsx +6 -3
- package/src/components/inspector-widgets/ShadowEditor.tsx +20 -33
- package/src/components/inspector-widgets/shared.tsx +90 -49
- package/src/components/inspectors/AnimationSection.tsx +39 -40
- package/src/components/inspectors/AudioSection.tsx +28 -39
- package/src/components/inspectors/BoneAttachmentSection.tsx +19 -24
- package/src/components/inspectors/CameraSection.tsx +14 -23
- package/src/components/inspectors/ComponentsSection.tsx +39 -43
- package/src/components/inspectors/JointsSection.tsx +34 -43
- package/src/components/inspectors/LightSection.tsx +90 -35
- package/src/components/inspectors/MaterialSection.tsx +137 -174
- package/src/components/inspectors/MeshSection.tsx +9 -17
- package/src/components/inspectors/NavigationSection.tsx +8 -15
- package/src/components/inspectors/ParticleSection.tsx +91 -76
- package/src/components/inspectors/PhysicsSection.tsx +42 -46
- package/src/components/inspectors/PostProcessingSection.tsx +28 -36
- package/src/components/inspectors/RenderingSection.tsx +12 -20
- package/src/components/inspectors/ShadowSection.tsx +7 -8
- package/src/components/inspectors/SplineSection.tsx +31 -42
- package/src/components/inspectors/TransformSection.tsx +14 -22
- package/src/components/patterns/Dialog.tsx +95 -0
- package/src/components/patterns/Fields.tsx +44 -0
- package/src/components/patterns/List.tsx +25 -0
- package/src/components/patterns/StateSurface.tsx +40 -0
- package/src/components/patterns/Surfaces.tsx +115 -0
- package/src/components/patterns/Tabs.tsx +80 -0
- package/src/components/patterns/Toolbar.tsx +51 -0
- package/src/components/patterns/Tree.tsx +72 -0
- package/src/components/primitives/Button.tsx +46 -0
- package/src/components/primitives/ColorInput.tsx +11 -47
- package/src/components/primitives/EditorIcon.tsx +99 -0
- package/src/components/primitives/FormControls.tsx +71 -0
- package/src/components/primitives/JsonInput.tsx +15 -2
- package/src/components/primitives/Layout.tsx +100 -0
- package/src/components/primitives/Menu.tsx +105 -0
- package/src/components/primitives/NumberInput.tsx +8 -35
- package/src/components/primitives/Panel.tsx +49 -44
- package/src/components/primitives/SectionHeader.tsx +10 -28
- package/src/components/primitives/Text.tsx +46 -0
- package/src/components/primitives/Tooltip.tsx +20 -12
- package/src/components/primitives/Vec3Input.tsx +3 -0
- package/src/components/primitives/banner-tones.ts +33 -0
- package/src/components/primitives/editor-icons.ts +102 -0
- package/src/components/primitives/panel-header-styles.ts +30 -0
- package/src/components/project-operation-documents.tsx +226 -0
- package/src/components/status-contributions.tsx +175 -0
- package/src/components/story-documents-register.ts +15 -0
- package/src/components/story-documents.tsx +1185 -0
- package/src/components/tool-documents.tsx +110 -0
- package/src/components/workspace-dock.css +293 -0
- package/src/components/workspace-history.ts +33 -0
- package/src/components/world-documents.tsx +145 -0
- package/src/components/xstate-documents.tsx +209 -0
- package/src/composite-screenshot.ts +248 -0
- package/src/design-system/index.ts +70 -0
- package/src/design-system-stories/Foundation.stories.tsx +183 -0
- package/src/design-system-stories/Patterns.stories.tsx +251 -0
- package/src/design-system-stories/Workspace.stories.tsx +538 -0
- package/src/doctor/report.ts +57 -13
- package/src/editor-api.ts +295 -31
- package/src/editor-compatibility.ts +200 -0
- package/src/editor-console.ts +35 -17
- package/src/editor-hotkeys.ts +85 -33
- package/src/editor-store.ts +538 -233
- package/src/editor-viewport.ts +160 -34
- package/src/entity-factory.ts +14 -3
- package/src/gizmo-registry.ts +21 -5
- package/src/harness-chat-editor-context.ts +37 -0
- package/src/harness-chat-indicator.ts +68 -0
- package/src/harness-chat-layout.ts +53 -0
- package/src/harness-chat-lifecycle.ts +170 -0
- package/src/harness-chat-reconnect.ts +85 -0
- package/src/harness-chat-types.ts +409 -0
- package/src/hierarchy-drop.ts +50 -0
- package/src/hierarchy-expansion-state.ts +100 -0
- package/src/hierarchy-menu-registry.ts +1 -1
- package/src/hierarchy-projection.ts +76 -0
- package/src/history/editor-session.ts +21 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-service.ts +904 -0
- package/src/history/json-history-resource.ts +165 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +266 -0
- package/src/history/project-root-history-backends.ts +53 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +108 -0
- package/src/history/source-history-backend.ts +374 -0
- package/src/history/types.ts +100 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hosted-example.ts +12 -2
- package/src/hotkeys.ts +89 -18
- package/src/ingest/discovery-react.ts +9 -10
- package/src/ingest/discovery.ts +4 -4
- package/src/ingest/discovery2d.ts +5 -5
- package/src/ingest/games/bloom-composer/vgai.game.json +3 -3
- package/src/ingest/games/embed-bundle/vgai.game.json +3 -3
- package/src/ingest/games/games-fps/vgai.game.json +3 -3
- package/src/ingest/games/iframe-reachable/vgai.game.json +3 -3
- package/src/ingest/games/interactive-cubes/vgai.game.json +3 -3
- package/src/ingest/games/mismatched-three/vgai.game.json +3 -3
- package/src/ingest/games/own-three-bundled/vgai.game.json +3 -3
- package/src/ingest/games/pointerlock-maze/vgai.game.json +7 -4
- package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +3 -3
- package/src/ingest/games-2d/bunnymark/vgai.game.json +3 -3
- package/src/ingest/games-2d/flappy/vgai.game.json +3 -3
- package/src/ingest/games-2d/flappy-pixi/vgai.game.json +3 -3
- package/src/ingest/games-2d/puzzling-potions/vgai.game.json +3 -3
- package/src/ingest/games-2d/tilemap-camera/vgai.game.json +3 -3
- package/src/ingest/games-react/react-rpg/vgai.game.json +3 -3
- package/src/ingest/types.ts +1 -1
- package/src/ingest-mode.ts +47 -52
- package/src/ingest-siblings.ts +23 -33
- package/src/initial-scene.ts +1 -2
- package/src/main.tsx +16 -8
- package/src/manifest-project.ts +10 -12
- package/src/model-thumbnail.ts +261 -26
- package/src/module-mode.ts +44 -50
- package/src/play-log-events.ts +26 -0
- package/src/play-mode.ts +495 -401
- package/src/play-scene-adoption.ts +23 -0
- package/src/playground/main.ts +68 -24
- package/src/playwright-shim.ts +473 -0
- package/src/project-manager.ts +90 -10
- package/src/project-operations.ts +112 -0
- package/src/project-story-discovery.ts +25 -0
- package/src/project-tool-discovery.ts +43 -0
- package/src/scene-serializer.ts +0 -6
- package/src/scene-sync.ts +7 -2
- package/src/script-loader.ts +3 -3
- package/src/skeleton-helper.ts +57 -0
- package/src/storage/seed.ts +68 -8
- package/src/stories/StoryPreviewMount.tsx +265 -0
- package/src/stories/action-stories.fixture.tsx +44 -0
- package/src/stories/button-stories.fixture.tsx +50 -0
- package/src/stories/compose-project-stories.ts +182 -0
- package/src/stories/loader-stories.fixture.tsx +53 -0
- package/src/stories/story-discovery.ts +130 -0
- package/src/stories/story-registry.ts +146 -0
- package/src/theme-css.ts +1049 -0
- package/src/theme-library.ts +238 -0
- package/src/theme-preference.ts +130 -0
- package/src/theme.ts +527 -0
- package/src/tool-loader.ts +80 -24
- package/src/ui-source/inspect.ts +27 -4
- package/src/ui-source/source-write-backend.ts +83 -22
- package/src/widgets/index.ts +9 -18
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-dock-controller.ts +64 -0
- package/src/workspace-document-ids.ts +5 -0
- package/src/workspace-document-registry.ts +367 -0
- package/src/workspace-state-persistence.ts +455 -0
- package/src/workspace-status-registry.ts +110 -0
- package/src/workspace-utility-commands.ts +49 -0
- package/src/workspace-utility-registry.ts +161 -0
- package/src/world-document-routing.ts +16 -0
- package/src/xstate-inspect/XStateMachineInspector.tsx +544 -0
- package/src/xstate-inspect/character-animation-machine.fixture.ts +74 -0
- package/src/xstate-inspect/use-live-actor-state.ts +39 -0
- package/src/xstate-inspect/xstate-graph.ts +265 -0
- package/src/xstate-inspect/xstate-layout.ts +76 -0
- package/src/z-index.ts +26 -0
- package/template/.claude/skills/editor/SKILL.md +129 -90
- package/template/AGENTS.md +1110 -0
- package/template/CLAUDE.md +1 -512
- package/template/IDIOMS.md +50 -0
- package/template/check-idioms.ts +706 -0
- package/template/manifest-entry-modules-plugin.ts +53 -0
- package/template/package.json +13 -4
- package/template/public/scenes/default.scn2d.json +6 -0
- package/template/public/scenes/default.vscn.json +7 -1
- package/template/public/scenes/untitled.vscn.json +10 -0
- package/template/scripts/playtest.ts +40 -0
- package/template/server/loopback.ts +75 -0
- package/template/server/rooms/arena-room.ts +69 -1
- package/template/server/rooms/game-room.ts +68 -1
- package/template/src/data/README.md +9 -4
- package/template/src/data/data-ref.ts +35 -0
- package/template/src/data/tuning.schema.ts +1 -1
- package/template/src/main.ts +41 -62
- package/template/src/manifest-entry-modules.d.ts +3 -0
- package/template/src/operations/README.md +88 -0
- package/template/src/runtime/pixi-adapter.ts +24 -0
- package/template/src/scripts/components/data-spinner.ts +43 -2
- package/template/src/scripts/components/spin-lap-math.ts +27 -0
- package/template/src/tools/README.md +5 -3
- package/template/src/tools/example.tool.tsx +13 -7
- package/template/src/ui/Button.stories.tsx +66 -0
- package/template/src/ui/RebindPanel.tsx +2 -6
- package/template/src/ui/game.tsx +17 -0
- package/template/tests/acceptance/example.spec.ts +64 -0
- package/template/tests/logic/example.test.ts +31 -0
- package/template/tests/logic/room.test.ts +100 -0
- package/template/tests/tsconfig.json +30 -0
- package/template/validate-manifest.ts +5 -5
- package/template/validate-scenes.ts +50 -18
- package/template/vgai.game.json +20 -13
- package/template/vite.config.ts +77 -16
- package/vite-plugin-ui-oid.ts +261 -17
- package/dist/assets/CCDIKSolver-Dz-ysxZF.js +0 -1
- package/dist/assets/SelectionBox-BXsv_6aH.js +0 -1
- package/dist/assets/browser-project-scripts-DOru4L1x.js +0 -2
- package/dist/assets/browserAll-CEkWYlFk.js +0 -1
- package/dist/assets/create-runtime-DYIWr3va.js +0 -1
- package/dist/assets/data-asset-Bb9sIM7i.js +0 -5
- package/dist/assets/game-8SDZPPgH.js +0 -1
- package/dist/assets/game-CevorxyV.js +0 -1
- package/dist/assets/game-Di7XlywD.js +0 -1
- package/dist/assets/game-DjnCaw8R.js +0 -1
- package/dist/assets/game-Q9A0aXSV.js +0 -1
- package/dist/assets/index-CPVV6pjw.js +0 -1
- package/dist/assets/index-CpOnYyeD.js +0 -213
- package/dist/assets/index-Dr8H_6Rl.js +0 -1
- package/dist/assets/index-_bCaipUk.js +0 -13650
- package/dist/assets/ingest-siblings-Dz8eEqrV.js +0 -1
- package/dist/assets/mount-manifest-Bhk0ohsl.js +0 -1
- package/dist/assets/scene-query-BivAHhJu.js +0 -1
- package/dist/assets/webworkerAll-BLrH0F6F.js +0 -1
- package/dist/assets/xstate-animation-binding-1NGLmw6y.js +0 -1
- package/dist/assets/xstate.esm-BgUD33nl.js +0 -3
- package/src/authoring/scene-ui-layer.ts +0 -485
- package/src/authoring/ui-authoring-adapter.ts +0 -325
- package/src/authoring/ui-hierarchy-menu.ts +0 -40
- package/src/authoring/ui-inspector-sections.tsx +0 -156
- package/src/authoring/undo-timeline.ts +0 -145
- package/src/components/BottomPanel.tsx +0 -326
- package/src/components/BuildPanel.tsx +0 -455
- package/src/components/FolderTree.tsx +0 -179
- package/src/components/RightPanel.tsx +0 -166
- package/src/components/WorldContextMenu.tsx +0 -257
- package/src/components/asset-viewers/AssetViewer.tsx +0 -38
- package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +0 -129
- package/src/scene-ui-mode/active-scene-ui.ts +0 -58
- package/src/scene-ui-mode/scene-ui-palette-panel.tsx +0 -152
- package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +0 -29
- package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +0 -74
- package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +0 -49
- package/src/scene-ui-mode/ui-prefab-io.ts +0 -76
- package/src/ui-editor/inspector.tsx +0 -563
- package/src/ui-editor/node-ops.ts +0 -266
- package/src/ui-editor/overlay.tsx +0 -380
- package/src/ui-editor/palette.tsx +0 -114
- package/src/ui-editor/react-store.ts +0 -78
- package/src/ui-editor/timeline-panel.tsx +0 -443
- package/src/ui-editor/ui-edit-store.ts +0 -552
- package/src/ui-editor/ui-prefab.ts +0 -95
- package/template/project.json +0 -9
- package/template/src/scripts/main.ts +0 -94
- package/template/src/ui/DefaultHud.tsx +0 -40
- package/template/src/ui/game-state.tsx +0 -37
- package/template/src/ui/mount-default-hud.tsx +0 -19
- package/template/src/ui/mount-ui.ts +0 -15
- package/vite-plugin-react-world-provider.ts +0 -81
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
declare const resourceKeyBrand: unique symbol;
|
|
2
|
+
|
|
3
|
+
/** Stable for the lifetime of one open project session, including across file moves. */
|
|
4
|
+
export type ResourceKey = string & { readonly [resourceKeyBrand]: true };
|
|
5
|
+
|
|
6
|
+
export type ResourceKind =
|
|
7
|
+
| 'scene'
|
|
8
|
+
| 'prefab'
|
|
9
|
+
| 'ui-tree'
|
|
10
|
+
| 'material'
|
|
11
|
+
| 'data'
|
|
12
|
+
| 'manifest'
|
|
13
|
+
| 'settings'
|
|
14
|
+
| 'source'
|
|
15
|
+
| 'overlay'
|
|
16
|
+
| 'project-file'
|
|
17
|
+
| 'session-state';
|
|
18
|
+
|
|
19
|
+
export interface ResourceDescriptor {
|
|
20
|
+
readonly key: ResourceKey;
|
|
21
|
+
readonly kind: ResourceKind;
|
|
22
|
+
readonly scope: 'project' | 'session';
|
|
23
|
+
readonly displayName: string;
|
|
24
|
+
readonly location: string | null;
|
|
25
|
+
readonly sessionId: string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ResourceSnapshot {
|
|
29
|
+
readonly revision: number;
|
|
30
|
+
readonly contentType: string;
|
|
31
|
+
readonly bytes: Uint8Array;
|
|
32
|
+
readonly sha256: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SnapshotRef {
|
|
36
|
+
readonly revision: number;
|
|
37
|
+
readonly contentType: string;
|
|
38
|
+
readonly sha256: string;
|
|
39
|
+
readonly blobKey: string;
|
|
40
|
+
readonly byteLength: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type PreflightResult =
|
|
44
|
+
| { readonly ok: true }
|
|
45
|
+
| {
|
|
46
|
+
readonly ok: false;
|
|
47
|
+
readonly reason: 'missing' | 'revision-conflict' | 'content-conflict' | 'expired';
|
|
48
|
+
readonly actualRevision?: number;
|
|
49
|
+
readonly actualSha256?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export interface ResourceDriver {
|
|
53
|
+
readonly descriptor: ResourceDescriptor;
|
|
54
|
+
capture(): Promise<ResourceSnapshot>;
|
|
55
|
+
preflight(expected: SnapshotRef): Promise<PreflightResult>;
|
|
56
|
+
restore(snapshot: SnapshotRef): Promise<void>;
|
|
57
|
+
estimateBytes(snapshot: SnapshotRef): number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type HistoryStatus =
|
|
61
|
+
| 'committed'
|
|
62
|
+
| 'undoing'
|
|
63
|
+
| 'undone'
|
|
64
|
+
| 'redoing'
|
|
65
|
+
| 'failed'
|
|
66
|
+
| 'failed-partial'
|
|
67
|
+
| 'expired';
|
|
68
|
+
|
|
69
|
+
export interface HistoryError {
|
|
70
|
+
readonly code:
|
|
71
|
+
| 'busy'
|
|
72
|
+
| 'conflict'
|
|
73
|
+
| 'expired'
|
|
74
|
+
| 'apply-failed'
|
|
75
|
+
| 'compensation-failed'
|
|
76
|
+
| 'history-limit';
|
|
77
|
+
readonly message: string;
|
|
78
|
+
readonly resources: readonly ResourceKey[];
|
|
79
|
+
readonly cause?: unknown;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ResourceChange {
|
|
83
|
+
readonly resource: ResourceKey;
|
|
84
|
+
readonly before: SnapshotRef;
|
|
85
|
+
readonly after: SnapshotRef;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface HistoryTransaction {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly label: string;
|
|
91
|
+
readonly detail: string | null;
|
|
92
|
+
readonly timestamp: number;
|
|
93
|
+
readonly scope: 'project' | 'session';
|
|
94
|
+
readonly sessionId: string | null;
|
|
95
|
+
readonly changes: readonly ResourceChange[];
|
|
96
|
+
readonly byteSize: number;
|
|
97
|
+
readonly mergeKey: string | null;
|
|
98
|
+
readonly status: HistoryStatus;
|
|
99
|
+
readonly error: HistoryError | null;
|
|
100
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns a module's registry contributions across Vite Fast Refresh.
|
|
3
|
+
*
|
|
4
|
+
* A module-local `registered` boolean is not sufficient: Vite may reload the
|
|
5
|
+
* contributor without reloading the registry (duplicates), or reload the
|
|
6
|
+
* registry without reloading the contributor (missing entries). Tracking the
|
|
7
|
+
* unregister callbacks in `import.meta.hot.data` gives the contribution one
|
|
8
|
+
* explicit lifetime and keeps strict duplicate-id checks meaningful.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export interface HmrRegistrationContext {
|
|
12
|
+
readonly data?: Record<string, unknown>;
|
|
13
|
+
dispose(callback: (data: Record<string, unknown>) => void): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface HmrRegistrationGroup {
|
|
17
|
+
ensure(register: (track: (unregister: () => void) => void) => void): void;
|
|
18
|
+
reset(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface PersistedRegistrationGroup {
|
|
22
|
+
dispose(): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createHmrRegistrationGroup(
|
|
26
|
+
hot: HmrRegistrationContext | undefined,
|
|
27
|
+
key: string,
|
|
28
|
+
): HmrRegistrationGroup {
|
|
29
|
+
const persistedKey = `vgai:registration-group:${key}`;
|
|
30
|
+
// Test runners and non-Vite hosts can expose a partial `import.meta.hot`
|
|
31
|
+
// shim without `data`. In that case the group still owns its local
|
|
32
|
+
// registrations, but there is no cross-refresh persistence to maintain.
|
|
33
|
+
const hotData = hot?.data;
|
|
34
|
+
const previous = hotData?.[persistedKey] as PersistedRegistrationGroup | undefined;
|
|
35
|
+
previous?.dispose();
|
|
36
|
+
|
|
37
|
+
let active = false;
|
|
38
|
+
let unregisters: Array<() => void> = [];
|
|
39
|
+
|
|
40
|
+
const reset = () => {
|
|
41
|
+
active = false;
|
|
42
|
+
const owned = unregisters;
|
|
43
|
+
unregisters = [];
|
|
44
|
+
for (let i = owned.length - 1; i >= 0; i--) owned[i]!();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const group: HmrRegistrationGroup = {
|
|
48
|
+
ensure(register) {
|
|
49
|
+
if (active) return;
|
|
50
|
+
active = true;
|
|
51
|
+
try {
|
|
52
|
+
register((unregister) => unregisters.push(unregister));
|
|
53
|
+
} catch (error) {
|
|
54
|
+
reset();
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
reset,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (hotData) {
|
|
62
|
+
hotData[persistedKey] = { dispose: reset } satisfies PersistedRegistrationGroup;
|
|
63
|
+
hot.dispose(reset);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return group;
|
|
67
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Context, createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Preserve a React context object across Vite module replacement.
|
|
5
|
+
*
|
|
6
|
+
* A provider from the previous module generation can remain mounted while a
|
|
7
|
+
* freshly imported consumer renders. If both generations call
|
|
8
|
+
* `createContext()`, the consumer observes a different context and falsely
|
|
9
|
+
* reports that it is outside the provider. Vite keeps `import.meta.hot.data`
|
|
10
|
+
* for exactly this kind of module-local state handoff.
|
|
11
|
+
*/
|
|
12
|
+
export function createHmrStableReactContext<T>(
|
|
13
|
+
hotData: Record<string, unknown> | undefined,
|
|
14
|
+
key: string,
|
|
15
|
+
defaultValue: T,
|
|
16
|
+
): Context<T> {
|
|
17
|
+
const existing = hotData?.[key];
|
|
18
|
+
if (existing) return existing as Context<T>;
|
|
19
|
+
|
|
20
|
+
const context = createContext(defaultValue);
|
|
21
|
+
if (hotData) hotData[key] = context;
|
|
22
|
+
return context;
|
|
23
|
+
}
|
package/src/hosted-example.ts
CHANGED
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
|
|
28
28
|
import { setAssetPrefix } from '@engine/loader';
|
|
29
29
|
import { GameManifestSchema } from '@engine/manifest/schema';
|
|
30
|
+
import { BUNDLED_EDITOR_COMPATIBILITY } from './build-identity';
|
|
31
|
+
import { assertProjectCompatibility } from './editor-compatibility';
|
|
30
32
|
import type { ActiveProject } from './project-manager';
|
|
31
33
|
|
|
32
34
|
/** Folder-name shape shared by every `examples/<id>/` — also a path-safety gate. */
|
|
@@ -44,7 +46,12 @@ export async function openExampleProject(exampleId: string): Promise<ActiveProje
|
|
|
44
46
|
if (!res.ok) {
|
|
45
47
|
throw new Error(`HTTP ${res.status} fetching ${manifestUrl} — not a bundled example?`);
|
|
46
48
|
}
|
|
47
|
-
const
|
|
49
|
+
const rawManifest: unknown = await res.json();
|
|
50
|
+
assertProjectCompatibility(
|
|
51
|
+
rawManifest && typeof rawManifest === 'object' ? rawManifest : {},
|
|
52
|
+
BUNDLED_EDITOR_COMPATIBILITY,
|
|
53
|
+
);
|
|
54
|
+
const manifest = GameManifestSchema.parse(rawManifest);
|
|
48
55
|
|
|
49
56
|
// Namespace relative asset resolution to this example's staged public/ —
|
|
50
57
|
// the same prefix `browser-play-entry.ts` sets at play dispatch, applied
|
|
@@ -55,8 +62,11 @@ export async function openExampleProject(exampleId: string): Promise<ActiveProje
|
|
|
55
62
|
return {
|
|
56
63
|
rootPath: `/examples/${exampleId}`,
|
|
57
64
|
config: {
|
|
65
|
+
manifestVersion: manifest.manifestVersion,
|
|
58
66
|
name: manifest.name,
|
|
59
|
-
|
|
67
|
+
version: manifest.version,
|
|
68
|
+
engine: manifest.engine,
|
|
69
|
+
defaultScene: manifest.roots[0]?.scene ?? null,
|
|
60
70
|
...(manifest.resolution ? { resolution: manifest.resolution } : {}),
|
|
61
71
|
},
|
|
62
72
|
exampleId,
|
package/src/hotkeys.ts
CHANGED
|
@@ -4,7 +4,22 @@ import { useEffect } from 'react';
|
|
|
4
4
|
// Types
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
|
|
7
|
-
export type HotkeyScope =
|
|
7
|
+
export type HotkeyScope =
|
|
8
|
+
| 'viewport'
|
|
9
|
+
| 'hierarchy'
|
|
10
|
+
| 'inspector'
|
|
11
|
+
| 'asset-browser'
|
|
12
|
+
| 'workspace'
|
|
13
|
+
| 'global';
|
|
14
|
+
|
|
15
|
+
const HOTKEY_SCOPES = new Set<HotkeyScope>([
|
|
16
|
+
'viewport',
|
|
17
|
+
'hierarchy',
|
|
18
|
+
'inspector',
|
|
19
|
+
'asset-browser',
|
|
20
|
+
'workspace',
|
|
21
|
+
'global',
|
|
22
|
+
]);
|
|
8
23
|
|
|
9
24
|
export interface HotkeyBinding {
|
|
10
25
|
/** The key to match (`e.key`, lowercase). Ignored when `code` is set. */
|
|
@@ -17,10 +32,17 @@ export interface HotkeyBinding {
|
|
|
17
32
|
shift?: boolean;
|
|
18
33
|
/** Require Alt/Option (D4 — `wrap`'s `Ctrl+Alt+G`). */
|
|
19
34
|
alt?: boolean;
|
|
20
|
-
/** Scope this binding belongs to. `'global'` bindings fire regardless of panel focus. */
|
|
21
|
-
scope: HotkeyScope;
|
|
35
|
+
/** Scope(s) this binding belongs to. `'global'` bindings fire regardless of panel focus. */
|
|
36
|
+
scope: HotkeyScope | readonly HotkeyScope[];
|
|
22
37
|
/** Action to execute when the binding matches. */
|
|
23
38
|
action: (e: KeyboardEvent) => void;
|
|
39
|
+
/** Optional runtime gate. When it returns false, the binding yields to the
|
|
40
|
+
* browser and does not call preventDefault(). Use this for commands whose
|
|
41
|
+
* shortcut overlaps native behavior, such as Copy with a DOM text selection. */
|
|
42
|
+
when?: (e: KeyboardEvent) => boolean;
|
|
43
|
+
/** Allow this binding while a form control/contenteditable owns focus.
|
|
44
|
+
* Reserved for commands such as Save that are expected inside editors. */
|
|
45
|
+
allowInEditable?: boolean;
|
|
24
46
|
/** Human-readable label for menus / tooltips. */
|
|
25
47
|
label?: string;
|
|
26
48
|
}
|
|
@@ -31,12 +53,58 @@ export interface HotkeyBinding {
|
|
|
31
53
|
|
|
32
54
|
let _activeScope: HotkeyScope = 'viewport';
|
|
33
55
|
|
|
56
|
+
const ACTIVE_SCOPE_DATA_KEY = 'editorActiveHotkeyScope';
|
|
57
|
+
|
|
34
58
|
export function getActiveScope(): HotkeyScope {
|
|
59
|
+
const shared = document.documentElement.dataset[ACTIVE_SCOPE_DATA_KEY];
|
|
60
|
+
if (shared && HOTKEY_SCOPES.has(shared as HotkeyScope)) return shared as HotkeyScope;
|
|
35
61
|
return _activeScope;
|
|
36
62
|
}
|
|
37
63
|
|
|
38
64
|
export function setActiveScope(scope: HotkeyScope): void {
|
|
39
65
|
_activeScope = scope;
|
|
66
|
+
// Vite can temporarily retain both pre- and post-HMR module instances.
|
|
67
|
+
// The editor shell is the durable ownership authority, so mirror the value
|
|
68
|
+
// onto the shared document rather than trusting one module-local singleton.
|
|
69
|
+
document.documentElement.dataset[ACTIVE_SCOPE_DATA_KEY] = scope;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** True when a DOM target belongs to a native text-editing surface. Shared
|
|
73
|
+
* by the global dispatcher and panel-local handlers so bubbled Backspace,
|
|
74
|
+
* Delete, and clipboard shortcuts cannot mutate editor state while typing. */
|
|
75
|
+
export function isEditableTarget(target: EventTarget | null): boolean {
|
|
76
|
+
if (!(target instanceof Element)) return false;
|
|
77
|
+
if (
|
|
78
|
+
target instanceof HTMLInputElement ||
|
|
79
|
+
target instanceof HTMLTextAreaElement ||
|
|
80
|
+
target instanceof HTMLSelectElement
|
|
81
|
+
) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (target instanceof HTMLElement && target.isContentEditable) return true;
|
|
85
|
+
return Boolean(target.closest('[contenteditable]:not([contenteditable="false"])'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function scopeFromOwnershipEvent(event: Event): HotkeyScope | null {
|
|
89
|
+
for (const target of event.composedPath()) {
|
|
90
|
+
if (!(target instanceof HTMLElement)) continue;
|
|
91
|
+
// Dockview moves focus through internal navigation sentinels that sit
|
|
92
|
+
// directly under the shell. A focusin on that infrastructure must not
|
|
93
|
+
// erase the concrete panel established by the preceding pointerdown.
|
|
94
|
+
// Pointerdown still uses the fallback, so genuinely clicking unclaimed
|
|
95
|
+
// chrome neutralizes authoring commands as intended.
|
|
96
|
+
if (event.type === 'focusin' && target.hasAttribute('data-editor-hotkey-fallback')) continue;
|
|
97
|
+
const candidate = target.dataset['editorHotkeyScope'];
|
|
98
|
+
if (candidate && HOTKEY_SCOPES.has(candidate as HotkeyScope)) {
|
|
99
|
+
return candidate as HotkeyScope;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function handleOwnershipEvent(event: Event): void {
|
|
106
|
+
const scope = scopeFromOwnershipEvent(event);
|
|
107
|
+
if (scope) setActiveScope(scope);
|
|
40
108
|
}
|
|
41
109
|
|
|
42
110
|
// ---------------------------------------------------------------------------
|
|
@@ -63,37 +131,32 @@ export function registerHotkeys(bindings: HotkeyBinding[]): () => void {
|
|
|
63
131
|
// ---------------------------------------------------------------------------
|
|
64
132
|
|
|
65
133
|
function handleKeyDown(e: KeyboardEvent): void {
|
|
66
|
-
// Skip
|
|
67
|
-
// only when not typing")
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
// needing another fix here).
|
|
72
|
-
if (
|
|
73
|
-
e.target instanceof HTMLInputElement ||
|
|
74
|
-
e.target instanceof HTMLTextAreaElement ||
|
|
75
|
-
e.target instanceof HTMLSelectElement ||
|
|
76
|
-
(e.target instanceof HTMLElement && e.target.isContentEditable)
|
|
77
|
-
)
|
|
78
|
-
return;
|
|
134
|
+
// Skip ordinary editor commands while typing — D4 (spec27 §6 D4 "each
|
|
135
|
+
// shortcut fires only when not typing") covers form fields and future
|
|
136
|
+
// contentEditable surfaces. A binding must explicitly opt in when its
|
|
137
|
+
// conventional behavior belongs inside an editor too (currently Save).
|
|
138
|
+
const editableTarget = isEditableTarget(e.target);
|
|
79
139
|
|
|
80
140
|
const mod = e.metaKey || e.ctrlKey;
|
|
81
141
|
const key = e.key.toLowerCase();
|
|
82
142
|
const code = e.code;
|
|
83
|
-
const scope =
|
|
143
|
+
const scope = getActiveScope();
|
|
84
144
|
|
|
85
145
|
// Check scoped bindings first, then global
|
|
86
146
|
const passes: HotkeyScope[] = scope === 'global' ? ['global'] : [scope, 'global'];
|
|
87
147
|
|
|
88
148
|
for (const pass of passes) {
|
|
89
149
|
for (const b of _bindings) {
|
|
90
|
-
|
|
150
|
+
const bindingScopes = Array.isArray(b.scope) ? b.scope : [b.scope];
|
|
151
|
+
if (!bindingScopes.includes(pass)) continue;
|
|
152
|
+
if (editableTarget && !b.allowInEditable) continue;
|
|
91
153
|
|
|
92
154
|
const keyMatch = b.code ? b.code === code : b.key === key;
|
|
93
155
|
if (!keyMatch) continue;
|
|
94
156
|
if ((b.mod ?? false) !== mod) continue;
|
|
95
157
|
if ((b.shift ?? false) !== e.shiftKey) continue;
|
|
96
158
|
if ((b.alt ?? false) !== e.altKey) continue;
|
|
159
|
+
if (b.when && !b.when(e)) continue;
|
|
97
160
|
|
|
98
161
|
e.preventDefault();
|
|
99
162
|
b.action(e);
|
|
@@ -107,12 +170,20 @@ let _installed = false;
|
|
|
107
170
|
/** Attach the global keydown listener. Call once at startup. */
|
|
108
171
|
export function installHotkeys(): void {
|
|
109
172
|
if (_installed) return;
|
|
173
|
+
// Capture ownership before React's panel-local bubble handlers run. The
|
|
174
|
+
// closest declarative scope in the composed path wins; the shell's
|
|
175
|
+
// `workspace` marker is therefore a safe neutral fallback for menus,
|
|
176
|
+
// utilities, document editors, and unclaimed chrome.
|
|
177
|
+
window.addEventListener('pointerdown', handleOwnershipEvent, true);
|
|
178
|
+
window.addEventListener('focusin', handleOwnershipEvent, true);
|
|
110
179
|
window.addEventListener('keydown', handleKeyDown);
|
|
111
180
|
_installed = true;
|
|
112
181
|
}
|
|
113
182
|
|
|
114
183
|
/** Detach the global keydown listener. */
|
|
115
184
|
export function uninstallHotkeys(): void {
|
|
185
|
+
window.removeEventListener('pointerdown', handleOwnershipEvent, true);
|
|
186
|
+
window.removeEventListener('focusin', handleOwnershipEvent, true);
|
|
116
187
|
window.removeEventListener('keydown', handleKeyDown);
|
|
117
188
|
_installed = false;
|
|
118
189
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* UNLIKE `discovery.ts`/`discovery2d.ts`, this module does NOT also glob the
|
|
11
11
|
* entry module itself: an `ingest-react` world mounts through
|
|
12
|
-
* `
|
|
12
|
+
* `resolveRootAdapter` (`adapter-resolver.ts`'s `resolveIngestReactAdapter`,
|
|
13
13
|
* N1) — the SAME `/@fs/`-dynamic-import + `createRoot` host stack
|
|
14
14
|
* `default-react` uses — rather than a capture-based bridge, so there is no
|
|
15
15
|
* "build an `IngestGame`/`IngestGame2D` descriptor with its own `load`
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* `games-react/*\/vgai.game.json`, validate its single world is a real
|
|
18
18
|
* `ingest-react` `'deduped'` world, and hand back the parsed
|
|
19
19
|
* `ResolvedGameManifest` + that world's absolute on-disk folder (the
|
|
20
|
-
* `projectRoot` `
|
|
20
|
+
* `projectRoot` `resolveRootAdapter` needs for its `entry`'s `/@fs/`
|
|
21
21
|
* dynamic import and its `loadProjectGameProvider` lookup) — see
|
|
22
22
|
* `ingest-mode.ts`'s `enterIngestModeReact` for the mount step.
|
|
23
23
|
*
|
|
@@ -62,21 +62,21 @@ export interface IngestGameReact {
|
|
|
62
62
|
|
|
63
63
|
function buildIngestGameReact(folderId: string, raw: unknown): IngestGameReact {
|
|
64
64
|
const manifest = loadGameManifest(raw);
|
|
65
|
-
if (manifest.
|
|
65
|
+
if (manifest.roots.length !== 1) {
|
|
66
66
|
throw new Error(
|
|
67
67
|
`react ingest discovery: "${folderId}/vgai.game.json" must declare exactly one world ` +
|
|
68
|
-
`(found ${manifest.
|
|
68
|
+
`(found ${manifest.roots.length}).`,
|
|
69
69
|
);
|
|
70
70
|
}
|
|
71
|
-
const world = manifest.
|
|
71
|
+
const world = manifest.roots[0]!;
|
|
72
72
|
if (
|
|
73
|
-
world.
|
|
73
|
+
world.surface !== 'react' ||
|
|
74
74
|
world.adapter.type !== 'ingest' ||
|
|
75
75
|
world.adapter.identity !== 'ingest-react'
|
|
76
76
|
) {
|
|
77
77
|
throw new Error(
|
|
78
78
|
`react ingest discovery: "${folderId}/vgai.game.json"'s world must be a react { ingest } ` +
|
|
79
|
-
`world (found kind "${world.
|
|
79
|
+
`world (found kind "${world.surface}", adapter identity "${world.adapter.identity}").`,
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
if (world.adapter.strategy !== 'deduped') {
|
|
@@ -117,9 +117,8 @@ export function getIngestGameReact(folderId: string): IngestGameReact | undefine
|
|
|
117
117
|
|
|
118
118
|
/**
|
|
119
119
|
* The absolute on-disk `projectRoot` for a discovered react ingest game's
|
|
120
|
-
* folder — what `
|
|
121
|
-
* `entry
|
|
122
|
-
* `src/ui/game-state.tsx` lookup). `undefined` when
|
|
120
|
+
* folder — what `resolveRootAdapter`/`resolveAllWorlds` need to resolve its
|
|
121
|
+
* `entry`. `undefined` when
|
|
123
122
|
* `__VGAI_ENGINE_ROOT__` isn't defined (browser-mode static build — no dev
|
|
124
123
|
* server, no `/@fs/` route to resolve through anyway).
|
|
125
124
|
*/
|
package/src/ingest/discovery.ts
CHANGED
|
@@ -98,7 +98,7 @@ function buildModuleLoadedGame(
|
|
|
98
98
|
if (!world.entry) {
|
|
99
99
|
throw new Error(
|
|
100
100
|
`ingest discovery: "${folderId}" (strategy "${strategy}") has no \`entry\` — ` +
|
|
101
|
-
"shared/deduped ingest
|
|
101
|
+
"shared/deduped ingest roots need the game module's folder-relative path there.",
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
const key = `./games/${folderId}/${world.entry}`;
|
|
@@ -139,13 +139,13 @@ function buildFileBackedGame(
|
|
|
139
139
|
|
|
140
140
|
function buildIngestGame(folderId: string, raw: unknown): IngestGame {
|
|
141
141
|
const manifest = loadGameManifest(raw);
|
|
142
|
-
if (manifest.
|
|
142
|
+
if (manifest.roots.length !== 1) {
|
|
143
143
|
throw new Error(
|
|
144
144
|
`ingest discovery: "${folderId}/vgai.game.json" must declare exactly one world ` +
|
|
145
|
-
`(found ${manifest.
|
|
145
|
+
`(found ${manifest.roots.length}).`,
|
|
146
146
|
);
|
|
147
147
|
}
|
|
148
|
-
const world = manifest.
|
|
148
|
+
const world = manifest.roots[0]!;
|
|
149
149
|
if (world.adapter.type !== 'ingest' || world.adapter.identity !== 'ingest-three') {
|
|
150
150
|
throw new Error(
|
|
151
151
|
`ingest discovery: "${folderId}/vgai.game.json"'s world must be a threejs { ingest } ` +
|
|
@@ -69,7 +69,7 @@ function buildModuleLoadedGame2D(
|
|
|
69
69
|
if (!world.entry) {
|
|
70
70
|
throw new Error(
|
|
71
71
|
`world2d ingest discovery: "${folderId}" (strategy "${strategy}") has no \`entry\` — ` +
|
|
72
|
-
"shared/deduped ingest-pixi
|
|
72
|
+
"shared/deduped ingest-pixi roots need the game module's folder-relative path there.",
|
|
73
73
|
);
|
|
74
74
|
}
|
|
75
75
|
const key = `./games-2d/${folderId}/${world.entry}`;
|
|
@@ -88,7 +88,7 @@ function buildModuleLoadedGame2D(
|
|
|
88
88
|
* the manifest's Track P fields (docs/PIXI-INGEST-LANDING-DESIGN.md §2) —
|
|
89
89
|
* `bundleUrl` is required by the schema's cross-field check for this
|
|
90
90
|
* strategy (exactly one of `bundleUrl`/`entryHtml`); `entryHtml`-only
|
|
91
|
-
* iframe-reachable
|
|
91
|
+
* iframe-reachable roots still have no builder here (mirrors the
|
|
92
92
|
* `resolveIngestDescriptor`/three-side gap: reading a raw HTML/inline-source
|
|
93
93
|
* file's contents needs a runtime fetch this synchronous builder doesn't do).
|
|
94
94
|
* `extraDeps`/`pixiModuleUrl` become LAZY thunks (`IngestGame2D.extraDeps`/
|
|
@@ -131,13 +131,13 @@ export function buildIframeReachableGame2D(
|
|
|
131
131
|
|
|
132
132
|
function buildIngestGame2D(folderId: string, raw: unknown): IngestGame2D {
|
|
133
133
|
const manifest = loadGameManifest(raw);
|
|
134
|
-
if (manifest.
|
|
134
|
+
if (manifest.roots.length !== 1) {
|
|
135
135
|
throw new Error(
|
|
136
136
|
`world2d ingest discovery: "${folderId}/vgai.game.json" must declare exactly one world ` +
|
|
137
|
-
`(found ${manifest.
|
|
137
|
+
`(found ${manifest.roots.length}).`,
|
|
138
138
|
);
|
|
139
139
|
}
|
|
140
|
-
const world = manifest.
|
|
140
|
+
const world = manifest.roots[0]!;
|
|
141
141
|
if (world.adapter.type !== 'ingest' || world.adapter.identity !== 'ingest-pixi') {
|
|
142
142
|
throw new Error(
|
|
143
143
|
`world2d ingest discovery: "${folderId}/vgai.game.json"'s world must be a pixijs ` +
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "Bloom EffectComposer repro standin (F13)",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "bloom-composer",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "A self-made, source-available three.js game that renders through its OWN EffectComposer (RenderPass + UnrealBloomPass) — a repro standin for F13 (docs/FTUE-EXTERNAL-R3F-GAME.md), NOT an upstream title (sanctioned stand-in precedent: ADAPTER-MAXIMAL-SPEC.json coverage_standins, same spirit as own-three-bundled). Exposes a dev-only window.__vgaiBloomComposer inspection hook reading its own composer's real render-target size. Used to prove the host ingest resize path never drives a game's own composer (docs/WAVE14-F13-BLOOM-COMPOSER-REPRO-DESIGN.md).",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "deduped"
|
|
16
16
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "Opaque bundle (embed-only floor)",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "embed-bundle",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "A self-contained opaque bundle (a dependency-free canvas app) standing in for any prebuilt bundle whose renderer the editor cannot reach. Demonstrates the iframe embed/lifecycle FLOOR (Tier 0–1): hosted + sized + disposed, scene NOT introspectable. Payload-agnostic — a real opaque three.js bundle (own realm-local three) is hosted identically.",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "opaque-embed",
|
|
16
16
|
"entryHtml": "embed.html"
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "three.js — Octree FPS (games_fps)",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "games-fps",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "Upstream mrdoob/three.js example: octree collisions, GLTF world, 100 physics spheres, pointer-lock FPS. Own scene/camera/renderer/rAF/input.",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "shared",
|
|
16
16
|
"assets": {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "Prebuilt bundle in iframe (reachable three)",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "iframe-reachable",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "A prebuilt bundle hosted in its OWN iframe document, but whose three is REACHABLE: the iframe importmap resolves `three` to the host instance (blob re-export), so its scene is captured in-realm and edited live in the editor (cov-iframe-reachable, tier 2–3). The middle tier between shared-ESM and opaque embed.",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "iframe-reachable",
|
|
16
16
|
"entryHtml": "game-source.js"
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "three.js — Interactive Cubes",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "interactive-cubes",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "Upstream webgl_interactive_cubes: 2000 procedurally-placed cubes, orbiting camera, per-frame raycaster hover-highlight. Own scene/camera/renderer/rAF. No external assets.",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "shared"
|
|
16
16
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "Mismatched/bundled three (graceful degrade)",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "mismatched-three",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "A game that uses a SEPARATE (non-host) three — stands in for a bundled/mismatched three version the capture trap cannot instrument. The editor detects the capture failure and degrades to embed-only (cov-mismatched-three) — never a silent failure.",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "shared",
|
|
16
16
|
"captureTimeoutMs": 2500
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
"manifestVersion":
|
|
2
|
+
"manifestVersion": 2,
|
|
3
3
|
"name": "Bundles-own-three (build-time dedupe)",
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"engine": {
|
|
6
6
|
"version": "0.1.0"
|
|
7
7
|
},
|
|
8
|
-
"
|
|
8
|
+
"roots": [
|
|
9
9
|
{
|
|
10
10
|
"id": "own-three-bundled",
|
|
11
|
-
"kind": "threejs",
|
|
12
11
|
"description": "A source-available game that ships its OWN nested node_modules/three. Build-time dedupe (resolve.dedupe:[three]) collapses it to the editor instance → LIVE capture + edit (cov-bundled-dedupe). A passing live ingest proves the collapse (else the bare import would hit the nested stub and capture would fail).",
|
|
13
12
|
"adapter": {
|
|
13
|
+
"surface": "threejs",
|
|
14
14
|
"ingest": {
|
|
15
15
|
"strategy": "deduped"
|
|
16
16
|
}
|