@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,27 @@
|
|
|
1
|
+
interface ButtonProps {
|
|
2
|
+
label: string;
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Button({ label, onClick, disabled = false }: ButtonProps) {
|
|
8
|
+
return (
|
|
9
|
+
<button
|
|
10
|
+
type="button"
|
|
11
|
+
onClick={onClick}
|
|
12
|
+
disabled={disabled}
|
|
13
|
+
style={{
|
|
14
|
+
background: disabled ? '#222' : '#2a3a4a',
|
|
15
|
+
color: disabled ? '#555' : '#9cf',
|
|
16
|
+
border: '1px solid #445',
|
|
17
|
+
borderRadius: 3,
|
|
18
|
+
padding: '3px 10px',
|
|
19
|
+
fontFamily: 'monospace',
|
|
20
|
+
fontSize: 12,
|
|
21
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
{label}
|
|
25
|
+
</button>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Button } from './Button';
|
|
3
|
+
import { Panel } from './Panel';
|
|
4
|
+
|
|
5
|
+
export interface DefaultHudProps {
|
|
6
|
+
/** Panel title — plain prop, no VGAI binding-expression language. */
|
|
7
|
+
title: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The template's default game HUD (C1,
|
|
12
|
+
* docs/AI-NATIVE-AUTHORING-IMPLEMENTATION-SPEC.md §9 "Make React the
|
|
13
|
+
* Template Default" / §5.1 React UI Contract): ordinary React — a plain
|
|
14
|
+
* `.tsx` component driven by props and a `useState` hook, normal inline
|
|
15
|
+
* styling (no CSS files), no `UINode`/Scene UI binding language.
|
|
16
|
+
*
|
|
17
|
+
* Mounted through the existing overlay seam — `mountUI(ctx.uiContainer, ...)`
|
|
18
|
+
* — by `mount-default-hud.tsx`, called from `../scripts/main.ts`'s `setup()`.
|
|
19
|
+
* Replace or delete this component freely; it exists to prove (and
|
|
20
|
+
* demonstrate) the React-HUD-by-default path, not to be load-bearing
|
|
21
|
+
* gameplay UI.
|
|
22
|
+
*/
|
|
23
|
+
export function DefaultHud({ title }: DefaultHudProps) {
|
|
24
|
+
const [paused, setPaused] = useState(false);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Panel title={title} position="top-left">
|
|
28
|
+
<div
|
|
29
|
+
data-testid="default-hud-status"
|
|
30
|
+
style={{ color: paused ? '#dd3d3d' : '#3ddc65', fontSize: 12 }}
|
|
31
|
+
>
|
|
32
|
+
{paused ? 'Paused' : 'Running'}
|
|
33
|
+
</div>
|
|
34
|
+
<Button
|
|
35
|
+
label={paused ? 'Resume' : 'Pause'}
|
|
36
|
+
onClick={() => setPaused((wasPaused) => !wasPaused)}
|
|
37
|
+
/>
|
|
38
|
+
</Panel>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface KeyHintProps {
|
|
2
|
+
keys: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function KeyHint({ keys, label }: KeyHintProps) {
|
|
7
|
+
return (
|
|
8
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 4, color: '#888' }}>
|
|
9
|
+
<kbd
|
|
10
|
+
style={{
|
|
11
|
+
background: '#333',
|
|
12
|
+
border: '1px solid #555',
|
|
13
|
+
borderRadius: 3,
|
|
14
|
+
padding: '1px 5px',
|
|
15
|
+
fontFamily: 'monospace',
|
|
16
|
+
fontSize: 11,
|
|
17
|
+
color: '#ccc',
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
{keys}
|
|
21
|
+
</kbd>
|
|
22
|
+
{label && <span>{label}</span>}
|
|
23
|
+
</span>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
4
|
+
|
|
5
|
+
interface PanelProps {
|
|
6
|
+
title: string;
|
|
7
|
+
position?: Position;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const positionStyles: Record<Position, React.CSSProperties> = {
|
|
12
|
+
'top-left': { top: 8, left: 8 },
|
|
13
|
+
'top-right': { top: 8, right: 8 },
|
|
14
|
+
'bottom-left': { bottom: 8, left: 8 },
|
|
15
|
+
'bottom-right': { bottom: 8, right: 8 },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function Panel({ title, position = 'bottom-left', children }: PanelProps) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
style={{
|
|
22
|
+
position: 'absolute',
|
|
23
|
+
...positionStyles[position],
|
|
24
|
+
background: 'rgba(18,18,18,0.88)',
|
|
25
|
+
border: '1px solid #444',
|
|
26
|
+
borderRadius: 4,
|
|
27
|
+
padding: '8px 12px',
|
|
28
|
+
fontFamily: 'monospace',
|
|
29
|
+
fontSize: 12,
|
|
30
|
+
color: '#ddd',
|
|
31
|
+
minWidth: 180,
|
|
32
|
+
pointerEvents: 'auto',
|
|
33
|
+
userSelect: 'none',
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<div
|
|
37
|
+
style={{
|
|
38
|
+
color: '#aaa',
|
|
39
|
+
fontSize: 10,
|
|
40
|
+
textTransform: 'uppercase',
|
|
41
|
+
letterSpacing: 1,
|
|
42
|
+
marginBottom: 8,
|
|
43
|
+
borderBottom: '1px solid #333',
|
|
44
|
+
paddingBottom: 4,
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
{title}
|
|
48
|
+
</div>
|
|
49
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>{children}</div>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { InputManager } from '@engine/input/input-manager';
|
|
2
|
+
import { RebindController, type RebindState } from '@engine/input/rebind-controller';
|
|
3
|
+
import { useCallback, useEffect, useReducer, useRef, useState } from 'react';
|
|
4
|
+
import { Button } from './Button';
|
|
5
|
+
import { Panel } from './Panel';
|
|
6
|
+
|
|
7
|
+
export interface RebindPanelProps {
|
|
8
|
+
/** The running game's InputManager (`ctx.input`) — this component reads
|
|
9
|
+
* and mutates it directly through F3's public rebinding API
|
|
10
|
+
* (`getBindings`/`replaceBinding`/`resetBindings`/`getPrompt`), the same
|
|
11
|
+
* API a CLI/SDK caller would use at the file level via B2's
|
|
12
|
+
* `project.inputMap.*` operations. */
|
|
13
|
+
input: InputManager;
|
|
14
|
+
/** Which registered actions to list/rebind (e.g. the game's own
|
|
15
|
+
* `input.actionNames()`, or a curated subset for this HUD). */
|
|
16
|
+
actionNames: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* F3 (spec §12 "Add Rebinding and Prompts") — a keyboard rebinding panel,
|
|
21
|
+
* demonstrating the AC "Rebinding UI is normal React, not Scene UI": this is
|
|
22
|
+
* an ordinary `.tsx` component (props + `useState`/`useReducer`/`useEffect`,
|
|
23
|
+
* plain inline styling via the C1 kit's `Panel`/`Button`) with no
|
|
24
|
+
* `@vgai/scene-ui` import and no `UINode` anywhere — mount it exactly like
|
|
25
|
+
* `DefaultHud` (`mountUI(ctx.uiContainer, <RebindPanel input={ctx.input}
|
|
26
|
+
* actionNames={[...]} />)`).
|
|
27
|
+
*
|
|
28
|
+
* All the actual rebind LOGIC (listening -> capture -> apply, with a
|
|
29
|
+
* collision surfaced structurally instead of silently applied) lives in the
|
|
30
|
+
* framework-free `RebindController` (`@engine/input/rebind-controller`) —
|
|
31
|
+
* this component is a thin wire-up: it forwards a captured `keydown` to
|
|
32
|
+
* `controller.capture()` while listening, and renders whatever `RebindState`
|
|
33
|
+
* comes back. That split is what makes the interaction itself unit-testable
|
|
34
|
+
* with no DOM (`packages/engine/test/rebind-controller.test.ts`); this file
|
|
35
|
+
* only needs a structural check
|
|
36
|
+
* (`packages/engine/test/input-rebind-panel-structural.test.ts`) that it
|
|
37
|
+
* really does wire up that controller instead of reinventing the state
|
|
38
|
+
* machine inline.
|
|
39
|
+
*/
|
|
40
|
+
export function RebindPanel({ input, actionNames }: RebindPanelProps) {
|
|
41
|
+
const controllerRef = useRef<RebindController | null>(null);
|
|
42
|
+
if (!controllerRef.current) controllerRef.current = new RebindController(input);
|
|
43
|
+
const controller = controllerRef.current;
|
|
44
|
+
|
|
45
|
+
const [rebindState, setRebindState] = useState<RebindState>(() => controller.getState());
|
|
46
|
+
// Bindings/prompts are read straight off `input` (mutable, not React
|
|
47
|
+
// state) on every render — this reducer's only job is forcing a re-render
|
|
48
|
+
// after a mutation (reset/apply) that doesn't itself change `rebindState`
|
|
49
|
+
// in a way React would otherwise notice.
|
|
50
|
+
const [, forceRefresh] = useReducer((n: number) => n + 1, 0);
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (rebindState.status !== 'listening') return undefined;
|
|
54
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
setRebindState(controller.capture({ type: 'key', code: e.code }));
|
|
57
|
+
forceRefresh();
|
|
58
|
+
};
|
|
59
|
+
window.addEventListener('keydown', onKeyDown);
|
|
60
|
+
return () => window.removeEventListener('keydown', onKeyDown);
|
|
61
|
+
}, [rebindState.status, controller]);
|
|
62
|
+
|
|
63
|
+
const startListening = useCallback(
|
|
64
|
+
(actionName: string) => {
|
|
65
|
+
controller.listen(actionName, 'replace', 0);
|
|
66
|
+
setRebindState(controller.getState());
|
|
67
|
+
},
|
|
68
|
+
[controller],
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const cancelListening = useCallback(() => {
|
|
72
|
+
controller.cancel();
|
|
73
|
+
setRebindState(controller.getState());
|
|
74
|
+
}, [controller]);
|
|
75
|
+
|
|
76
|
+
const overrideConflict = useCallback(() => {
|
|
77
|
+
setRebindState(controller.resolveOverride());
|
|
78
|
+
forceRefresh();
|
|
79
|
+
}, [controller]);
|
|
80
|
+
|
|
81
|
+
const resetAction = useCallback(
|
|
82
|
+
(actionName: string) => {
|
|
83
|
+
input.resetBindings(actionName);
|
|
84
|
+
forceRefresh();
|
|
85
|
+
},
|
|
86
|
+
[input],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const isListening = rebindState.status === 'listening';
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Panel title="Rebind Controls" position="top-right">
|
|
93
|
+
{actionNames.map((actionName) => {
|
|
94
|
+
const listeningForThis = isListening && rebindState.actionName === actionName;
|
|
95
|
+
const bindings = input.getBindings(actionName);
|
|
96
|
+
const prompt = input.getPrompt(actionName, 'keyboard');
|
|
97
|
+
const currentLabel = listeningForThis
|
|
98
|
+
? 'Press a key…'
|
|
99
|
+
: (prompt?.label ?? (bindings.length > 0 ? bindings[0]!.type : 'Unbound'));
|
|
100
|
+
return (
|
|
101
|
+
<div key={actionName} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
|
102
|
+
<span style={{ flex: 1, color: '#ccc' }}>{actionName}</span>
|
|
103
|
+
<span style={{ color: '#9cf', minWidth: 72, textAlign: 'right' }}>{currentLabel}</span>
|
|
104
|
+
<Button
|
|
105
|
+
label="Rebind"
|
|
106
|
+
onClick={() => startListening(actionName)}
|
|
107
|
+
disabled={isListening}
|
|
108
|
+
/>
|
|
109
|
+
<Button label="Reset" onClick={() => resetAction(actionName)} disabled={isListening} />
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
})}
|
|
113
|
+
{rebindState.status === 'conflict' && (
|
|
114
|
+
<div style={{ color: '#f66', display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|
115
|
+
<span>Conflicts with: {rebindState.conflicts.map((c) => c.actionName).join(', ')}</span>
|
|
116
|
+
<div style={{ display: 'flex', gap: 6 }}>
|
|
117
|
+
<Button label="Use Anyway" onClick={overrideConflict} />
|
|
118
|
+
<Button label="Cancel" onClick={cancelListening} />
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
{isListening && (
|
|
123
|
+
<div style={{ display: 'flex' }}>
|
|
124
|
+
<Button label="Cancel" onClick={cancelListening} />
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
</Panel>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface SliderProps {
|
|
2
|
+
label: string;
|
|
3
|
+
value: number;
|
|
4
|
+
min: number;
|
|
5
|
+
max: number;
|
|
6
|
+
step?: number;
|
|
7
|
+
onChange: (value: number) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function Slider({ label, value, min, max, step = 0.01, onChange }: SliderProps) {
|
|
11
|
+
return (
|
|
12
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
13
|
+
<span style={{ minWidth: 90, color: '#ccc' }}>{label}</span>
|
|
14
|
+
<input
|
|
15
|
+
type="range"
|
|
16
|
+
min={min}
|
|
17
|
+
max={max}
|
|
18
|
+
step={step}
|
|
19
|
+
value={value}
|
|
20
|
+
onChange={(e) => onChange(parseFloat(e.target.value))}
|
|
21
|
+
style={{ flex: 1, accentColor: '#4af', cursor: 'pointer' }}
|
|
22
|
+
/>
|
|
23
|
+
<span style={{ minWidth: 36, textAlign: 'right', color: '#aaa' }}>
|
|
24
|
+
{value.toFixed(step < 0.1 ? 2 : 1)}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface StatusDotProps {
|
|
2
|
+
color: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function StatusDot({ color, label }: StatusDotProps) {
|
|
7
|
+
return (
|
|
8
|
+
<span style={{ display: 'flex', alignItems: 'center', gap: 6, color: '#ccc' }}>
|
|
9
|
+
<span
|
|
10
|
+
style={{
|
|
11
|
+
width: 8,
|
|
12
|
+
height: 8,
|
|
13
|
+
borderRadius: '50%',
|
|
14
|
+
background: color,
|
|
15
|
+
flexShrink: 0,
|
|
16
|
+
boxShadow: `0 0 4px ${color}`,
|
|
17
|
+
}}
|
|
18
|
+
/>
|
|
19
|
+
{label}
|
|
20
|
+
</span>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface ToggleProps {
|
|
2
|
+
label: string;
|
|
3
|
+
value: boolean;
|
|
4
|
+
onChange: (value: boolean) => void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Toggle({ label, value, onChange }: ToggleProps) {
|
|
8
|
+
return (
|
|
9
|
+
<label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
|
|
10
|
+
<span style={{ flex: 1, color: '#ccc' }}>{label}</span>
|
|
11
|
+
<input
|
|
12
|
+
type="checkbox"
|
|
13
|
+
checked={value}
|
|
14
|
+
onChange={(e) => onChange(e.target.checked)}
|
|
15
|
+
style={{ accentColor: '#4af', width: 14, height: 14, cursor: 'pointer' }}
|
|
16
|
+
/>
|
|
17
|
+
</label>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin re-export of the engine-published state bridge (D-Z5,
|
|
3
|
+
* `docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md` §D-Z5) — `GameProvider`/`useGame`/
|
|
4
|
+
* `useGameState`/`useWorldObservation` now live canonically at
|
|
5
|
+
* `@engine/react/game-state` (`packages/engine/src/react/game-state.tsx`,
|
|
6
|
+
* the spec this file used to BE before D-Z5; see that module's doc comment
|
|
7
|
+
* for the full implementation and the context-identity rule it documents).
|
|
8
|
+
*
|
|
9
|
+
* This file KEEPS EXISTING on purpose — every scaffolded project still has
|
|
10
|
+
* `src/ui/game-state.tsx`, so:
|
|
11
|
+
* - `packages/editor/vite-plugin-react-world-provider.ts`'s virtual module
|
|
12
|
+
* (`export { GameProvider } from '/@fs/<root>/src/ui/game-state.tsx'`)
|
|
13
|
+
* keeps working byte-for-byte — it re-exports from THIS file, which now
|
|
14
|
+
* re-exports from the engine, but the file it points at (and the
|
|
15
|
+
* identity `useGame()` resolves against) is unchanged.
|
|
16
|
+
* - a react-world entry's own relative `import { useGameState } from
|
|
17
|
+
* './ui/game-state'` keeps resolving here too — both routes still
|
|
18
|
+
* converge on ONE module instance (this file), which itself resolves the
|
|
19
|
+
* engine's `@engine/react/game-state` exactly once, so `createContext()`
|
|
20
|
+
* runs exactly once per project. No context split.
|
|
21
|
+
*
|
|
22
|
+
* Adoption of the engine module is an OPTION, not a migration: existing
|
|
23
|
+
* projects that already have their OWN full copy of this file (their own
|
|
24
|
+
* `createContext`) are untouched by this change — only NEW projects
|
|
25
|
+
* scaffolded from the template get this canonical re-export. A project that
|
|
26
|
+
* wants a customized bridge can still replace this file with its own full
|
|
27
|
+
* implementation, exactly as before.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
GameProvider,
|
|
32
|
+
requireWorldObserver,
|
|
33
|
+
shallow,
|
|
34
|
+
useGame,
|
|
35
|
+
useGameState,
|
|
36
|
+
useWorldObservation,
|
|
37
|
+
} from '@engine/react/game-state';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Button } from './Button';
|
|
2
|
+
export { KeyHint } from './KeyHint';
|
|
3
|
+
export { Panel } from './Panel';
|
|
4
|
+
export { RebindPanel } from './RebindPanel';
|
|
5
|
+
export { Slider } from './Slider';
|
|
6
|
+
export { StatusDot } from './StatusDot';
|
|
7
|
+
export { Toggle } from './Toggle';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DefaultHud } from './DefaultHud';
|
|
2
|
+
import { mountUI } from './mount-ui';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mounts the template's default React HUD into the shared UI overlay
|
|
6
|
+
* (`ctx.uiContainer` — `pointer-events:none`; `Panel`/`Button` inside opt
|
|
7
|
+
* back in via `pointer-events:auto`, so the game canvas keeps receiving
|
|
8
|
+
* pointer events everywhere except the HUD's own controls) and returns an
|
|
9
|
+
* unmount function. Kept as its own `.tsx` module so `../scripts/main.ts` —
|
|
10
|
+
* the game SETUP script, not a component — never needs JSX syntax itself.
|
|
11
|
+
*
|
|
12
|
+
* Usage (see `../scripts/main.ts`):
|
|
13
|
+
* const unmountHud = mountDefaultHud(ctx.uiContainer);
|
|
14
|
+
* // ... later, in the returned GameCleanup:
|
|
15
|
+
* // dispose() { unmountHud(); sceneInstance.dispose(); }
|
|
16
|
+
*/
|
|
17
|
+
export function mountDefaultHud(container: HTMLDivElement): () => void {
|
|
18
|
+
return mountUI(container, <DefaultHud title="Game Status" />);
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mount a React element into a container div and return a cleanup function.
|
|
6
|
+
*
|
|
7
|
+
* Usage in example dispose():
|
|
8
|
+
* const unmount = mountUI(ctx.uiContainer, <MyHUD />);
|
|
9
|
+
* return { dispose: unmount };
|
|
10
|
+
*/
|
|
11
|
+
export function mountUI(container: HTMLDivElement, element: ReactNode): () => void {
|
|
12
|
+
const root = createRoot(container);
|
|
13
|
+
root.render(element);
|
|
14
|
+
return () => root.unmount();
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noUncheckedIndexedAccess": true,
|
|
9
|
+
"noFallthroughCasesInSwitch": true,
|
|
10
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
11
|
+
"exactOptionalPropertyTypes": true,
|
|
12
|
+
"experimentalDecorators": true,
|
|
13
|
+
"useDefineForClassFields": false,
|
|
14
|
+
"noUnusedLocals": true,
|
|
15
|
+
"noUnusedParameters": true,
|
|
16
|
+
"verbatimModuleSyntax": true,
|
|
17
|
+
"esModuleInterop": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"isolatedModules": true,
|
|
21
|
+
"skipLibCheck": true,
|
|
22
|
+
"noEmit": true,
|
|
23
|
+
"jsx": "react-jsx",
|
|
24
|
+
"types": ["vite/client"],
|
|
25
|
+
"baseUrl": ".",
|
|
26
|
+
"paths": {
|
|
27
|
+
"@engine/*": ["../../engine/src/*"],
|
|
28
|
+
"@editor/*": ["../src/*"]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"../../engine/src/types-n8ao.d.ts",
|
|
33
|
+
"../../engine/src/types-realism-effects.d.ts"
|
|
34
|
+
],
|
|
35
|
+
"include": ["src"]
|
|
36
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { InputMapFileSchema } from '@vgai/engine/input/schema';
|
|
3
|
+
import { parseInstancesFile, parseMaterialFile, SceneParseError } from '@vgai/engine/scene/parse';
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Content validation for the fetched-asset formats (`.mat.json` /
|
|
7
|
+
// `.inputmap.json` / `.instances.json`), through the SAME
|
|
8
|
+
// engine Zod schemas the runtime rejects them with at fetch time. Used by
|
|
9
|
+
// `validate-scenes.ts` (the `npm run validate-scenes` command —
|
|
10
|
+
// previously these formats were only existence-checked when a scene
|
|
11
|
+
// referenced them, so a present-but-malformed asset passed the command and
|
|
12
|
+
// failed at load) and directly unit-testable against a tmpdir
|
|
13
|
+
// (`packages/editor/test/validate-asset-content.test.ts`) so broken fixtures
|
|
14
|
+
// never need to live inside the template.
|
|
15
|
+
//
|
|
16
|
+
// Separate module (rather than inline in validate-scenes.ts) because
|
|
17
|
+
// validate-scenes.ts is a top-level script — importing it executes it.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
/** The asset formats this module content-validates (engine Zod schemas). */
|
|
21
|
+
export const ASSET_CONTENT_EXTENSIONS = ['.mat.json', '.inputmap.json', '.instances.json'] as const;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Content-parse one asset file through its engine Zod schema. Returns error
|
|
25
|
+
* strings in validate-scenes' established `${file}: ${path}: ${message}`
|
|
26
|
+
* format (empty array = valid). Throws only on a programming error (a path
|
|
27
|
+
* that isn't one of the three supported formats).
|
|
28
|
+
*/
|
|
29
|
+
export function validateAssetContentFile(path: string): string[] {
|
|
30
|
+
let raw: unknown;
|
|
31
|
+
try {
|
|
32
|
+
raw = JSON.parse(readFileSync(path, 'utf-8'));
|
|
33
|
+
} catch (e) {
|
|
34
|
+
return [`${path}: invalid JSON — ${e instanceof Error ? e.message : String(e)}`];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const errors: string[] = [];
|
|
38
|
+
if (path.endsWith('.mat.json')) {
|
|
39
|
+
// The engine has a ready-made SceneParseError-throwing wrapper for
|
|
40
|
+
// materials — reuse it (same function the runtime's fetch path uses).
|
|
41
|
+
try {
|
|
42
|
+
parseMaterialFile(raw, path);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (e instanceof SceneParseError) {
|
|
45
|
+
for (const issue of e.issues) {
|
|
46
|
+
errors.push(`${path}: ${issue.path.join('.')}: ${issue.message}`);
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
errors.push(`${path}: ${e}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} else if (path.endsWith('.inputmap.json')) {
|
|
53
|
+
const result = InputMapFileSchema.safeParse(raw);
|
|
54
|
+
if (!result.success) {
|
|
55
|
+
for (const issue of result.error.issues) {
|
|
56
|
+
errors.push(`${path}: ${issue.path.join('.')}: ${issue.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else if (path.endsWith('.instances.json')) {
|
|
60
|
+
// Same ready-made SceneParseError-throwing wrapper pattern as .mat.json (F3).
|
|
61
|
+
try {
|
|
62
|
+
parseInstancesFile(raw, path);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
if (e instanceof SceneParseError) {
|
|
65
|
+
for (const issue of e.issues) {
|
|
66
|
+
errors.push(`${path}: ${issue.path.join('.')}: ${issue.message}`);
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
errors.push(`${path}: ${e}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`validateAssetContentFile: "${path}" is not one of the supported formats (${ASSET_CONTENT_EXTENSIONS.join(', ')})`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return errors;
|
|
78
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { loadGameManifestFile } from '@vgai/engine/manifest/load-file';
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Usage: npx tsx validate-manifest.ts [manifestPath...]
|
|
7
|
+
//
|
|
8
|
+
// Single source of truth for game-manifest validation, shipped IN the
|
|
9
|
+
// project template (mirrors validate-scenes.ts) so every scaffolded game
|
|
10
|
+
// gets a working `npm run validate-manifest`. Validates each given
|
|
11
|
+
// `vgai.game.json` path via `loadGameManifestFile` (parse -> cross-field
|
|
12
|
+
// checks -> resolution, see docs/GAME-MANIFEST-DESIGN.md §5) and prints the
|
|
13
|
+
// resolved world list (id, kind, resolved adapter identity, per-context
|
|
14
|
+
// capability tiers) on success. Any failure prints a descriptive error and
|
|
15
|
+
// exits 1.
|
|
16
|
+
//
|
|
17
|
+
// Defaults to THIS template's own manifest (`vgai.game.json`, a sibling of
|
|
18
|
+
// this script) when no path is given, so `npm run validate-manifest` works
|
|
19
|
+
// out of the box both from the monorepo root and from a scaffolded project.
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
const defaultManifestPath = fileURLToPath(new URL('./vgai.game.json', import.meta.url));
|
|
23
|
+
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const manifestPaths = args.length > 0 ? args.map((p) => resolve(p)) : [defaultManifestPath];
|
|
26
|
+
|
|
27
|
+
let hadError = false;
|
|
28
|
+
|
|
29
|
+
for (const manifestPath of manifestPaths) {
|
|
30
|
+
try {
|
|
31
|
+
const resolved = loadGameManifestFile(manifestPath);
|
|
32
|
+
console.log(
|
|
33
|
+
`${manifestPath}: OK — "${resolved.name}" v${resolved.version} (engine ${resolved.engine.version})`,
|
|
34
|
+
);
|
|
35
|
+
for (const world of resolved.worlds) {
|
|
36
|
+
const { adapter } = world;
|
|
37
|
+
const adapterLabel =
|
|
38
|
+
adapter.type === 'ingest' ? `${adapter.identity} (${adapter.strategy})` : adapter.identity;
|
|
39
|
+
console.log(
|
|
40
|
+
` world "${world.id}" kind=${world.kind} adapter=${adapterLabel} ` +
|
|
41
|
+
`tiers={local: ${world.capabilities.local}, hosted: ${world.capabilities.hosted}}`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
hadError = true;
|
|
46
|
+
console.error(`${manifestPath}: FAILED`);
|
|
47
|
+
console.error(` ${e instanceof Error ? e.message : String(e)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (hadError) {
|
|
52
|
+
process.exit(1);
|
|
53
|
+
} else {
|
|
54
|
+
console.log(`Validated ${manifestPaths.length} manifest(s) — all OK`);
|
|
55
|
+
}
|