@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,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viewport pick context (B4, D12) — the camera/canvas seam that
|
|
3
|
+
* `VgaiSceneAuthoringAdapter.pickable.pick` needs but cannot own itself: both
|
|
4
|
+
* live on `EditorViewport`, not on the adapter (the adapter only ever held a
|
|
5
|
+
* `store` — see its own doc comment). A tiny module-level slot, same shape as
|
|
6
|
+
* `./active-systems.ts`: `EditorViewport`'s constructor sets it once its
|
|
7
|
+
* camera/canvas exist; its `dispose()` clears it.
|
|
8
|
+
*
|
|
9
|
+
* Absent (module load, a headless unit test that builds the adapter with no
|
|
10
|
+
* live viewport, or after `dispose()`) ⇒ `pick()` returns `null` — an honest
|
|
11
|
+
* degrade, never a throw.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type * as THREE from 'three';
|
|
15
|
+
|
|
16
|
+
export interface ViewportPickContext {
|
|
17
|
+
readonly camera: THREE.Camera;
|
|
18
|
+
readonly canvas: HTMLCanvasElement;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let _ctx: ViewportPickContext | null = null;
|
|
22
|
+
|
|
23
|
+
/** Install/clear the live viewport's pick context (`EditorViewport` ctor/dispose). */
|
|
24
|
+
export function setViewportPickContext(ctx: ViewportPickContext | null): void {
|
|
25
|
+
_ctx = ctx;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The live viewport's camera/canvas, or `null` when none is mounted. */
|
|
29
|
+
export function getViewportPickContext(): ViewportPickContext | null {
|
|
30
|
+
return _ctx;
|
|
31
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared threejs viewport raycast pick (B4, D12) — the adapter-AGNOSTIC
|
|
3
|
+
* entity-under-the-pointer raycast, extracted verbatim from
|
|
4
|
+
* `editor-viewport.ts`'s former `_raycastEntity` so EVERY threejs-backed
|
|
5
|
+
* authoring adapter whose live objects sit in `store.objectMap` reuses the
|
|
6
|
+
* exact same logic:
|
|
7
|
+
* - first-party `VgaiSceneAuthoringAdapter` (edit mode's focused world),
|
|
8
|
+
* - `IngestAuthoringAdapter` (an ingested foreign threejs game — bare ingest
|
|
9
|
+
* mode AND the threejs child of a multi-world PLAY composite).
|
|
10
|
+
*
|
|
11
|
+
* Pre-B4, `_onPointerUp` ran this raycast UNCONDITIONALLY against
|
|
12
|
+
* `store.objectMap` regardless of which adapter was active, so an ingest/
|
|
13
|
+
* multi-world-play canvas click selected the object under the pointer. B4's
|
|
14
|
+
* `pickTopmost` routes through the active adapter's `pickable` instead, so
|
|
15
|
+
* that behavior only survives if each threejs adapter exposes a `pickable`
|
|
16
|
+
* backed by THIS helper (the raycast never depended on `SceneEntity`/`.vscn` —
|
|
17
|
+
* only on `store.objectMap` + `userData.entityId` + `store.isEntityLocked`,
|
|
18
|
+
* all of which an ingest mount populates identically to a first-party one).
|
|
19
|
+
*
|
|
20
|
+
* The camera/canvas live only on `EditorViewport`, reached through the
|
|
21
|
+
* `viewport-pick-context.ts` seam (its ctor/`dispose()` set/clear it). Absent
|
|
22
|
+
* (a headless unit test, or no live viewport mounted) ⇒ `null`, an honest
|
|
23
|
+
* degrade rather than a throw. Uses its OWN `THREE.Raycaster` with
|
|
24
|
+
* `layers.enableAll()` replicated so it hits gizmo-adjacent EDITOR_LAYER-tagged
|
|
25
|
+
* geometry exactly like the original.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { getUserData } from '@engine/scene/user-data';
|
|
29
|
+
import * as THREE from 'three';
|
|
30
|
+
import type { EditorStore } from '../editor-store';
|
|
31
|
+
import { getViewportPickContext } from './viewport-pick-context';
|
|
32
|
+
|
|
33
|
+
/** Raycast `store.objectMap` and return the entity id under `(clientX,
|
|
34
|
+
* clientY)`, or `null`. Skips editor-helper geometry and locked entities,
|
|
35
|
+
* identical to the pre-B4 viewport raycast. */
|
|
36
|
+
export function raycastPick(store: EditorStore, clientX: number, clientY: number): string | null {
|
|
37
|
+
const ctx = getViewportPickContext();
|
|
38
|
+
if (!ctx) return null; // no live viewport mounted — honest degrade
|
|
39
|
+
const rect = ctx.canvas.getBoundingClientRect();
|
|
40
|
+
const mouse = new THREE.Vector2(
|
|
41
|
+
((clientX - rect.left) / rect.width) * 2 - 1,
|
|
42
|
+
-((clientY - rect.top) / rect.height) * 2 + 1,
|
|
43
|
+
);
|
|
44
|
+
const raycaster = new THREE.Raycaster();
|
|
45
|
+
raycaster.layers.enableAll();
|
|
46
|
+
raycaster.setFromCamera(mouse, ctx.camera);
|
|
47
|
+
|
|
48
|
+
const entityObjects: THREE.Object3D[] = [];
|
|
49
|
+
for (const obj of store.objectMap.values()) entityObjects.push(obj);
|
|
50
|
+
|
|
51
|
+
const intersects = raycaster.intersectObjects(entityObjects, true);
|
|
52
|
+
for (const isect of intersects) {
|
|
53
|
+
// Skip editor helper geometry (wireframes, frustum lines, etc.) — these
|
|
54
|
+
// are visual-only; selection should go through the entity mesh or icon
|
|
55
|
+
// billboard.
|
|
56
|
+
let isHelper = false;
|
|
57
|
+
let walk: THREE.Object3D | null = isect.object;
|
|
58
|
+
while (walk) {
|
|
59
|
+
if (getUserData(walk, 'editorHelper')) {
|
|
60
|
+
isHelper = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (getUserData(walk, 'entityId')) break;
|
|
64
|
+
walk = walk.parent;
|
|
65
|
+
}
|
|
66
|
+
if (isHelper) continue;
|
|
67
|
+
|
|
68
|
+
// Walk up to find the entity root.
|
|
69
|
+
let hit: THREE.Object3D | null = isect.object;
|
|
70
|
+
while (hit && !getUserData(hit, 'entityId')) {
|
|
71
|
+
hit = hit.parent;
|
|
72
|
+
}
|
|
73
|
+
if (hit) {
|
|
74
|
+
const eid = getUserData(hit, 'entityId') as string;
|
|
75
|
+
// Skip locked entities in viewport selection.
|
|
76
|
+
if (!store.isEntityLocked(eid)) return eid;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manifest-era world overlay persistence (T6.1 slice 3, docs/MULTI-WORLD-DESIGN.md
|
|
3
|
+
* §1.G) — overlay storage for a `WorldMountSpec` id in the multi-world play path,
|
|
4
|
+
* keyed by the manifest's own `world.id` (unlike `ingest-overlay.ts`'s game id or
|
|
5
|
+
* `world2d-overlay.ts`'s `2d-`-prefixed silo id). Same overlay-file MECHANICS as
|
|
6
|
+
* those two (a JSON blob keyed by structural-path ids, reapplied on remount), but
|
|
7
|
+
* a DIFFERENT root: `.vgai/overlays/<world-id>.json` under the PROJECT ROOT, not
|
|
8
|
+
* under `public/`.
|
|
9
|
+
*
|
|
10
|
+
* Why a separate root from the (now-deleted) `world2d-overlay.ts`'s `2d-`-prefixed
|
|
11
|
+
* silo: those overlays went through `StorageBackend` (`getStorageBackend()`), and
|
|
12
|
+
* in server mode that is `HttpStorage`, which is hard-rooted at `<projectRoot>/public/`
|
|
13
|
+
* (its own doc comment says so) — so a `.vgai/overlays/<id>.json` written through
|
|
14
|
+
* it actually landed at `<projectRoot>/public/.vgai/overlays/<id>.json`, contradicting
|
|
15
|
+
* the overlay path functions' "project-root-relative" doc comments. That finding is
|
|
16
|
+
* recorded in `docs/BACKBONE-TASKS.md`'s T3.3 close-out. This module was the first
|
|
17
|
+
* "unify toward one namespace" half of §1.G: NEW manifest-world-id overlays are
|
|
18
|
+
* honestly project-root-relative from the start, using:
|
|
19
|
+
* - server mode: the dedicated `/__editor/vgai-file` route pair
|
|
20
|
+
* (`editor-server.ts`), which reads/writes `<projectRoot>/.vgai/...` directly
|
|
21
|
+
* via `node:fs` — the SAME root the editor-state/thumbnail machinery already
|
|
22
|
+
* uses, bypassing `HttpStorage`'s `public/` rooting entirely.
|
|
23
|
+
* - browser mode: `getStorageBackend()` directly — `OpfsStorage`/`FsaStorage`
|
|
24
|
+
* (`HandleStorage`) root at the TRUE project folder (OPFS root / the
|
|
25
|
+
* FSA-picked directory), with no `public/` insertion at all, so no duality
|
|
26
|
+
* exists there to work around.
|
|
27
|
+
* `ingest-overlay.ts`'s `loadOverlay`/`saveOverlay` later adopted this EXACT
|
|
28
|
+
* mode-branched pattern too (the T3.3 finding's remediation) — both overlay
|
|
29
|
+
* families now share the one project-root `.vgai/` namespace, via the SAME
|
|
30
|
+
* `/__editor/vgai-file` route pair in server mode.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { getEditorMode } from '../editor-mode';
|
|
34
|
+
import { getStorageBackend } from '../storage';
|
|
35
|
+
|
|
36
|
+
const BASE = '/__editor';
|
|
37
|
+
|
|
38
|
+
/** Where a manifest world's overlay lives, project-root-relative (§1.G). */
|
|
39
|
+
export function worldOverlayPath(worldId: string): string {
|
|
40
|
+
return `.vgai/overlays/${worldId}.json`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Load a manifest world's saved overlay, or `{}` if none exists / is unreadable. */
|
|
44
|
+
export async function loadWorldOverlay<T extends object = Record<string, unknown>>(
|
|
45
|
+
worldId: string,
|
|
46
|
+
): Promise<T> {
|
|
47
|
+
const path = worldOverlayPath(worldId);
|
|
48
|
+
try {
|
|
49
|
+
if (getEditorMode() === 'browser') {
|
|
50
|
+
const backend = getStorageBackend();
|
|
51
|
+
if (!(await backend.exists(path))) return {} as T;
|
|
52
|
+
return JSON.parse(await backend.read(path)) as T;
|
|
53
|
+
}
|
|
54
|
+
const res = await fetch(`${BASE}/vgai-file?${new URLSearchParams({ path })}`);
|
|
55
|
+
if (!res.ok) return {} as T;
|
|
56
|
+
return JSON.parse(await res.text()) as T;
|
|
57
|
+
} catch {
|
|
58
|
+
return {} as T;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Persist a manifest world's overlay (§1.G — project-root `.vgai/overlays/`). */
|
|
63
|
+
export async function saveWorldOverlay(worldId: string, overlay: object): Promise<void> {
|
|
64
|
+
const path = worldOverlayPath(worldId);
|
|
65
|
+
const content = JSON.stringify(overlay, null, 2);
|
|
66
|
+
if (getEditorMode() === 'browser') {
|
|
67
|
+
await getStorageBackend().write(path, content);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const res = await fetch(`${BASE}/vgai-file`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: { 'Content-Type': 'application/json' },
|
|
73
|
+
body: JSON.stringify({ path, content }),
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) throw new Error(`saveWorldOverlay '${worldId}': HTTP ${res.status}`);
|
|
76
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World pan state (spec27 §8 "space-pan" row, D4 rebuild —
|
|
3
|
+
* docs/unified-world-editor/27-visual-react-editing.md) — a module-level
|
|
4
|
+
* subscribable singleton (mirrors `eyedropper-session.ts`'s "bare singleton +
|
|
5
|
+
* own listener set" shape) holding the CURRENT SHARED pan translate `(x, y)`
|
|
6
|
+
* applied, in LOCKSTEP, to both every design-time world-layer host
|
|
7
|
+
* (`design-time-layers.ts`'s `createLayerElement`-produced react/pixi layers)
|
|
8
|
+
* and `WorldSelectionOverlay`'s own outer wrapper.
|
|
9
|
+
*
|
|
10
|
+
* SOUNDNESS (why lockstep preserves the "zero-correction" host-relative rect
|
|
11
|
+
* invariant `WorldSelectionOverlay.tsx`'s own doc comment establishes):
|
|
12
|
+
* `RectProvider.rect(id)` is computed as `el.getBoundingClientRect()` MINUS
|
|
13
|
+
* the owning world's own root/host `getBoundingClientRect()`
|
|
14
|
+
* (`react-world-authoring-adapter.ts`'s `toHostRelative`/`hostRect` — `this
|
|
15
|
+
* .root` IS the exact layer div `createLayerElement` produces). A CSS
|
|
16
|
+
* `transform: translate()` applied directly to that host element shifts the
|
|
17
|
+
* host's OWN rendered rect AND every descendant's rendered rect by the
|
|
18
|
+
* IDENTICAL `(x, y)` delta — a rigid subtree translation — so the
|
|
19
|
+
* subtraction is invariant under pan: `rect(id)` returns the SAME
|
|
20
|
+
* host-relative numbers at any pan offset, unmodified, with no pan-awareness
|
|
21
|
+
* needed in the adapter, `inspect.ts`'s geometry math, or any of the ~14
|
|
22
|
+
* overlay chrome consumers. `PickProvider.pick` needs no changes either — it
|
|
23
|
+
* hit-tests real rendered rects against the real client cursor position,
|
|
24
|
+
* both of which already reflect the applied transform natively.
|
|
25
|
+
*
|
|
26
|
+
* Applying the exact SAME transform to `WorldSelectionOverlay`'s own outer
|
|
27
|
+
* wrapper (a SIBLING of every world-layer host inside the SAME
|
|
28
|
+
* `ViewportPanel` containerRef parent — see that file's own mount-site doc
|
|
29
|
+
* comment) shifts the overlay's local coordinate origin by the identical
|
|
30
|
+
* `(x, y)` — so drawing a chrome element at `rect(id)`'s (pan-invariant)
|
|
31
|
+
* host-relative `(x, y)` inside the panned overlay wrapper lands it at the
|
|
32
|
+
* SAME screen position as the panned live element it describes. This is the
|
|
33
|
+
* entire "lockstep" contract: every consumer on both sides of the pan reads
|
|
34
|
+
* ONE shared value (`getWorldPan()`) and applies it through the ONE shared
|
|
35
|
+
* pure helper (`panTransformValue`) — never two independently-computed
|
|
36
|
+
* transforms that could drift.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
export interface WorldPan {
|
|
40
|
+
readonly x: number;
|
|
41
|
+
readonly y: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const ZERO_PAN: WorldPan = { x: 0, y: 0 };
|
|
45
|
+
|
|
46
|
+
let _pan: WorldPan = ZERO_PAN;
|
|
47
|
+
const listeners = new Set<() => void>();
|
|
48
|
+
|
|
49
|
+
function notify(): void {
|
|
50
|
+
for (const l of listeners) l();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The current shared pan translate, in CSS px. */
|
|
54
|
+
export function getWorldPan(): WorldPan {
|
|
55
|
+
return _pan;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Set the shared pan translate to an absolute `(x, y)`. */
|
|
59
|
+
export function setWorldPan(x: number, y: number): void {
|
|
60
|
+
if (_pan.x === x && _pan.y === y) return;
|
|
61
|
+
_pan = { x, y };
|
|
62
|
+
notify();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Set the shared pan translate by a RELATIVE `(dx, dy)` — a convenience
|
|
66
|
+
* wrapper over `setWorldPan` (not used by `WorldSelectionOverlay`'s own
|
|
67
|
+
* space-drag, which composes onto a captured drag-start snapshot instead —
|
|
68
|
+
* see its own doc comment — but kept here as the natural pure counterpart
|
|
69
|
+
* for any future incremental caller, e.g. a nudge-pan keybinding). */
|
|
70
|
+
export function panWorldBy(dx: number, dy: number): void {
|
|
71
|
+
setWorldPan(_pan.x + dx, _pan.y + dy);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Reset pan to `(0, 0)` — called on a world-layer remount (`design-time-
|
|
75
|
+
* layers.ts`'s `mountDesignTimeLayers`, invoked on initial edit-mode install
|
|
76
|
+
* AND every `'editor:edit-mode-rebuild'`), so switching/reloading the active
|
|
77
|
+
* world set never leaves a stale pan offset applied over a DIFFERENT layer
|
|
78
|
+
* stack. A no-op (no `notify()`) when already at rest, so a fresh session
|
|
79
|
+
* never fires a spurious subscriber tick. */
|
|
80
|
+
export function resetWorldPan(): void {
|
|
81
|
+
if (_pan.x === 0 && _pan.y === 0) return;
|
|
82
|
+
_pan = ZERO_PAN;
|
|
83
|
+
notify();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Subscribe to pan changes — both `design-time-layers.ts` (imperative DOM
|
|
87
|
+
* style writes) and `WorldSelectionOverlay` (`useSyncExternalStore`) bind
|
|
88
|
+
* this so every lockstep mount point re-applies the SAME new value the
|
|
89
|
+
* instant it changes. */
|
|
90
|
+
export function subscribeWorldPan(listener: () => void): () => void {
|
|
91
|
+
listeners.add(listener);
|
|
92
|
+
return () => listeners.delete(listener);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The ONE shared CSS `transform` value both lockstep mount points apply —
|
|
97
|
+
* pure, so a unit test can assert the world-layer host and the overlay
|
|
98
|
+
* wrapper are handed byte-identical strings for any given pan (the actual
|
|
99
|
+
* "lockstep" proof). `undefined` at rest `(0, 0)` so neither mount point ever
|
|
100
|
+
* carries a no-op `transform: translate(0px, 0px)` — keeps every pre-pan
|
|
101
|
+
* pixel-position snapshot (the full 27x suite, pinned at pan=0) byte-identical
|
|
102
|
+
* to its pre-this-feature output.
|
|
103
|
+
*/
|
|
104
|
+
export function panTransformValue(pan: WorldPan): string | undefined {
|
|
105
|
+
if (pan.x === 0 && pan.y === 0) return undefined;
|
|
106
|
+
return `translate(${pan.x}px, ${pan.y}px)`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Test-only reset (mirrors `eyedropper-session.ts`'s/`world-session-
|
|
110
|
+
* state.ts`'s identical helpers) — drops pan + every subscriber so unit
|
|
111
|
+
* tests don't leak state across cases. */
|
|
112
|
+
export function _resetWorldPanStateForTest(): void {
|
|
113
|
+
_pan = ZERO_PAN;
|
|
114
|
+
listeners.clear();
|
|
115
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World session state (B1, docs/unified-world-editor/26-unified-editor-spec.md
|
|
3
|
+
* §3 B1 · D9) — a module-level subscribable singleton (same shape as
|
|
4
|
+
* `./mount-failure-report.ts`: a bare get/set slot, no subscribe of its own —
|
|
5
|
+
* every caller that mutates it follows up with `store.notifyIngestEdit()`,
|
|
6
|
+
* which every panel already re-renders off via `useSyncExternalStore(store.subscribe,
|
|
7
|
+
* …)`) holding THREE session-local, per-worldId toggles that are NEVER
|
|
8
|
+
* serialized/persisted (D9: "eye = session-local viewport visibility, never
|
|
9
|
+
* serialized" — generalized here to all three, none of which is an authored
|
|
10
|
+
* property):
|
|
11
|
+
*
|
|
12
|
+
* - `hidden` — the eye (A2/D9). LIFTED out of `GameHierarchy.tsx`'s former
|
|
13
|
+
* local `useState<Set<string>> hiddenWorldIds` (module-private React state
|
|
14
|
+
* the design-time layer stack could never see) so `design-time-layers.ts`
|
|
15
|
+
* can hide/show a world's actual DOM layer, not just dim its hierarchy row.
|
|
16
|
+
* - `interactive` — forwards real pointer events to the layer (for testing
|
|
17
|
+
* hover/press states at design time); off by default (`pointer-events:none`
|
|
18
|
+
* is the layer's resting state — see `design-time-layers.ts`).
|
|
19
|
+
* - `pickLock` — stored here for B4 to consume (layered viewport picking,
|
|
20
|
+
* D12): a pick-locked layer is skipped by the topmost-first pick walk.
|
|
21
|
+
* B1 only stores/exposes the toggle; nothing reads it yet.
|
|
22
|
+
*
|
|
23
|
+
* Keyed by the RAW manifest world id (`CompositeChild.worldId` /
|
|
24
|
+
* `ResolvedWorldEntry.id`) — the SAME id `design-time-layers.ts` gets from
|
|
25
|
+
* `composite.childAdapters()`, NOT the composite's synthetic `world:<id>`
|
|
26
|
+
* group-node id. `GameHierarchy.tsx` (whose rows ARE keyed by the group-node
|
|
27
|
+
* id) resolves the raw worldId via `compositeGroupBadge`'s `worldId` field
|
|
28
|
+
* before calling into this module — see that file's row component.
|
|
29
|
+
*
|
|
30
|
+
* A process-lifetime singleton (not project-scoped): switching projects
|
|
31
|
+
* within the same tab does not reset these toggles. That's a deliberate
|
|
32
|
+
* relaxation of the former per-mount-React-state behavior (which reset on
|
|
33
|
+
* every `GameHierarchy` remount) — "session-local" here means "this browser
|
|
34
|
+
* tab's session", matching D9's own framing; nothing depends on a
|
|
35
|
+
* project-switch reset.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
export interface WorldSessionState {
|
|
39
|
+
readonly hidden: boolean;
|
|
40
|
+
readonly interactive: boolean;
|
|
41
|
+
readonly pickLock: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const DEFAULT_STATE: WorldSessionState = { hidden: false, interactive: false, pickLock: false };
|
|
45
|
+
|
|
46
|
+
const _states = new Map<string, WorldSessionState>();
|
|
47
|
+
|
|
48
|
+
function get(worldId: string): WorldSessionState {
|
|
49
|
+
return _states.get(worldId) ?? DEFAULT_STATE;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function patch(worldId: string, partial: Partial<WorldSessionState>): void {
|
|
53
|
+
_states.set(worldId, { ...get(worldId), ...partial });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The eye (A2/D9): true while `worldId`'s design-time layer is hidden. */
|
|
57
|
+
export function isWorldHidden(worldId: string): boolean {
|
|
58
|
+
return get(worldId).hidden;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function setWorldHidden(worldId: string, hidden: boolean): void {
|
|
62
|
+
patch(worldId, { hidden });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function toggleWorldHidden(worldId: string): void {
|
|
66
|
+
setWorldHidden(worldId, !isWorldHidden(worldId));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** True while `worldId`'s layer forwards real pointer events (design-time
|
|
70
|
+
* hover/press testing) instead of its resting `pointer-events:none`. */
|
|
71
|
+
export function isWorldInteractive(worldId: string): boolean {
|
|
72
|
+
return get(worldId).interactive;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function setWorldInteractive(worldId: string, interactive: boolean): void {
|
|
76
|
+
patch(worldId, { interactive });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function toggleWorldInteractive(worldId: string): void {
|
|
80
|
+
setWorldInteractive(worldId, !isWorldInteractive(worldId));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** B4 will read this to skip a layer in the topmost-first pick walk; B1 only
|
|
84
|
+
* stores/exposes the toggle. */
|
|
85
|
+
export function isWorldPickLocked(worldId: string): boolean {
|
|
86
|
+
return get(worldId).pickLock;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function setWorldPickLock(worldId: string, pickLock: boolean): void {
|
|
90
|
+
patch(worldId, { pickLock });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function toggleWorldPickLock(worldId: string): void {
|
|
94
|
+
setWorldPickLock(worldId, !isWorldPickLocked(worldId));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Test-only: drop every world's session state back to defaults so unit
|
|
98
|
+
* tests don't leak toggles across cases (this module is a process-lifetime
|
|
99
|
+
* singleton — see the header comment). */
|
|
100
|
+
export function _resetWorldSessionStateForTest(): void {
|
|
101
|
+
_states.clear();
|
|
102
|
+
}
|