@volter/game-editor 0.5.65
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/BUNDLED_NOTICES +11228 -0
- package/LICENSE +686 -0
- package/LICENSE-BLENDER +1409 -0
- package/LICENSE-MCP +21 -0
- package/NOTICE +21 -0
- package/catalog/entries/audio.json +14 -0
- package/catalog/entries/bake.json +36 -0
- package/catalog/entries/blender.json +17 -0
- package/catalog/entries/react-root.json +24 -0
- package/catalog/entries/reflections.json +29 -0
- package/catalog/entries/static-batch.json +25 -0
- package/catalog/project-source/LICENSE +37 -0
- package/catalog/project-source/src/contributions/bake.kind.ts +40 -0
- package/catalog/project-source/src/contributions/builder-document.tsx +65 -0
- package/catalog/project-source/src/contributions/builder-state.ts +27 -0
- package/catalog/project-source/src/contributions/builder-ui.tsx +61 -0
- package/catalog/project-source/src/contributions/module-source.ts +502 -0
- package/catalog/project-source/src/contributions/pages.finder.ts +61 -0
- package/catalog/project-source/src/lib/audio/sfx.ts +255 -0
- package/catalog/project-source/src/lib/bake/asset-seed.ts +128 -0
- package/catalog/project-source/src/lib/bake/bake-schema.ts +65 -0
- package/catalog/project-source/src/lib/bake/clip-layering.ts +203 -0
- package/catalog/project-source/src/lib/bake/gltf-bake.ts +657 -0
- package/catalog/project-source/src/lib/bake/mesh-slice.ts +157 -0
- package/catalog/project-source/src/lib/bake/node-image.ts +463 -0
- package/catalog/project-source/src/lib/bake/object3d-bake.ts +121 -0
- package/catalog/project-source/src/lib/bake/object3d-lifecycle.ts +15 -0
- package/catalog/project-source/src/lib/bake/object3d-source.ts +8 -0
- package/catalog/project-source/src/lib/bake/params.ts +75 -0
- package/catalog/project-source/src/lib/bake/rest-relative-animation.ts +217 -0
- package/catalog/project-source/src/lib/bake/use-model.ts +95 -0
- package/catalog/project-source/src/lib/react-root/index.ts +20 -0
- package/catalog/project-source/src/lib/react-root/react-root-adapter.tsx +57 -0
- package/catalog/project-source/src/lib/reflections/ReflectionProbe.tsx +201 -0
- package/catalog/project-source/src/lib/reflections/index.ts +19 -0
- package/catalog/project-source/src/lib/reflections/probe-controller.ts +75 -0
- package/catalog/project-source/src/lib/reflections/reflection-probe-registry.ts +402 -0
- package/catalog/project-source/src/lib/reflections/volume-reflection-material.ts +416 -0
- package/catalog/project-source/src/lib/static-batch/Frozen.tsx +91 -0
- package/catalog/project-source/src/lib/static-batch/freeze.ts +579 -0
- package/catalog/project-source/src/lib/static-batch/index.ts +44 -0
- package/catalog/project-source/src/lib/static-batch/mutation-watch.ts +149 -0
- package/catalog/project-source/src/lib/static-batch/shadow-cache.ts +171 -0
- package/catalog/project-source/src/tools/bake-module.tool.ts +139 -0
- package/catalog/project-source/src/tools/bake-preview.tool.ts +475 -0
- package/dist/.vite/manifest.json +8304 -0
- package/dist/assets/AssetBudgetPanel-J9--TZPU.js +23 -0
- package/dist/assets/AudioViewer-CR7333fe.js +1 -0
- package/dist/assets/BVHLoader-6bQIXhMX.js +1 -0
- package/dist/assets/BufferGeometryUtils-Nz37EVXf.js +1 -0
- package/dist/assets/CCDIKSolver-CD7vLpsK.js +1 -0
- package/dist/assets/CSS3DRenderer-CL7ABLVK.js +1 -0
- package/dist/assets/CanvasSceneViewport-Bpi6gVTC.js +1 -0
- package/dist/assets/ColladaLoader-aVOPIsCh.js +3 -0
- package/dist/assets/ColorInput-DQBNrW-K.js +1 -0
- package/dist/assets/ConvexGeometry-CAzXlPVG.js +1 -0
- package/dist/assets/ConvexHull-BINCESFp.js +1 -0
- package/dist/assets/CopyShader-BzTUYzf6.js +24 -0
- package/dist/assets/DecalGeometry-160KRdfg.js +1 -0
- package/dist/assets/EXRLoader-Cdans_oJ.js +1 -0
- package/dist/assets/EffectComposer-DQxfsXBZ.js +1 -0
- package/dist/assets/EntityModelDocument-Ccvw66N9.js +1 -0
- package/dist/assets/EnvironmentAssetDocument-Dg-Qq6O6.js +1 -0
- package/dist/assets/FBXLoader-B4MoUtAn.js +1 -0
- package/dist/assets/Fbo-Dz-Soul3.js +1 -0
- package/dist/assets/FontLoader-CvGoVI5a.js +2 -0
- package/dist/assets/GLTFExporter-HgrCle4L.js +1 -0
- package/dist/assets/GameplaySessionTimeline-B52W3FVZ.js +1 -0
- package/dist/assets/Gltf-UHVWKz65.js +2 -0
- package/dist/assets/HDRLoader-THU88oVD.js +5 -0
- package/dist/assets/ImageViewer-Tn7s_MnW.js +1 -0
- package/dist/assets/InspectorCanvasPreview-CEr_Kxna.js +1 -0
- package/dist/assets/InspectorObjectPreview-CVejvLRg.js +1 -0
- package/dist/assets/JsonAssetDocument-C7VGcLhu.js +3 -0
- package/dist/assets/LineSegments2-CsOpKSiM.js +370 -0
- package/dist/assets/MTLLoader-_Xzd4_0p.js +2 -0
- package/dist/assets/MarchingCubes-Bsp4wrzd.js +1 -0
- package/dist/assets/MeshBVH-BiDHDcu-.js +1 -0
- package/dist/assets/ModelAssetDocument-F5GACirk.js +1 -0
- package/dist/assets/NonThreeAuthoringBootstrap-C3woOMxX.js +1 -0
- package/dist/assets/OBJLoader-BhIC6Hwo.js +5 -0
- package/dist/assets/Object3DDocumentViewport-DB7T0NTl.js +2 -0
- package/dist/assets/Object3DPreview-DL8oi7Xs.js +2 -0
- package/dist/assets/OnlineAssetDetail-C6z9RvYK.js +2 -0
- package/dist/assets/OrbitControls-CM3bPray.js +1 -0
- package/dist/assets/OrbitControls-DLpayAaK.js +1 -0
- package/dist/assets/OrthographicCamera-bQozawrh.js +1 -0
- package/dist/assets/PLYLoader-DYQqs5Ik.js +2 -0
- package/dist/assets/PerspectiveCamera-CQ2lh01o.js +1 -0
- package/dist/assets/PlayBar-BR-Vg3Jb.js +2 -0
- package/dist/assets/RGBELoader-BgBcQv8j.js +1 -0
- package/dist/assets/RectAreaLightUniformsLib-CMMoWfll.js +1 -0
- package/dist/assets/RenderPass-DPrn-Uky.js +1 -0
- package/dist/assets/ResolutionPicker-C67vs1F3.js +1 -0
- package/dist/assets/RootSelectionOverlay-BZPlxmXU.js +1 -0
- package/dist/assets/RoundedBox-BDGBg6QZ.js +1 -0
- package/dist/assets/RoundedBoxGeometry-CyUuYPfW.js +1 -0
- package/dist/assets/STLLoader-Dyv3lsxY.js +1 -0
- package/dist/assets/SelectionBox-D_75KrNW.js +1 -0
- package/dist/assets/ShaderPass-QYRpPuFJ.js +1 -0
- package/dist/assets/ShadowEditor-DkImwu1Y.js +1 -0
- package/dist/assets/SimplifyModifier-C8ayvRzd.js +1 -0
- package/dist/assets/SkeletonUtils-Cps8GOC6.js +1 -0
- package/dist/assets/Sky-CQKCgYDs.js +154 -0
- package/dist/assets/SourceAssetViewer-2SWQoUut.js +12 -0
- package/dist/assets/StageHost-BN-IoTef.js +2 -0
- package/dist/assets/StoryPreviewMount-DjyxRCXu.js +1 -0
- package/dist/assets/TDSLoader-D_T8XJ81.js +1 -0
- package/dist/assets/TextGeometry-DOWAEUV0.js +1 -0
- package/dist/assets/ThreeBoardDocument-CVncZyIq.js +2 -0
- package/dist/assets/ThreeIsolationSceneContent-C8C8whSF.js +1 -0
- package/dist/assets/ToolObject3DPreview-BRoDWe4Q.js +1 -0
- package/dist/assets/TrackballControls-DfznuQTh.js +1 -0
- package/dist/assets/TransientHint-BB1fwrvK.js +1 -0
- package/dist/assets/UnrealBloomPass-CR-cS_K5.js +83 -0
- package/dist/assets/VideoViewer-C6kocgIU.js +1 -0
- package/dist/assets/_commonjsHelpers-D6-XlEtG.js +1 -0
- package/dist/assets/active-ingest-CT6jSGhr.js +3 -0
- package/dist/assets/adapter-surface-Y37Nzcyw.js +1 -0
- package/dist/assets/after-paint-CB4bz1-e.js +1 -0
- package/dist/assets/agx-base-srgb-BjWZJgrZ.lut +0 -0
- package/dist/assets/agx-look-medium-high-contrast-D5F_ob1L.lut +0 -0
- package/dist/assets/agx-look-punchy-dxsnycNs.lut +0 -0
- package/dist/assets/animation-clock-CnjZqfJp.js +1 -0
- package/dist/assets/asset-budget-asset.menu-Di3KiQCd.js +1 -0
- package/dist/assets/asset-budget.action-DCzzcuTh.js +1 -0
- package/dist/assets/asset-budget.document-BWU8wnVW.js +1 -0
- package/dist/assets/asset-budget.menu-BGZpT_31.js +1 -0
- package/dist/assets/asset-editor-persistence-BBaONOJt.js +1 -0
- package/dist/assets/asset-loaders-BOy5Ss8k.js +2 -0
- package/dist/assets/asset-parse-error-BHMwBRU3.js +3 -0
- package/dist/assets/assets-BuSoGjBX.js +1 -0
- package/dist/assets/audio-meter-CyiToeUW.js +1 -0
- package/dist/assets/audio-unlock.service-CfUgUQVy.js +1 -0
- package/dist/assets/audio.utility-C6K6jem8.js +1 -0
- package/dist/assets/authoring-CgcOFhGS.js +1 -0
- package/dist/assets/autoplay.service-BZBGNSvt.js +1 -0
- package/dist/assets/axe-LkjAB6Lv.js +30 -0
- package/dist/assets/babylon-authoring-adapter-CL02gWDn.js +1 -0
- package/dist/assets/binding-Bmxqznjk.js +1 -0
- package/dist/assets/binding-identity-DcTpbvyg.js +1 -0
- package/dist/assets/binding-resolver-Dsh-6Vor.js +2 -0
- package/dist/assets/blender-emscripten-engine-9ZIRYNhe.js +2 -0
- package/dist/assets/blender-node-editor.document-iIDkB9sI.js +1 -0
- package/dist/assets/blender-properties-tab-C5CyPydi.js +3 -0
- package/dist/assets/blender-runtime-host-BpBwGv7r.js +4 -0
- package/dist/assets/blender-runtime-skin-DyQ9B6CR.js +7140 -0
- package/dist/assets/blender-runtime.document-lIYhhPtv.js +8 -0
- package/dist/assets/blender-timeline.document-77fx96N7.js +1 -0
- package/dist/assets/blender-uv-editor.document-fsT7B4gV.js +1 -0
- package/dist/assets/blender-version.status-o6dBm3n6.js +1 -0
- package/dist/assets/blender-wali-engine-wTOcrOMC.js +2 -0
- package/dist/assets/blender.command-BtJeWk-A.js +1 -0
- package/dist/assets/blender.keymap-GAQgeklK.js +1 -0
- package/dist/assets/blender.status-ujwGU6dU.js +1 -0
- package/dist/assets/blender.style-Dcem5f_T.js +1 -0
- package/dist/assets/board-guides-DziKSTss.js +1 -0
- package/dist/assets/body-marks-h_xDxiDE.js +1 -0
- package/dist/assets/bridge.command-o5gDNEwa.js +3 -0
- package/dist/assets/browserAll-DeWblVez.js +1 -0
- package/dist/assets/build-profiles.document-kW8iw8Xj.js +2 -0
- package/dist/assets/build-progress.status-BNRLytg2.js +1 -0
- package/dist/assets/build-session-C_sg3CEn.js +9 -0
- package/dist/assets/build.action-lYjTLb7K.js +1 -0
- package/dist/assets/build.command-DIGgUPU_.js +1 -0
- package/dist/assets/build.header-CKajx5U3.js +1 -0
- package/dist/assets/build.menu-BdU0QXny.js +1 -0
- package/dist/assets/build.service-CbBAyeu3.js +1 -0
- package/dist/assets/bus-mixer-CGfWDP3C.js +1 -0
- package/dist/assets/camera-KEsKvOL7.js +1 -0
- package/dist/assets/camera-runtime.inspector-B7unX4g1.js +1 -0
- package/dist/assets/canvas-entry-runtime-SfBxaR9M.js +2 -0
- package/dist/assets/capability-coverage-Czas4C18.js +7 -0
- package/dist/assets/chrome-trace-YZHMz60-.js +1 -0
- package/dist/assets/client-DNXj_opT.js +25 -0
- package/dist/assets/clip-planes-CnAI6DZn.js +1 -0
- package/dist/assets/collaboration-presence-DLoZ7EA3.js +1 -0
- package/dist/assets/collider-Bw0mXlsW.js +1 -0
- package/dist/assets/collider-dimensions-9xoFADXN.js +1 -0
- package/dist/assets/collision-system-DpNUJRJ3.js +1 -0
- package/dist/assets/command-results-CUQD49AB.js +1 -0
- package/dist/assets/component-board-registry-DrIa2csL.js +1 -0
- package/dist/assets/component-board.service-DCwcUssB.js +2 -0
- package/dist/assets/component-board.service-DidCyM4O.js +2 -0
- package/dist/assets/component-verbs.command-7xzfjGMZ.js +1 -0
- package/dist/assets/component-verbs.service-Bv9jId3q.js +1 -0
- package/dist/assets/config-CEZk921y.js +6 -0
- package/dist/assets/configurations-DTBMdaTL.js +1 -0
- package/dist/assets/connection.status-BifnQdOs.js +1 -0
- package/dist/assets/console-bridge-CHcb-xk5.js +1 -0
- package/dist/assets/constraint-De8f1Uiq.js +1 -0
- package/dist/assets/constraints.inspector-B9U9Yj-u.js +1 -0
- package/dist/assets/countdown-timer-CUm74dom.js +1 -0
- package/dist/assets/coverage.service-VTX5Mcsx.js +3 -0
- package/dist/assets/crash-null-boundary-v3a0uEgw.js +1 -0
- package/dist/assets/create-runtime-CVCc1BDx.js +1 -0
- package/dist/assets/curve-7Q79VgU4.js +1 -0
- package/dist/assets/data-asset-4hjS642k.js +5 -0
- package/dist/assets/data-check-core-CQEjuFyt.js +1 -0
- package/dist/assets/data-ref-CQI28C0D.js +1 -0
- package/dist/assets/debug-bridge-CCohG-d-.js +1 -0
- package/dist/assets/debug-registry-Dgvitx8M.js +1 -0
- package/dist/assets/defaults-DKiBJCPN.js +1 -0
- package/dist/assets/deferred-commands-CEMmvL47.js +1 -0
- package/dist/assets/deferred-ingest-play-DCJi_Pgu.js +2 -0
- package/dist/assets/design-time-layers-wYgOTgni.js +1 -0
- package/dist/assets/design-time-mount-registry-DUpXCg1U.js +1 -0
- package/dist/assets/design-time-mount.service-BzY21e1F.js +2 -0
- package/dist/assets/design-time-react-mount-DM9WLrF2.js +1 -0
- package/dist/assets/dev-build-gDYrq68M.js +1 -0
- package/dist/assets/directional-shadow-fit-BVkOKAv2.js +1 -0
- package/dist/assets/document-preview-three-Kbg2GCLm.js +1 -0
- package/dist/assets/dom-authoring-adapter-CY8C7f4T.js +1 -0
- package/dist/assets/draco3d-BBUTcNkz.js +1 -0
- package/dist/assets/draco_decoder-DsQ12WqX.wasm +0 -0
- package/dist/assets/draco_encoder-2Tcju8Ns.wasm +0 -0
- package/dist/assets/edit-mode-audio.service-Bzetwd5B.js +1 -0
- package/dist/assets/edit-mode-authoring-B47TfLqu.js +1 -0
- package/dist/assets/edit-mode-networking.service-YCX6RRb_.js +1 -0
- package/dist/assets/editor-api-BoJIcyZG.js +1 -0
- package/dist/assets/editor-port-C_FeBdeV.js +1 -0
- package/dist/assets/editor-presentation-activity-C7SNSmTd.js +1 -0
- package/dist/assets/entry-adjudication-Cq8Yeb74.js +1 -0
- package/dist/assets/environment-capture-7himRh2L.js +1 -0
- package/dist/assets/esbuild-BHljloGq.wasm +0 -0
- package/dist/assets/events-156d8d12.esm-ErOhDXXB.js +36 -0
- package/dist/assets/extend-B-eOccUm.js +36 -0
- package/dist/assets/extends-CF3RwP-h.js +1 -0
- package/dist/assets/eyedropper-session-bjPXnfeX.js +1 -0
- package/dist/assets/fflate.module-DPuTF8aG.js +6 -0
- package/dist/assets/filmic-srgb-Ct35FIH6.lut +0 -0
- package/dist/assets/first-party-audio-system-DxnGJOER.js +1 -0
- package/dist/assets/first-party-navigation-system-CL5Bquub.js +1 -0
- package/dist/assets/fork-menu-BoVyw2Wu.js +1 -0
- package/dist/assets/frame-debugger-store-D1Mf_5up.js +1 -0
- package/dist/assets/frame-delta-D2nsw_Ht.js +1 -0
- package/dist/assets/frame-pacing-D5acoOzO.js +1 -0
- package/dist/assets/frame-selector-cache-cCeUbcjG.js +1 -0
- package/dist/assets/game-DHOZVb-7.js +1 -0
- package/dist/assets/game-contract-seams-a5YXejOu.js +1 -0
- package/dist/assets/game-css-scope-transform-Eng4wS8E.js +33 -0
- package/dist/assets/game-document.service-DbRfx2V0.js +1 -0
- package/dist/assets/game-eval.command-D-7Dxbj_.js +2 -0
- package/dist/assets/game-input-seams-CIQdetRw.js +1 -0
- package/dist/assets/game-loop-CZvXlY00.js +1 -0
- package/dist/assets/game-module-access-B2mFxv-i.js +1 -0
- package/dist/assets/game.layout-CBASrvQu.js +1 -0
- package/dist/assets/gameplay-export-BoKXm51x.js +1 -0
- package/dist/assets/gameplay-replay-e5umMlXv.js +1 -0
- package/dist/assets/gameplay-rng-trap-CTNhm-UW.js +3 -0
- package/dist/assets/gameplay.command-DxcVYX6F.js +1 -0
- package/dist/assets/generation-DhwCUHPf.css +1 -0
- package/dist/assets/generation-jobs-BQrXbGp_.js +1 -0
- package/dist/assets/generation.service-CDIgObuw.js +1 -0
- package/dist/assets/generations-DzUogZsM.js +1 -0
- package/dist/assets/generations.status-CgOUBCum.js +1 -0
- package/dist/assets/hierarchy-marks-BLPfSIym.js +1 -0
- package/dist/assets/host-pointer-DbGSCjE9.js +1 -0
- package/dist/assets/hosted-asset-materialization-CiIvWkGU.js +2 -0
- package/dist/assets/ibl-override-material-BlmCxFKq.js +6 -0
- package/dist/assets/index-96FBF1Oj.js +1 -0
- package/dist/assets/index-BAWkB0dv.js +1 -0
- package/dist/assets/index-BDnS2b6S.js +1 -0
- package/dist/assets/index-BHp07vN0.js +2 -0
- package/dist/assets/index-BMxv2MNV.js +1 -0
- package/dist/assets/index-BP6wv2A0.js +5 -0
- package/dist/assets/index-BcCBqgM_.js +952 -0
- package/dist/assets/index-Bge9JUr6.js +1 -0
- package/dist/assets/index-BjTCPEQ7.js +134 -0
- package/dist/assets/index-BncK9THk.js +1 -0
- package/dist/assets/index-CJbYy-CF.js +3 -0
- package/dist/assets/index-CVCb_ImQ.js +1 -0
- package/dist/assets/index-CZd9o7Lu.js +1 -0
- package/dist/assets/index-CanA16PU.js +2 -0
- package/dist/assets/index-CinJrH5C.js +9 -0
- package/dist/assets/index-CtzuWnCS.js +1 -0
- package/dist/assets/index-D2fNXpHa.css +1 -0
- package/dist/assets/index-DUpHH6JR.js +3120 -0
- package/dist/assets/index-DUqP1RMl.js +1 -0
- package/dist/assets/index-D_NuPfjr.js +9 -0
- package/dist/assets/index-Da9JhEvW.js +25 -0
- package/dist/assets/index-DgapqSPi.js +7 -0
- package/dist/assets/index-FUuS4qwW.js +562 -0
- package/dist/assets/index-GIL7oGEO.js +4894 -0
- package/dist/assets/index-IEjydI9d.js +1 -0
- package/dist/assets/index-OrYXPk3Z.js +487 -0
- package/dist/assets/index-V1R-e5Bd.js +1 -0
- package/dist/assets/index-bQE2NA0D.js +1 -0
- package/dist/assets/index-gHZae-lw.js +13 -0
- package/dist/assets/index-mjWQmGhM.js +1 -0
- package/dist/assets/index-nmcBqr7Y.js +1 -0
- package/dist/assets/inference-diagnostics-Dhmtfbq_.js +1 -0
- package/dist/assets/ingest-BbYMC2vQ.js +1 -0
- package/dist/assets/ingest-boot-viewport-D5rI_Kk_.js +1 -0
- package/dist/assets/ingest-siblings-Bop2kqVl.js +1 -0
- package/dist/assets/ingest-source-persistence-C_6Hiyra.js +1 -0
- package/dist/assets/ingest.service-BTDnQfM1.js +1 -0
- package/dist/assets/input-manager-DH_hGW6d.js +1 -0
- package/dist/assets/input-router-BNQvtIqw.js +1 -0
- package/dist/assets/inspect-BZfi3mmo.js +1 -0
- package/dist/assets/inspection-CObLhnrs.js +1 -0
- package/dist/assets/instance-fork-actions-D3sRzS3K.js +1 -0
- package/dist/assets/instances.command-D6UkZNO8.js +1 -0
- package/dist/assets/instruments-CKR02Y8I.js +1 -0
- package/dist/assets/json-history-resource-BbxllWfV.js +1 -0
- package/dist/assets/jsx-runtime-DPjLkJKQ.js +9 -0
- package/dist/assets/light-D-_wsKTq.js +1 -0
- package/dist/assets/light-camera-factory-CWbbe9gI.js +1 -0
- package/dist/assets/lil-gui.module.min-BF55BEwA.js +10 -0
- package/dist/assets/live-behaviors-Bxq49Maz.js +1 -0
- package/dist/assets/live-gesture-lock-DJbrjOqf.js +1 -0
- package/dist/assets/loader-CaF_I7Yt.js +1 -0
- package/dist/assets/logger-Dqis-7W1.js +1 -0
- package/dist/assets/loop-gate-report-N52EWFGD.js +1 -0
- package/dist/assets/matcap-texture-CVfalpWT.js +1 -0
- package/dist/assets/material-CpAdjDxn.js +1 -0
- package/dist/assets/material-factory-Bz6h__6g.js +1 -0
- package/dist/assets/mesh-B3WPtNKO.js +1 -0
- package/dist/assets/mesh-shadow-CZnXrw_l.js +1 -0
- package/dist/assets/mikktspace.module-DO88SLib.js +1 -0
- package/dist/assets/model-asset-sections-CFvvihfx.css +1 -0
- package/dist/assets/model-asset-sections.service-CHhFS3ZX.js +1 -0
- package/dist/assets/model.layout-BJUEQYUI.js +1 -0
- package/dist/assets/models.finder-G2jQgIRu.js +1 -0
- package/dist/assets/module-mode-DVBLT9d-.js +2 -0
- package/dist/assets/mount-canvas-ingest-root-DDuAWf_C.js +2 -0
- package/dist/assets/mount-dom-ingest-root-D_EiBgpn.js +2 -0
- package/dist/assets/mount-game-6t9cKNo4.js +1 -0
- package/dist/assets/mount-ingest-root-glv2SSWf.js +2 -0
- package/dist/assets/mount-manifest-CGVxhmAw.js +1 -0
- package/dist/assets/mount-readiness-Ds0HvvLH.js +4 -0
- package/dist/assets/mount-three-ingest-root-hrUt9VVU.js +1 -0
- package/dist/assets/mounted-authoring-Dmg5xmhP.js +1 -0
- package/dist/assets/mounted-story-viewport-source-DjP6RA9U.js +1 -0
- package/dist/assets/native-debug-module-CWicoSGD.js +1 -0
- package/dist/assets/native-entry-surface-BE8LJNdu.js +1 -0
- package/dist/assets/navigation-CIiCx-SM.js +1 -0
- package/dist/assets/navmesh-workflow-store-Cmnm57TB.js +1 -0
- package/dist/assets/navmesh.menu-CAKiH8PW.js +1 -0
- package/dist/assets/navmesh.service-jgDWlgj1.js +1 -0
- package/dist/assets/network.utility-CEu5nHf7.js +1 -0
- package/dist/assets/object-marks-DwvIEBOK.js +1 -0
- package/dist/assets/object3d-authoring-subject-CH5sI2oP.js +1 -0
- package/dist/assets/output-DK8waum9.js +195 -0
- package/dist/assets/particles-Y626p22p.js +1 -0
- package/dist/assets/particles-factory-DnLOHXT8.js +1 -0
- package/dist/assets/pasteboard-materialize-BqSS4QzV.js +20 -0
- package/dist/assets/pasteboard.action-DU3UHtJG.js +2 -0
- package/dist/assets/performance-profiler-D_Jey87L.js +1 -0
- package/dist/assets/physics-registry-B2Jkp8e6.js +1 -0
- package/dist/assets/physics-registry-CUB9cT9p.js +1 -0
- package/dist/assets/pixi-authoring-adapter-CjibysC3.js +1 -0
- package/dist/assets/pixi-live-write-target-DuWydlWb.js +1 -0
- package/dist/assets/pixi-primitive-DlWbUPN9.js +1 -0
- package/dist/assets/pixi-react-root-factory-DYsznYRQ.js +1 -0
- package/dist/assets/pixi-story-model-DNkfnWUV.js +1 -0
- package/dist/assets/pixi-transform-channels-VjdohT11.js +1 -0
- package/dist/assets/play-mode-BFU2PCkG.js +22 -0
- package/dist/assets/play.command-BpqqLqkq.js +2 -0
- package/dist/assets/playtest-BXIL1JEF.js +1 -0
- package/dist/assets/pose-guard-6Osb2cFu.js +1 -0
- package/dist/assets/presentation-BPP5pXeQ.js +1 -0
- package/dist/assets/product-DFhyARJj.js +1 -0
- package/dist/assets/profiler.action-CaXJDp3t.js +1 -0
- package/dist/assets/profiler.menu-BIMF6Bi4.js +1 -0
- package/dist/assets/profiler.utility-BExw9wBO.js +1 -0
- package/dist/assets/project-authoring-session-Bnt6icLr.js +2 -0
- package/dist/assets/project-provenance-BoP3nrle.js +1 -0
- package/dist/assets/prompt-labels-DSMdM2_B.js +1 -0
- package/dist/assets/properties-bone-constraints.inspector-ByT6p7S-.js +1 -0
- package/dist/assets/properties-bone.inspector-z4qJwKO5.js +1 -0
- package/dist/assets/properties-collection.inspector-D0_3ijWU.js +1 -0
- package/dist/assets/properties-constraints.inspector-CESzjuls.js +1 -0
- package/dist/assets/properties-data.inspector-hG8Wgyzb.js +1 -0
- package/dist/assets/properties-material.inspector-CzY0JCQ6.js +1 -0
- package/dist/assets/properties-modifiers.inspector-3dDhwf7g.js +1 -0
- package/dist/assets/properties-object.inspector-CiarfxkT.js +1 -0
- package/dist/assets/properties-output.inspector-DKJxmKSD.js +1 -0
- package/dist/assets/properties-particles.inspector-CCEdYWGm.js +1 -0
- package/dist/assets/properties-physics.inspector-B2c0KUyA.js +1 -0
- package/dist/assets/properties-render.inspector-Bcm0HLRW.js +1 -0
- package/dist/assets/properties-scene.inspector-PIM_eTb_.js +1 -0
- package/dist/assets/properties-texture.inspector-CgFlnyr8.js +1 -0
- package/dist/assets/properties-view-layer.inspector-DGjF_Aqo.js +1 -0
- package/dist/assets/properties-world.inspector-CrMvaRvB.js +1 -0
- package/dist/assets/r3f-design-session-D-4yyDO9.js +2 -0
- package/dist/assets/r3f-physics-binding-BBo8oma9.js +1 -0
- package/dist/assets/r3f-root-factory-z9llD1OU.js +1 -0
- package/dist/assets/r3f-source-authoring-adapter-w6Bc60K-.js +13 -0
- package/dist/assets/rapier-physics-adapter-CaZqWLu0.js +1 -0
- package/dist/assets/rapier-physics-bridge-CMoeVo3Y.js +1 -0
- package/dist/assets/react-18-By2b4xR9.js +1 -0
- package/dist/assets/react-inspector.service-B_neRnSK.js +1 -0
- package/dist/assets/react-root-CEz5NTck.js +1 -0
- package/dist/assets/react-story-board-BDDwiE2H.js +1 -0
- package/dist/assets/react-three-fiber.esm-CycrbDlA.js +1 -0
- package/dist/assets/react-three-rapier.esm-CEfKpvxT.js +1 -0
- package/dist/assets/react-world-authoring-adapter-DmrwM3py.js +1 -0
- package/dist/assets/realm-services-CobQsq_X.js +1 -0
- package/dist/assets/rebind-controller-Dtq19Vb3.js +1 -0
- package/dist/assets/recast-navigation.wasm-compat-Dsoa_MD-.js +1 -0
- package/dist/assets/reflection-probe-Don-M3Fj.js +1 -0
- package/dist/assets/reflection-probe-capture.inspector-CmFUoJCx.js +1 -0
- package/dist/assets/register-render-vitals-BiZk29b2.js +1 -0
- package/dist/assets/registry-02YZjMNp.js +1 -0
- package/dist/assets/relative-path-guard-GiM7Lsz8.js +1 -0
- package/dist/assets/render-audio-control-vMRlePWb.js +1 -0
- package/dist/assets/render-batch-system-0vq7p0VC.js +1 -0
- package/dist/assets/render-census-BrQX_CXv.js +1 -0
- package/dist/assets/render-control-Df3yTiyr.js +1 -0
- package/dist/assets/render-env-D2IV2x5k.js +1 -0
- package/dist/assets/render-features-CPQ_e568.js +1 -0
- package/dist/assets/render-seed-DF4JHy7P.js +1 -0
- package/dist/assets/render-settings-Bw4W9SYF.js +1 -0
- package/dist/assets/render-vitals-BZ5HtvMi.js +1 -0
- package/dist/assets/renderer-config-BqG4O8i9.js +1 -0
- package/dist/assets/resolve-three-SZE_WWUM.js +702 -0
- package/dist/assets/root-seam-contract-Z0VWX3Bk.js +1 -0
- package/dist/assets/rrweb-Cd2ifIRP.js +142 -0
- package/dist/assets/run-ticks-settled-C4ksViyA.js +1 -0
- package/dist/assets/runtime-inspection-l2iFQSsg.js +1 -0
- package/dist/assets/scene-capture-BQKzU0NT.js +1 -0
- package/dist/assets/scene-capture-CGYF-Viw.js +1 -0
- package/dist/assets/scene-document.service-qkDjUrlP.js +2 -0
- package/dist/assets/scene-framing-Cat0GtyJ.js +1 -0
- package/dist/assets/scene-index-B6BZOHMk.js +1 -0
- package/dist/assets/scene-query-C7_N-TpI.js +1 -0
- package/dist/assets/schema-kl9-2B_J.js +1 -0
- package/dist/assets/sculpt.layout-zJF55yCR.js +1 -0
- package/dist/assets/seeded-random-i3mtgBKZ.js +1 -0
- package/dist/assets/session-CZ5JPg-z.js +4877 -0
- package/dist/assets/setup-audio-S8GQF91f.js +1 -0
- package/dist/assets/setup-particles-GCXlnkj_.js +1 -0
- package/dist/assets/setup-physics-BeZ7-LKD.js +1 -0
- package/dist/assets/setup-renderer-DVXaSGin.js +1587 -0
- package/dist/assets/shading.layout-DULYZV6M.js +1 -0
- package/dist/assets/sim-clock-CLflx7kg.js +1 -0
- package/dist/assets/sky-precompute-worker-ChN7J87v.js +1 -0
- package/dist/assets/soft-particle-depth-DGvfQDi1.js +1 -0
- package/dist/assets/source-object3d-authoring-adapter-B-L6Ha6f.js +1 -0
- package/dist/assets/source-persistence-backend-C-aR-B_Y.js +1 -0
- package/dist/assets/spark-renderer-lifecycle-ynWESJcv.js +1 -0
- package/dist/assets/spark.module-4pXQoz5d.js +12120 -0
- package/dist/assets/stage-invalidation-DBg3C3Ta.js +1 -0
- package/dist/assets/stage-keyboard-n-5kKH-m.js +1 -0
- package/dist/assets/stage-overlay-set-B9zp2sLB.js +1 -0
- package/dist/assets/stage-presence-markers-DiGI6A45.js +1 -0
- package/dist/assets/standard-viewport-dressing-CzjAe_0A.js +7 -0
- package/dist/assets/state-bridge-DLP1jLRW.js +1 -0
- package/dist/assets/state-watch.action-BOvQR2qt.js +1 -0
- package/dist/assets/state-watch.menu-CNLvDeeY.js +1 -0
- package/dist/assets/state-watch.utility-Bg1tTTQU.js +1 -0
- package/dist/assets/static-batch-advisor-B13QEH7d.js +1 -0
- package/dist/assets/stats.module-BL02l9NC.js +1 -0
- package/dist/assets/story-arg-descriptors-Ek86ExX7.js +1 -0
- package/dist/assets/story-capture-_gC8dXV-.js +1 -0
- package/dist/assets/story-documents--TDLaPeL.js +3 -0
- package/dist/assets/story-documents.service-BiS_YbNQ.js +1 -0
- package/dist/assets/story-documents.service-CxOPYJ2j.js +1 -0
- package/dist/assets/story-media-presence-BHzk2IV5.js +1 -0
- package/dist/assets/story-mount-turn-DFRTj5hi.js +1 -0
- package/dist/assets/story-pixi-preview-BUrOJZXS.js +1 -0
- package/dist/assets/story-presentation-j2AVN-mK.js +1 -0
- package/dist/assets/story-three-preview-BHEDZzcl.js +2 -0
- package/dist/assets/structural-ids-Dc-7rEwi.js +1 -0
- package/dist/assets/structural-signature-0w-i_ats.js +1 -0
- package/dist/assets/surface-content-Dg9Kkazf.js +1 -0
- package/dist/assets/surface-state-DaxyruCj.js +3 -0
- package/dist/assets/system-adapters-rIC8FSGP.js +1 -0
- package/dist/assets/system-runner-DkOjxEBt.js +1 -0
- package/dist/assets/system-slot-E2mEdiih.js +1 -0
- package/dist/assets/team-playtest.service-DqOinFVA.js +1 -0
- package/dist/assets/texture.layout-DASpHVht.js +1 -0
- package/dist/assets/three-CDSueJyJ.js +1 -0
- package/dist/assets/three-authoring-adapter-CmSQ3Vui.js +1 -0
- package/dist/assets/three-authoring.service-iuHLwtf1.js +2 -0
- package/dist/assets/three-ingest-runtime-QzDYk6tU.js +1 -0
- package/dist/assets/three-projection-core-BmKMZ-nf.js +1 -0
- package/dist/assets/three-viewport-presentation-QBQpSdMh.js +1 -0
- package/dist/assets/three.module-D396a9Mn.js +3840 -0
- package/dist/assets/three.quarks.esm-B1C61jGo.js +1039 -0
- package/dist/assets/tools-B_NJsk05.js +1 -0
- package/dist/assets/transform-writer-BhBBTx33.js +1 -0
- package/dist/assets/transport.header-B-6HQlU2.js +1 -0
- package/dist/assets/trigger-volume-BNK2XzPL.js +1 -0
- package/dist/assets/tuples-CIQ4Bn1U.js +1 -0
- package/dist/assets/tween.module-DciWpAG6.js +1 -0
- package/dist/assets/ui-board-document-Bwtt--xp.js +2 -0
- package/dist/assets/unexported-game-trap-Dm1JYKHy.js +2 -0
- package/dist/assets/unmanaged-root-detector-B8CpbkSN.js +2 -0
- package/dist/assets/upstream-pin-BdgRH6ID.js +1 -0
- package/dist/assets/use-data-Dzq-MytE.js +1 -0
- package/dist/assets/use-live-actor-state-DErbWQWF.js +1 -0
- package/dist/assets/use-selection-DbR73-xd.js +1 -0
- package/dist/assets/user-data-BB2Of6Ht.js +1 -0
- package/dist/assets/utility-view-state-BHypxA33.js +1 -0
- package/dist/assets/uv-editing.layout-BEKHxmHw.js +1 -0
- package/dist/assets/vgai-shared-fontawesome-CU65D4Ij.js +1 -0
- package/dist/assets/vgai-shared-jsx-dev-runtime-DFDKL7fx.js +1 -0
- package/dist/assets/vgai-shared-jsx-runtime-DIqBpTut.js +1 -0
- package/dist/assets/vgai-shared-react-BT7rMc2H.js +1 -0
- package/dist/assets/vgai-shared-react-dom-DFajMqMT.js +1 -0
- package/dist/assets/vgai-shared-react-dom-client-S0ozfl6_.js +1 -0
- package/dist/assets/vgai-shared-three-Bc5PvpLM.js +1 -0
- package/dist/assets/viewport-pick-context-DkawXbEi.js +1 -0
- package/dist/assets/viewport-root-presentation-CWsE56K6.js +1 -0
- package/dist/assets/viewport-shading-BuA88e_A.js +1 -0
- package/dist/assets/viewport-shading-boundary-B_-_gABg.js +82 -0
- package/dist/assets/viewport-surface-status-B3om4Kcf.js +1 -0
- package/dist/assets/vision_bundle-DX0dWqEa.js +15 -0
- package/dist/assets/voxel-surface-DtcsSWRL.js +1 -0
- package/dist/assets/wav-encode-D31zWF6O.js +1 -0
- package/dist/assets/webgl-frame-capture-FlF9zQmW.js +1 -0
- package/dist/assets/webgl-gpu-timer-D3YX7RaD.js +1 -0
- package/dist/assets/webworkerAll-CM2o_dnz.js +1 -0
- package/dist/assets/worker-UrMcrc5_.js +2 -0
- package/dist/assets/world-documents-147tiFZe.js +1 -0
- package/dist/assets/world-root-stage-binding-vwTrtBz6.js +1 -0
- package/dist/assets/world-state-BWG-IcOd.js +1 -0
- package/dist/assets/writer-B-KovzkA.js +5 -0
- package/dist/assets/xstate-animation-binding-Brd0NST6.js +1 -0
- package/dist/assets/xstate-animation-meta-Q3u9zh_m.js +1 -0
- package/dist/assets/xstate-behavior.action-B8UluFBK.js +1 -0
- package/dist/assets/xstate-behavior.document-CKAsE45I.js +1 -0
- package/dist/assets/xstate-behavior.inspector-vJJyuifc.js +1 -0
- package/dist/assets/xstate-behavior.menu-BXbPICIh.js +1 -0
- package/dist/assets/xstate-inspection-BsZv8LS9.js +1 -0
- package/dist/vgai-shared-react.json +10 -0
- package/dist/vgai-shared-three.json +3 -0
- package/dist-node/cli.js +9320 -0
- package/dist-node/create.js +3239 -0
- package/package.json +91 -0
- package/presets.mjs +2 -0
- package/src/contributions.d.ts +4 -0
- package/src/index.ts +38 -0
- package/starter/cube.blend +0 -0
- package/starter/cube.py +81 -0
- package/template/.agents/references/project-manual.md +341 -0
- package/template/.agents/skills/editor/SKILL.md +53 -0
- package/template/.agents/skills/editor/agents/openai.yaml +4 -0
- package/template/.agents/skills/editor/references/editor-control.md +363 -0
- package/template/.agents/skills/vgai-3d-models/SKILL.md +64 -0
- package/template/.agents/skills/vgai-ingest-existing-game/SKILL.md +112 -0
- package/template/.agents/skills/vgai-threejs-authoring/SKILL.md +347 -0
- package/template/.agents/skills/vgai-threejs-authoring/agents/openai.yaml +4 -0
- package/template/.agents/skills/vgai-threejs-authoring/references/helper-catalog.md +65 -0
- package/template/.claude/skills/editor/SKILL.md +53 -0
- package/template/.claude/skills/editor/agents/openai.yaml +4 -0
- package/template/.claude/skills/editor/references/editor-control.md +363 -0
- package/template/.claude/skills/vgai-3d-models/SKILL.md +64 -0
- package/template/.claude/skills/vgai-ingest-existing-game/SKILL.md +112 -0
- package/template/.claude/skills/vgai-threejs-authoring/SKILL.md +347 -0
- package/template/.claude/skills/vgai-threejs-authoring/agents/openai.yaml +4 -0
- package/template/.claude/skills/vgai-threejs-authoring/references/helper-catalog.md +65 -0
- package/template/.github/copilot-instructions.md +6 -0
- package/template/.github/skills/editor/SKILL.md +53 -0
- package/template/.github/skills/editor/agents/openai.yaml +4 -0
- package/template/.github/skills/editor/references/editor-control.md +363 -0
- package/template/.github/skills/vgai-3d-models/SKILL.md +64 -0
- package/template/.github/skills/vgai-ingest-existing-game/SKILL.md +112 -0
- package/template/.github/skills/vgai-threejs-authoring/SKILL.md +347 -0
- package/template/.github/skills/vgai-threejs-authoring/agents/openai.yaml +4 -0
- package/template/.github/skills/vgai-threejs-authoring/references/helper-catalog.md +65 -0
- package/template/.mcp.json +12 -0
- package/template/.vgai/assets.json +1 -0
- package/template/.vgai/provenance.json +4 -0
- package/template/.volter/tracker/validation/.preset.base.mts +178 -0
- package/template/.volter/tracker/validation/preset.mts +186 -0
- package/template/.volter/tracker/visualizer/.extension.base.tsx +14 -0
- package/template/.volter/tracker/visualizer/extension.tsx +14 -0
- package/template/.volter/tracker-config.json +17 -0
- package/template/AGENTS.md +176 -0
- package/template/CLAUDE.md +1 -0
- package/template/DEVLOG.md +20 -0
- package/template/IDIOMS.md +118 -0
- package/template/LICENSE +30 -0
- package/template/README.md +83 -0
- package/template/ROADMAP.md +20 -0
- package/template/asset-manifest.json +3 -0
- package/template/check-idioms.ts +1533 -0
- package/template/index.html +18 -0
- package/template/manifest-entry-modules-plugin.ts +53 -0
- package/template/package.json +62 -0
- package/template/public/jsm/libs/basis/basis_transcoder.js +19 -0
- package/template/public/jsm/libs/basis/basis_transcoder.wasm +0 -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/shaders/daylight-sky.frag.glsl +15 -0
- package/template/public/shaders/daylight-sky.vert.glsl +7 -0
- package/template/scripts/patch-drei-stats-gl.mjs +35 -0
- package/template/server/colyseus-setup.ts +111 -0
- package/template/server/loopback.ts +76 -0
- package/template/server/main.ts +78 -0
- package/template/server/rooms/arena-room.ts +488 -0
- package/template/server/rooms/game-room.ts +274 -0
- package/template/server/rooms.ts +15 -0
- package/template/server/tsconfig.json +19 -0
- package/template/src/bot/QaTester.tsx +35 -0
- package/template/src/bot/behaviors.ts +203 -0
- package/template/src/bot/bot-station.ts +192 -0
- package/template/src/bot/tester-run.ts +238 -0
- package/template/src/bot/tester-station.ts +193 -0
- package/template/src/components/environment/DaylightSky.tsx +54 -0
- package/template/src/components/environment/Ground.tsx +129 -0
- package/template/src/components/environment/SceneAtmosphere.tsx +14 -0
- package/template/src/components/environment/SoftGroundShadow.tsx +62 -0
- package/template/src/components/environment/SunShadowFit.tsx +141 -0
- package/template/src/contributions/README.md +98 -0
- package/template/src/contributions/analytics.analytics.tsx +26 -0
- package/template/src/contributions/data.document.tsx +35 -0
- package/template/src/contributions/pages.finder.ts +61 -0
- package/template/src/contributions/tester.inspector.tsx +64 -0
- package/template/src/contributions/use-game-modules.ts +80 -0
- package/template/src/data/README.md +17 -0
- package/template/src/input.ts +97 -0
- package/template/src/lib/audio/capability.json +4 -0
- package/template/src/lib/audio/sfx.ts +255 -0
- package/template/src/lib/react-root/capability.json +4 -0
- package/template/src/lib/react-root/index.ts +20 -0
- package/template/src/lib/react-root/react-root-adapter.tsx +57 -0
- package/template/src/lib/reflections/ReflectionProbe.tsx +201 -0
- package/template/src/lib/reflections/capability.json +4 -0
- package/template/src/lib/reflections/index.ts +19 -0
- package/template/src/lib/reflections/probe-controller.ts +75 -0
- package/template/src/lib/reflections/reflection-probe-registry.ts +402 -0
- package/template/src/lib/reflections/volume-reflection-material.ts +416 -0
- package/template/src/lib/static-batch/Frozen.tsx +91 -0
- package/template/src/lib/static-batch/capability.json +4 -0
- package/template/src/lib/static-batch/freeze.ts +579 -0
- package/template/src/lib/static-batch/index.ts +44 -0
- package/template/src/lib/static-batch/mutation-watch.ts +149 -0
- package/template/src/lib/static-batch/shadow-cache.ts +171 -0
- package/template/src/main.ts +63 -0
- package/template/src/manifest-entry-modules.d.ts +3 -0
- package/template/src/prefabs/HeroBox.stories.tsx +23 -0
- package/template/src/prefabs/HeroBox.tsx +35 -0
- package/template/src/scenes/MainScene.tsx +77 -0
- package/template/src/world.tsx +87 -0
- package/template/tsconfig.json +35 -0
- package/template/tsconfig.node.json +32 -0
- package/template/tsconfig.tools.json +22 -0
- package/template/validate-asset-content.ts +27 -0
- package/template/validate-assets.ts +60 -0
- package/template/validate-manifest.ts +55 -0
- package/template/vgai.adapter.ts +76 -0
- package/template/vgai.project.json +24 -0
- package/template/vite.config.ts +247 -0
- package/template-dotfiles/gitignore +63 -0
- package/workbench/src/media/game-cover.css +83 -0
- package/workbench/src/product.contribution.ts +188 -0
- package/workbench/src/vgaiGameSkew.ts +276 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { ToolContext } from '@volter/editor-sdk/tools/registry';
|
|
2
|
+
import type * as THREE from 'three';
|
|
3
|
+
import type { Object3DSourceBuild } from '../bake/object3d-source';
|
|
4
|
+
import {
|
|
5
|
+
collectMorphTargets,
|
|
6
|
+
exportObject3DToGlb,
|
|
7
|
+
type GlbValidationOptions,
|
|
8
|
+
installNodeThreePolyfills,
|
|
9
|
+
validateExportedGlb,
|
|
10
|
+
} from './gltf-bake';
|
|
11
|
+
|
|
12
|
+
type SourceFacts = Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
type ToolOutcome<T> = { ok: true; value: T } | { ok: false; error: unknown };
|
|
15
|
+
|
|
16
|
+
async function captureOutcome<T>(operation: Promise<T>): Promise<ToolOutcome<T>> {
|
|
17
|
+
try {
|
|
18
|
+
return { ok: true, value: await operation };
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return { ok: false, error };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Object3DBakeOptions<
|
|
25
|
+
TBuild extends Object3DSourceBuild,
|
|
26
|
+
TFacts extends SourceFacts,
|
|
27
|
+
> {
|
|
28
|
+
ctx: ToolContext;
|
|
29
|
+
name: string;
|
|
30
|
+
dryRun: boolean;
|
|
31
|
+
build(): TBuild;
|
|
32
|
+
resolveAnimations?(
|
|
33
|
+
build: TBuild,
|
|
34
|
+
): readonly THREE.AnimationClip[] | Promise<readonly THREE.AnimationClip[]>;
|
|
35
|
+
validateSource?(build: TBuild, animations: readonly THREE.AnimationClip[]): void | Promise<void>;
|
|
36
|
+
/** Round-trip validation thresholds. May be a function of the built source
|
|
37
|
+
* so source-derived facts (bone count, a sampled vertex color) can be
|
|
38
|
+
* asserted against the reimported GLB. `requiredClips` and
|
|
39
|
+
* `requiredMorphTargets` are NOT settable here: both are read off the built
|
|
40
|
+
* source below, so no lib can bake an asset that quietly asserts less than
|
|
41
|
+
* what it authored. */
|
|
42
|
+
validation:
|
|
43
|
+
| Omit<GlbValidationOptions, 'requiredClips' | 'requiredMorphTargets'>
|
|
44
|
+
| ((build: TBuild) => Omit<GlbValidationOptions, 'requiredClips' | 'requiredMorphTargets'>);
|
|
45
|
+
inspectSource(build: TBuild): TFacts;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Compile an ordinary Object3D factory into the runtime asset pair. This is a
|
|
50
|
+
* build helper, not a modeling abstraction: geometry, materials, hierarchy,
|
|
51
|
+
* rigging, and animation remain native Three.js in the caller.
|
|
52
|
+
*/
|
|
53
|
+
export async function bakeObject3DSource<
|
|
54
|
+
TBuild extends Object3DSourceBuild,
|
|
55
|
+
TFacts extends SourceFacts,
|
|
56
|
+
>(options: Object3DBakeOptions<TBuild, TFacts>) {
|
|
57
|
+
const { ctx } = options;
|
|
58
|
+
const projectOutputs = ctx.projectOutputs;
|
|
59
|
+
if (!projectOutputs) throw new Error('Object3D baking requires a project output writer.');
|
|
60
|
+
if (ctx.signal?.aborted) throw new Error('Object3D baking was cancelled.');
|
|
61
|
+
|
|
62
|
+
const restoreGlobals = installNodeThreePolyfills();
|
|
63
|
+
let built: TBuild | undefined;
|
|
64
|
+
const runOperation = async () => {
|
|
65
|
+
const currentBuild = options.build();
|
|
66
|
+
built = currentBuild;
|
|
67
|
+
const animations = options.resolveAnimations
|
|
68
|
+
? await options.resolveAnimations(currentBuild)
|
|
69
|
+
: (currentBuild.animations ?? []);
|
|
70
|
+
await options.validateSource?.(currentBuild, animations);
|
|
71
|
+
|
|
72
|
+
const requiredMorphTargets = collectMorphTargets(currentBuild.root);
|
|
73
|
+
const glb = await exportObject3DToGlb(currentBuild.root, animations);
|
|
74
|
+
const validationOptions =
|
|
75
|
+
typeof options.validation === 'function'
|
|
76
|
+
? options.validation(currentBuild)
|
|
77
|
+
: options.validation;
|
|
78
|
+
const validation = await validateExportedGlb(glb, {
|
|
79
|
+
...validationOptions,
|
|
80
|
+
requiredClips: animations.map((clip) => clip.name),
|
|
81
|
+
requiredMorphTargets,
|
|
82
|
+
});
|
|
83
|
+
const model = `public/models/generated/${options.name}.glb`;
|
|
84
|
+
const output = await projectOutputs.write(
|
|
85
|
+
[{ path: model, content: glb, mediaType: 'model/gltf-binary', role: 'asset' }],
|
|
86
|
+
{ dryRun: options.dryRun },
|
|
87
|
+
);
|
|
88
|
+
return {
|
|
89
|
+
model,
|
|
90
|
+
...options.inspectSource(currentBuild),
|
|
91
|
+
...validation,
|
|
92
|
+
...output,
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const outcome = await captureOutcome(runOperation());
|
|
97
|
+
const operationError = outcome.ok ? undefined : outcome.error;
|
|
98
|
+
|
|
99
|
+
const cleanupErrors: unknown[] = [];
|
|
100
|
+
if (built) {
|
|
101
|
+
try {
|
|
102
|
+
built.dispose();
|
|
103
|
+
} catch (error) {
|
|
104
|
+
cleanupErrors.push(error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
restoreGlobals();
|
|
109
|
+
} catch (error) {
|
|
110
|
+
cleanupErrors.push(error);
|
|
111
|
+
}
|
|
112
|
+
if (cleanupErrors.length > 0) {
|
|
113
|
+
throw new AggregateError(
|
|
114
|
+
operationError === undefined ? cleanupErrors : [operationError, ...cleanupErrors],
|
|
115
|
+
'Object3D baking failed to clean up completely.',
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (operationError !== undefined) throw operationError;
|
|
119
|
+
if (!outcome.ok) throw outcome.error;
|
|
120
|
+
return outcome.value;
|
|
121
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
export function disposeObject3D(root: THREE.Object3D): void {
|
|
4
|
+
root.traverse((object) => {
|
|
5
|
+
const mesh = object as THREE.Mesh;
|
|
6
|
+
mesh.geometry?.dispose();
|
|
7
|
+
for (const material of Array.isArray(mesh.material)
|
|
8
|
+
? mesh.material
|
|
9
|
+
: mesh.material
|
|
10
|
+
? [mesh.material]
|
|
11
|
+
: []) {
|
|
12
|
+
material.dispose();
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
/** Project-local structural boundary between raw Three.js source and bake/preview helpers. */
|
|
4
|
+
export interface Object3DSourceBuild {
|
|
5
|
+
root: THREE.Object3D;
|
|
6
|
+
animations?: readonly THREE.AnimationClip[];
|
|
7
|
+
dispose(): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a declared params schema as tuning controls.
|
|
3
|
+
*
|
|
4
|
+
* The parameterization contract (the `vgai-3d-assets` skill,
|
|
5
|
+
* "Parametric asset libs") says a
|
|
6
|
+
* parametric asset lib exports a PAIR — a declared parameter object and the
|
|
7
|
+
* function that takes it — and that any tuning UI is DERIVED from that
|
|
8
|
+
* declaration, never hand-mirrored. A hand-kept control table is a second
|
|
9
|
+
* list of the same facts, and second lists rot: a knob added to the schema
|
|
10
|
+
* gets no control, and a bound changed there silently leaves a slider driving
|
|
11
|
+
* values the generator would reject at parse.
|
|
12
|
+
*
|
|
13
|
+
* `z.toJSONSchema` is zod's own public projection of exactly what was
|
|
14
|
+
* declared — bounds, defaults, and `.describe()` prose — so this file is the
|
|
15
|
+
* whole mechanism. Both shipped libs (`lib/humanoid`, `lib/castle`)
|
|
16
|
+
* bind their Builder controls to it; a lib of your own gets a tuning UI by
|
|
17
|
+
* declaring a schema and nothing else.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { z } from 'zod';
|
|
21
|
+
import * as zod from 'zod';
|
|
22
|
+
|
|
23
|
+
/** One numeric knob, read off a declared params schema. */
|
|
24
|
+
export interface NumericParamDescriptor {
|
|
25
|
+
readonly key: string;
|
|
26
|
+
readonly min: number;
|
|
27
|
+
readonly max: number;
|
|
28
|
+
/** The declared default; absent for an optional param that has none. */
|
|
29
|
+
readonly default?: number;
|
|
30
|
+
/** The field's `.describe()` prose — control hint / tooltip copy. */
|
|
31
|
+
readonly description: string;
|
|
32
|
+
/** True when the param may be omitted (it has no default). */
|
|
33
|
+
readonly optional: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Every bounded numeric field of a params schema, in declaration order.
|
|
37
|
+
* Fields without both bounds are skipped: an unbounded number has no slider
|
|
38
|
+
* range, so a UI must decide what to do with it explicitly. */
|
|
39
|
+
export function describeNumericParams(schema: z.ZodType): readonly NumericParamDescriptor[] {
|
|
40
|
+
const json = zod.toJSONSchema(schema) as {
|
|
41
|
+
properties?: Record<
|
|
42
|
+
string,
|
|
43
|
+
{ type?: string; minimum?: number; maximum?: number; default?: unknown; description?: string }
|
|
44
|
+
>;
|
|
45
|
+
required?: string[];
|
|
46
|
+
};
|
|
47
|
+
const required = new Set(json.required ?? []);
|
|
48
|
+
return Object.entries(json.properties ?? {}).flatMap(([key, property]) => {
|
|
49
|
+
const { minimum, maximum } = property;
|
|
50
|
+
if (property.type !== 'number' || minimum === undefined || maximum === undefined) return [];
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
key,
|
|
54
|
+
min: minimum,
|
|
55
|
+
max: maximum,
|
|
56
|
+
...(typeof property.default === 'number' ? { default: property.default } : {}),
|
|
57
|
+
description: property.description ?? '',
|
|
58
|
+
optional: !required.has(key),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Descriptor defaults as a plain params object — the initial state of a
|
|
65
|
+
* control set. Params with no declared default are omitted (the generator's
|
|
66
|
+
* own "natural" behavior stands until the user types a value). */
|
|
67
|
+
export function defaultParams(
|
|
68
|
+
descriptors: readonly NumericParamDescriptor[],
|
|
69
|
+
): Record<string, number> {
|
|
70
|
+
return Object.fromEntries(
|
|
71
|
+
descriptors
|
|
72
|
+
.filter((descriptor) => descriptor.default !== undefined)
|
|
73
|
+
.map((descriptor) => [descriptor.key, descriptor.default as number]),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST-RELATIVE CLIP AUTHORING + the clip self-checks, for any rigged asset:
|
|
3
|
+
* `assertClipRestBoundaries` (does it return to REST — what an additive layer
|
|
4
|
+
* needs) and `assertClipLoops` (does it return to WHERE IT STARTED — what a
|
|
5
|
+
* cyclic clip needs), plus `sampleAnimatedDeformedBounds`.
|
|
6
|
+
*
|
|
7
|
+
* Skeleton-agnostic by construction — it speaks `THREE.Bone`, `THREE.Object3D`
|
|
8
|
+
* and `THREE.AnimationClip` and knows nothing about humanoids — so it lives
|
|
9
|
+
* here in `lib/bake`, the procedural-asset family's shared home, beside
|
|
10
|
+
* `clip-layering.ts`. `lib/humanoid/rest-relative-animation.ts` re-exports it
|
|
11
|
+
* verbatim, so every import path that ever worked still does.
|
|
12
|
+
*
|
|
13
|
+
* REMOVAL LINE: delete this file and its humanoid re-export. You lose the
|
|
14
|
+
* ability to AUTHOR clips as pose deltas and the loud checks; retargeted
|
|
15
|
+
* clips and baking are unaffected.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import * as THREE from 'three';
|
|
19
|
+
|
|
20
|
+
export type EulerDelta = readonly [x: number, y: number, z: number];
|
|
21
|
+
|
|
22
|
+
function createTrackInterpolant(track: THREE.KeyframeTrack): {
|
|
23
|
+
evaluate(time: number): ArrayLike<number>;
|
|
24
|
+
} {
|
|
25
|
+
// Three assigns this native factory at runtime, but its r180 declarations
|
|
26
|
+
// omit the property. Keep the runtime factory so custom track interpolation
|
|
27
|
+
// remains intact.
|
|
28
|
+
const factory = (
|
|
29
|
+
track as THREE.KeyframeTrack & {
|
|
30
|
+
createInterpolant?: () => { evaluate(time: number): ArrayLike<number> };
|
|
31
|
+
}
|
|
32
|
+
).createInterpolant;
|
|
33
|
+
if (!factory) throw new Error(`Animation track ${track.name} has no interpolant factory.`);
|
|
34
|
+
return factory.call(track);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Build an absolute quaternion track from local deltas without erasing rest orientation. */
|
|
38
|
+
export function createRestRelativeQuaternionTrack(
|
|
39
|
+
bone: THREE.Bone,
|
|
40
|
+
times: readonly number[],
|
|
41
|
+
deltas: readonly EulerDelta[],
|
|
42
|
+
): THREE.QuaternionKeyframeTrack {
|
|
43
|
+
if (times.length !== deltas.length || times.length === 0) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Rest-relative track for ${bone.name} needs one delta per time (${times.length} times, ${deltas.length} deltas).`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
const rest = bone.quaternion.clone().normalize();
|
|
49
|
+
const values: number[] = [];
|
|
50
|
+
let previous: THREE.Quaternion | undefined;
|
|
51
|
+
for (const [x, y, z] of deltas) {
|
|
52
|
+
const delta = new THREE.Quaternion().setFromEuler(new THREE.Euler(x, y, z));
|
|
53
|
+
const value = rest.clone().multiply(delta).normalize();
|
|
54
|
+
if (previous && previous.dot(value) < 0) value.set(-value.x, -value.y, -value.z, -value.w);
|
|
55
|
+
values.push(value.x, value.y, value.z, value.w);
|
|
56
|
+
previous = value;
|
|
57
|
+
}
|
|
58
|
+
return new THREE.QuaternionKeyframeTrack(`${bone.name}.quaternion`, [...times], values);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Assert that a clip intentionally authored to return to rest actually does so. */
|
|
62
|
+
export function assertClipRestBoundaries(
|
|
63
|
+
root: THREE.Object3D,
|
|
64
|
+
clip: THREE.AnimationClip,
|
|
65
|
+
sampleTimes: readonly number[] = [0, clip.duration],
|
|
66
|
+
toleranceRadians = 1e-4,
|
|
67
|
+
): void {
|
|
68
|
+
for (const track of clip.tracks) {
|
|
69
|
+
if (!track.name.endsWith('.quaternion')) continue;
|
|
70
|
+
const nodeName = track.name.slice(0, -'.quaternion'.length);
|
|
71
|
+
const node = root.getObjectByName(nodeName);
|
|
72
|
+
if (!node) throw new Error(`Clip '${clip.name}' targets missing node '${nodeName}'.`);
|
|
73
|
+
const rest = node.quaternion.clone().normalize();
|
|
74
|
+
const interpolant = createTrackInterpolant(track);
|
|
75
|
+
for (const time of sampleTimes) {
|
|
76
|
+
const sample = interpolant.evaluate(time);
|
|
77
|
+
const value = new THREE.Quaternion(sample[0], sample[1], sample[2], sample[3]).normalize();
|
|
78
|
+
const angle = 2 * Math.acos(THREE.MathUtils.clamp(Math.abs(rest.dot(value)), -1, 1));
|
|
79
|
+
if (!Number.isFinite(angle) || angle > toleranceRadians) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Clip '${clip.name}' erases the rest orientation of '${nodeName}' at t=${time.toFixed(3)} (error ${angle.toFixed(6)} rad).`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Assert that a clip authored to LOOP actually does: every track's first and
|
|
90
|
+
* last keyframe values agree within `tolerance`, over a positive duration.
|
|
91
|
+
*
|
|
92
|
+
* The cyclic sibling of {@link assertClipRestBoundaries}, and deliberately a
|
|
93
|
+
* different check. That one asks "does the clip return to REST" — the property
|
|
94
|
+
* an additive layer needs, measured against the skeleton. This one asks "does
|
|
95
|
+
* the clip return to WHERE IT STARTED", which is what a looping clip needs and
|
|
96
|
+
* is a strictly weaker, skeleton-free property: a walk cycle, a wingbeat or an
|
|
97
|
+
* idle breath holds a pose that is nowhere near rest and must still meet
|
|
98
|
+
* itself seamlessly. Reaching for the rest check on a cyclic clip fails every
|
|
99
|
+
* honest loop; reaching for neither is how a one-frame pop ships, because the
|
|
100
|
+
* seam is exactly the frame nobody scrubs to.
|
|
101
|
+
*
|
|
102
|
+
* Works on the raw track VALUES rather than an interpolant, so it is exact and
|
|
103
|
+
* says nothing about the interpolation between the ends: what it catches is
|
|
104
|
+
* the authoring mistake — a phase gradient that does not close, a sine sampled
|
|
105
|
+
* over an open interval, a keyed track whose last value was never brought back
|
|
106
|
+
* — not a curve's shape.
|
|
107
|
+
*
|
|
108
|
+
* Throws naming the failing track and its drift; returns nothing when clean.
|
|
109
|
+
*/
|
|
110
|
+
export function assertClipLoops(clip: THREE.AnimationClip, tolerance = 1e-4): void {
|
|
111
|
+
if (!(clip.duration > 0)) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Clip '${clip.name}' cannot loop: its duration is ${clip.duration} — a cycle with no length.`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
for (const track of clip.tracks) {
|
|
117
|
+
const stride = track.getValueSize();
|
|
118
|
+
const { values } = track;
|
|
119
|
+
if (values.length < stride) {
|
|
120
|
+
throw new Error(`Clip '${clip.name}' track '${track.name}' has no keyframe values.`);
|
|
121
|
+
}
|
|
122
|
+
let drift = 0;
|
|
123
|
+
for (let i = 0; i < stride; i += 1) {
|
|
124
|
+
drift = Math.max(
|
|
125
|
+
drift,
|
|
126
|
+
Math.abs((values[i] as number) - (values[values.length - stride + i] as number)),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
if (!Number.isFinite(drift) || drift > tolerance) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Clip '${clip.name}' does not loop: track '${track.name}' drifts by ${drift.toFixed(5)} ` +
|
|
132
|
+
`between t=0 and t=${clip.duration} (tolerance ${tolerance}).`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface AnimatedBoundsSample {
|
|
139
|
+
bindDiagonal: number;
|
|
140
|
+
maximumDiagonal: number;
|
|
141
|
+
maximumExpansionRatio: number;
|
|
142
|
+
samples: number;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Sample precise SkinnedMesh bounds across a clip, restoring the source pose afterward. */
|
|
146
|
+
export function sampleAnimatedDeformedBounds(
|
|
147
|
+
root: THREE.Object3D,
|
|
148
|
+
clip: THREE.AnimationClip,
|
|
149
|
+
sampleCount = 20,
|
|
150
|
+
allowedExpansionRatio = 3,
|
|
151
|
+
): AnimatedBoundsSample {
|
|
152
|
+
if (sampleCount < 1) throw new Error('Animated bounds sampling needs at least one interval.');
|
|
153
|
+
const saved = new Map<
|
|
154
|
+
THREE.Object3D,
|
|
155
|
+
{ position: THREE.Vector3; quaternion: THREE.Quaternion; scale: THREE.Vector3 }
|
|
156
|
+
>();
|
|
157
|
+
root.traverse((object) => {
|
|
158
|
+
saved.set(object, {
|
|
159
|
+
position: object.position.clone(),
|
|
160
|
+
quaternion: object.quaternion.clone(),
|
|
161
|
+
scale: object.scale.clone(),
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
const preciseBounds = () => {
|
|
165
|
+
root.updateMatrixWorld(true);
|
|
166
|
+
const bounds = new THREE.Box3();
|
|
167
|
+
root.traverse((object) => {
|
|
168
|
+
const mesh = object as THREE.Mesh;
|
|
169
|
+
if (!mesh.isMesh || !mesh.geometry) return;
|
|
170
|
+
if ((mesh as THREE.SkinnedMesh).isSkinnedMesh) {
|
|
171
|
+
const skinned = mesh as THREE.SkinnedMesh;
|
|
172
|
+
skinned.computeBoundingBox();
|
|
173
|
+
if (skinned.boundingBox) {
|
|
174
|
+
bounds.union(skinned.boundingBox.clone().applyMatrix4(skinned.matrixWorld));
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox();
|
|
178
|
+
if (mesh.geometry.boundingBox) {
|
|
179
|
+
bounds.union(mesh.geometry.boundingBox.clone().applyMatrix4(mesh.matrixWorld));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
if (bounds.isEmpty()) throw new Error('Animated bounds sampling found no mesh bounds.');
|
|
184
|
+
const diagonal = bounds.getSize(new THREE.Vector3()).length();
|
|
185
|
+
if (!Number.isFinite(diagonal) || diagonal <= 0) {
|
|
186
|
+
throw new Error(`Animated bounds produced invalid diagonal ${diagonal}.`);
|
|
187
|
+
}
|
|
188
|
+
return diagonal;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const bindDiagonal = preciseBounds();
|
|
192
|
+
const mixer = new THREE.AnimationMixer(root);
|
|
193
|
+
mixer.clipAction(clip).play();
|
|
194
|
+
let maximumDiagonal = bindDiagonal;
|
|
195
|
+
try {
|
|
196
|
+
for (let index = 0; index <= sampleCount; index += 1) {
|
|
197
|
+
mixer.setTime((clip.duration * index) / sampleCount);
|
|
198
|
+
maximumDiagonal = Math.max(maximumDiagonal, preciseBounds());
|
|
199
|
+
}
|
|
200
|
+
} finally {
|
|
201
|
+
mixer.stopAllAction();
|
|
202
|
+
mixer.uncacheRoot(root);
|
|
203
|
+
for (const [object, transform] of saved) {
|
|
204
|
+
object.position.copy(transform.position);
|
|
205
|
+
object.quaternion.copy(transform.quaternion);
|
|
206
|
+
object.scale.copy(transform.scale);
|
|
207
|
+
}
|
|
208
|
+
root.updateMatrixWorld(true);
|
|
209
|
+
}
|
|
210
|
+
const maximumExpansionRatio = maximumDiagonal / bindDiagonal;
|
|
211
|
+
if (!Number.isFinite(maximumExpansionRatio) || maximumExpansionRatio > allowedExpansionRatio) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`Clip '${clip.name}' expands deformed bounds by ${maximumExpansionRatio.toFixed(3)}× (limit ${allowedExpansionRatio}×).`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return { bindDiagonal, maximumDiagonal, maximumExpansionRatio, samples: sampleCount + 1 };
|
|
217
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import type * as THREE from 'three';
|
|
3
|
+
import { clone as cloneSkeleton } from 'three/addons/utils/SkeletonUtils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* THE SEAM BETWEEN A MODEL BUILDER AND A PREFAB.
|
|
7
|
+
*
|
|
8
|
+
* A game authors a 3D asset as a builder returning an Object3D — that is what
|
|
9
|
+
* `project.bake.preview` photographs in isolation and what `project.bake`
|
|
10
|
+
* bakes. To place one in a world it has to become an R3F component, and until
|
|
11
|
+
* this existed the engine offered no way across that gap, so every project
|
|
12
|
+
* hand-rolled the same three decisions: build once or per instance, clone or
|
|
13
|
+
* duplicate, and how to hold the result across renders.
|
|
14
|
+
*
|
|
15
|
+
* The obvious hand-rolled answer is wrong, and wrong SILENTLY:
|
|
16
|
+
*
|
|
17
|
+
* const model = useMemo(() => build(), []); // <- stale after any edit
|
|
18
|
+
*
|
|
19
|
+
* React Fast Refresh re-renders a mounted component rather than remounting it,
|
|
20
|
+
* and deliberately preserves hook state. An empty dep array therefore survives
|
|
21
|
+
* every hot update, so the component goes on handing out the Object3D built
|
|
22
|
+
* from the module version before the edit. The new geometry is built correctly
|
|
23
|
+
* and nothing ever asks for it. Nothing errors; the model simply stops
|
|
24
|
+
* changing, which reads as "HMR is broken" and sends people to restart the
|
|
25
|
+
* host — the failure that motivated this file.
|
|
26
|
+
*
|
|
27
|
+
* `useModel` keys its cache on the BUILDER ITSELF. A hot update re-executes the
|
|
28
|
+
* module that defines the builder, which mints a new function identity, so the
|
|
29
|
+
* dep changes exactly when the source changed and at no other time.
|
|
30
|
+
*
|
|
31
|
+
* Instances share buffers: the builder runs once per builder identity, and each
|
|
32
|
+
* caller gets a `clone()`, which copies the scene graph while sharing geometry
|
|
33
|
+
* and material by reference. A hall with ten of a machine pays for ten graph
|
|
34
|
+
* entries and one set of buffers.
|
|
35
|
+
*
|
|
36
|
+
* function Scanner(props: ThreeElements['group']) {
|
|
37
|
+
* const model = useModel(buildScanner);
|
|
38
|
+
* return <group {...props}><primitive object={model} /></group>;
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* Disposal is deliberately NOT done here. The shared source outlives any one
|
|
42
|
+
* component, and clones share its buffers, so disposing on unmount would free
|
|
43
|
+
* geometry still in use by every sibling. A project that spawns and destroys
|
|
44
|
+
* models at runtime owns that lifetime itself — `disposeObject3D` is next door.
|
|
45
|
+
*/
|
|
46
|
+
const sources = new WeakMap<() => THREE.Object3D, THREE.Object3D>();
|
|
47
|
+
|
|
48
|
+
/** Build (or reuse) a model and return an instance of it, HMR-correct. */
|
|
49
|
+
export function useModel(build: () => THREE.Object3D): THREE.Object3D {
|
|
50
|
+
return useMemo(() => instantiate(build), [build]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The same thing outside React, for callers placing models imperatively. Kept
|
|
55
|
+
* beside the hook rather than duplicated, so both share one cache.
|
|
56
|
+
*/
|
|
57
|
+
export function instantiate(build: () => THREE.Object3D): THREE.Object3D {
|
|
58
|
+
let source = sources.get(build);
|
|
59
|
+
if (!source) {
|
|
60
|
+
source = build();
|
|
61
|
+
sources.set(build, source);
|
|
62
|
+
}
|
|
63
|
+
return cloneModel(source);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Clone a built model — and use `SkeletonUtils` when it is RIGGED.
|
|
68
|
+
*
|
|
69
|
+
* `Object3D.clone()` copies the meshes and the bones but NOT the bone↔skeleton
|
|
70
|
+
* wiring: the copied `SkinnedMesh` keeps a reference to the ORIGINAL's
|
|
71
|
+
* `THREE.Skeleton`, so it is driven by the original's bones and the clone's own
|
|
72
|
+
* bones drive nothing. One instance animates and every other stands frozen —
|
|
73
|
+
* with no error anywhere, because nothing is broken, only pointed elsewhere.
|
|
74
|
+
* This is the same trap the 3D-assets skill names for a baked GLB
|
|
75
|
+
* ("a SKINNED GLB must be cloned with `SkeletonUtils.clone`"); it applies to a
|
|
76
|
+
* model MODULE for exactly the same reason, and `useModel` is the seam every
|
|
77
|
+
* model module reaches a scene through.
|
|
78
|
+
*
|
|
79
|
+
* Measured by the adventurer driver: a story wound its clip onto the clone's
|
|
80
|
+
* bones and the character rendered its REST pose in every variant.
|
|
81
|
+
*
|
|
82
|
+
* `animations` is carried across too. Three's clone drops the field, and the
|
|
83
|
+
* model-file contract puts a model's clips on `root.animations` — a prefab
|
|
84
|
+
* that could not read them would have to rebuild them, which is a second
|
|
85
|
+
* implementation of the thing the module already shipped.
|
|
86
|
+
*/
|
|
87
|
+
function cloneModel(source: THREE.Object3D): THREE.Object3D {
|
|
88
|
+
let rigged = false;
|
|
89
|
+
source.traverse((object) => {
|
|
90
|
+
if ((object as THREE.SkinnedMesh).isSkinnedMesh === true) rigged = true;
|
|
91
|
+
});
|
|
92
|
+
const copy = rigged ? cloneSkeleton(source) : source.clone();
|
|
93
|
+
if (source.animations.length > 0) copy.animations = source.animations;
|
|
94
|
+
return copy;
|
|
95
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React as the implementer of this project's `dom` roots.
|
|
3
|
+
*
|
|
4
|
+
* A `dom` root is one of the three things the host can hand you: an
|
|
5
|
+
* `HTMLElement` (the others being a `<canvas>` and a shared `three`
|
|
6
|
+
* instance). What mounts into that element is entirely your choice — the
|
|
7
|
+
* engine has no opinion and ships no default, which is why this file lives in
|
|
8
|
+
* your project rather than in the engine.
|
|
9
|
+
*
|
|
10
|
+
* React is the shipped choice because the editor's JSX authoring
|
|
11
|
+
* (OID-addressed hierarchy, style/className write-back to source) is built on
|
|
12
|
+
* it. Nothing forces it: register your own factory for `'dom'` and the same
|
|
13
|
+
* root mounts Vue, Svelte, or plain DOM. You lose the JSX authoring panels
|
|
14
|
+
* until that stack supplies its own authoring adapter — the panel is the
|
|
15
|
+
* reward for implementing the adapter, and the game runs regardless.
|
|
16
|
+
*
|
|
17
|
+
* Thirty lines, and every one of them is React's own API — `createRoot`,
|
|
18
|
+
* `flushSync`, `unmount`. Copied in, yours to edit.
|
|
19
|
+
*/
|
|
20
|
+
export { createReactRootAdapter, registerReactAdapter } from './react-root-adapter';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { WorldProvider } from '@volter/game-runtime/react/world-state';
|
|
2
|
+
import type { GameDomHostContext } from '@volter/game-runtime/runtime/host-context';
|
|
3
|
+
import type { MountedReactGame, ReactRootAdapter } from '@volter/game-runtime/runtime/create-runtime';
|
|
4
|
+
import { isAdapterRegistered, registerAdapter } from '@volter/game-runtime/runtime/mount-game';
|
|
5
|
+
import { type ComponentType, createElement } from 'react';
|
|
6
|
+
import { flushSync } from 'react-dom';
|
|
7
|
+
import { createRoot } from 'react-dom/client';
|
|
8
|
+
|
|
9
|
+
interface ReactEntryModule {
|
|
10
|
+
readonly default?: ComponentType;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Construct one canonical React root adapter for direct host composition. */
|
|
14
|
+
export function createReactRootAdapter(id: string, Entry: ComponentType): ReactRootAdapter {
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
async mount(host: GameDomHostContext): Promise<MountedReactGame> {
|
|
18
|
+
if (!host.game) throw new Error(`React root "${id}" requires a Game host.`);
|
|
19
|
+
const reactRoot = createRoot(host.container);
|
|
20
|
+
flushSync(() => {
|
|
21
|
+
reactRoot.render(createElement(WorldProvider, { game: host.game! }, createElement(Entry)));
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
kind: 'dom',
|
|
25
|
+
container: host.container,
|
|
26
|
+
drivesOwnLoop: false,
|
|
27
|
+
dispose: () => reactRoot.unmount(),
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Register React as the factory for this project's `dom` roots. Call once at
|
|
35
|
+
* module load, before mounting — ADD the call to your `src/main.ts` yourself:
|
|
36
|
+
* the scaffold's main.ts registers only `three`, and installing this
|
|
37
|
+
* capability does not edit it.
|
|
38
|
+
*
|
|
39
|
+
* Registration is what makes a `dom` root mount at all; the engine ships no
|
|
40
|
+
* default. Swap React out by not calling this and registering your own
|
|
41
|
+
* factory for `'dom'` instead — the host hands that factory an `HTMLElement`
|
|
42
|
+
* and asks for a dispose, which is all `createApp().mount(el)` or
|
|
43
|
+
* `new Svelte({ target })` needs.
|
|
44
|
+
*/
|
|
45
|
+
export function registerReactAdapter(): void {
|
|
46
|
+
if (isAdapterRegistered('dom')) return;
|
|
47
|
+
registerAdapter('dom', (root, { entryModule }) => {
|
|
48
|
+
const Entry = (entryModule as ReactEntryModule | undefined)?.default;
|
|
49
|
+
if (!Entry) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`React root "${root.id}" entry "${root.entry ?? '(missing)'}" must default-export a component.`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { kind: 'dom', adapter: createReactRootAdapter(root.id, Entry) };
|
|
56
|
+
});
|
|
57
|
+
}
|