@needle-tools/engine 5.1.0-canary.deec6e4 → 5.1.0-canary.e6680fa
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/CHANGELOG.md +99 -1
- package/SKILL.md +4 -1
- package/components.needle.json +1 -1
- package/dist/needle-engine.bundle-Bl_hyH5G.umd.cjs +1734 -0
- package/dist/needle-engine.bundle-Cduc1gj6.min.js +1734 -0
- package/dist/{needle-engine.bundle-CvtELXh0.js → needle-engine.bundle-DNcqT8nJ.js} +19415 -18452
- package/dist/needle-engine.d.ts +1588 -374
- package/dist/needle-engine.js +572 -569
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/three.js +1 -0
- package/dist/three.min.js +21 -21
- package/dist/three.umd.cjs +16 -16
- package/lib/engine/api.d.ts +8 -1
- package/lib/engine/api.js +7 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +10 -18
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_audio.d.ts +68 -0
- package/lib/engine/engine_audio.js +172 -0
- package/lib/engine/engine_audio.js.map +1 -1
- package/lib/engine/engine_camera.fit.js +16 -4
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_components.js +1 -1
- package/lib/engine/engine_components.js.map +1 -1
- package/lib/engine/engine_context.d.ts +21 -8
- package/lib/engine/engine_context.js +46 -16
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_eventbus.d.ts +47 -0
- package/lib/engine/engine_context_eventbus.js +47 -0
- package/lib/engine/engine_context_eventbus.js.map +1 -0
- package/lib/engine/engine_disposable.d.ts +172 -0
- package/lib/engine/engine_disposable.js +136 -0
- package/lib/engine/engine_disposable.js.map +1 -0
- package/lib/engine/engine_gameobject.d.ts +1 -10
- package/lib/engine/engine_gameobject.js +22 -120
- package/lib/engine/engine_gameobject.js.map +1 -1
- package/lib/engine/engine_gltf_builtin_components.js +7 -69
- package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
- package/lib/engine/engine_init.js +7 -7
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_input.d.ts +24 -5
- package/lib/engine/engine_input.js +3 -2
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
- package/lib/engine/engine_instantiate_resolve.js +372 -0
- package/lib/engine/engine_instantiate_resolve.js.map +1 -0
- package/lib/engine/engine_license.d.ts +7 -7
- package/lib/engine/engine_license.js +186 -58
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_mainloop_utils.js +7 -4
- package/lib/engine/engine_mainloop_utils.js.map +1 -1
- package/lib/engine/engine_networking.d.ts +51 -37
- package/lib/engine/engine_networking.js +132 -82
- package/lib/engine/engine_networking.js.map +1 -1
- package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
- package/lib/engine/engine_networking.transport.websocket.js +38 -0
- package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
- package/lib/engine/engine_networking_blob.js +4 -4
- package/lib/engine/engine_networking_blob.js.map +1 -1
- package/lib/engine/engine_networking_instantiate.js +2 -2
- package/lib/engine/engine_networking_instantiate.js.map +1 -1
- package/lib/engine/engine_networking_types.d.ts +39 -1
- package/lib/engine/engine_networking_types.js +7 -0
- package/lib/engine/engine_networking_types.js.map +1 -1
- package/lib/engine/engine_physics_rapier.d.ts +21 -3
- package/lib/engine/engine_physics_rapier.js +94 -25
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_pmrem.js +51 -3
- package/lib/engine/engine_pmrem.js.map +1 -1
- package/lib/engine/engine_scenedata.js +2 -2
- package/lib/engine/engine_scenedata.js.map +1 -1
- package/lib/engine/engine_serialization_builtin_serializer.js +28 -5
- package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
- package/lib/engine/engine_serialization_core.d.ts +1 -0
- package/lib/engine/engine_serialization_core.js +7 -0
- package/lib/engine/engine_serialization_core.js.map +1 -1
- package/lib/engine/engine_types.d.ts +29 -11
- package/lib/engine/engine_types.js +1 -1
- package/lib/engine/engine_types.js.map +1 -1
- package/lib/engine/engine_util_decorator.js +7 -2
- package/lib/engine/engine_util_decorator.js.map +1 -1
- package/lib/engine/engine_utils.d.ts +1 -1
- package/lib/engine/engine_utils.js +19 -5
- package/lib/engine/engine_utils.js.map +1 -1
- package/lib/engine/engine_utils_format.js +20 -14
- package/lib/engine/engine_utils_format.js.map +1 -1
- package/lib/engine/engine_utils_qrcode.js +2 -2
- package/lib/engine/engine_utils_qrcode.js.map +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
- package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +6 -6
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.d.ts +10 -4
- package/lib/engine/webcomponents/needle-engine.js +3 -3
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
- package/lib/engine/xr/NeedleXRSession.js +50 -14
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/TempXRContext.js +2 -2
- package/lib/engine/xr/TempXRContext.js.map +1 -1
- package/lib/engine/xr/events.d.ts +1 -1
- package/lib/engine/xr/events.js.map +1 -1
- package/lib/engine-components/Animation.js +17 -16
- package/lib/engine-components/Animation.js.map +1 -1
- package/lib/engine-components/AnimationBuilder.d.ts +158 -0
- package/lib/engine-components/AnimationBuilder.js +305 -0
- package/lib/engine-components/AnimationBuilder.js.map +1 -0
- package/lib/engine-components/Animator.d.ts +6 -0
- package/lib/engine-components/Animator.js +23 -13
- package/lib/engine-components/Animator.js.map +1 -1
- package/lib/engine-components/AnimatorController.builder.d.ts +191 -0
- package/lib/engine-components/AnimatorController.builder.js +263 -0
- package/lib/engine-components/AnimatorController.builder.js.map +1 -0
- package/lib/engine-components/AnimatorController.d.ts +2 -119
- package/lib/engine-components/AnimatorController.js +33 -232
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioSource.d.ts +19 -3
- package/lib/engine-components/AudioSource.js +121 -68
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/Camera.d.ts +6 -1
- package/lib/engine-components/Camera.js +16 -3
- package/lib/engine-components/Camera.js.map +1 -1
- package/lib/engine-components/CameraUtils.js +14 -6
- package/lib/engine-components/CameraUtils.js.map +1 -1
- package/lib/engine-components/Collider.d.ts +18 -9
- package/lib/engine-components/Collider.js +61 -14
- package/lib/engine-components/Collider.js.map +1 -1
- package/lib/engine-components/Component.d.ts +72 -9
- package/lib/engine-components/Component.js +114 -10
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +1 -0
- package/lib/engine-components/ContactShadows.js +14 -1
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DragControls.d.ts +7 -0
- package/lib/engine-components/DragControls.js +19 -7
- package/lib/engine-components/DragControls.js.map +1 -1
- package/lib/engine-components/DropListener.js +4 -0
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/EventList.d.ts +31 -9
- package/lib/engine-components/EventList.js +37 -76
- package/lib/engine-components/EventList.js.map +1 -1
- package/lib/engine-components/Joints.d.ts +4 -2
- package/lib/engine-components/Joints.js +19 -3
- package/lib/engine-components/Joints.js.map +1 -1
- package/lib/engine-components/Light.js +9 -1
- package/lib/engine-components/Light.js.map +1 -1
- package/lib/engine-components/Networking.d.ts +1 -1
- package/lib/engine-components/Networking.js +1 -1
- package/lib/engine-components/OrbitControls.d.ts +1 -2
- package/lib/engine-components/OrbitControls.js +37 -14
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/RigidBody.d.ts +12 -4
- package/lib/engine-components/RigidBody.js +18 -4
- package/lib/engine-components/RigidBody.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +3 -0
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/SeeThrough.js +2 -2
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +8 -2
- package/lib/engine-components/VideoPlayer.js +42 -19
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/Voip.d.ts +16 -7
- package/lib/engine-components/Voip.js +90 -53
- package/lib/engine-components/Voip.js.map +1 -1
- package/lib/engine-components/api.d.ts +3 -1
- package/lib/engine-components/api.js +3 -1
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/codegen/components.d.ts +7 -13
- package/lib/engine-components/codegen/components.js +7 -13
- package/lib/engine-components/codegen/components.js.map +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +21 -11
- package/lib/engine-components/timeline/PlayableDirector.js +75 -67
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
- package/lib/engine-components/timeline/SignalAsset.js +1 -0
- package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
- package/lib/engine-components/timeline/TimelineBuilder.d.ts +413 -0
- package/lib/engine-components/timeline/TimelineBuilder.js +506 -0
- package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
- package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
- package/lib/engine-components/timeline/TimelineModels.js +3 -0
- package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +37 -6
- package/lib/engine-components/timeline/TimelineTracks.js +92 -26
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/timeline/index.d.ts +2 -1
- package/lib/engine-components/timeline/index.js +2 -0
- package/lib/engine-components/timeline/index.js.map +1 -1
- package/lib/engine-components/ui/Canvas.d.ts +1 -1
- package/lib/engine-components/ui/Canvas.js +2 -8
- package/lib/engine-components/ui/Canvas.js.map +1 -1
- package/lib/engine-components/ui/Text.d.ts +1 -0
- package/lib/engine-components/ui/Text.js +10 -7
- package/lib/engine-components/ui/Text.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +0 -1
- package/lib/engine-components/web/CursorFollow.js +21 -13
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +62 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +59 -2
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +2 -83
- package/plugins/common/cloud.js +6 -1
- package/plugins/common/license.js +55 -12
- package/plugins/common/worker.js +9 -4
- package/plugins/types/userconfig.d.ts +4 -1
- package/plugins/vite/asap.js +17 -8
- package/plugins/vite/build-pipeline.js +57 -20
- package/plugins/vite/dependencies.js +29 -10
- package/plugins/vite/dependency-watcher.js +2 -2
- package/plugins/vite/editor-connection.js +3 -3
- package/plugins/vite/license.js +42 -7
- package/plugins/vite/local-files-core.js +3 -3
- package/plugins/vite/local-files-utils.d.ts +3 -1
- package/plugins/vite/local-files-utils.js +29 -5
- package/plugins/vite/reload.js +1 -1
- package/plugins/vite/server.js +2 -1
- package/src/engine/api.ts +11 -1
- package/src/engine/codegen/register_types.ts +10 -18
- package/src/engine/engine_audio.ts +184 -0
- package/src/engine/engine_camera.fit.ts +15 -4
- package/src/engine/engine_components.ts +1 -1
- package/src/engine/engine_context.ts +52 -19
- package/src/engine/engine_context_eventbus.ts +73 -0
- package/src/engine/engine_disposable.ts +214 -0
- package/src/engine/engine_gameobject.ts +54 -159
- package/src/engine/engine_gltf_builtin_components.ts +7 -76
- package/src/engine/engine_init.ts +7 -7
- package/src/engine/engine_input.ts +28 -7
- package/src/engine/engine_instantiate_resolve.ts +407 -0
- package/src/engine/engine_license.ts +202 -56
- package/src/engine/engine_mainloop_utils.ts +7 -4
- package/src/engine/engine_networking.transport.websocket.ts +45 -0
- package/src/engine/engine_networking.ts +161 -137
- package/src/engine/engine_networking_blob.ts +4 -4
- package/src/engine/engine_networking_instantiate.ts +2 -2
- package/src/engine/engine_networking_types.ts +41 -1
- package/src/engine/engine_physics_rapier.ts +102 -33
- package/src/engine/engine_pmrem.ts +53 -3
- package/src/engine/engine_scenedata.ts +3 -3
- package/src/engine/engine_serialization_builtin_serializer.ts +32 -9
- package/src/engine/engine_serialization_core.ts +9 -0
- package/src/engine/engine_types.ts +46 -27
- package/src/engine/engine_util_decorator.ts +7 -2
- package/src/engine/engine_utils.ts +16 -5
- package/src/engine/engine_utils_format.ts +20 -14
- package/src/engine/engine_utils_qrcode.ts +2 -2
- package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
- package/src/engine/webcomponents/needle menu/needle-menu.ts +6 -6
- package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
- package/src/engine/webcomponents/needle-engine.ts +12 -6
- package/src/engine/xr/NeedleXRSession.ts +48 -13
- package/src/engine/xr/TempXRContext.ts +2 -2
- package/src/engine/xr/events.ts +1 -1
- package/src/engine-components/Animation.ts +19 -16
- package/src/engine-components/AnimationBuilder.ts +472 -0
- package/src/engine-components/Animator.ts +24 -12
- package/src/engine-components/AnimatorController.builder.ts +387 -0
- package/src/engine-components/AnimatorController.ts +20 -291
- package/src/engine-components/AudioSource.ts +130 -79
- package/src/engine-components/Camera.ts +16 -3
- package/src/engine-components/CameraUtils.ts +12 -5
- package/src/engine-components/Collider.ts +66 -18
- package/src/engine-components/Component.ts +118 -20
- package/src/engine-components/ContactShadows.ts +15 -1
- package/src/engine-components/DragControls.ts +18 -11
- package/src/engine-components/DropListener.ts +4 -0
- package/src/engine-components/EventList.ts +45 -83
- package/src/engine-components/Joints.ts +20 -4
- package/src/engine-components/Light.ts +10 -2
- package/src/engine-components/Networking.ts +1 -1
- package/src/engine-components/OrbitControls.ts +42 -16
- package/src/engine-components/RigidBody.ts +18 -4
- package/src/engine-components/SceneSwitcher.ts +3 -0
- package/src/engine-components/SeeThrough.ts +2 -2
- package/src/engine-components/VideoPlayer.ts +40 -17
- package/src/engine-components/Voip.ts +88 -53
- package/src/engine-components/api.ts +3 -1
- package/src/engine-components/codegen/components.ts +7 -13
- package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
- package/src/engine-components/timeline/PlayableDirector.ts +83 -81
- package/src/engine-components/timeline/SignalAsset.ts +4 -1
- package/src/engine-components/timeline/TimelineBuilder.ts +824 -0
- package/src/engine-components/timeline/TimelineModels.ts +5 -1
- package/src/engine-components/timeline/TimelineTracks.ts +96 -27
- package/src/engine-components/timeline/index.ts +2 -1
- package/src/engine-components/ui/Canvas.ts +2 -8
- package/src/engine-components/ui/Text.ts +12 -8
- package/src/engine-components/web/CursorFollow.ts +21 -14
- package/src/engine-components/webxr/WebXRImageTracking.ts +79 -7
- package/dist/needle-engine.bundle-1s2gOoKZ.min.js +0 -1732
- package/dist/needle-engine.bundle-j4nGJXCs.umd.cjs +0 -1732
- package/lib/engine-components/AvatarLoader.d.ts +0 -80
- package/lib/engine-components/AvatarLoader.js +0 -232
- package/lib/engine-components/AvatarLoader.js.map +0 -1
- package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
- package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
- package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
- package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
- package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
- package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
- package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
- package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
- package/src/engine-components/AvatarLoader.ts +0 -264
- package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
- package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
- package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
- package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
- package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
- package/src/vite-env.d.ts +0 -16
|
@@ -113,25 +113,49 @@ export function ensureTrailingSlash(path) {
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* @param {string} src
|
|
116
|
+
* @param {string} [base] - Vite base path (e.g. "/" or "/app/"). When provided,
|
|
117
|
+
* ext/ paths are made absolute so they resolve correctly under SPA routing.
|
|
116
118
|
* @returns {string}
|
|
117
119
|
*/
|
|
118
|
-
export function fixRelativeNewURL(src) {
|
|
120
|
+
export function fixRelativeNewURL(src, base) {
|
|
121
|
+
/** @param {string} path */
|
|
122
|
+
function makeAbsolute(path) {
|
|
123
|
+
// Strip any leading ./ ../ or / prefix to get the clean ext/... path
|
|
124
|
+
const clean = path.replace(/^(?:\.\.?\/)+/, '').replace(/^\//, '');
|
|
125
|
+
if (base) return base.replace(/\/+$/, '') + '/' + clean;
|
|
126
|
+
return clean;
|
|
127
|
+
}
|
|
128
|
+
|
|
119
129
|
src = src.replace(
|
|
120
130
|
/(?<==\s*)(["'])((?:(?:\.{1,2}\/)|\/)?ext\/[^"']*\/)\1/g,
|
|
121
131
|
(/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
|
|
122
|
-
const
|
|
123
|
-
return `new URL(${quote}${
|
|
132
|
+
const resolved = makeAbsolute(path);
|
|
133
|
+
return `new URL(${quote}${resolved}${quote}, self.location?.href || ${quote}${quote}).href`;
|
|
124
134
|
}
|
|
125
135
|
);
|
|
126
136
|
|
|
127
137
|
src = src.replace(
|
|
128
138
|
/new\s+URL\s*\(\s*(["'`])((?:(?:\.{1,2}\/)|\/)?ext\/[^"'`]+)\1\s*\)/g,
|
|
129
139
|
(/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
|
|
130
|
-
const
|
|
131
|
-
return `new URL(${quote}${
|
|
140
|
+
const resolved = makeAbsolute(path);
|
|
141
|
+
return `new URL(${quote}${resolved}${quote}, self.location?.href)`;
|
|
132
142
|
}
|
|
133
143
|
);
|
|
134
144
|
|
|
145
|
+
// Make remaining ext/ string literals absolute (e.g. font paths passed as
|
|
146
|
+
// function arguments like addVariant("normal","normal","ext/fonts/...")).
|
|
147
|
+
// The regexes above already consumed paths inside new URL() calls and
|
|
148
|
+
// assignment-based patterns, so this only catches leftover bare strings.
|
|
149
|
+
if (base) {
|
|
150
|
+
src = src.replace(
|
|
151
|
+
/(["'`])((?:\.{1,2}\/)?ext\/[^"'`]+)\1/g,
|
|
152
|
+
(/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
|
|
153
|
+
const resolved = makeAbsolute(path);
|
|
154
|
+
return `${quote}${resolved}${quote}`;
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
135
159
|
return src;
|
|
136
160
|
}
|
|
137
161
|
|
package/plugins/vite/reload.js
CHANGED
|
@@ -225,7 +225,7 @@ async function scheduleReload(server, level = 0) {
|
|
|
225
225
|
if (existsSync(lockFile)) {
|
|
226
226
|
if (level === 0)
|
|
227
227
|
needleLog(pluginName, "Lock file exists, waiting for export to finish...");
|
|
228
|
-
setTimeout(() => scheduleReload(server, level += 1), 300);
|
|
228
|
+
setTimeout(() => scheduleReload(server, level += 1), 300).unref();
|
|
229
229
|
return;
|
|
230
230
|
}
|
|
231
231
|
|
package/plugins/vite/server.js
CHANGED
|
@@ -60,7 +60,8 @@ export function needleServer(command, config, userSettings) {
|
|
|
60
60
|
})
|
|
61
61
|
.catch((err) => console.error("ERR: [needle:server] 'open' package not found - please make sure to install 'open' in your package.json\n", err));
|
|
62
62
|
}
|
|
63
|
-
}, 100)
|
|
63
|
+
}, 100);
|
|
64
|
+
i.unref();
|
|
64
65
|
}
|
|
65
66
|
},
|
|
66
67
|
}
|
package/src/engine/api.ts
CHANGED
|
@@ -114,6 +114,9 @@ export * from "./engine_addressables.js";
|
|
|
114
114
|
/** Animation playback and control utilities */
|
|
115
115
|
export { AnimationUtils } from "./engine_animation.js";
|
|
116
116
|
|
|
117
|
+
/** Standalone audio clip for playback control */
|
|
118
|
+
export { AudioClip } from "./engine_audio.js";
|
|
119
|
+
|
|
117
120
|
/** Application-level state and utilities */
|
|
118
121
|
export { Application } from "./engine_application.js";
|
|
119
122
|
|
|
@@ -164,6 +167,9 @@ export * from "./engine_constants.js";
|
|
|
164
167
|
*/
|
|
165
168
|
export * from "./engine_context.js";
|
|
166
169
|
|
|
170
|
+
/** Typed event bus for decoupled component communication via {@link Context.events} */
|
|
171
|
+
export * from "./engine_context_eventbus.js";
|
|
172
|
+
|
|
167
173
|
/** Registry for managing multiple engine contexts */
|
|
168
174
|
export * from "./engine_context_registry.js";
|
|
169
175
|
|
|
@@ -173,6 +179,10 @@ export * from "./engine_context_registry.js";
|
|
|
173
179
|
*/
|
|
174
180
|
export * from "./engine_coroutine.js"
|
|
175
181
|
|
|
182
|
+
/** DisposableStore for managing lifecycle-bound cleanup in components */
|
|
183
|
+
export { DisposableStore, on, isDisposable } from "./engine_disposable.js";
|
|
184
|
+
export type { DisposeFn, IDisposable } from "./engine_disposable.js";
|
|
185
|
+
|
|
176
186
|
/** Factory functions for creating primitives and objects */
|
|
177
187
|
export * from "./engine_create_objects.js";
|
|
178
188
|
|
|
@@ -220,7 +230,7 @@ export * from "./engine_input.js";
|
|
|
220
230
|
export { InstancingUtil } from "./engine_instancing.js";
|
|
221
231
|
|
|
222
232
|
/** License checking utilities */
|
|
223
|
-
export {
|
|
233
|
+
export { __gGoBKfJa, __CYjiNy, $TXm } from "./engine_license.js";
|
|
224
234
|
|
|
225
235
|
|
|
226
236
|
// ============================================================================
|
|
@@ -7,11 +7,6 @@ import { Animation } from "../../engine-components/Animation.js";
|
|
|
7
7
|
import { Animator } from "../../engine-components/Animator.js";
|
|
8
8
|
import { AudioListener } from "../../engine-components/AudioListener.js";
|
|
9
9
|
import { AudioSource } from "../../engine-components/AudioSource.js";
|
|
10
|
-
import { Avatar_Brain_LookAt } from "../../engine-components/avatar/Avatar_Brain_LookAt.js";
|
|
11
|
-
import { Avatar_MouthShapes } from "../../engine-components/avatar/Avatar_MouthShapes.js";
|
|
12
|
-
import { Avatar_MustacheShake } from "../../engine-components/avatar/Avatar_MustacheShake.js";
|
|
13
|
-
import { AvatarBlink_Simple } from "../../engine-components/avatar/AvatarBlink_Simple.js";
|
|
14
|
-
import { AvatarEyeLook_Rotation } from "../../engine-components/avatar/AvatarEyeLook_Rotation.js";
|
|
15
10
|
import { AxesHelper } from "../../engine-components/AxesHelper.js";
|
|
16
11
|
import { BasicIKConstraint } from "../../engine-components/BasicIKConstraint.js";
|
|
17
12
|
import { BoxHelperComponent } from "../../engine-components/BoxHelperComponent.js";
|
|
@@ -106,11 +101,12 @@ import { TestRunner } from "../../engine-components/TestRunner.js";
|
|
|
106
101
|
import { TestSimulateUserData } from "../../engine-components/TestRunner.js";
|
|
107
102
|
import { PlayableDirector } from "../../engine-components/timeline/PlayableDirector.js";
|
|
108
103
|
import { SignalReceiver } from "../../engine-components/timeline/SignalAsset.js";
|
|
109
|
-
import {
|
|
110
|
-
import {
|
|
111
|
-
import {
|
|
104
|
+
import { TimelineAnimationTrack } from "../../engine-components/timeline/TimelineTracks.js";
|
|
105
|
+
import { TimelineAudioTrack } from "../../engine-components/timeline/TimelineTracks.js";
|
|
106
|
+
import { TimelineMarkerTrack } from "../../engine-components/timeline/TimelineTracks.js";
|
|
112
107
|
import { SignalTrackHandler } from "../../engine-components/timeline/TimelineTracks.js";
|
|
113
|
-
import {
|
|
108
|
+
import { TimelineActivationTrack } from "../../engine-components/timeline/TimelineTracks.js";
|
|
109
|
+
import { TimelineControlTrack } from "../../engine-components/timeline/TimelineTracks.js";
|
|
114
110
|
import { TransformGizmo } from "../../engine-components/TransformGizmo.js";
|
|
115
111
|
import { BaseUIComponent } from "../../engine-components/ui/BaseUIComponent.js";
|
|
116
112
|
import { UIRootComponent } from "../../engine-components/ui/BaseUIComponent.js";
|
|
@@ -167,11 +163,6 @@ export function initBuiltinTypes() {
|
|
|
167
163
|
TypeStore.add("Animator", Animator);
|
|
168
164
|
TypeStore.add("AudioListener", AudioListener);
|
|
169
165
|
TypeStore.add("AudioSource", AudioSource);
|
|
170
|
-
TypeStore.add("Avatar_Brain_LookAt", Avatar_Brain_LookAt);
|
|
171
|
-
TypeStore.add("Avatar_MouthShapes", Avatar_MouthShapes);
|
|
172
|
-
TypeStore.add("Avatar_MustacheShake", Avatar_MustacheShake);
|
|
173
|
-
TypeStore.add("AvatarBlink_Simple", AvatarBlink_Simple);
|
|
174
|
-
TypeStore.add("AvatarEyeLook_Rotation", AvatarEyeLook_Rotation);
|
|
175
166
|
TypeStore.add("AxesHelper", AxesHelper);
|
|
176
167
|
TypeStore.add("BasicIKConstraint", BasicIKConstraint);
|
|
177
168
|
TypeStore.add("BoxHelperComponent", BoxHelperComponent);
|
|
@@ -266,11 +257,12 @@ export function initBuiltinTypes() {
|
|
|
266
257
|
TypeStore.add("TestSimulateUserData", TestSimulateUserData);
|
|
267
258
|
TypeStore.add("PlayableDirector", PlayableDirector);
|
|
268
259
|
TypeStore.add("SignalReceiver", SignalReceiver);
|
|
269
|
-
TypeStore.add("
|
|
270
|
-
TypeStore.add("
|
|
271
|
-
TypeStore.add("
|
|
260
|
+
TypeStore.add("TimelineAnimationTrack", TimelineAnimationTrack);
|
|
261
|
+
TypeStore.add("TimelineAudioTrack", TimelineAudioTrack);
|
|
262
|
+
TypeStore.add("TimelineMarkerTrack", TimelineMarkerTrack);
|
|
272
263
|
TypeStore.add("SignalTrackHandler", SignalTrackHandler);
|
|
273
|
-
TypeStore.add("
|
|
264
|
+
TypeStore.add("TimelineActivationTrack", TimelineActivationTrack);
|
|
265
|
+
TypeStore.add("TimelineControlTrack", TimelineControlTrack);
|
|
274
266
|
TypeStore.add("TransformGizmo", TransformGizmo);
|
|
275
267
|
TypeStore.add("BaseUIComponent", BaseUIComponent);
|
|
276
268
|
TypeStore.add("UIRootComponent", UIRootComponent);
|
|
@@ -21,4 +21,188 @@ export function ensureAudioContextIsResumed() {
|
|
|
21
21
|
}, 500);
|
|
22
22
|
});
|
|
23
23
|
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Represents an audio clip that can be loaded and played independently.
|
|
29
|
+
* The AudioClip class encapsulates the URL of the audio resource and provides
|
|
30
|
+
* methods for playback control (play, pause, stop) and querying duration.
|
|
31
|
+
*/
|
|
32
|
+
export class AudioClip {
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new AudioClip instance with the specified URL.
|
|
36
|
+
* @param url The URL of the audio resource to load. This can be a path to an audio file or a MediaStream URL.
|
|
37
|
+
*/
|
|
38
|
+
constructor(public readonly url: string) {
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Whether the clip is currently playing.
|
|
42
|
+
* @returns `true` if the clip is actively playing audio.
|
|
43
|
+
*/
|
|
44
|
+
get isPlaying(): boolean {
|
|
45
|
+
return this._audioElement !== undefined
|
|
46
|
+
&& !this._audioElement.paused
|
|
47
|
+
&& !this._audioElement.ended;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The total duration of the audio clip in seconds.
|
|
52
|
+
* Loads the audio metadata if not already available.
|
|
53
|
+
* @returns A promise that resolves with the duration in seconds.
|
|
54
|
+
*/
|
|
55
|
+
getDuration(): Promise<number> {
|
|
56
|
+
if (this._duration !== undefined) {
|
|
57
|
+
return Promise.resolve(this._duration);
|
|
58
|
+
}
|
|
59
|
+
return this.ensureAudioElement().then(audio => {
|
|
60
|
+
this._duration = audio.duration;
|
|
61
|
+
return audio.duration;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Plays the audio clip from the current position.
|
|
67
|
+
* @returns A promise that resolves when playback finishes, or rejects on error.
|
|
68
|
+
* If the clip is looping, the promise will never resolve on its own – call {@link stop} or {@link pause} to end playback.
|
|
69
|
+
*/
|
|
70
|
+
// #region Play
|
|
71
|
+
play(): Promise<void> {
|
|
72
|
+
return this.ensureAudioElement().then(audio => {
|
|
73
|
+
return new Promise<void>((resolve, reject) => {
|
|
74
|
+
const onEnded = () => {
|
|
75
|
+
cleanup();
|
|
76
|
+
resolve();
|
|
77
|
+
};
|
|
78
|
+
const onError = () => {
|
|
79
|
+
cleanup();
|
|
80
|
+
reject(new Error(`Playback error for ${this.url}`));
|
|
81
|
+
};
|
|
82
|
+
const onPause = () => {
|
|
83
|
+
// pause/stop also resolve the promise
|
|
84
|
+
cleanup();
|
|
85
|
+
resolve();
|
|
86
|
+
};
|
|
87
|
+
const cleanup = () => {
|
|
88
|
+
audio.removeEventListener("ended", onEnded);
|
|
89
|
+
audio.removeEventListener("error", onError);
|
|
90
|
+
audio.removeEventListener("pause", onPause);
|
|
91
|
+
};
|
|
92
|
+
audio.addEventListener("ended", onEnded);
|
|
93
|
+
audio.addEventListener("error", onError);
|
|
94
|
+
audio.addEventListener("pause", onPause);
|
|
95
|
+
audio.play().catch(err => {
|
|
96
|
+
cleanup();
|
|
97
|
+
reject(err);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Pauses playback at the current position.
|
|
105
|
+
* Call {@link play} to resume.
|
|
106
|
+
*/
|
|
107
|
+
// #region Pause/Stop
|
|
108
|
+
pause(): void {
|
|
109
|
+
this._audioElement?.pause();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Stops playback and resets the position to the beginning.
|
|
114
|
+
*/
|
|
115
|
+
stop(): void {
|
|
116
|
+
if (this._audioElement) {
|
|
117
|
+
this._audioElement.pause();
|
|
118
|
+
this._audioElement.currentTime = 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Whether the clip should loop when reaching the end. */
|
|
123
|
+
get loop(): boolean { return this._loop; }
|
|
124
|
+
set loop(value: boolean) {
|
|
125
|
+
this._loop = value;
|
|
126
|
+
if (this._audioElement) this._audioElement.loop = value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Playback volume from 0 (silent) to 1 (full). */
|
|
130
|
+
get volume(): number { return this._volume; }
|
|
131
|
+
set volume(value: number) {
|
|
132
|
+
this._volume = value;
|
|
133
|
+
if (this._audioElement) this._audioElement.volume = value;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Current playback position in seconds. */
|
|
137
|
+
get currentTime(): number { return this._audioElement?.currentTime ?? 0; }
|
|
138
|
+
set currentTime(value: number) {
|
|
139
|
+
if (this._audioElement) this._audioElement.currentTime = value;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Normalized playback progress from 0 to 1.
|
|
143
|
+
* @returns The current playback position as a value between 0 and 1, or 0 if the duration is unknown.
|
|
144
|
+
*/
|
|
145
|
+
get progress(): number {
|
|
146
|
+
if (!this._audioElement || !this._duration) return 0;
|
|
147
|
+
return this._audioElement.currentTime / this._duration;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Seeks to a normalized position (0–1) in the clip.
|
|
152
|
+
* @param position A value between 0 (start) and 1 (end).
|
|
153
|
+
*/
|
|
154
|
+
// #region Seek
|
|
155
|
+
seek(position: number): void {
|
|
156
|
+
if (this._audioElement && this._duration) {
|
|
157
|
+
this._audioElement.currentTime = Math.max(0, Math.min(1, position)) * this._duration;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** The underlying HTMLAudioElement, or `undefined` if not yet created.
|
|
162
|
+
* Use this to connect the element to the Web Audio API via `createMediaElementSource()`.
|
|
163
|
+
* @returns The HTMLAudioElement if the clip has been loaded or played, otherwise `undefined`.
|
|
164
|
+
*/
|
|
165
|
+
get audioElement(): HTMLAudioElement | undefined { return this._audioElement; }
|
|
166
|
+
|
|
167
|
+
private _audioElement?: HTMLAudioElement;
|
|
168
|
+
private _duration?: number;
|
|
169
|
+
private _loadPromise?: Promise<HTMLAudioElement>;
|
|
170
|
+
private _loop: boolean = false;
|
|
171
|
+
private _volume: number = 1;
|
|
172
|
+
|
|
173
|
+
/** Lazily creates and loads the shared HTMLAudioElement. */
|
|
174
|
+
private ensureAudioElement(): Promise<HTMLAudioElement> {
|
|
175
|
+
if (this._audioElement && this._loadPromise) {
|
|
176
|
+
return this._loadPromise;
|
|
177
|
+
}
|
|
178
|
+
const audio = this._audioElement ?? new Audio(this.url);
|
|
179
|
+
this._audioElement = audio;
|
|
180
|
+
audio.loop = this._loop;
|
|
181
|
+
audio.volume = this._volume;
|
|
182
|
+
|
|
183
|
+
if (audio.readyState >= HTMLMediaElement.HAVE_METADATA) {
|
|
184
|
+
this._duration = audio.duration;
|
|
185
|
+
this._loadPromise = Promise.resolve(audio);
|
|
186
|
+
return this._loadPromise;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this._loadPromise = new Promise<HTMLAudioElement>((resolve, reject) => {
|
|
190
|
+
const onLoaded = () => {
|
|
191
|
+
cleanup();
|
|
192
|
+
this._duration = audio.duration;
|
|
193
|
+
resolve(audio);
|
|
194
|
+
};
|
|
195
|
+
const onError = (e: Event) => {
|
|
196
|
+
cleanup();
|
|
197
|
+
reject(new Error(`Failed to load audio clip from ${this.url}: ${e}`));
|
|
198
|
+
};
|
|
199
|
+
const cleanup = () => {
|
|
200
|
+
audio.removeEventListener("loadedmetadata", onLoaded);
|
|
201
|
+
audio.removeEventListener("error", onError);
|
|
202
|
+
};
|
|
203
|
+
audio.addEventListener("loadedmetadata", onLoaded);
|
|
204
|
+
audio.addEventListener("error", onError);
|
|
205
|
+
});
|
|
206
|
+
return this._loadPromise;
|
|
207
|
+
}
|
|
24
208
|
}
|
|
@@ -257,12 +257,23 @@ export function fitCamera(options?: FitCameraOptions): null | FitCameraReturnTyp
|
|
|
257
257
|
else {
|
|
258
258
|
direction.sub(camera.worldPosition);
|
|
259
259
|
}
|
|
260
|
-
if (centerCamera === "y")
|
|
261
|
-
|
|
260
|
+
if (centerCamera === "y") {
|
|
261
|
+
// Preserve the camera's current elevation angle when it's already above the center,
|
|
262
|
+
// but clamp to a minimum elevation to prevent the camera from ending up at or below
|
|
263
|
+
// the scene center (which causes a "looking up from below" effect).
|
|
264
|
+
// direction points FROM camera TO center, so negative Y = camera is above center.
|
|
265
|
+
const horizontalLen = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
|
|
266
|
+
if (horizontalLen > 0.0001) {
|
|
267
|
+
const minY = -horizontalLen * verticalOffset * 4;
|
|
268
|
+
if (direction.y > minY) direction.y = minY;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// Camera is directly above/below center — pick a default slight angle from +Z
|
|
272
|
+
direction.set(0, -verticalOffset * 4, 1);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
262
275
|
direction.normalize();
|
|
263
276
|
direction.multiplyScalar(distance);
|
|
264
|
-
if (centerCamera === "y")
|
|
265
|
-
direction.y += -verticalOffset * 4 * distance;
|
|
266
277
|
|
|
267
278
|
let cameraLocalPosition = center.clone().sub(direction);
|
|
268
279
|
if (options.cameraOffset) {
|
|
@@ -8,9 +8,9 @@ import { InstantiateIdProvider } from "./engine_networking_instantiate.js";
|
|
|
8
8
|
import { Context, registerComponent } from "./engine_setup.js";
|
|
9
9
|
import type { ComponentInit, Constructor, ConstructorConcrete, IComponent, IGameObject } from "./engine_types.js";
|
|
10
10
|
import { $componentName } from "./engine_types.js";
|
|
11
|
+
import { TypeStore } from "./engine_typestore.js";
|
|
11
12
|
import { getParam } from "./engine_utils.js";
|
|
12
13
|
import { apply } from "./js-extensions/index.js";
|
|
13
|
-
import { TypeStore } from "./engine_typestore.js";
|
|
14
14
|
|
|
15
15
|
const COMPONENT_GUID_NAMESPACE = 'eff8ba80-635d-11ec-90d6-0242ac120003';
|
|
16
16
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'three/examples/jsm/renderers/webgl-legacy/nodes/WebGLNodes.js';
|
|
2
2
|
|
|
3
|
+
import type { SceneData } from 'needle-bindings';
|
|
3
4
|
import type { EffectComposer } from "postprocessing";
|
|
4
5
|
import {
|
|
5
6
|
BufferGeometry, Camera, Color, DepthTexture, Group,
|
|
@@ -22,6 +23,7 @@ import { Application } from './engine_application.js';
|
|
|
22
23
|
import { AssetDatabase } from './engine_assetdatabase.js';
|
|
23
24
|
import { FocusRect, FocusRectSettings, updateCameraFocusRect } from './engine_camera.js';
|
|
24
25
|
import { VERSION } from './engine_constants.js';
|
|
26
|
+
import { EventBus } from './engine_context_eventbus.js';
|
|
25
27
|
import { ContextEvent, ContextRegistry } from './engine_context_registry.js';
|
|
26
28
|
import { WaitForPromise } from './engine_coroutine.js';
|
|
27
29
|
import { ObjectUtils } from "./engine_create_objects.js";
|
|
@@ -36,9 +38,8 @@ import * as looputils from './engine_mainloop_utils.js';
|
|
|
36
38
|
import { NetworkConnection } from './engine_networking.js';
|
|
37
39
|
import { Physics } from './engine_physics.js';
|
|
38
40
|
import { PlayerViewManager } from './engine_playerview.js';
|
|
39
|
-
import { RendererData as SceneLighting } from './engine_scenelighting.js';
|
|
40
41
|
import { getSceneData } from './engine_scenedata.js';
|
|
41
|
-
import
|
|
42
|
+
import { RendererData as SceneLighting } from './engine_scenelighting.js';
|
|
42
43
|
import { getTempColor, logHierarchy } from './engine_three_utils.js';
|
|
43
44
|
import { Time } from './engine_time.js';
|
|
44
45
|
import { patchTonemapping } from './engine_tonemapping.js';
|
|
@@ -151,7 +152,7 @@ export function registerComponent(script: IComponent, context?: Context) {
|
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
/**
|
|
154
|
-
* The Needle Engine context is the main access point that holds all the data and state of a Needle Engine application.
|
|
155
|
+
* The Needle Engine context is the main access point that holds all the data and state of a Needle Engine application.
|
|
155
156
|
* It can be used to access the {@link Context.scene}, {@link Context.renderer}, {@link Context.mainCamera}, {@link Context.input}, {@link Context.physics}, {@link Context.time}, {@link Context.connection} (networking), and more.
|
|
156
157
|
*
|
|
157
158
|
* The context is automatically created when using the `<needle-engine>` web component.
|
|
@@ -511,6 +512,13 @@ export class Context implements IContext {
|
|
|
511
512
|
}
|
|
512
513
|
if (!this._fallbackCamera) {
|
|
513
514
|
this._fallbackCamera = new PerspectiveCamera(75, this.domWidth / this.domHeight, 0.1, 1000);
|
|
515
|
+
// Put the fallback into the scene graph. Without this, callers who
|
|
516
|
+
// do `ctx.mainCamera.add(child)` end up parenting children to an
|
|
517
|
+
// orphan camera that the renderer never traverses (since
|
|
518
|
+
// `renderer.render(scene, camera)` walks `scene`, not `camera`).
|
|
519
|
+
// Safe because this branch only runs before a real main camera
|
|
520
|
+
// component exists, and the fallback is replaced once one does.
|
|
521
|
+
this.scene.add(this._fallbackCamera);
|
|
514
522
|
}
|
|
515
523
|
return this._fallbackCamera;
|
|
516
524
|
}
|
|
@@ -522,19 +530,31 @@ export class Context implements IContext {
|
|
|
522
530
|
private _fallbackCamera: PerspectiveCamera | null = null;
|
|
523
531
|
|
|
524
532
|
/** access application state (e.g. if all audio should be muted) */
|
|
525
|
-
application: Application;
|
|
533
|
+
get application(): Application { return this._application; }
|
|
534
|
+
private _application!: Application;
|
|
526
535
|
/** access animation mixer used by components in the scene */
|
|
527
|
-
animations: AnimationsRegistry;
|
|
536
|
+
get animations(): AnimationsRegistry { return this._animations; }
|
|
537
|
+
private _animations!: AnimationsRegistry;
|
|
528
538
|
/** access timings (current frame number, deltaTime, timeScale, ...) */
|
|
529
|
-
time: Time;
|
|
539
|
+
get time(): Time { return this._time; }
|
|
540
|
+
private _time!: Time;
|
|
530
541
|
/** access input data (e.g. click or touch events) */
|
|
531
|
-
input: Input;
|
|
542
|
+
get input(): Input { return this._input; }
|
|
543
|
+
private _input!: Input;
|
|
532
544
|
/** access physics related methods (e.g. raycasting). To access the phyiscs engine use `context.physics.engine` */
|
|
533
|
-
physics: Physics;
|
|
545
|
+
get physics(): Physics { return this._physics; }
|
|
546
|
+
private _physics!: Physics;
|
|
534
547
|
/** access postprocessing effects stack. Add/remove effects and configure adaptive performance settings */
|
|
535
|
-
postprocessing: PostProcessing;
|
|
548
|
+
get postprocessing(): PostProcessing { return this._postprocessing; }
|
|
549
|
+
private _postprocessing!: PostProcessing;
|
|
536
550
|
/** access networking methods (use it to send or listen to messages or join a networking backend) */
|
|
537
|
-
connection: NetworkConnection;
|
|
551
|
+
get connection(): NetworkConnection { return this._connection; }
|
|
552
|
+
private _connection!: NetworkConnection;
|
|
553
|
+
/** context-level event bus for decoupled component communication
|
|
554
|
+
* @see {@link ContextEventMap} for known event types
|
|
555
|
+
*/
|
|
556
|
+
get events(): EventBus { return this._events; }
|
|
557
|
+
private _events = new EventBus();
|
|
538
558
|
/** @deprecated AssetDatabase is deprecated */
|
|
539
559
|
assets: AssetDatabase;
|
|
540
560
|
|
|
@@ -606,12 +626,12 @@ export class Context implements IContext {
|
|
|
606
626
|
else this.scene = new Scene();
|
|
607
627
|
if (args?.camera) this._mainCamera = args.camera;
|
|
608
628
|
|
|
609
|
-
this.
|
|
610
|
-
this.
|
|
611
|
-
this.
|
|
612
|
-
this.
|
|
613
|
-
this.
|
|
614
|
-
this.
|
|
629
|
+
this._application = new Application(this);
|
|
630
|
+
this._time = new Time();
|
|
631
|
+
this._input = new Input(this);
|
|
632
|
+
this._physics = new Physics(this);
|
|
633
|
+
this._postprocessing = new PostProcessing(this);
|
|
634
|
+
this._connection = new NetworkConnection(this);
|
|
615
635
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
616
636
|
this.assets = new AssetDatabase();
|
|
617
637
|
this.sceneLighting = new SceneLighting(this);
|
|
@@ -620,7 +640,7 @@ export class Context implements IContext {
|
|
|
620
640
|
this.players = new PlayerViewManager(this);
|
|
621
641
|
this.menu = new NeedleMenu(this);
|
|
622
642
|
this.lodsManager = new LODsManager(this);
|
|
623
|
-
this.
|
|
643
|
+
this._animations = new AnimationsRegistry(this);
|
|
624
644
|
this.accessibility = new AccessibilityManager(this);
|
|
625
645
|
|
|
626
646
|
|
|
@@ -863,12 +883,14 @@ export class Context implements IContext {
|
|
|
863
883
|
this.scene = new Scene();
|
|
864
884
|
this.addressables?.dispose();
|
|
865
885
|
this.lightmaps?.clear();
|
|
866
|
-
this.physics?.engine?.
|
|
886
|
+
this.physics?.engine?.dispose();
|
|
867
887
|
this.lodsManager.disable();
|
|
868
888
|
this.accessibility?.clear();
|
|
869
889
|
|
|
870
890
|
this._onBeforeRenderListeners.clear();
|
|
871
891
|
this._onAfterRenderListeners.clear();
|
|
892
|
+
this._events.clear();
|
|
893
|
+
this._events = new EventBus();
|
|
872
894
|
|
|
873
895
|
this.lights.length = 0;
|
|
874
896
|
|
|
@@ -912,6 +934,7 @@ export class Context implements IContext {
|
|
|
912
934
|
this.scene = null!;
|
|
913
935
|
this.renderer = null!;
|
|
914
936
|
this.input.dispose();
|
|
937
|
+
this.connection.dispose();
|
|
915
938
|
this.menu.onDestroy();
|
|
916
939
|
this.animations.onDestroy();
|
|
917
940
|
for (const cb of this._disposeCallbacks) {
|
|
@@ -1792,6 +1815,7 @@ export class Context implements IContext {
|
|
|
1792
1815
|
? (`${((window.performance as any).memory.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`)
|
|
1793
1816
|
: "n/a";
|
|
1794
1817
|
|
|
1818
|
+
const gl = this.renderer.getContext();
|
|
1795
1819
|
console.log(this.renderer.info.render.calls + " DrawCalls", "\nRender:",
|
|
1796
1820
|
{
|
|
1797
1821
|
shaders: this.renderer.info.programs?.length,
|
|
@@ -1801,7 +1825,16 @@ export class Context implements IContext {
|
|
|
1801
1825
|
{
|
|
1802
1826
|
usedMemory: usedJSHeapSize,
|
|
1803
1827
|
...this.renderer.info.memory
|
|
1804
|
-
},
|
|
1828
|
+
},
|
|
1829
|
+
"\nRenderer:",
|
|
1830
|
+
{
|
|
1831
|
+
dpr: this.renderer.getPixelRatio(),
|
|
1832
|
+
windowDpr: window.devicePixelRatio,
|
|
1833
|
+
antialias: gl.getContextAttributes()?.antialias,
|
|
1834
|
+
samples: gl.getParameter(gl.SAMPLES),
|
|
1835
|
+
resolution: `${this.renderer.domElement.width}x${this.renderer.domElement.height}`,
|
|
1836
|
+
},
|
|
1837
|
+
"\nTarget Framerate: " + this.targetFrameRate);
|
|
1805
1838
|
}
|
|
1806
1839
|
}
|
|
1807
1840
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Object3D } from "three";
|
|
2
|
+
|
|
3
|
+
import type { IComponent } from "./engine_types.js";
|
|
4
|
+
|
|
5
|
+
/** Typed event map for {@link Context.events}.
|
|
6
|
+
* Known events get full autocomplete; custom events can be typed at the call site via generic parameter.
|
|
7
|
+
*/
|
|
8
|
+
export interface ContextEventMap {
|
|
9
|
+
"scene-content-changed": {
|
|
10
|
+
/** The component that triggered the change (e.g. SceneSwitcher, DropListener) */
|
|
11
|
+
readonly source: IComponent;
|
|
12
|
+
/** The root object that was added/loaded */
|
|
13
|
+
readonly object: Object3D;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Options for {@link EventBus.on}. */
|
|
18
|
+
export interface EventBusListenerOptions {
|
|
19
|
+
/** If true the listener is automatically removed after the first invocation. */
|
|
20
|
+
once?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Typed event bus. Known {@link ContextEventMap} events get full autocomplete.
|
|
24
|
+
* Custom events can be typed at the call site via generic parameter.
|
|
25
|
+
* @example Known events
|
|
26
|
+
* ```ts
|
|
27
|
+
* context.events.on("scene-content-changed", e => e.object);
|
|
28
|
+
* ```
|
|
29
|
+
* @example Custom events — type at call site
|
|
30
|
+
* ```ts
|
|
31
|
+
* context.events.emit<{ pts: number }>("scored", { pts: 10 });
|
|
32
|
+
* context.events.on<{ pts: number }>("scored", e => e.pts);
|
|
33
|
+
* ```
|
|
34
|
+
* @example Once
|
|
35
|
+
* ```ts
|
|
36
|
+
* context.events.on("scene-content-changed", e => { ... }, { once: true });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class EventBus {
|
|
40
|
+
private _listeners = new Map<string, Function[]>();
|
|
41
|
+
|
|
42
|
+
/** Emit a known {@link ContextEventMap} event */
|
|
43
|
+
emit<K extends keyof ContextEventMap & string>(type: K, detail?: ContextEventMap[K]): void;
|
|
44
|
+
/** Emit a custom event with user-provided type */
|
|
45
|
+
emit<T>(type: string, detail?: T): void;
|
|
46
|
+
emit(type: string, detail?: unknown): void {
|
|
47
|
+
const arr = this._listeners.get(type);
|
|
48
|
+
if (arr) for (const cb of [...arr]) cb(detail);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Subscribe to a known {@link ContextEventMap} event. Returns an unsubscribe function. */
|
|
52
|
+
on<K extends keyof ContextEventMap & string>(type: K, callback: (args: ContextEventMap[K]) => void, options?: EventBusListenerOptions): () => void;
|
|
53
|
+
/** Subscribe to a custom event with user-provided type. Returns an unsubscribe function. */
|
|
54
|
+
on<T>(type: string, callback: (args: T) => void, options?: EventBusListenerOptions): () => void;
|
|
55
|
+
on(type: string, callback: Function, options?: EventBusListenerOptions): () => void {
|
|
56
|
+
let arr = this._listeners.get(type);
|
|
57
|
+
if (!arr) { arr = []; this._listeners.set(type, arr); }
|
|
58
|
+
const unsub = () => {
|
|
59
|
+
const i = arr.indexOf(wrapped);
|
|
60
|
+
if (i >= 0) arr.splice(i, 1);
|
|
61
|
+
};
|
|
62
|
+
const wrapped = options?.once
|
|
63
|
+
? (...args: unknown[]) => { unsub(); callback(...args); }
|
|
64
|
+
: callback;
|
|
65
|
+
arr.push(wrapped);
|
|
66
|
+
return unsub;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Remove all listeners. Called when the context is cleared or destroyed. */
|
|
70
|
+
clear(): void {
|
|
71
|
+
this._listeners.clear();
|
|
72
|
+
}
|
|
73
|
+
}
|