@vgai/editor 0.2.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/LICENSE +661 -0
- package/README.md +35 -0
- package/dist/a/b/c/test-nested.json +1 -0
- package/dist/assets/CCDIKSolver-Dz-ysxZF.js +1 -0
- package/dist/assets/SelectionBox-BXsv_6aH.js +1 -0
- package/dist/assets/browser-project-scripts-DOru4L1x.js +2 -0
- package/dist/assets/browserAll-CEkWYlFk.js +1 -0
- package/dist/assets/collision-world-DniMB0qq.glb +0 -0
- package/dist/assets/create-runtime-DYIWr3va.js +1 -0
- package/dist/assets/data-asset-Bb9sIM7i.js +5 -0
- package/dist/assets/esbuild-BHljloGq.wasm +0 -0
- package/dist/assets/fake-three-BMTQ9rl_.js +1 -0
- package/dist/assets/game-8SDZPPgH.js +1 -0
- package/dist/assets/game-BI111o5f.js +10 -0
- package/dist/assets/game-CevorxyV.js +1 -0
- package/dist/assets/game-Di1H0gFj.js +1 -0
- package/dist/assets/game-Di7XlywD.js +1 -0
- package/dist/assets/game-DjnCaw8R.js +1 -0
- package/dist/assets/game-Q9A0aXSV.js +1 -0
- package/dist/assets/game-pt_1lQLv.js +1 -0
- package/dist/assets/game-source-CvidN7AB.js +1 -0
- package/dist/assets/game-xsOho_wg.js +83 -0
- package/dist/assets/index-Bp5cecD6.js +12 -0
- package/dist/assets/index-CPVV6pjw.js +1 -0
- package/dist/assets/index-CpOnYyeD.js +213 -0
- package/dist/assets/index-Cs8xwv3e.js +1 -0
- package/dist/assets/index-DL7RcQ0n.js +27 -0
- package/dist/assets/index-Dr8H_6Rl.js +1 -0
- package/dist/assets/index-_bCaipUk.js +13650 -0
- package/dist/assets/ingest-siblings-Dz8eEqrV.js +1 -0
- package/dist/assets/mount-manifest-Bhk0ohsl.js +1 -0
- package/dist/assets/recast-navigation.wasm-compat-CvP4UGK6.js +1 -0
- package/dist/assets/scene-query-BivAHhJu.js +1 -0
- package/dist/assets/stats.module--VATS4Kh.js +1 -0
- package/dist/assets/webworkerAll-BLrH0F6F.js +1 -0
- package/dist/assets/xstate-animation-binding-1NGLmw6y.js +1 -0
- package/dist/assets/xstate.esm-BgUD33nl.js +3 -0
- package/dist/index.html +37 -0
- package/dist/ingest/racing-game/UPSTREAM.md +68 -0
- package/dist/ingest/racing-game/a/Inter-Black.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Black.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-BlackItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-BlackItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-Bold.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Bold.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-BoldItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-BoldItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraBold.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraBold.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraBoldItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraBoldItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraLight.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraLight.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraLightItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-ExtraLightItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-Italic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Italic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-Light.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Light.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-LightItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-LightItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-Medium.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Medium.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-MediumItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-MediumItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-Regular.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Regular.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-SemiBold.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-SemiBold.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-SemiBoldItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-SemiBoldItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-Thin.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-Thin.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-ThinItalic.woff +0 -0
- package/dist/ingest/racing-game/a/Inter-ThinItalic.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-italic.var.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter-roman.var.woff2 +0 -0
- package/dist/ingest/racing-game/a/Inter.var.woff2 +0 -0
- package/dist/ingest/racing-game/a/index.css +1 -0
- package/dist/ingest/racing-game/images/bronze.png +0 -0
- package/dist/ingest/racing-game/images/gold.png +0 -0
- package/dist/ingest/racing-game/images/silver.png +0 -0
- package/dist/ingest/racing-game/index.html +15 -0
- package/dist/ingest/racing-game/models/chassis-draco.glb +0 -0
- package/dist/ingest/racing-game/models/track-draco.glb +0 -0
- package/dist/ingest/racing-game/models/wheel-draco.glb +0 -0
- package/dist/ingest/racing-game/rg-entry.js +1 -0
- package/dist/ingest/racing-game/sounds/accelerate.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/boost.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/crash.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/engine.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/honk.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/tire-brake.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/train.mp3 +0 -0
- package/dist/ingest/racing-game/sounds/water.mp3 +0 -0
- package/dist/ingest/racing-game/textures/cursor.svg +3 -0
- package/dist/ingest/racing-game/textures/dikhololo_night_1k.hdr +0 -0
- package/dist/ingest/racing-game/textures/heightmap_1024.png +0 -0
- package/dist/ingest/racing-game/textures/mask.svg +11 -0
- package/dist/ingest/racing-game/textures/no_sound.png +0 -0
- package/dist/ingest/racing-game/three-r139.module.js +50617 -0
- package/dist/ingest/racing-game/vendor.js +179 -0
- package/dist/ingest/racing-game/vgai.game.json +20 -0
- package/dist/ingest/simcity/UPSTREAM.md +65 -0
- package/dist/ingest/simcity/favicon.ico +0 -0
- package/dist/ingest/simcity/fonts/Bebas-Regular.otf +0 -0
- package/dist/ingest/simcity/fonts/Digitalt.otf +0 -0
- package/dist/ingest/simcity/fonts/Stanberry.ttf +0 -0
- package/dist/ingest/simcity/icons/bulldozer-color.png +0 -0
- package/dist/ingest/simcity/icons/bulldozer.png +0 -0
- package/dist/ingest/simcity/icons/calendar.png +0 -0
- package/dist/ingest/simcity/icons/factory-color.png +0 -0
- package/dist/ingest/simcity/icons/factory.png +0 -0
- package/dist/ingest/simcity/icons/house-color.png +0 -0
- package/dist/ingest/simcity/icons/house.png +0 -0
- package/dist/ingest/simcity/icons/job.png +0 -0
- package/dist/ingest/simcity/icons/office.png +0 -0
- package/dist/ingest/simcity/icons/pause-color.png +0 -0
- package/dist/ingest/simcity/icons/pause.png +0 -0
- package/dist/ingest/simcity/icons/person.png +0 -0
- package/dist/ingest/simcity/icons/play-color.png +0 -0
- package/dist/ingest/simcity/icons/play.png +0 -0
- package/dist/ingest/simcity/icons/power-color.png +0 -0
- package/dist/ingest/simcity/icons/power-line-color.png +0 -0
- package/dist/ingest/simcity/icons/power.png +0 -0
- package/dist/ingest/simcity/icons/road-color.png +0 -0
- package/dist/ingest/simcity/icons/road.png +0 -0
- package/dist/ingest/simcity/icons/select-color.png +0 -0
- package/dist/ingest/simcity/icons/select.png +0 -0
- package/dist/ingest/simcity/icons/store-color.png +0 -0
- package/dist/ingest/simcity/index.html +94 -0
- package/dist/ingest/simcity/index.js +58 -0
- package/dist/ingest/simcity/main.css +233 -0
- package/dist/ingest/simcity/models/armored-truck.glb +0 -0
- package/dist/ingest/simcity/models/building-block-4floor-corner.glb +0 -0
- package/dist/ingest/simcity/models/building-block-4floor-short.glb +0 -0
- package/dist/ingest/simcity/models/building-block-5floor.glb +0 -0
- package/dist/ingest/simcity/models/building-burger-joint.glb +0 -0
- package/dist/ingest/simcity/models/building-cafe.glb +0 -0
- package/dist/ingest/simcity/models/building-casino.glb +0 -0
- package/dist/ingest/simcity/models/building-cinema.glb +0 -0
- package/dist/ingest/simcity/models/building-house-block-big.glb +0 -0
- package/dist/ingest/simcity/models/building-house-family-large.glb +0 -0
- package/dist/ingest/simcity/models/building-house-family-small.glb +0 -0
- package/dist/ingest/simcity/models/building-office-balcony.glb +0 -0
- package/dist/ingest/simcity/models/building-office-big.glb +0 -0
- package/dist/ingest/simcity/models/building-office-pyramid.glb +0 -0
- package/dist/ingest/simcity/models/building-office-tall.glb +0 -0
- package/dist/ingest/simcity/models/building-office.glb +0 -0
- package/dist/ingest/simcity/models/building-restaurant.glb +0 -0
- package/dist/ingest/simcity/models/building-skyscraper.glb +0 -0
- package/dist/ingest/simcity/models/car-ambulance-pickup.glb +0 -0
- package/dist/ingest/simcity/models/car-baywatch.glb +0 -0
- package/dist/ingest/simcity/models/car-hippie-van.glb +0 -0
- package/dist/ingest/simcity/models/car-passenger-race.glb +0 -0
- package/dist/ingest/simcity/models/car-passenger.glb +0 -0
- package/dist/ingest/simcity/models/car-police.glb +0 -0
- package/dist/ingest/simcity/models/car-taxi.glb +0 -0
- package/dist/ingest/simcity/models/car-tow-truck.glb +0 -0
- package/dist/ingest/simcity/models/car-truck-dump.glb +0 -0
- package/dist/ingest/simcity/models/car-veteran.glb +0 -0
- package/dist/ingest/simcity/models/construction-small.glb +0 -0
- package/dist/ingest/simcity/models/data-center.glb +0 -0
- package/dist/ingest/simcity/models/industry-factory-old.glb +0 -0
- package/dist/ingest/simcity/models/industry-factory.glb +0 -0
- package/dist/ingest/simcity/models/industry-refinery.glb +0 -0
- package/dist/ingest/simcity/models/industry-warehouse.glb +0 -0
- package/dist/ingest/simcity/models/power_line_pole_modified.glb +0 -0
- package/dist/ingest/simcity/models/tile-plain_grass.glb +0 -0
- package/dist/ingest/simcity/models/tile-road-curve.glb +0 -0
- package/dist/ingest/simcity/models/tile-road-end.glb +0 -0
- package/dist/ingest/simcity/models/tile-road-intersection-t.glb +0 -0
- package/dist/ingest/simcity/models/tile-road-intersection.glb +0 -0
- package/dist/ingest/simcity/models/tile-road-straight.glb +0 -0
- package/dist/ingest/simcity/models/truck.glb +0 -0
- package/dist/ingest/simcity/statusIcons/no-power.png +0 -0
- package/dist/ingest/simcity/statusIcons/no-road-access.png +0 -0
- package/dist/ingest/simcity/textures/base.png +0 -0
- package/dist/ingest/simcity/textures/grid.png +0 -0
- package/dist/ingest/simcity/textures/specular.png +0 -0
- package/dist/ingest/simcity/three-r155.module.js +51466 -0
- package/dist/ingest/simcity/vgai.game.json +20 -0
- package/dist/ingest/tanks/UPSTREAM.md +69 -0
- package/dist/ingest/tanks/index.html +214 -0
- package/dist/ingest/tanks/models/pixelTank.fbx +0 -0
- package/dist/ingest/tanks/tanks-entry.js +92 -0
- package/dist/ingest/tanks/three-r170.module.js +54571 -0
- package/dist/ingest/tanks/vgai.game.json +20 -0
- package/dist/inputmaps/default.inputmap.json +41 -0
- package/dist/jsm/libs/draco/gltf/draco_decoder.js +33 -0
- package/dist/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
- package/dist/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
- package/dist/scenes/untitled.vscn.json +29 -0
- package/dist/textures/waternormals.jpg +0 -0
- package/dist-server/packaged.mjs +18155 -0
- package/package.json +36 -0
- package/server/asset-library-routes.ts +833 -0
- package/server/canonical-path.ts +50 -0
- package/server/cloud-asset-catalog.ts +101 -0
- package/server/dev.ts +350 -0
- package/server/editor-server.ts +1537 -0
- package/server/editor-sse.ts +73 -0
- package/server/game-globals-shadow.ts +58 -0
- package/server/local-asset-catalog.ts +163 -0
- package/server/packaged.ts +571 -0
- package/server/prod.ts +75 -0
- package/server/project-optimize-deps-entries.ts +149 -0
- package/server/project-view.ts +65 -0
- package/server/server-utils.ts +430 -0
- package/server/session-registry.ts +93 -0
- package/src/EditorContext.tsx +87 -0
- package/src/achieved-tier.ts +126 -0
- package/src/action-registry.ts +268 -0
- package/src/adapter-resolver.ts +1858 -0
- package/src/asset-events.ts +100 -0
- package/src/authoring/active-adapter.ts +98 -0
- package/src/authoring/active-systems.ts +50 -0
- package/src/authoring/boundary-authoring-adapter.ts +178 -0
- package/src/authoring/composite-authoring-adapter.ts +891 -0
- package/src/authoring/design-time-layers.ts +776 -0
- package/src/authoring/edit-mode-authoring.ts +643 -0
- package/src/authoring/embed-only-adapter.ts +57 -0
- package/src/authoring/ephemeral-persistence.ts +26 -0
- package/src/authoring/eyedropper-session.ts +69 -0
- package/src/authoring/first-party-hierarchy-menu.ts +74 -0
- package/src/authoring/first-party-inspector/AddSectionMenu.tsx +118 -0
- package/src/authoring/first-party-inspector/EnvironmentSection.tsx +550 -0
- package/src/authoring/first-party-inspector/HeaderSection.tsx +329 -0
- package/src/authoring/first-party-inspector/is-first-party-selection.ts +44 -0
- package/src/authoring/first-party-inspector/register.tsx +108 -0
- package/src/authoring/ingest-authoring-adapter.ts +475 -0
- package/src/authoring/ingest-capture.ts +94 -0
- package/src/authoring/ingest-game-adapter.ts +291 -0
- package/src/authoring/ingest-iframe-adapter.ts +38 -0
- package/src/authoring/ingest-iframe-reachable-adapter.ts +401 -0
- package/src/authoring/ingest-overlay.ts +193 -0
- package/src/authoring/layered-pick.ts +87 -0
- package/src/authoring/mount-failure-report.ts +112 -0
- package/src/authoring/overlay-report.ts +52 -0
- package/src/authoring/project-scenes.ts +111 -0
- package/src/authoring/react-dom-authoring-adapter.ts +795 -0
- package/src/authoring/react-inspector-section.tsx +1041 -0
- package/src/authoring/react-world-authoring-adapter.ts +2400 -0
- package/src/authoring/root-activation.ts +61 -0
- package/src/authoring/scene-ui-layer.ts +485 -0
- package/src/authoring/story-overlay.ts +48 -0
- package/src/authoring/ui-authoring-adapter.ts +325 -0
- package/src/authoring/ui-hierarchy-menu.ts +40 -0
- package/src/authoring/ui-inspector-sections.tsx +156 -0
- package/src/authoring/undo-timeline.ts +145 -0
- package/src/authoring/vgai-scene-authoring-adapter.ts +746 -0
- package/src/authoring/viewport-pick-context.ts +31 -0
- package/src/authoring/viewport-raycast.ts +80 -0
- package/src/authoring/world-overlay.ts +76 -0
- package/src/authoring/world-pan-state.ts +115 -0
- package/src/authoring/world-session-state.ts +102 -0
- package/src/authoring/world2d-authoring-adapter.ts +313 -0
- package/src/browser-external-watch.ts +98 -0
- package/src/browser-play-entry.ts +112 -0
- package/src/browser-project-scripts.ts +112 -0
- package/src/browser-transpile.ts +246 -0
- package/src/browser-watch-reload.ts +100 -0
- package/src/command-listener.ts +326 -0
- package/src/components/AlignToolbar.tsx +189 -0
- package/src/components/AppRoot.tsx +73 -0
- package/src/components/AssetBrowser.tsx +502 -0
- package/src/components/BottomPanel.tsx +326 -0
- package/src/components/BuildPanel.tsx +455 -0
- package/src/components/CameraInfo.tsx +56 -0
- package/src/components/CommandPalette.tsx +265 -0
- package/src/components/ConsolePanel.tsx +272 -0
- package/src/components/DataPanel.tsx +1268 -0
- package/src/components/DefaultEditorLayout.tsx +509 -0
- package/src/components/FolderTree.tsx +179 -0
- package/src/components/GameHierarchy.tsx +1349 -0
- package/src/components/Inspector.tsx +671 -0
- package/src/components/InspectorToolSection.tsx +74 -0
- package/src/components/MountFailureBanner.tsx +110 -0
- package/src/components/NetworkSection.tsx +109 -0
- package/src/components/OnlineAssetBrowser.tsx +448 -0
- package/src/components/OverlayReportBanner.tsx +122 -0
- package/src/components/PlayBar.tsx +356 -0
- package/src/components/PrefabSaveDialog.tsx +201 -0
- package/src/components/ProjectHeader.tsx +174 -0
- package/src/components/ProjectScreen.tsx +1004 -0
- package/src/components/RightPanel.tsx +166 -0
- package/src/components/RootActivateDialog.tsx +105 -0
- package/src/components/SaveDialog.tsx +197 -0
- package/src/components/SaveStatus.tsx +69 -0
- package/src/components/StatsOverlay.tsx +35 -0
- package/src/components/ToolHost.tsx +80 -0
- package/src/components/Toolbar.tsx +307 -0
- package/src/components/ViewportOverlay.tsx +234 -0
- package/src/components/ViewportPanel.tsx +369 -0
- package/src/components/WorldContextMenu.tsx +257 -0
- package/src/components/WorldSelectionOverlay.tsx +2003 -0
- package/src/components/WorldTextEditor.tsx +86 -0
- package/src/components/asset-viewers/AssetViewer.tsx +38 -0
- package/src/components/asset-viewers/AudioViewer.tsx +149 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +77 -0
- package/src/components/asset-viewers/ImageViewer.tsx +65 -0
- package/src/components/asset-viewers/InputMapViewer.tsx +206 -0
- package/src/components/asset-viewers/ModelViewer.tsx +180 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +236 -0
- package/src/components/data-csv.ts +301 -0
- package/src/components/entity-name-commit.ts +18 -0
- package/src/components/inspector-property-grouping.ts +65 -0
- package/src/components/inspector-widgets/AlignmentGrid.tsx +188 -0
- package/src/components/inspector-widgets/BorderEditor.tsx +305 -0
- package/src/components/inspector-widgets/ColorPicker.tsx +548 -0
- package/src/components/inspector-widgets/FilterEditor.tsx +108 -0
- package/src/components/inspector-widgets/FontPicker.tsx +196 -0
- package/src/components/inspector-widgets/GradientEditor.tsx +277 -0
- package/src/components/inspector-widgets/ScrubbableInput.tsx +152 -0
- package/src/components/inspector-widgets/ShadowEditor.tsx +332 -0
- package/src/components/inspector-widgets/color-utils.ts +202 -0
- package/src/components/inspector-widgets/gallery-main.tsx +167 -0
- package/src/components/inspector-widgets/index.ts +22 -0
- package/src/components/inspector-widgets/shared.tsx +135 -0
- package/src/components/inspectors/AnimationSection.tsx +143 -0
- package/src/components/inspectors/AudioSection.tsx +215 -0
- package/src/components/inspectors/BoneAttachmentSection.tsx +82 -0
- package/src/components/inspectors/CameraSection.tsx +105 -0
- package/src/components/inspectors/ComponentsSection.tsx +358 -0
- package/src/components/inspectors/JointsSection.tsx +255 -0
- package/src/components/inspectors/LightSection.tsx +116 -0
- package/src/components/inspectors/MaterialSection.tsx +1189 -0
- package/src/components/inspectors/MeshSection.tsx +99 -0
- package/src/components/inspectors/NavigationSection.tsx +58 -0
- package/src/components/inspectors/ParticleSection.tsx +681 -0
- package/src/components/inspectors/PhysicsSection.tsx +326 -0
- package/src/components/inspectors/PostProcessingSection.tsx +1290 -0
- package/src/components/inspectors/RenderingSection.tsx +109 -0
- package/src/components/inspectors/ShadowSection.tsx +84 -0
- package/src/components/inspectors/SplineSection.tsx +191 -0
- package/src/components/inspectors/TransformSection.tsx +191 -0
- package/src/components/inspectors/json-schema-fields.ts +281 -0
- package/src/components/inspectors/multi-edit-utils.ts +49 -0
- package/src/components/inspectors/zod-fields.ts +184 -0
- package/src/components/primitives/ColorInput.tsx +109 -0
- package/src/components/primitives/JsonInput.tsx +98 -0
- package/src/components/primitives/NumberInput.tsx +164 -0
- package/src/components/primitives/Panel.tsx +68 -0
- package/src/components/primitives/SectionHeader.tsx +45 -0
- package/src/components/primitives/Tooltip.tsx +82 -0
- package/src/components/primitives/Vec3Input.tsx +62 -0
- package/src/components/world-overlay-gestures.ts +1438 -0
- package/src/doctor/data-checks.ts +285 -0
- package/src/doctor/report.ts +386 -0
- package/src/editor-api.ts +700 -0
- package/src/editor-console.ts +194 -0
- package/src/editor-hotkeys.ts +441 -0
- package/src/editor-layers.ts +2 -0
- package/src/editor-mode.ts +28 -0
- package/src/editor-store.ts +2225 -0
- package/src/editor-viewport.ts +1924 -0
- package/src/entity-factory.ts +221 -0
- package/src/game-globals-prelude.ts +27 -0
- package/src/gated-globals.ts +131 -0
- package/src/generated/setup-by-example.generated.ts +53 -0
- package/src/gizmo-registry.ts +608 -0
- package/src/handle-system.ts +221 -0
- package/src/hierarchy-menu-registry.ts +70 -0
- package/src/hierarchy-rows.ts +73 -0
- package/src/hosted-example.ts +160 -0
- package/src/hotkeys.ts +142 -0
- package/src/ingest/discovery-react.ts +132 -0
- package/src/ingest/discovery.ts +205 -0
- package/src/ingest/discovery2d.ts +204 -0
- package/src/ingest/esm-entry-resolution.ts +102 -0
- package/src/ingest/games/bloom-composer/game.js +99 -0
- package/src/ingest/games/bloom-composer/vgai.game.json +21 -0
- package/src/ingest/games/embed-bundle/embed.html +10 -0
- package/src/ingest/games/embed-bundle/vgai.game.json +21 -0
- package/src/ingest/games/games-fps/assets/collision-world.glb +0 -0
- package/src/ingest/games/games-fps/game.js +479 -0
- package/src/ingest/games/games-fps/vgai.game.json +24 -0
- package/src/ingest/games/iframe-reachable/game-source.js +58 -0
- package/src/ingest/games/iframe-reachable/vgai.game.json +21 -0
- package/src/ingest/games/interactive-cubes/game.js +139 -0
- package/src/ingest/games/interactive-cubes/vgai.game.json +21 -0
- package/src/ingest/games/mismatched-three/fake-three.js +38 -0
- package/src/ingest/games/mismatched-three/game.js +10 -0
- package/src/ingest/games/mismatched-three/vgai.game.json +22 -0
- package/src/ingest/games/own-three-bundled/game.js +43 -0
- package/src/ingest/games/own-three-bundled/vgai.game.json +21 -0
- package/src/ingest/games/pointerlock-maze/game.js +288 -0
- package/src/ingest/games/pointerlock-maze/vgai.game.json +22 -0
- package/src/ingest/games-2d/_fixtures/first-party-scene.scn2d.json +124 -0
- package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +25 -0
- package/src/ingest/games-2d/bunnymark/game.ts +88 -0
- package/src/ingest/games-2d/bunnymark/vgai.game.json +21 -0
- package/src/ingest/games-2d/flappy/game.ts +148 -0
- package/src/ingest/games-2d/flappy/vgai.game.json +21 -0
- package/src/ingest/games-2d/flappy-pixi/vgai.game.json +25 -0
- package/src/ingest/games-2d/puzzling-potions/vgai.game.json +25 -0
- package/src/ingest/games-2d/tilemap-camera/game.ts +115 -0
- package/src/ingest/games-2d/tilemap-camera/vgai.game.json +21 -0
- package/src/ingest/games-react/react-rpg/entry.tsx +185 -0
- package/src/ingest/games-react/react-rpg/shims.d.ts +26 -0
- package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +129 -0
- package/src/ingest/games-react/react-rpg/vgai.game.json +21 -0
- package/src/ingest/host-namespace-registry.ts +196 -0
- package/src/ingest/types.ts +127 -0
- package/src/ingest-hierarchy-rows.ts +207 -0
- package/src/ingest-mode.ts +2092 -0
- package/src/ingest-siblings.ts +466 -0
- package/src/initial-scene.ts +194 -0
- package/src/inspector-section-registry.ts +117 -0
- package/src/interactive-edit-scope.ts +34 -0
- package/src/main.tsx +23 -0
- package/src/manifest-project.ts +43 -0
- package/src/model-thumbnail.ts +156 -0
- package/src/module-mode.ts +513 -0
- package/src/navmesh-handler.ts +94 -0
- package/src/packaged-runtime.ts +49 -0
- package/src/play-mode.ts +1148 -0
- package/src/playground/main.ts +206 -0
- package/src/project-manager.ts +173 -0
- package/src/scene-diff.ts +112 -0
- package/src/scene-serializer.ts +144 -0
- package/src/scene-sync.ts +587 -0
- package/src/scene-ui-mode/active-scene-ui.ts +58 -0
- package/src/scene-ui-mode/scene-ui-palette-panel.tsx +152 -0
- package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +29 -0
- package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +74 -0
- package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +49 -0
- package/src/scene-ui-mode/ui-prefab-io.ts +76 -0
- package/src/script-loader.ts +143 -0
- package/src/storage/fsa-storage.ts +55 -0
- package/src/storage/handle-storage.ts +150 -0
- package/src/storage/handle-store.ts +116 -0
- package/src/storage/http-storage.ts +137 -0
- package/src/storage/index.ts +147 -0
- package/src/storage/mem-storage.ts +135 -0
- package/src/storage/opfs-storage.ts +25 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/seed.ts +106 -0
- package/src/storage/types.ts +110 -0
- package/src/tool-loader.ts +291 -0
- package/src/ui-editor/inspector.tsx +563 -0
- package/src/ui-editor/node-ops.ts +266 -0
- package/src/ui-editor/overlay.tsx +380 -0
- package/src/ui-editor/palette.tsx +114 -0
- package/src/ui-editor/react-store.ts +78 -0
- package/src/ui-editor/timeline-panel.tsx +443 -0
- package/src/ui-editor/ui-edit-store.ts +552 -0
- package/src/ui-editor/ui-prefab.ts +95 -0
- package/src/ui-source/inspect.ts +544 -0
- package/src/ui-source/oid-transform.ts +133 -0
- package/src/ui-source/source-write-backend.ts +203 -0
- package/src/ui-source/tailwind-map.ts +174 -0
- package/src/ui-source/writer.ts +1175 -0
- package/src/widgets/index.ts +73 -0
- package/template/.claude/skills/editor/SKILL.md +252 -0
- package/template/CLAUDE.md +512 -0
- package/template/LICENSE +30 -0
- package/template/emit-schemas.ts +42 -0
- package/template/index.html +17 -0
- package/template/package.json +53 -0
- package/template/project.json +9 -0
- package/template/public/audio/ambient-arena.wav +0 -0
- package/template/public/audio/ambient-music.wav +0 -0
- package/template/public/audio/ambient-nature.wav +0 -0
- package/template/public/audio/ambient-wind.wav +0 -0
- package/template/public/inputmaps/default.inputmap.json +41 -0
- package/template/public/jsm/libs/draco/gltf/draco_decoder.js +33 -0
- package/template/public/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
- package/template/public/jsm/libs/draco/gltf/draco_encoder.js +33 -0
- package/template/public/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
- package/template/public/scenes/default.vscn.json +43 -0
- package/template/public/scenes/untitled.vscn.json +29 -0
- package/template/public/textures/waternormals.jpg +0 -0
- package/template/server/colyseus-setup.ts +85 -0
- package/template/server/main.ts +34 -0
- package/template/server/rooms/arena-room.ts +420 -0
- package/template/server/rooms/game-room.ts +162 -0
- package/template/server/rooms.ts +15 -0
- package/template/server/tsconfig.json +19 -0
- package/template/src/data/README.md +40 -0
- package/template/src/data/assets.ts +31 -0
- package/template/src/data/tuning.data.json +5 -0
- package/template/src/data/tuning.schema.json +21 -0
- package/template/src/data/tuning.schema.ts +34 -0
- package/template/src/data/tuning.ts +24 -0
- package/template/src/main.ts +157 -0
- package/template/src/scripts/components/data-spinner.ts +45 -0
- package/template/src/scripts/components/scene-camera.ts +40 -0
- package/template/src/scripts/main.ts +94 -0
- package/template/src/scripts/registry.ts +46 -0
- package/template/src/tools/README.md +14 -0
- package/template/src/tools/example.tool.tsx +91 -0
- package/template/src/tools/spin.tool.tsx +101 -0
- package/template/src/ui/Button.tsx +27 -0
- package/template/src/ui/DefaultHud.tsx +40 -0
- package/template/src/ui/KeyHint.tsx +25 -0
- package/template/src/ui/Panel.tsx +52 -0
- package/template/src/ui/RebindPanel.tsx +129 -0
- package/template/src/ui/Slider.tsx +28 -0
- package/template/src/ui/StatusDot.tsx +22 -0
- package/template/src/ui/Toggle.tsx +19 -0
- package/template/src/ui/game-state.tsx +37 -0
- package/template/src/ui/index.ts +7 -0
- package/template/src/ui/mount-default-hud.tsx +19 -0
- package/template/src/ui/mount-ui.ts +15 -0
- package/template/tsconfig.json +36 -0
- package/template/validate-asset-content.ts +78 -0
- package/template/validate-manifest.ts +55 -0
- package/template/validate-scenes.ts +211 -0
- package/template/vgai.game.json +21 -0
- package/template/vite.config.ts +128 -0
- package/vite-plugin-example-assets.ts +60 -0
- package/vite-plugin-game-globals.ts +46 -0
- package/vite-plugin-game-static.ts +71 -0
- package/vite-plugin-project-game-static.ts +84 -0
- package/vite-plugin-react-game-static.ts +98 -0
- package/vite-plugin-react-world-provider.ts +81 -0
- package/vite-plugin-react-world-runtime.ts +76 -0
- package/vite-plugin-ui-oid.ts +561 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged editor server — the entry a `@vgai/editor` npm package resolves
|
|
3
|
+
* from a PROJECT's own `node_modules`, with NO monorepo checkout on disk
|
|
4
|
+
* (Phase B, docs/FRONTEND-FIRST-ROADMAP.md; see the phase plan's D-FORK
|
|
5
|
+
* decision + §0/§3 "the real work" for `@vgai/editor`).
|
|
6
|
+
*
|
|
7
|
+
* Run with:
|
|
8
|
+
* VGAI_PROJECT=<projectDir> node dist-server/packaged.mjs
|
|
9
|
+
*
|
|
10
|
+
* ## Why this file exists (and isn't just `prod.ts`)
|
|
11
|
+
*
|
|
12
|
+
* `dev.ts` boots ONE Vite instance rooted at the monorepo checkout, which
|
|
13
|
+
* does double duty: it builds the editor's OWN React app AND resolves the
|
|
14
|
+
* OPENED PROJECT's module graph (bare imports like `three`/`zod`/`react`
|
|
15
|
+
* resolve only because that Vite's `root` is the repo root, whose hoisted
|
|
16
|
+
* `node_modules` has everything). `prod.ts` (the Electron packaging path)
|
|
17
|
+
* has no Vite at all — its `serveScripts` fallback in `editor-server.ts` is
|
|
18
|
+
* a hand-rolled `/@fs` route that only rewrites `@engine/` imports; it has
|
|
19
|
+
* NO handler for bare npm specifiers or `/node_modules/*` at all, so it
|
|
20
|
+
* cannot serve a real project's own module graph (see the phase plan's §0).
|
|
21
|
+
*
|
|
22
|
+
* This file is the missing second code path: it serves the editor's OWN
|
|
23
|
+
* app as a PREBUILT static SPA (`../dist/`, produced by the workspace-local
|
|
24
|
+
* `npm run build -w @vgai/editor`) — no dev-mode transform of the editor's
|
|
25
|
+
* own source is needed, since a project author isn't hot-reloading the
|
|
26
|
+
* editor's own UI — and boots a SEPARATE, PROJECT-ROOTED Vite instance
|
|
27
|
+
* (`root: <project>`, `configFile: false`, middleware mode, HMR + watch
|
|
28
|
+
* ENABLED) whose job is ONLY to resolve/transform the opened PROJECT's own
|
|
29
|
+
* source. Because that Vite instance's `root` is the project directory,
|
|
30
|
+
* Vite's own resolver naturally walks the PROJECT's OWN `node_modules` for
|
|
31
|
+
* every bare specifier (`three`, `zod`, `react`, `@vgai/scene-ui`, ...) —
|
|
32
|
+
* for free, with zero hand-written import rewriting. This is the same
|
|
33
|
+
* pattern `packages/editor/scripts/run-conformance.ts` uses to run the
|
|
34
|
+
* adapter conformance kit against an arbitrary external folder, adapted for
|
|
35
|
+
* live editing (HMR/watch on) instead of a one-shot SSR run.
|
|
36
|
+
*
|
|
37
|
+
* The `@engine/` alias project source still uses (pending the `@engine/*` →
|
|
38
|
+
* `@vgai/engine/*` migration the phase plan defers to a follow-up cleanup
|
|
39
|
+
* slice) is reconstructed here too — pointed at the PROJECT's own installed
|
|
40
|
+
* `@vgai/engine`, not a copy baked into this package's own tarball. A
|
|
41
|
+
* project pinning `@vgai/engine@0.3.0` must be served ITS 0.3.0 source, so
|
|
42
|
+
* `@vgai/engine`/`@vgai/scene-ui` are resolved via `createRequire`, rooted
|
|
43
|
+
* at the project directory — Node's own resolution algorithm, not a
|
|
44
|
+
* hardcoded path (see `resolveInstalledPackageSrcDir` in `server-utils.ts`,
|
|
45
|
+
* shared with `editor-server.ts`'s equivalent fix for `prod.ts`'s route).
|
|
46
|
+
*
|
|
47
|
+
* ## React-world OID authoring parity (DEBT-4 follow-on)
|
|
48
|
+
*
|
|
49
|
+
* `dev.ts` reaches TWO extra plugins via its `configFile:` (repo-root
|
|
50
|
+
* `vite.config.ts`): `uiOidPlugin()` (stamps `data-oid` on every JSX element
|
|
51
|
+
* in project-scoped `.tsx` files + serves the `/__ui-source/*` read/write
|
|
52
|
+
* endpoints the hierarchy/inspector's source-write path needs) and
|
|
53
|
+
* `reactWorldProviderPlugin()` (resolves the synthetic
|
|
54
|
+
* `/__vgai-game-provider` module `adapter-resolver.ts`'s
|
|
55
|
+
* `loadProjectGameProvider` imports — WITHOUT it, every `kind: 'react'`
|
|
56
|
+
* world 404s on mount, not just "authors without OID"). Both are carried
|
|
57
|
+
* over here, imported straight from this package's own `vite-plugin-ui-oid`
|
|
58
|
+
* / `vite-plugin-react-world-provider` (same files, no copy) and registered
|
|
59
|
+
* with NO extra scoping beyond their own built-in `defaultProjectScopeInclude`
|
|
60
|
+
* (already project-scoped — see that file's doc comment: excludes
|
|
61
|
+
* `node_modules`, vendored trees, and the vgai tooling/engine source, which
|
|
62
|
+
* this Vite instance never serves anyway since its `root` IS the project).
|
|
63
|
+
*
|
|
64
|
+
* `@vitejs/plugin-react` (`react()`) is DELIBERATELY NOT added here — this
|
|
65
|
+
* is the one piece of `dev.ts` parity that is a genuine, structural
|
|
66
|
+
* incompatibility, not a missing plugin call:
|
|
67
|
+
*
|
|
68
|
+
* 1. **Fast Refresh's preamble has nowhere to run.** `@vitejs/plugin-react`
|
|
69
|
+
* only skips its fast-refresh code-injection when `config.isProduction ||
|
|
70
|
+
* config.command === 'build' || config.server.hmr === false` — none of
|
|
71
|
+
* which hold here (this instance is `middlewareMode` `serve` with `hmr`
|
|
72
|
+
* ON, by design, for live editing). With fast-refresh injection ON, every
|
|
73
|
+
* transformed `.tsx` module gets a trailer that THROWS
|
|
74
|
+
* (`"@vitejs/plugin-react can't detect preamble. Something is wrong."`)
|
|
75
|
+
* unless `window.$RefreshReg$`/`$RefreshSig$` were set by the preamble
|
|
76
|
+
* script `transformIndexHtml` injects into an HTML page THAT INSTANCE
|
|
77
|
+
* SERVES. This instance is `appType: 'custom'` (no HTML serving at all —
|
|
78
|
+
* the editor's own shell is a PREBUILT static `dist/`, sent by `express.
|
|
79
|
+
* static` below with zero Vite involvement, so no `transformIndexHtml`
|
|
80
|
+
* hook ever runs for it either). Registering `react()` as-is would not
|
|
81
|
+
* degrade gracefully to "no Fast Refresh" — it would make every react-
|
|
82
|
+
* world/component module throw on first load, a regression versus
|
|
83
|
+
* today's baseline (plain esbuild JSX, which works fine for basic JSX —
|
|
84
|
+
* proven by the default template). The only way to silence just the
|
|
85
|
+
* fast-refresh half (short of a bespoke preamble-bootstrap module the
|
|
86
|
+
* browser would need to import before any project entry, itself a new
|
|
87
|
+
* client-side subsystem) is `server.hmr: false` on the WHOLE instance,
|
|
88
|
+
* which would also kill the `vgai-script-hmr` plugin below's WebSocket
|
|
89
|
+
* delivery — not an acceptable trade for this slice.
|
|
90
|
+
* 2. **JSX compilation itself doesn't need it.** Vite's default esbuild JSX
|
|
91
|
+
* transform (`automatic` runtime, no config here) already compiles
|
|
92
|
+
* `.tsx`/`.jsx` correctly without `@vitejs/plugin-react` — proven by the
|
|
93
|
+
* default (threejs-only) template authoring fine today, and unaffected
|
|
94
|
+
* by this file's plugin list either way.
|
|
95
|
+
*
|
|
96
|
+
* So: OID stamping (source-write authoring) and the `GameProvider` identity
|
|
97
|
+
* fix are real, working parity gained by this change. React Fast Refresh
|
|
98
|
+
* for a project's own components remains NOT at `dev.ts` parity under the
|
|
99
|
+
* packaged runtime — a documented, structural gap, not a hidden one.
|
|
100
|
+
*
|
|
101
|
+
* **A second, deeper gap this change surfaced — FIXED by the C1 follow-on**
|
|
102
|
+
* (`phase-b/c1-react-mount`): `adapter-resolver.ts` used to mount every react
|
|
103
|
+
* world with THIS PACKAGE'S OWN bundled `react`/`react-dom` (`import {
|
|
104
|
+
* createRoot } from 'react-dom/client'` / `createElement`, statically baked
|
|
105
|
+
* into the prebuilt `dist/` at `npm run build -w @vgai/editor` time), while
|
|
106
|
+
* the entry component's own hooks ran against WHATEVER `react` the
|
|
107
|
+
* PROJECT'S OWN `node_modules` resolves (this Vite instance's `root` is the
|
|
108
|
+
* project, so bare `react` imports resolve there, by design — a project pins
|
|
109
|
+
* its own react version, independent of the editor). `dev.ts` avoids this
|
|
110
|
+
* exact failure mode via repo-root `vite.config.ts`'s `resolve.dedupe:
|
|
111
|
+
* ['react', 'react-dom', ...]`, which works ONLY because dev.ts's single
|
|
112
|
+
* Vite instance resolves BOTH the editor's own source and the opened
|
|
113
|
+
* project's source through the SAME `node_modules` — there is no equivalent
|
|
114
|
+
* collapsing point here: the editor's own react is baked into a separate,
|
|
115
|
+
* already-built production bundle, physically disconnected from this
|
|
116
|
+
* instance's live resolution of the project's react. Two separate `react`
|
|
117
|
+
* module instances meant the mounting `react-dom`'s hook dispatcher and the
|
|
118
|
+
* entry component's own `useState`/`useContext` calls read DIFFERENT
|
|
119
|
+
* internal singleton objects — the classic "duplicate React copies" failure.
|
|
120
|
+
* **Confirmed live, not theoretical, at the time this was still open**: a
|
|
121
|
+
* real-browser Playwright run against a tarball-installed, checkout-absent
|
|
122
|
+
* packaged editor (`vgai.game.json`'s `kind: 'react'` "hud" world,
|
|
123
|
+
* `useGameState`) threw exactly this at mount: `TypeError: Cannot read
|
|
124
|
+
* properties of null (reading 'useContext')` inside `useGame()`
|
|
125
|
+
* (`src/ui/game-state.tsx`), called from the project's `Hud` component,
|
|
126
|
+
* rendered by the editor's OWN bundled `react_stack_bottom_frame`
|
|
127
|
+
* (`assets/index-*.js`).
|
|
128
|
+
*
|
|
129
|
+
* The fix (C1): a react world's mount does NOT need to share react with the
|
|
130
|
+
* editor's own UI at all — it is an isolated `createRoot` subtree that only
|
|
131
|
+
* needs to be internally consistent with itself. So
|
|
132
|
+
* `adapter-resolver.ts`'s `resolveReactWorldMountRuntime()` now resolves
|
|
133
|
+
* `createElement`/`createRoot`/the engine-`GameProvider` fallback from the
|
|
134
|
+
* PROJECT's own graph under the packaged runtime, via this file's newly
|
|
135
|
+
* registered `reactWorldRuntimePlugin()` (a synthetic virtual module,
|
|
136
|
+
* `/__vgai-react-world-runtime`, the same "literal static re-export" trick
|
|
137
|
+
* `reactWorldProviderPlugin()` already uses for `GameProvider` — see
|
|
138
|
+
* `vite-plugin-react-world-runtime.ts`'s doc comment) — converging the mount
|
|
139
|
+
* call and the entry component's hooks on ONE react instance, the project's
|
|
140
|
+
* own. Gated on `isPackagedRuntime()` (`src/packaged-runtime.ts`, itself
|
|
141
|
+
* reading a `packaged` flag `/__editor/project` now reports) so `dev.ts`/
|
|
142
|
+
* Electron's existing static-import path — already correct via
|
|
143
|
+
* `resolve.dedupe` — stays byte-unchanged. See `adapter-resolver.ts`'s
|
|
144
|
+
* `resolveReactWorldMountRuntime` doc comment for the full mechanism, and
|
|
145
|
+
* the C1 build report for the real-browser proof (checkout absent, tarball-
|
|
146
|
+
* installed, no console error, DOM rendered).
|
|
147
|
+
*
|
|
148
|
+
* ## Scoped dependency discovery, not disabled discovery (C3 follow-on)
|
|
149
|
+
*
|
|
150
|
+
* `optimizeDeps` below used to carry `noDiscovery: true` (see git history for
|
|
151
|
+
* the exact prior comment): with the boot-time crawl DEFAULT-targeting the
|
|
152
|
+
* project's own `index.html`, and a scaffolded project's `src/main.ts`
|
|
153
|
+
* bootstrap containing a `?net=p2p-host`-gated `await import('../server/
|
|
154
|
+
* rooms')` that esbuild's scanner statically follows regardless of the
|
|
155
|
+
* runtime guard around it, that crawl reached real Colyseus SERVER code
|
|
156
|
+
* (`colyseus` -> `@colyseus/core` -> `@pm2/io`, a package with no browser-
|
|
157
|
+
* resolvable entry) and crashed the esbuild prebundle step outright. Turning
|
|
158
|
+
* discovery off entirely sidestepped that crash — at the cost of any CJS-
|
|
159
|
+
* only dependency NOT in the hardcoded `include` list below being served raw
|
|
160
|
+
* to the browser and failing (this is exactly what broke `examples/
|
|
161
|
+
* r3f-probe`: `@react-three/fiber`'s CJS transitive deps, e.g.
|
|
162
|
+
* `use-sync-external-store/shim/with-selector.js`, have no place to be
|
|
163
|
+
* hardcoded — this server serves ARBITRARY projects, most without R3F
|
|
164
|
+
* installed at all, and Vite errors on `include`-ing a not-installed dep).
|
|
165
|
+
*
|
|
166
|
+
* The fix (C3, `phase-b/c3-r3f-packaged`) is not "add R3F to the allowlist"
|
|
167
|
+
* — that just moves the whack-a-mole to the next ecosystem a project
|
|
168
|
+
* happens to pull in. It SCOPES the crawl instead of disabling it:
|
|
169
|
+
* `optimizeDeps.entries` is set (see `projectOptimizeDepsEntries` /
|
|
170
|
+
* `computeProjectOptimizeDepsEntries` in `project-optimize-deps-entries.ts`)
|
|
171
|
+
* to the OPENED PROJECT's own `vgai.game.json`-declared world `entry` files
|
|
172
|
+
* — the exact per-world mount code the editor's adapter-resolver dynamically
|
|
173
|
+
* imports for Play mode, never the project's `src/main.ts` bootstrap (a
|
|
174
|
+
* standalone-build concern this Vite instance never serves — the editor's
|
|
175
|
+
* own prebuilt SPA answers `/`). A world entry's own import graph reaches
|
|
176
|
+
* real client packages (react, R3F, a legitimate client `@colyseus/sdk`
|
|
177
|
+
* import for real multiplayer — `examples/third-person-arena/src/
|
|
178
|
+
* network.ts`) but never `server/`, so the `@pm2/io` crash class cannot
|
|
179
|
+
* occur no matter what a project's room code imports, while ANY CJS-needing-
|
|
180
|
+
* prebundle client dependency a world reaches gets auto-discovered and
|
|
181
|
+
* prebundled — no per-package allowlist, adapts to whatever the opened
|
|
182
|
+
* project actually has installed. `project-optimize-deps-entries.ts`'s doc
|
|
183
|
+
* comment has the empirical proof (direct `vite.optimizeDeps` runs, not just
|
|
184
|
+
* theory): scoped to the template's world entry, prebundling succeeds
|
|
185
|
+
* clean; scoped to `index.html` (the old default), it reproduces the exact
|
|
186
|
+
* `@pm2/io` crash; scoped to `examples/r3f-probe`'s world entries, `@react-
|
|
187
|
+
* three/fiber`/`@react-three/drei` are discovered and prebundled with no
|
|
188
|
+
* hardcoding; scoped to `examples/third-person-arena`'s world entry (a real
|
|
189
|
+
* colyseus multiplayer project), `@colyseus/sdk` prebundles clean too — the
|
|
190
|
+
* client SDK's own published build is self-contained and never reaches
|
|
191
|
+
* `@colyseus/core`'s server-only `Stats.mjs`. See the C3 build report for
|
|
192
|
+
* the real-browser proof (checkout absent, tarball-installed): R3F's
|
|
193
|
+
* `examples/r3f-probe` "net" world mounts with no console error, AND the
|
|
194
|
+
* pre-existing react-world (C1) / colyseus-bearing-project (this section)
|
|
195
|
+
* cases still work — no regression.
|
|
196
|
+
*
|
|
197
|
+
* ## Known scope trims (v1 — flagged, not silently dropped)
|
|
198
|
+
*
|
|
199
|
+
* - "New Project" scaffolding from WITHIN a packaged (no-checkout) editor
|
|
200
|
+
* fails loudly instead of scaffolding — see `editor-server.ts`'s
|
|
201
|
+
* `/__editor/create-project` handler (`packagedNoMonorepoTemplateError`).
|
|
202
|
+
* `scaffoldProject`'s `monoRoot` assumes a monorepo checkout layout
|
|
203
|
+
* (`<monoRoot>/packages/editor/template`), which a `node_modules`-
|
|
204
|
+
* installed `@vgai/editor` does not have (only a bare `template/` at its
|
|
205
|
+
* own package root). The phase plan (§6 landmine 5) already recommends
|
|
206
|
+
* relocating `template/` into `create-vgai-project` as the real fix —
|
|
207
|
+
* deferred there, not attempted here; `vgai create <name>` from a terminal
|
|
208
|
+
* is the supported path today.
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
import { realpathSync } from 'node:fs';
|
|
212
|
+
import path from 'node:path';
|
|
213
|
+
import { fileURLToPath } from 'node:url';
|
|
214
|
+
import express from 'express';
|
|
215
|
+
import { createServer as createViteServer } from 'vite';
|
|
216
|
+
import { projectGameStaticPlugin } from '../vite-plugin-project-game-static';
|
|
217
|
+
import { reactWorldProviderPlugin } from '../vite-plugin-react-world-provider';
|
|
218
|
+
import { reactWorldRuntimePlugin } from '../vite-plugin-react-world-runtime';
|
|
219
|
+
import { uiOidPlugin } from '../vite-plugin-ui-oid';
|
|
220
|
+
import { canonicalProjectRoot } from './canonical-path';
|
|
221
|
+
import { createEditorServer } from './editor-server';
|
|
222
|
+
import { shouldShadowGameGlobals } from './game-globals-shadow';
|
|
223
|
+
import {
|
|
224
|
+
SERVER_ONLY_PREBUNDLE_EXCLUDE,
|
|
225
|
+
computeProjectOptimizeDepsEntries,
|
|
226
|
+
} from './project-optimize-deps-entries';
|
|
227
|
+
import {
|
|
228
|
+
friendlyListenError,
|
|
229
|
+
resolveBindHost,
|
|
230
|
+
resolveInstalledPackageSrcDir,
|
|
231
|
+
} from './server-utils';
|
|
232
|
+
import { registerSession, unregisterSession } from './session-registry';
|
|
233
|
+
|
|
234
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
235
|
+
// This file lives directly under the `@vgai/editor` package root either as
|
|
236
|
+
// `packages/editor/server/packaged.ts` (source, run via tsx) or as the
|
|
237
|
+
// esbuild-bundled `packages/editor/dist-server/packaged.mjs` (`server/` and
|
|
238
|
+
// `dist-server/` are BOTH direct children of the package root) — so
|
|
239
|
+
// `resolve(__dirname, '..')` lands on the package root in either shape.
|
|
240
|
+
const editorPackageRoot = path.resolve(__dirname, '..');
|
|
241
|
+
// The workspace-local `npm run build -w @vgai/editor` (root `vite.config.ts`,
|
|
242
|
+
// `--outDir packages/editor/dist`) output — the editor's own prebuilt SPA.
|
|
243
|
+
const distPath = path.resolve(editorPackageRoot, 'dist');
|
|
244
|
+
|
|
245
|
+
const PORT = Number(process.env['PORT']) || Number(process.env['VGAI_EDITOR_PORT']) || 5173;
|
|
246
|
+
const HMR_PORT = Number(process.env['VGAI_HMR_PORT']) || (PORT === 5173 ? 24678 : PORT + 100);
|
|
247
|
+
// S3: bind to loopback by default; opt-in to a wider interface via env.
|
|
248
|
+
const HOST = resolveBindHost();
|
|
249
|
+
|
|
250
|
+
if (!process.env['VGAI_PROJECT']) {
|
|
251
|
+
console.error(
|
|
252
|
+
'\n \x1b[31mVGAI_PROJECT is required — the packaged editor has no monorepo checkout to fall ' +
|
|
253
|
+
'back to. Set VGAI_PROJECT=<absolute path to your vgai project>.\x1b[0m\n',
|
|
254
|
+
);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
// Canonicalized (symlink-resolved) — see canonical-path.ts's doc comment
|
|
258
|
+
// (dev.ts's identical fix: a react world's `GameProvider` colocation breaks
|
|
259
|
+
// if this path and Vite's own resolver disagree on a symlinked segment).
|
|
260
|
+
const projectPath = canonicalProjectRoot(process.env['VGAI_PROJECT']);
|
|
261
|
+
|
|
262
|
+
// Worktree / hoisted-`node_modules` support — same rationale as dev.ts:
|
|
263
|
+
// `node_modules` is very often a symlink, and Vite's `server.fs.allow`
|
|
264
|
+
// matches on the symlink-RESOLVED path.
|
|
265
|
+
const projectNodeModulesRealPath = (() => {
|
|
266
|
+
try {
|
|
267
|
+
const real = realpathSync(path.join(projectPath, 'node_modules'));
|
|
268
|
+
return real.startsWith(projectPath) ? null : real;
|
|
269
|
+
} catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
})();
|
|
273
|
+
|
|
274
|
+
// D-X2: the project-static route must follow the CURRENTLY open project, not
|
|
275
|
+
// a boot-time snapshot — mirrors dev.ts's `currentProjectRoot` box, updated
|
|
276
|
+
// in the SAME `onProjectOpened` callback that extends Vite's fs.allow/
|
|
277
|
+
// watcher/game-globals shadow for a newly opened project.
|
|
278
|
+
let currentProjectRoot: string = projectPath;
|
|
279
|
+
const projectRoots = new Set<string>([projectPath]);
|
|
280
|
+
|
|
281
|
+
// C3: the OPENED project's own manifest-declared world entry files — scopes
|
|
282
|
+
// `optimizeDeps.entries` below to exactly the client code a world can mount,
|
|
283
|
+
// never `index.html`/the project's own bootstrap `main.ts` (which is how the
|
|
284
|
+
// crawl used to reach `server/` room code and crash on `@pm2/io`). Boot-time
|
|
285
|
+
// snapshot only, same trim as `engineSrc`/`resolve.alias` below — see
|
|
286
|
+
// `project-optimize-deps-entries.ts`'s doc comment for the full rationale
|
|
287
|
+
// and the empirical proof this avoids the colyseus-scanner crash.
|
|
288
|
+
const projectOptimizeDepsEntries = computeProjectOptimizeDepsEntries(projectPath);
|
|
289
|
+
|
|
290
|
+
// Kept byte-identical to dev.ts's copy (see its own doc comment) — the
|
|
291
|
+
// lexical shadow prepended to every project module so `window`/`document`
|
|
292
|
+
// resolve to the editor's gated proxies instead of the real, shared globals.
|
|
293
|
+
const GAME_GLOBALS_PRELUDE =
|
|
294
|
+
'const window=(globalThis.__vgaiGameWindow||globalThis.window),' +
|
|
295
|
+
'document=(globalThis.__vgaiGameDocument||globalThis.document);\n';
|
|
296
|
+
|
|
297
|
+
async function main(): Promise<void> {
|
|
298
|
+
const app = express();
|
|
299
|
+
|
|
300
|
+
// The project's own installed `@vgai/engine` — resolved from the PROJECT's
|
|
301
|
+
// node_modules (Node's own resolution algorithm), never a copy baked into
|
|
302
|
+
// this package's own tarball (see this file's header doc comment). Falls
|
|
303
|
+
// back to nothing (alias omitted) when unresolvable — e.g. a project that
|
|
304
|
+
// hasn't `npm install`ed yet, or predates Phase B — so a bad/missing
|
|
305
|
+
// install degrades to "no @engine alias" rather than blocking boot.
|
|
306
|
+
const engineSrc = resolveInstalledPackageSrcDir(projectPath, '@vgai/engine');
|
|
307
|
+
if (!engineSrc) {
|
|
308
|
+
console.warn(
|
|
309
|
+
'\n \x1b[33mWarning:\x1b[0m no @vgai/engine resolvable from ' +
|
|
310
|
+
`${projectPath} — run npm install in the project first. ` +
|
|
311
|
+
'`@engine/*` imports will fail to resolve until then.\n',
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 1. Boot a Vite instance rooted at the PROJECT, not this editor package
|
|
316
|
+
// or a monorepo checkout — its own node_modules resolves every bare
|
|
317
|
+
// specifier for free (the run-conformance.ts pattern, live-editing not
|
|
318
|
+
// one-shot: HMR + watch stay ON, unlike that script's headless SSR run).
|
|
319
|
+
const vite = await createViteServer({
|
|
320
|
+
configFile: false,
|
|
321
|
+
root: projectPath,
|
|
322
|
+
appType: 'custom', // no HTML serving/SPA-fallback — this instance only serves project modules
|
|
323
|
+
plugins: [
|
|
324
|
+
// React-world OID authoring parity (see this file's header doc comment,
|
|
325
|
+
// "React-world OID authoring parity"): live `data-oid` instrumentation +
|
|
326
|
+
// the `/__ui-source/*` read/write endpoints the hierarchy/inspector's
|
|
327
|
+
// source-write path needs. Uses its own built-in `defaultProjectScopeInclude`
|
|
328
|
+
// (already project-scoped) unmodified — no extra scoping needed since this
|
|
329
|
+
// instance's `root` IS the project already.
|
|
330
|
+
uiOidPlugin(),
|
|
331
|
+
// Resolves the synthetic `/__vgai-game-provider` module
|
|
332
|
+
// `adapter-resolver.ts`'s `loadProjectGameProvider` imports for every
|
|
333
|
+
// `kind: 'react'` world's mount — WITHOUT this, a react world 404s at
|
|
334
|
+
// mount time in packaged mode (this is a correctness fix, not just an
|
|
335
|
+
// authoring nicety). See vite-plugin-react-world-provider.ts's doc comment.
|
|
336
|
+
reactWorldProviderPlugin(),
|
|
337
|
+
// Resolves the synthetic `/__vgai-react-world-runtime` module
|
|
338
|
+
// `adapter-resolver.ts`'s `resolveReactWorldMountRuntime` imports —
|
|
339
|
+
// the dual-React-instance fix (this file's header doc comment,
|
|
340
|
+
// "React-world OID authoring parity" section, final paragraph): a
|
|
341
|
+
// react world's `createElement`/`createRoot`/engine-`GameProvider`
|
|
342
|
+
// fallback must come from THIS project-rooted Vite instance's own
|
|
343
|
+
// react, not the editor's separately-bundled static SPA copy. See
|
|
344
|
+
// vite-plugin-react-world-runtime.ts's doc comment.
|
|
345
|
+
reactWorldRuntimePlugin(),
|
|
346
|
+
// vgai-game-globals — byte-identical rationale to dev.ts's copy.
|
|
347
|
+
{
|
|
348
|
+
name: 'vgai-game-globals',
|
|
349
|
+
transform(code: string, id: string) {
|
|
350
|
+
const file = id.split('?')[0]!;
|
|
351
|
+
if (!shouldShadowGameGlobals(file, projectRoots)) return null;
|
|
352
|
+
return { code: GAME_GLOBALS_PRELUDE + code, map: null };
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
// Project-rooted verbatim static serving (D-X2) — same plugin dev.ts uses.
|
|
356
|
+
projectGameStaticPlugin(() => currentProjectRoot),
|
|
357
|
+
// Intercept project script changes and send a custom HMR event instead
|
|
358
|
+
// of triggering a full page reload — byte-identical to dev.ts's copy
|
|
359
|
+
// (always registered here since a project is ALWAYS open in packaged
|
|
360
|
+
// mode, unlike dev.ts's conditional-on-boot-time-projectPath gate).
|
|
361
|
+
{
|
|
362
|
+
name: 'vgai-script-hmr',
|
|
363
|
+
handleHotUpdate({
|
|
364
|
+
file,
|
|
365
|
+
server,
|
|
366
|
+
}: {
|
|
367
|
+
file: string;
|
|
368
|
+
server: { ws: { send: (msg: unknown) => void } };
|
|
369
|
+
}) {
|
|
370
|
+
if (/\.(ts|tsx|js|jsx)$/.test(file)) {
|
|
371
|
+
server.ws.send({ type: 'custom', event: 'vgai:script-update', data: { file } });
|
|
372
|
+
}
|
|
373
|
+
// Swallow all project file changes — the editor handles scene/asset
|
|
374
|
+
// updates via its own SSE channel (mirrors dev.ts's `return []`).
|
|
375
|
+
return [];
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
optimizeDeps: {
|
|
380
|
+
// C3 (phase-b/c3-r3f-packaged) — SCOPED auto-discovery, not disabled
|
|
381
|
+
// discovery. This used to be `noDiscovery: true` (see git history for
|
|
382
|
+
// the pre-C3 version of this comment): that flag disabled Vite's
|
|
383
|
+
// AUTO-prebundling entirely — both the boot-time crawl AND the lazy,
|
|
384
|
+
// on-request discovery of new bare specifiers — because the DEFAULT
|
|
385
|
+
// crawl target (the project's own `index.html`) follows everything
|
|
386
|
+
// dynamically reachable from it, including the project's `server/`
|
|
387
|
+
// room code (a scaffolded project's `src/main.ts` dynamically imports
|
|
388
|
+
// `../server/rooms` behind a `?net=p2p-host` URL-param branch — a
|
|
389
|
+
// branch esbuild's scanner still statically follows), whose colyseus
|
|
390
|
+
// server transitive deps (`@colyseus/core` -> `@pm2/io`) have no
|
|
391
|
+
// browser-resolvable entry and crash the esbuild prebundle step
|
|
392
|
+
// (`Failed to resolve entry for package "@pm2/io"`).
|
|
393
|
+
//
|
|
394
|
+
// That worked for the react-only CJS fix (C1) because the fix could be
|
|
395
|
+
// fully hardcoded: react/react-dom are ALWAYS present (the editor
|
|
396
|
+
// itself depends on them). It does NOT work for R3F (or any other
|
|
397
|
+
// ecosystem a project's own `package.json` happens to pull in): this
|
|
398
|
+
// server can't hardcode `@react-three/fiber` into `include` for every
|
|
399
|
+
// possible project — most projects don't have it installed, and Vite
|
|
400
|
+
// errors on `include`-ing a dep that isn't there.
|
|
401
|
+
//
|
|
402
|
+
// The actual fix: scope the CRAWL, don't disable it. `entries` below
|
|
403
|
+
// points the crawl at the OPENED PROJECT's own manifest-declared world
|
|
404
|
+
// entry files (`computeProjectOptimizeDepsEntries` /
|
|
405
|
+
// `project-optimize-deps-entries.ts`) instead of `index.html` — the
|
|
406
|
+
// exact per-world mount code the editor's adapter-resolver dynamically
|
|
407
|
+
// imports for Play mode (NEVER the project's own `src/main.ts`
|
|
408
|
+
// bootstrap, which is a standalone-build concern this Vite instance
|
|
409
|
+
// never serves anyway — the editor's own prebuilt SPA answers `/`).
|
|
410
|
+
// A world entry's import graph can reach real client packages
|
|
411
|
+
// (`react`, `@react-three/fiber`, `@react-three/drei`, a legitimate
|
|
412
|
+
// client `@colyseus/sdk` import for real multiplayer) but never
|
|
413
|
+
// `server/` — see `project-optimize-deps-entries.ts`'s doc comment for
|
|
414
|
+
// the empirical proof (a direct `vite.optimizeDeps` run) that this
|
|
415
|
+
// scoping avoids the `@pm2/io` crash for a colyseus-bearing project
|
|
416
|
+
// while a `@react-three/fiber`-bearing world's CJS transitive deps
|
|
417
|
+
// (`use-sync-external-store` and friends) get discovered and
|
|
418
|
+
// prebundled automatically — no allowlist, adapts to whatever the
|
|
419
|
+
// opened project actually has installed.
|
|
420
|
+
//
|
|
421
|
+
// `include` below is now a MINIMUM baseline, not the only mechanism:
|
|
422
|
+
// React's JSX-runtime specifiers are INJECTED by the JSX transform
|
|
423
|
+
// (not written as literal source imports), so even an entries-scoped
|
|
424
|
+
// crawl does not reliably discover them on its own — the repo-root
|
|
425
|
+
// `vite.config.ts` / template `vite.config.ts` `optimizeDeps.include`
|
|
426
|
+
// carry the identical comment/list for the same reason. Kept
|
|
427
|
+
// unconditional (not project-conditional) since react/react-dom are
|
|
428
|
+
// always present (the editor's own react-world mount runtime depends
|
|
429
|
+
// on them regardless of what a given project uses).
|
|
430
|
+
//
|
|
431
|
+
// `react-dom` (bare, NOT just `/client`) was added for C1
|
|
432
|
+
// (`phase-b/c1-react-mount`): `vite-plugin-react-world-runtime.ts`'s
|
|
433
|
+
// synthetic `/__vgai-react-world-runtime` module re-exports `flushSync`
|
|
434
|
+
// from bare `react-dom` (the same peer `react-dom/client`'s `createRoot`
|
|
435
|
+
// comes from — `design-time-layers.ts`'s react-world layer mount needs
|
|
436
|
+
// it from that SAME installed package). Confirmed live at the time:
|
|
437
|
+
// a real-browser Playwright run against a tarball-installed,
|
|
438
|
+
// checkout-absent packaged editor threw exactly `SyntaxError: The
|
|
439
|
+
// requested module '/node_modules/react-dom/index.js' does not
|
|
440
|
+
// provide an export named 'flushSync'` at Play-mode mount before this
|
|
441
|
+
// entry was added.
|
|
442
|
+
include: [
|
|
443
|
+
'react',
|
|
444
|
+
'react-dom',
|
|
445
|
+
'react-dom/client',
|
|
446
|
+
'react/jsx-runtime',
|
|
447
|
+
'react/jsx-dev-runtime',
|
|
448
|
+
],
|
|
449
|
+
entries: projectOptimizeDepsEntries,
|
|
450
|
+
// C3 hardening: belt to the entries-scoping suspenders. Entries-scoping
|
|
451
|
+
// ALREADY keeps the crawl out of `server/` for a well-formed project
|
|
452
|
+
// (so the colyseus server stack is never reached), but a project that
|
|
453
|
+
// VIOLATES D2 by value-importing `server/` room code FROM a world entry
|
|
454
|
+
// would drag `@colyseus/core` -> `@pm2/io` into the crawl and crash the
|
|
455
|
+
// esbuild prebundle step — which, unhandled in the async optimizer,
|
|
456
|
+
// hard-kills the whole packaged process (the only authoring surface).
|
|
457
|
+
// Excluding these SERVER-ONLY names stops esbuild crawling into them, so
|
|
458
|
+
// that pathological world degrades to a benign in-browser import failure
|
|
459
|
+
// instead of process death. Does NOT include `@colyseus/sdk` — the
|
|
460
|
+
// legitimate CLIENT SDK a real multiplayer project imports (D2, dynamic-
|
|
461
|
+
// imported) must still prebundle; it is a separate package and its path
|
|
462
|
+
// is untouched. See `project-optimize-deps-entries.ts`'s
|
|
463
|
+
// `SERVER_ONLY_PREBUNDLE_EXCLUDE` doc comment for the live proof.
|
|
464
|
+
exclude: [...SERVER_ONLY_PREBUNDLE_EXCLUDE],
|
|
465
|
+
},
|
|
466
|
+
resolve: {
|
|
467
|
+
alias: [
|
|
468
|
+
// The `@engine/*` alias project source still uses (pending the
|
|
469
|
+
// `@engine/*` → `@vgai/engine/*` migration deferred to a follow-up
|
|
470
|
+
// slice) — pointed at THIS project's own installed engine version,
|
|
471
|
+
// never a checkout or this editor package's own copy. Omitted
|
|
472
|
+
// entirely when unresolvable (see the warning above) rather than
|
|
473
|
+
// pointing at a wrong/nonexistent directory.
|
|
474
|
+
...(engineSrc ? [{ find: /^@engine\//, replacement: `${engineSrc}/` }] : []),
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
server: {
|
|
478
|
+
middlewareMode: true,
|
|
479
|
+
hmr: { port: HMR_PORT },
|
|
480
|
+
watch: {},
|
|
481
|
+
fs: {
|
|
482
|
+
allow: [projectPath, ...(projectNodeModulesRealPath ? [projectNodeModulesRealPath] : [])],
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// 2. Mount editor API routes (/__editor/*). `engineRoot` has no monorepo
|
|
488
|
+
// meaning in packaged mode (no checkout exists) — it's used by
|
|
489
|
+
// `createEditorServer` only as (a) the "no project open" sentinel
|
|
490
|
+
// default for `projectRoot`, which is never hit here since
|
|
491
|
+
// `projectPath` is always set, and (b) `create-project`'s `monoRoot`
|
|
492
|
+
// (New Project scaffolding from the in-editor UI — a pre-existing gap
|
|
493
|
+
// in packaged mode, see this file's header doc comment). Pointing it at
|
|
494
|
+
// this editor package's own root is the closest available analog and
|
|
495
|
+
// keeps both uses well-defined rather than pointing at nothing.
|
|
496
|
+
const editorRouter = createEditorServer({
|
|
497
|
+
engineRoot: editorPackageRoot,
|
|
498
|
+
projectPath,
|
|
499
|
+
onProjectOpened(newProjectPath: string) {
|
|
500
|
+
const allowed = vite.config.server.fs.allow;
|
|
501
|
+
if (!allowed.includes(newProjectPath)) {
|
|
502
|
+
allowed.push(newProjectPath);
|
|
503
|
+
}
|
|
504
|
+
vite.watcher.add(newProjectPath);
|
|
505
|
+
projectRoots.add(newProjectPath);
|
|
506
|
+
currentProjectRoot = newProjectPath;
|
|
507
|
+
// Session parity with dev.ts (D12/Phase B): keep the registry pointing
|
|
508
|
+
// at the CURRENT project so `vgai edit`/`sessions`/cwd-resolution see
|
|
509
|
+
// switches, not boot state — same call, same shape.
|
|
510
|
+
registerSession({
|
|
511
|
+
project: newProjectPath,
|
|
512
|
+
port: PORT,
|
|
513
|
+
pid: process.pid,
|
|
514
|
+
startedAt: sessionStartedAt,
|
|
515
|
+
});
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
app.use(editorRouter);
|
|
519
|
+
|
|
520
|
+
// 3. The project-rooted Vite instance — handles `/@fs/`, `/@id/`, and any
|
|
521
|
+
// request matching a real file under the project root (module
|
|
522
|
+
// transform + bare-specifier resolution through the PROJECT's own
|
|
523
|
+
// node_modules). `appType: 'custom'` means it calls `next()` instead of
|
|
524
|
+
// synthesizing an HTML/404 response for anything else, so requests for
|
|
525
|
+
// the editor's OWN app (`/`, `/assets/*`) fall through to step 4.
|
|
526
|
+
app.use(vite.middlewares);
|
|
527
|
+
|
|
528
|
+
// 4. Serve the editor's own PREBUILT SPA (static — no dev-mode transform
|
|
529
|
+
// of the editor's own source; see this file's header doc comment).
|
|
530
|
+
app.use(express.static(distPath));
|
|
531
|
+
app.use((_req, res) => {
|
|
532
|
+
res.sendFile(path.join(distPath, 'index.html'));
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// 5. Start Express
|
|
536
|
+
const sessionStartedAt = new Date().toISOString();
|
|
537
|
+
const server = app.listen(PORT, HOST, () => {
|
|
538
|
+
console.log(
|
|
539
|
+
`\n \x1b[32mEditor server\x1b[0m (packaged) running at \x1b[36mhttp://${HOST}:${PORT}\x1b[0m`,
|
|
540
|
+
);
|
|
541
|
+
console.log(` \x1b[33mProject\x1b[0m: ${projectPath}`);
|
|
542
|
+
console.log(` \x1b[33mEditor\x1b[0m: \x1b[36mhttp://${HOST}:${PORT}/\x1b[0m\n`);
|
|
543
|
+
// D12/Phase B: announce this session so `vgai edit`/`sessions`/`play`
|
|
544
|
+
// (cwd-resolution) see the packaged runtime exactly like dev.ts's.
|
|
545
|
+
registerSession({
|
|
546
|
+
project: projectPath,
|
|
547
|
+
port: PORT,
|
|
548
|
+
pid: process.pid,
|
|
549
|
+
startedAt: sessionStartedAt,
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
server.on('error', (err: NodeJS.ErrnoException) => {
|
|
554
|
+
console.error(`\n \x1b[31m${friendlyListenError(err, PORT, HOST)}\x1b[0m\n`);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
const shutdown = () => {
|
|
559
|
+
unregisterSession(process.pid);
|
|
560
|
+
vite.close();
|
|
561
|
+
server.close();
|
|
562
|
+
};
|
|
563
|
+
process.once('SIGINT', shutdown);
|
|
564
|
+
process.once('SIGTERM', shutdown);
|
|
565
|
+
process.once('exit', () => unregisterSession(process.pid));
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
main().catch((err) => {
|
|
569
|
+
console.error('Failed to start packaged editor server:', err);
|
|
570
|
+
process.exit(1);
|
|
571
|
+
});
|
package/server/prod.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor production server — Express serves built frontend + API.
|
|
3
|
+
*
|
|
4
|
+
* Used by Electron or standalone production deployment.
|
|
5
|
+
* Run with:
|
|
6
|
+
* npx tsx packages/editor/server/prod.ts
|
|
7
|
+
*
|
|
8
|
+
* Supports VGAI_PROJECT env var for initial project path.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import express from 'express';
|
|
14
|
+
import { canonicalProjectRoot } from './canonical-path';
|
|
15
|
+
import { createEditorServer } from './editor-server';
|
|
16
|
+
import { friendlyListenError, resolveBindHost } from './server-utils';
|
|
17
|
+
|
|
18
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const PORT = Number(process.env['PORT']) || 5173;
|
|
20
|
+
// S3: bind to loopback by default; opt-in to a wider interface via env.
|
|
21
|
+
const HOST = resolveBindHost();
|
|
22
|
+
const engineRoot = process.env['VGAI_ENGINE_ROOT']
|
|
23
|
+
? path.resolve(process.env['VGAI_ENGINE_ROOT'])
|
|
24
|
+
: path.resolve(__dirname, '../../..');
|
|
25
|
+
// Canonicalized — see canonical-path.ts's doc comment (dev.ts's sibling fix).
|
|
26
|
+
const projectPath = process.env['VGAI_PROJECT']
|
|
27
|
+
? canonicalProjectRoot(process.env['VGAI_PROJECT'])
|
|
28
|
+
: undefined;
|
|
29
|
+
|
|
30
|
+
async function main(): Promise<void> {
|
|
31
|
+
const app = express();
|
|
32
|
+
|
|
33
|
+
// 1. Mount editor API routes
|
|
34
|
+
const editorRouter = createEditorServer({ engineRoot, projectPath, serveScripts: true });
|
|
35
|
+
app.use(editorRouter);
|
|
36
|
+
|
|
37
|
+
// 2. Serve built frontend from dist/
|
|
38
|
+
const distPath = path.resolve(engineRoot, 'dist');
|
|
39
|
+
app.use(express.static(distPath));
|
|
40
|
+
|
|
41
|
+
// Fallback: serve index.html for unmatched routes (SPA behavior)
|
|
42
|
+
app.use((_req, res) => {
|
|
43
|
+
res.sendFile(path.join(distPath, 'index.html'));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// 3. Start Express
|
|
47
|
+
const server = app.listen(PORT, HOST, () => {
|
|
48
|
+
const addr = server.address();
|
|
49
|
+
const actualPort = typeof addr === 'object' && addr ? addr.port : PORT;
|
|
50
|
+
console.log(`\n \x1b[32mProduction server\x1b[0m running at \x1b[36mhttp://${HOST}:${actualPort}\x1b[0m`);
|
|
51
|
+
if (projectPath) {
|
|
52
|
+
console.log(` \x1b[33mProject\x1b[0m: ${projectPath}`);
|
|
53
|
+
}
|
|
54
|
+
console.log();
|
|
55
|
+
// Machine-readable signal for Electron to detect server readiness
|
|
56
|
+
console.log(`EDITOR_SERVER_READY:${actualPort}`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// SC5: friendly message instead of an opaque crash on port conflict.
|
|
60
|
+
server.on('error', (err: NodeJS.ErrnoException) => {
|
|
61
|
+
console.error(`\n \x1b[31m${friendlyListenError(err, PORT, HOST)}\x1b[0m\n`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const shutdown = () => {
|
|
66
|
+
server.close();
|
|
67
|
+
};
|
|
68
|
+
process.once('SIGINT', shutdown);
|
|
69
|
+
process.once('SIGTERM', shutdown);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
main().catch((err) => {
|
|
73
|
+
console.error('Failed to start production server:', err);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|