@webspatial/core-sdk 1.6.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/README.md +10 -0
- package/dist/JSBCommand.d.ts +398 -0
- package/dist/JSBCommand.js +668 -0
- package/dist/JSBCommand.js.map +1 -0
- package/dist/Spatial.d.ts +63 -0
- package/dist/Spatial.js +60 -0
- package/dist/Spatial.js.map +1 -0
- package/dist/SpatialObject.d.ts +19 -0
- package/dist/SpatialObject.js +44 -0
- package/dist/SpatialObject.js.map +1 -0
- package/dist/SpatialScene.d.ts +51 -0
- package/dist/SpatialScene.js +74 -0
- package/dist/SpatialScene.js.map +1 -0
- package/dist/SpatialSession.d.ts +143 -0
- package/dist/SpatialSession.js +173 -0
- package/dist/SpatialSession.js.map +1 -0
- package/dist/SpatialWebEvent.d.ts +8 -0
- package/dist/SpatialWebEvent.js +18 -0
- package/dist/SpatialWebEvent.js.map +1 -0
- package/dist/SpatialWebEventCreator.d.ts +11 -0
- package/dist/SpatialWebEventCreator.js +11 -0
- package/dist/SpatialWebEventCreator.js.map +1 -0
- package/dist/Spatialized2DElement.d.ts +42 -0
- package/dist/Spatialized2DElement.js +47 -0
- package/dist/Spatialized2DElement.js.map +1 -0
- package/dist/SpatializedDynamic3DElement.d.ts +7 -0
- package/dist/SpatializedDynamic3DElement.js +43 -0
- package/dist/SpatializedDynamic3DElement.js.map +1 -0
- package/dist/SpatializedElement.d.ts +7 -0
- package/dist/SpatializedElement.js +206 -0
- package/dist/SpatializedElement.js.map +1 -0
- package/dist/SpatializedElementCreator.d.ts +15 -0
- package/dist/SpatializedElementCreator.js +47 -0
- package/dist/SpatializedElementCreator.js.map +1 -0
- package/dist/SpatializedStatic3DElement.d.ts +195 -0
- package/dist/SpatializedStatic3DElement.js +327 -0
- package/dist/SpatializedStatic3DElement.js.map +1 -0
- package/dist/WebMsgCommand.d.ts +7 -0
- package/dist/WebMsgCommand.js +23 -0
- package/dist/WebMsgCommand.js.map +1 -0
- package/dist/index.d.ts +35 -1101
- package/dist/index.js +21 -3393
- package/dist/index.js.map +1 -1
- package/dist/install-polyfills.d.ts +2 -0
- package/dist/install-polyfills.js +13 -0
- package/dist/install-polyfills.js.map +1 -0
- package/dist/isSSREnv.d.ts +3 -0
- package/dist/isSSREnv.js +6 -0
- package/dist/isSSREnv.js.map +1 -0
- package/dist/motion/AnimationObject.d.ts +7 -0
- package/dist/motion/AnimationObject.js +140 -0
- package/dist/motion/AnimationObject.js.map +1 -0
- package/dist/motion/compute/index.d.ts +10 -0
- package/dist/motion/compute/index.js +19 -0
- package/dist/motion/compute/index.js.map +1 -0
- package/dist/motion/compute/motionPropertyValues.d.ts +19 -0
- package/dist/motion/compute/motionPropertyValues.js +50 -0
- package/dist/motion/compute/motionPropertyValues.js.map +1 -0
- package/dist/motion/compute/normalize.d.ts +31 -0
- package/dist/motion/compute/normalize.js +201 -0
- package/dist/motion/compute/normalize.js.map +1 -0
- package/dist/motion/compute/validate.d.ts +22 -0
- package/dist/motion/compute/validate.js +103 -0
- package/dist/motion/compute/validate.js.map +1 -0
- package/dist/motion/index.d.ts +8 -0
- package/dist/motion/index.js +6 -0
- package/dist/motion/index.js.map +1 -0
- package/dist/motion/native/serializeMotionTimeline.d.ts +12 -0
- package/dist/motion/native/serializeMotionTimeline.js +21 -0
- package/dist/motion/native/serializeMotionTimeline.js.map +1 -0
- package/dist/physicalMetrics-W5uZ5xKb.d.ts +48 -0
- package/dist/physicalMetrics.d.ts +1 -0
- package/dist/physicalMetrics.js +58 -0
- package/dist/physicalMetrics.js.map +1 -0
- package/dist/platform-adapter/CommandResultUtils.d.ts +12 -0
- package/dist/platform-adapter/CommandResultUtils.js +21 -0
- package/dist/platform-adapter/CommandResultUtils.js.map +1 -0
- package/dist/platform-adapter/createPlatformSync.d.ts +16 -0
- package/dist/platform-adapter/createPlatformSync.js +30 -0
- package/dist/platform-adapter/createPlatformSync.js.map +1 -0
- package/dist/platform-adapter/index.d.ts +12 -0
- package/dist/platform-adapter/index.js +10 -0
- package/dist/platform-adapter/index.js.map +1 -0
- package/dist/platform-adapter/interface.d.ts +7 -0
- package/dist/platform-adapter/interface.js +1 -0
- package/dist/platform-adapter/interface.js.map +1 -0
- package/dist/platform-adapter/pico-os/PicoOSPlatform.d.ts +25 -0
- package/dist/platform-adapter/pico-os/PicoOSPlatform.js +168 -0
- package/dist/platform-adapter/pico-os/PicoOSPlatform.js.map +1 -0
- package/dist/platform-adapter/puppeteer/PuppeteerPlatform.d.ts +66 -0
- package/dist/platform-adapter/puppeteer/PuppeteerPlatform.js +372 -0
- package/dist/platform-adapter/puppeteer/PuppeteerPlatform.js.map +1 -0
- package/dist/platform-adapter/spatialRequestMetadata.d.ts +6 -0
- package/dist/platform-adapter/spatialRequestMetadata.js +39 -0
- package/dist/platform-adapter/spatialRequestMetadata.js.map +1 -0
- package/dist/platform-adapter/spatialSceneQuery.d.ts +12 -0
- package/dist/platform-adapter/spatialSceneQuery.js +12 -0
- package/dist/platform-adapter/spatialSceneQuery.js.map +1 -0
- package/dist/platform-adapter/vision-os/VisionOSPlatform.d.ts +19 -0
- package/dist/platform-adapter/vision-os/VisionOSPlatform.js +77 -0
- package/dist/platform-adapter/vision-os/VisionOSPlatform.js.map +1 -0
- package/dist/platform-runtime.d.ts +12 -0
- package/dist/platform-runtime.js +14 -0
- package/dist/platform-runtime.js.map +1 -0
- package/dist/reality/Attachment.d.ts +19 -0
- package/dist/reality/Attachment.js +39 -0
- package/dist/reality/Attachment.js.map +1 -0
- package/dist/reality/component/ModelComponent.d.ts +14 -0
- package/dist/reality/component/ModelComponent.js +11 -0
- package/dist/reality/component/ModelComponent.js.map +1 -0
- package/dist/reality/component/SpatialComponent.d.ts +8 -0
- package/dist/reality/component/SpatialComponent.js +19 -0
- package/dist/reality/component/SpatialComponent.js.map +1 -0
- package/dist/reality/component/index.d.ts +8 -0
- package/dist/reality/component/index.js +3 -0
- package/dist/reality/component/index.js.map +1 -0
- package/dist/reality/entity/SpatialEntity.d.ts +7 -0
- package/dist/reality/entity/SpatialEntity.js +291 -0
- package/dist/reality/entity/SpatialEntity.js.map +1 -0
- package/dist/reality/entity/SpatialModelEntity.d.ts +17 -0
- package/dist/reality/entity/SpatialModelEntity.js +17 -0
- package/dist/reality/entity/SpatialModelEntity.js.map +1 -0
- package/dist/reality/entity/index.d.ts +8 -0
- package/dist/reality/entity/index.js +3 -0
- package/dist/reality/entity/index.js.map +1 -0
- package/dist/reality/geometry/SpatialBoxGeometry.d.ts +16 -0
- package/dist/reality/geometry/SpatialBoxGeometry.js +13 -0
- package/dist/reality/geometry/SpatialBoxGeometry.js.map +1 -0
- package/dist/reality/geometry/SpatialConeGeometry.d.ts +16 -0
- package/dist/reality/geometry/SpatialConeGeometry.js +13 -0
- package/dist/reality/geometry/SpatialConeGeometry.js.map +1 -0
- package/dist/reality/geometry/SpatialCylinderGeometry.d.ts +16 -0
- package/dist/reality/geometry/SpatialCylinderGeometry.js +13 -0
- package/dist/reality/geometry/SpatialCylinderGeometry.js.map +1 -0
- package/dist/reality/geometry/SpatialGeometry.d.ts +7 -0
- package/dist/reality/geometry/SpatialGeometry.js +13 -0
- package/dist/reality/geometry/SpatialGeometry.js.map +1 -0
- package/dist/reality/geometry/SpatialPlaneGeometry.d.ts +16 -0
- package/dist/reality/geometry/SpatialPlaneGeometry.js +13 -0
- package/dist/reality/geometry/SpatialPlaneGeometry.js.map +1 -0
- package/dist/reality/geometry/SpatialSphereGeometry.d.ts +16 -0
- package/dist/reality/geometry/SpatialSphereGeometry.js +13 -0
- package/dist/reality/geometry/SpatialSphereGeometry.js.map +1 -0
- package/dist/reality/geometry/index.d.ts +12 -0
- package/dist/reality/geometry/index.js +7 -0
- package/dist/reality/geometry/index.js.map +1 -0
- package/dist/reality/index.d.ts +18 -0
- package/dist/reality/index.js +7 -0
- package/dist/reality/index.js.map +1 -0
- package/dist/reality/material/SpatialMaterial.d.ts +7 -0
- package/dist/reality/material/SpatialMaterial.js +13 -0
- package/dist/reality/material/SpatialMaterial.js.map +1 -0
- package/dist/reality/material/SpatialUnlitMaterial.d.ts +16 -0
- package/dist/reality/material/SpatialUnlitMaterial.js +16 -0
- package/dist/reality/material/SpatialUnlitMaterial.js.map +1 -0
- package/dist/reality/material/index.d.ts +8 -0
- package/dist/reality/material/index.js +3 -0
- package/dist/reality/material/index.js.map +1 -0
- package/dist/reality/realityCreator.d.ts +22 -0
- package/dist/reality/realityCreator.js +89 -0
- package/dist/reality/realityCreator.js.map +1 -0
- package/dist/reality/resource/SpatialModelAsset.d.ts +15 -0
- package/dist/reality/resource/SpatialModelAsset.js +12 -0
- package/dist/reality/resource/SpatialModelAsset.js.map +1 -0
- package/dist/reality/resource/SpatialTextureResource.d.ts +16 -0
- package/dist/reality/resource/SpatialTextureResource.js +16 -0
- package/dist/reality/resource/SpatialTextureResource.js.map +1 -0
- package/dist/reality/resource/index.d.ts +9 -0
- package/dist/reality/resource/index.js +3 -0
- package/dist/reality/resource/index.js.map +1 -0
- package/dist/runtime/WebSpatialRuntimeError.d.ts +10 -0
- package/dist/runtime/WebSpatialRuntimeError.js +14 -0
- package/dist/runtime/WebSpatialRuntimeError.js.map +1 -0
- package/dist/runtime/capability-data.d.ts +12 -0
- package/dist/runtime/capability-data.js +134 -0
- package/dist/runtime/capability-data.js.map +1 -0
- package/dist/runtime/index.d.ts +8 -0
- package/dist/runtime/index.js +27 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/jsbAdapterPlatform.d.ts +9 -0
- package/dist/runtime/jsbAdapterPlatform.js +38 -0
- package/dist/runtime/jsbAdapterPlatform.js.map +1 -0
- package/dist/runtime/keys.d.ts +34 -0
- package/dist/runtime/keys.js +122 -0
- package/dist/runtime/keys.js.map +1 -0
- package/dist/runtime/semver.d.ts +8 -0
- package/dist/runtime/semver.js +32 -0
- package/dist/runtime/semver.js.map +1 -0
- package/dist/runtime/supports.d.ts +22 -0
- package/dist/runtime/supports.js +78 -0
- package/dist/runtime/supports.js.map +1 -0
- package/dist/runtime/types.d.ts +12 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/userAgent.d.ts +20 -0
- package/dist/runtime/userAgent.js +41 -0
- package/dist/runtime/userAgent.js.map +1 -0
- package/dist/scene-polyfill.d.ts +18 -0
- package/dist/scene-polyfill.js +480 -0
- package/dist/scene-polyfill.js.map +1 -0
- package/dist/spatial-host.d.ts +13 -0
- package/dist/spatial-host.js +18 -0
- package/dist/spatial-host.js.map +1 -0
- package/dist/spatial-window-polyfill.d.ts +3 -0
- package/dist/spatial-window-polyfill.js +155 -0
- package/dist/spatial-window-polyfill.js.map +1 -0
- package/dist/spatializedElementMotion-_0XWPQCE.d.ts +1009 -0
- package/dist/types/animation.d.ts +7 -0
- package/dist/types/animation.js +1 -0
- package/dist/types/animation.js.map +1 -0
- package/dist/types/global.d.ts +38 -0
- package/dist/types/global.js +1 -0
- package/dist/types/global.js.map +1 -0
- package/dist/types/internal.d.ts +7 -0
- package/dist/types/internal.js +12 -0
- package/dist/types/internal.js.map +1 -0
- package/dist/types/motion/index.d.ts +7 -0
- package/dist/types/motion/index.js +3 -0
- package/dist/types/motion/index.js.map +1 -0
- package/dist/types/motion/spatializedElementMotion.d.ts +7 -0
- package/dist/types/motion/spatializedElementMotion.js +1 -0
- package/dist/types/motion/spatializedElementMotion.js.map +1 -0
- package/dist/types/motion/spatializedMotion.d.ts +7 -0
- package/dist/types/motion/spatializedMotion.js +16 -0
- package/dist/types/motion/spatializedMotion.js.map +1 -0
- package/dist/types/motion/spatializedPlayback.d.ts +11 -0
- package/dist/types/motion/spatializedPlayback.js +1 -0
- package/dist/types/motion/spatializedPlayback.js.map +1 -0
- package/dist/types/motion/spatializedVisual.d.ts +35 -0
- package/dist/types/motion/spatializedVisual.js +1 -0
- package/dist/types/motion/spatializedVisual.js.map +1 -0
- package/dist/types/types.d.ts +7 -0
- package/dist/types/types.js +117 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils.d.ts +44 -0
- package/dist/utils.js +86 -0
- package/dist/utils.js.map +1 -0
- package/package.json +20 -4
- package/src/JSBCommand.ts +148 -91
- package/src/Spatial.ts +0 -21
- package/src/SpatialObject.ts +10 -0
- package/src/SpatialScene.ts +1 -5
- package/src/SpatialSession.ts +17 -3
- package/src/Spatialized2DElement.ts +5 -0
- package/src/SpatializedDynamic3DElement.ts +5 -1
- package/src/SpatializedElement.ts +29 -0
- package/src/SpatializedElementCreator.ts +6 -4
- package/src/SpatializedStatic3DElement.test.ts +99 -0
- package/src/SpatializedStatic3DElement.ts +141 -4
- package/src/WebMsgCommand.ts +50 -0
- package/src/coverage-boost.test.ts +258 -316
- package/src/index.ts +28 -12
- package/src/install-polyfills.ts +38 -0
- package/src/jsbcommand.coverage.test.ts +42 -48
- package/src/motion/AnimationObject.test.ts +421 -0
- package/src/motion/AnimationObject.ts +208 -0
- package/src/motion/compute/index.ts +10 -0
- package/src/motion/compute/motionPropertyValues.test.ts +55 -0
- package/src/motion/compute/motionPropertyValues.ts +70 -0
- package/src/motion/compute/normalize.test.ts +99 -0
- package/src/motion/compute/normalize.ts +289 -0
- package/src/motion/compute/validate.test.ts +229 -0
- package/src/motion/compute/validate.ts +156 -0
- package/src/motion/index.ts +2 -0
- package/src/motion/native/serializeMotionTimeline.test.ts +61 -0
- package/src/motion/native/serializeMotionTimeline.ts +27 -0
- package/src/platform-adapter/CommandResultUtils.ts +2 -2
- package/src/platform-adapter/createPlatformSync.ts +36 -0
- package/src/platform-adapter/index.ts +5 -51
- package/src/platform-adapter/interface.ts +35 -23
- package/src/platform-adapter/pico-os/PicoOSPlatform.ts +156 -59
- package/src/platform-adapter/puppeteer/PuppeteerPlatform.ts +37 -11
- package/src/platform-adapter/spatialRequestMetadata.test.ts +175 -0
- package/src/platform-adapter/spatialRequestMetadata.ts +48 -0
- package/src/platform-adapter/spatialSceneQuery.ts +17 -0
- package/src/platform-adapter/vision-os/VisionOSPlatform.ts +60 -24
- package/src/platform-runtime.ts +13 -0
- package/src/reality/Attachment.ts +2 -2
- package/src/reality/entity/SpatialEntity.ts +127 -2
- package/src/reality/realityCreator.ts +15 -1
- package/src/reality/resource/SpatialTextureResource.ts +16 -0
- package/src/reality/resource/index.ts +1 -0
- package/src/runtime/WebSpatialRuntimeError.ts +16 -0
- package/src/runtime/capability-data.ts +213 -0
- package/src/runtime/contract-review.test.ts +44 -0
- package/src/runtime/index.ts +17 -0
- package/src/runtime/jsbAdapterPlatform.test.ts +36 -0
- package/src/runtime/jsbAdapterPlatform.ts +51 -0
- package/src/runtime/keys.ts +140 -0
- package/src/runtime/semver.ts +33 -0
- package/src/runtime/supports.test.ts +346 -0
- package/src/runtime/supports.ts +112 -0
- package/src/runtime/types.ts +11 -0
- package/src/runtime/useAnimation.capability.test.ts +275 -0
- package/src/runtime/userAgent.ts +64 -0
- package/src/scene-polyfill.manifest.test.ts +312 -9
- package/src/scene-polyfill.request-metadata.test.ts +39 -0
- package/src/scene-polyfill.test.ts +33 -94
- package/src/scene-polyfill.ts +125 -92
- package/src/spatial-host.ts +25 -0
- package/src/spatial-window-polyfill.ts +18 -2
- package/src/transform-roundtrip.test.ts +90 -0
- package/src/types/animation.ts +224 -0
- package/src/types/{global.d.ts → global.ts} +10 -12
- package/src/types/motion/index.ts +10 -0
- package/src/types/motion/spatializedElementMotion.ts +49 -0
- package/src/types/motion/spatializedMotion.ts +147 -0
- package/src/types/motion/spatializedPlayback.ts +17 -0
- package/src/types/motion/spatializedVisual.ts +24 -0
- package/src/types/types.ts +12 -0
- package/src/utils.ts +54 -0
- package/tsup.config.ts +61 -36
- package/vitest.config.ts +5 -1
- package/dist/iife/index.d.ts +0 -1101
- package/dist/iife/index.global.js +0 -75
- package/dist/iife/index.global.js.map +0 -1
- package/src/platform-adapter/android/AndroidPlatform.ts +0 -133
- package/src/platform-adapter/ssr/SSRPlatform.ts +0 -43
- /package/src/{ssr-polyfill.ts → isSSREnv.ts} +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
describe('spatial request metadata', () => {
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
vi.useRealTimers()
|
|
6
|
+
vi.restoreAllMocks()
|
|
7
|
+
vi.unstubAllGlobals()
|
|
8
|
+
vi.resetModules()
|
|
9
|
+
delete window.__webspatialsdk__
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('builds opaque request ids and includes page epoch when available', async () => {
|
|
13
|
+
window.__webspatialsdk__ = { pageEpoch: 7 }
|
|
14
|
+
const { buildSpatialRequestQuery, createSpatialRequestId } = await import(
|
|
15
|
+
'./spatialRequestMetadata'
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const first = createSpatialRequestId()
|
|
19
|
+
const second = createSpatialRequestId()
|
|
20
|
+
expect(first).not.toBe(second)
|
|
21
|
+
|
|
22
|
+
const params = new URLSearchParams(buildSpatialRequestQuery(first))
|
|
23
|
+
expect(params.get('rid')).toBe(first)
|
|
24
|
+
expect(params.get('wsepoch')).toBe('7')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('emits request id without epoch when host state is unavailable', async () => {
|
|
28
|
+
const { buildSpatialRequestQuery, createSpatialRequestId } = await import(
|
|
29
|
+
'./spatialRequestMetadata'
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const requestId = createSpatialRequestId()
|
|
33
|
+
const params = new URLSearchParams(buildSpatialRequestQuery(requestId))
|
|
34
|
+
expect(params.get('rid')).toBe(requestId)
|
|
35
|
+
expect(params.get('wsepoch')).toBeNull()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('builds refresh-safe request ids across module reinitialization', async () => {
|
|
39
|
+
const nonceValues = [
|
|
40
|
+
[1, 2],
|
|
41
|
+
[3, 4],
|
|
42
|
+
]
|
|
43
|
+
const getRandomValues = vi.fn((values: Uint32Array) => {
|
|
44
|
+
const next = nonceValues.shift() ?? [5, 6]
|
|
45
|
+
values[0] = next[0]
|
|
46
|
+
values[1] = next[1]
|
|
47
|
+
return values
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
vi.stubGlobal('crypto', { getRandomValues })
|
|
51
|
+
|
|
52
|
+
const firstModule = await import('./spatialRequestMetadata')
|
|
53
|
+
const first = firstModule.createSpatialRequestId()
|
|
54
|
+
|
|
55
|
+
vi.resetModules()
|
|
56
|
+
|
|
57
|
+
const secondModule = await import('./spatialRequestMetadata')
|
|
58
|
+
const second = secondModule.createSpatialRequestId()
|
|
59
|
+
|
|
60
|
+
expect(first).toMatch(/^wsreq_/)
|
|
61
|
+
expect(second).toMatch(/^wsreq_/)
|
|
62
|
+
expect(first).not.toBe(second)
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('PicoOSPlatform SpatialDiv request correlation', () => {
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
vi.useRealTimers()
|
|
69
|
+
vi.restoreAllMocks()
|
|
70
|
+
vi.resetModules()
|
|
71
|
+
delete window.__webspatialsdk__
|
|
72
|
+
delete (window as any).__SpatialWebEvent
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('opens SpatialDiv protocol with rid and wsepoch', async () => {
|
|
76
|
+
window.__webspatialsdk__ = { pageEpoch: '3' }
|
|
77
|
+
const { SpatialWebEvent } = await import('../SpatialWebEvent')
|
|
78
|
+
SpatialWebEvent.init()
|
|
79
|
+
const open = vi.fn(
|
|
80
|
+
() =>
|
|
81
|
+
({
|
|
82
|
+
document: {
|
|
83
|
+
readyState: 'complete',
|
|
84
|
+
addEventListener: vi.fn(),
|
|
85
|
+
removeEventListener: vi.fn(),
|
|
86
|
+
},
|
|
87
|
+
}) as unknown as Window,
|
|
88
|
+
)
|
|
89
|
+
vi.spyOn(window, 'open').mockImplementation(open)
|
|
90
|
+
|
|
91
|
+
const { PicoOSPlatform } = await import('./pico-os/PicoOSPlatform')
|
|
92
|
+
const platform = new PicoOSPlatform()
|
|
93
|
+
const pending = platform.createNativeSpatialDiv()
|
|
94
|
+
|
|
95
|
+
const openedUrl = (open.mock.calls[0] as unknown[])[0] as string
|
|
96
|
+
const url = new URL(openedUrl)
|
|
97
|
+
const requestId = url.searchParams.get('rid')
|
|
98
|
+
expect(url.protocol).toBe('webspatial:')
|
|
99
|
+
expect(url.host).toBe('createSpatialized2DElement')
|
|
100
|
+
expect(requestId).toBeTruthy()
|
|
101
|
+
expect(url.searchParams.get('wsepoch')).toBe('3')
|
|
102
|
+
|
|
103
|
+
window.__SpatialWebEvent({
|
|
104
|
+
id: requestId!,
|
|
105
|
+
data: { spatialId: 'spatial-1' },
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
await expect(pending).resolves.toMatchObject({
|
|
109
|
+
success: true,
|
|
110
|
+
data: { id: 'spatial-1' },
|
|
111
|
+
})
|
|
112
|
+
expect(SpatialWebEvent.eventReceiver[requestId!]).toBeUndefined()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('opens attachment protocol with rid and wsepoch', async () => {
|
|
116
|
+
window.__webspatialsdk__ = { pageEpoch: '4' }
|
|
117
|
+
const { SpatialWebEvent } = await import('../SpatialWebEvent')
|
|
118
|
+
SpatialWebEvent.init()
|
|
119
|
+
const open = vi.fn(
|
|
120
|
+
() =>
|
|
121
|
+
({
|
|
122
|
+
document: {
|
|
123
|
+
readyState: 'complete',
|
|
124
|
+
addEventListener: vi.fn(),
|
|
125
|
+
removeEventListener: vi.fn(),
|
|
126
|
+
},
|
|
127
|
+
}) as unknown as Window,
|
|
128
|
+
)
|
|
129
|
+
vi.spyOn(window, 'open').mockImplementation(open)
|
|
130
|
+
|
|
131
|
+
const { PicoOSPlatform } = await import('./pico-os/PicoOSPlatform')
|
|
132
|
+
const platform = new PicoOSPlatform()
|
|
133
|
+
const pending = platform.createNativeAttachment()
|
|
134
|
+
|
|
135
|
+
const openedUrl = (open.mock.calls[0] as unknown[])[0] as string
|
|
136
|
+
const url = new URL(openedUrl)
|
|
137
|
+
const requestId = url.searchParams.get('rid')
|
|
138
|
+
expect(url.protocol).toBe('webspatial:')
|
|
139
|
+
expect(url.host).toBe('createAttachment')
|
|
140
|
+
expect(requestId).toBeTruthy()
|
|
141
|
+
expect(url.searchParams.get('wsepoch')).toBe('4')
|
|
142
|
+
|
|
143
|
+
window.__SpatialWebEvent({
|
|
144
|
+
id: requestId!,
|
|
145
|
+
data: { spatialId: 'attachment-1' },
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
await expect(pending).resolves.toMatchObject({
|
|
149
|
+
success: true,
|
|
150
|
+
data: { id: 'attachment-1' },
|
|
151
|
+
})
|
|
152
|
+
expect(SpatialWebEvent.eventReceiver[requestId!]).toBeUndefined()
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('times out pending SpatialDiv requests', async () => {
|
|
156
|
+
vi.useFakeTimers()
|
|
157
|
+
vi.spyOn(window, 'open').mockImplementation(() => null)
|
|
158
|
+
const { SpatialWebEvent } = await import('../SpatialWebEvent')
|
|
159
|
+
|
|
160
|
+
const { PicoOSPlatform } = await import('./pico-os/PicoOSPlatform')
|
|
161
|
+
const { DEFAULT_SPATIAL_REQUEST_TIMEOUT_MS } = await import(
|
|
162
|
+
'./spatialRequestMetadata'
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
const platform = new PicoOSPlatform()
|
|
166
|
+
const pending = platform.createNativeSpatialDiv()
|
|
167
|
+
await vi.advanceTimersByTimeAsync(DEFAULT_SPATIAL_REQUEST_TIMEOUT_MS)
|
|
168
|
+
|
|
169
|
+
await expect(pending).resolves.toMatchObject({
|
|
170
|
+
success: false,
|
|
171
|
+
errorCode: 'E_SPATIAL_REQUEST_TIMEOUT',
|
|
172
|
+
})
|
|
173
|
+
expect(Object.keys(SpatialWebEvent.eventReceiver)).toHaveLength(0)
|
|
174
|
+
})
|
|
175
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const REQUEST_ID_PREFIX = 'wsreq'
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_SPATIAL_REQUEST_TIMEOUT_MS = 30_000
|
|
4
|
+
|
|
5
|
+
let requestSequence = 0
|
|
6
|
+
|
|
7
|
+
// One nonce per JS execution context keeps request ids refresh-safe without
|
|
8
|
+
// exposing host-specific lifecycle details in the protocol surface.
|
|
9
|
+
const contextNonce = createContextNonce()
|
|
10
|
+
|
|
11
|
+
function createContextNonce(): string {
|
|
12
|
+
const cryptoApi = globalThis.crypto
|
|
13
|
+
if (cryptoApi?.getRandomValues) {
|
|
14
|
+
const values = new Uint32Array(2)
|
|
15
|
+
cryptoApi.getRandomValues(values)
|
|
16
|
+
return Array.from(values, value => value.toString(36)).join('')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Math.random().toString(36).slice(2, 12)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createSpatialRequestId(): string {
|
|
23
|
+
requestSequence += 1
|
|
24
|
+
return `${REQUEST_ID_PREFIX}_${contextNonce}_${requestSequence}`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getCurrentPageEpoch(): string | undefined {
|
|
28
|
+
const pageEpoch = window.__webspatialsdk__?.pageEpoch
|
|
29
|
+
if (pageEpoch === undefined || pageEpoch === null || pageEpoch === '') {
|
|
30
|
+
return undefined
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return String(pageEpoch)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildSpatialRequestQuery(
|
|
37
|
+
requestId: string,
|
|
38
|
+
pageEpoch = getCurrentPageEpoch(),
|
|
39
|
+
): string {
|
|
40
|
+
const params = new URLSearchParams()
|
|
41
|
+
params.set('rid', requestId)
|
|
42
|
+
|
|
43
|
+
if (pageEpoch !== undefined) {
|
|
44
|
+
params.set('wsepoch', pageEpoch)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return params.toString()
|
|
48
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SpatialSceneCreationOptionsInternal } from '../types/internal'
|
|
2
|
+
|
|
3
|
+
/** Build query string for webspatial://createSpatialScene (url + config). */
|
|
4
|
+
export function buildSpatialSceneQuery(
|
|
5
|
+
url: string,
|
|
6
|
+
config: SpatialSceneCreationOptionsInternal | undefined,
|
|
7
|
+
): string {
|
|
8
|
+
const params: Record<string, any> = { url, config }
|
|
9
|
+
return Object.keys(params)
|
|
10
|
+
.map(key => {
|
|
11
|
+
const value = params[key]
|
|
12
|
+
const finalValue =
|
|
13
|
+
typeof value === 'object' ? JSON.stringify(value) : value
|
|
14
|
+
return `${key}=${encodeURIComponent(finalValue)}`
|
|
15
|
+
})
|
|
16
|
+
.join('&')
|
|
17
|
+
}
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
PlatformAbility,
|
|
3
|
+
CommandResult,
|
|
4
|
+
WebSpatialProtocolResult,
|
|
5
|
+
} from '../interface'
|
|
2
6
|
import {
|
|
3
7
|
CommandResultFailure,
|
|
4
8
|
CommandResultSuccess,
|
|
5
9
|
} from '../CommandResultUtils'
|
|
10
|
+
import { buildSpatialSceneQuery } from '../spatialSceneQuery'
|
|
11
|
+
import type { SpatialSceneCreationOptionsInternal } from '../../types/internal'
|
|
12
|
+
import type { AttachmentEntityOptions } from '../../types/types'
|
|
13
|
+
import {
|
|
14
|
+
buildSpatialRequestQuery,
|
|
15
|
+
createSpatialRequestId,
|
|
16
|
+
} from '../spatialRequestMetadata'
|
|
6
17
|
|
|
7
18
|
type JSBError = {
|
|
19
|
+
code?: string
|
|
8
20
|
message: string
|
|
9
21
|
}
|
|
10
22
|
|
|
23
|
+
const UUID_RE =
|
|
24
|
+
/\b([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})\b/gi
|
|
25
|
+
|
|
11
26
|
export class VisionOSPlatform implements PlatformAbility {
|
|
12
27
|
async callJSB(cmd: string, msg: string): Promise<CommandResult> {
|
|
13
28
|
try {
|
|
@@ -17,41 +32,48 @@ export class VisionOSPlatform implements PlatformAbility {
|
|
|
17
32
|
return CommandResultSuccess(result)
|
|
18
33
|
} catch (error: unknown) {
|
|
19
34
|
// console.error(`VisionOSPlatform cmd: ${cmd}, msg: ${msg} error: ${error}`)
|
|
20
|
-
const { code, message } =
|
|
35
|
+
const { code, message } = this.parseJSBError(error)
|
|
21
36
|
return CommandResultFailure(code, message)
|
|
22
37
|
}
|
|
23
38
|
}
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
openSpatialSceneSync(
|
|
41
|
+
url: string,
|
|
42
|
+
config: SpatialSceneCreationOptionsInternal | undefined,
|
|
28
43
|
target?: string,
|
|
29
44
|
features?: string,
|
|
30
|
-
):
|
|
31
|
-
const
|
|
32
|
-
|
|
45
|
+
): WebSpatialProtocolResult {
|
|
46
|
+
const query = buildSpatialSceneQuery(url, config)
|
|
47
|
+
const { spatialId: id = '', windowProxy } = this.openWindow(
|
|
48
|
+
'createSpatialScene',
|
|
33
49
|
query,
|
|
34
50
|
target,
|
|
35
51
|
features,
|
|
36
52
|
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
53
|
+
|
|
54
|
+
return CommandResultSuccess({ windowProxy, id })
|
|
40
55
|
}
|
|
41
56
|
|
|
42
|
-
|
|
57
|
+
createNativeSpatialDiv(): Promise<WebSpatialProtocolResult> {
|
|
58
|
+
return this.openProtocolAsync('createSpatialized2DElement')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
createNativeAttachment(
|
|
62
|
+
_options?: AttachmentEntityOptions,
|
|
63
|
+
): Promise<WebSpatialProtocolResult> {
|
|
64
|
+
return this.openProtocolAsync('createAttachment')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private async openProtocolAsync(
|
|
43
68
|
command: string,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
features?: string,
|
|
47
|
-
): CommandResult {
|
|
69
|
+
): Promise<WebSpatialProtocolResult> {
|
|
70
|
+
const requestId = createSpatialRequestId()
|
|
48
71
|
const { spatialId: id = '', windowProxy } = this.openWindow(
|
|
49
72
|
command,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
73
|
+
buildSpatialRequestQuery(requestId),
|
|
74
|
+
undefined,
|
|
75
|
+
undefined,
|
|
53
76
|
)
|
|
54
|
-
|
|
55
77
|
return CommandResultSuccess({ windowProxy, id })
|
|
56
78
|
}
|
|
57
79
|
|
|
@@ -60,17 +82,31 @@ export class VisionOSPlatform implements PlatformAbility {
|
|
|
60
82
|
query?: string,
|
|
61
83
|
target?: string,
|
|
62
84
|
features?: string,
|
|
63
|
-
) {
|
|
85
|
+
): { spatialId?: string; windowProxy: WindowProxy | null } {
|
|
64
86
|
const windowProxy = window.open(
|
|
65
87
|
`webspatial://${command}?${query || ''}`,
|
|
66
88
|
target,
|
|
67
89
|
features,
|
|
68
90
|
)
|
|
69
91
|
const ua = windowProxy?.navigator.userAgent
|
|
70
|
-
const spatialId = ua?.match(
|
|
71
|
-
/\b([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})\b/gi,
|
|
72
|
-
)?.[0]
|
|
92
|
+
const spatialId = ua?.match(UUID_RE)?.[0]
|
|
73
93
|
|
|
74
94
|
return { spatialId, windowProxy }
|
|
75
95
|
}
|
|
96
|
+
|
|
97
|
+
private parseJSBError(error: unknown): { code: string; message: string } {
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse((error as JSBError).message ?? '')
|
|
100
|
+
return {
|
|
101
|
+
code: parsed.code ?? 'E_VISIONOS_JSB',
|
|
102
|
+
message: parsed.message ?? 'VisionOS JSB execution failed',
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
return {
|
|
106
|
+
code: 'E_VISIONOS_JSB',
|
|
107
|
+
message:
|
|
108
|
+
(error as JSBError)?.message ?? 'VisionOS JSB execution failed',
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
76
112
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createPlatformSync } from './platform-adapter'
|
|
2
|
+
import type { PlatformAbility } from './platform-adapter/interface'
|
|
3
|
+
|
|
4
|
+
let platformResolved: PlatformAbility | undefined
|
|
5
|
+
|
|
6
|
+
export function getPlatformSync(): PlatformAbility {
|
|
7
|
+
platformResolved ??= createPlatformSync()
|
|
8
|
+
return platformResolved
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function getPlatform(): Promise<PlatformAbility> {
|
|
12
|
+
return getPlatformSync()
|
|
13
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SpatialObject } from '../SpatialObject'
|
|
2
2
|
import {
|
|
3
|
-
CreateAttachmentEntityCommand,
|
|
4
3
|
UpdateAttachmentEntityCommand,
|
|
5
4
|
InitializeAttachmentCommand,
|
|
6
5
|
} from '../JSBCommand'
|
|
6
|
+
import { createNativeAttachment } from '../spatial-host'
|
|
7
7
|
import {
|
|
8
8
|
AttachmentEntityOptions,
|
|
9
9
|
AttachmentEntityUpdateOptions,
|
|
@@ -37,7 +37,7 @@ export class Attachment extends SpatialObject {
|
|
|
37
37
|
export async function createAttachmentEntity(
|
|
38
38
|
options: AttachmentEntityOptions,
|
|
39
39
|
): Promise<Attachment> {
|
|
40
|
-
const result = await
|
|
40
|
+
const result = await createNativeAttachment(options)
|
|
41
41
|
if (!result.success) {
|
|
42
42
|
throw new Error('createAttachmentEntity failed: ' + result?.errorMessage)
|
|
43
43
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
ConvertFromEntityToSceneCommand,
|
|
4
4
|
ConvertFromSceneToEntityCommand,
|
|
5
5
|
SetParentForEntityCommand,
|
|
6
|
+
AnimateTransformJSBCommand,
|
|
6
7
|
} from './../../JSBCommand'
|
|
7
8
|
import {
|
|
8
9
|
SpatialEntityEventType,
|
|
@@ -10,11 +11,15 @@ import {
|
|
|
10
11
|
SpatialEntityUserData,
|
|
11
12
|
Vec3,
|
|
12
13
|
} from '../../types/types'
|
|
14
|
+
import type {
|
|
15
|
+
AnimateTransformCommand,
|
|
16
|
+
AnimateTransformResult,
|
|
17
|
+
TransformValues,
|
|
18
|
+
AnimationError,
|
|
19
|
+
} from '../../types/animation'
|
|
13
20
|
import {
|
|
14
21
|
AddComponentToEntityCommand,
|
|
15
|
-
AddEntityToEntityCommand,
|
|
16
22
|
RemoveComponentFromEntityCommand,
|
|
17
|
-
RemoveEntityFromParentCommand,
|
|
18
23
|
UpdateEntityEventCommand,
|
|
19
24
|
UpdateEntityPropertiesCommand,
|
|
20
25
|
} from '../../JSBCommand'
|
|
@@ -23,6 +28,7 @@ import { SpatialEntityProperties } from '../../types/types'
|
|
|
23
28
|
import { SpatialComponent } from '../component/SpatialComponent'
|
|
24
29
|
import { SpatialWebEvent } from '../../SpatialWebEvent'
|
|
25
30
|
import { createSpatialEvent } from '../../SpatialWebEventCreator'
|
|
31
|
+
import { decomposeSRT } from '../../utils'
|
|
26
32
|
import {
|
|
27
33
|
ObjectDestroyMsg,
|
|
28
34
|
SpatialDragEndMsg,
|
|
@@ -34,6 +40,9 @@ import {
|
|
|
34
40
|
SpatialRotateMsg,
|
|
35
41
|
SpatialTapMsg,
|
|
36
42
|
SpatialWebMsgType,
|
|
43
|
+
AnimationCompletedEventPayload,
|
|
44
|
+
AnimationCanceledEventPayload,
|
|
45
|
+
AnimationFailedEventPayload,
|
|
37
46
|
} from '../../WebMsgCommand'
|
|
38
47
|
|
|
39
48
|
export class SpatialEntity extends SpatialObject {
|
|
@@ -120,6 +129,122 @@ export class SpatialEntity extends SpatialObject {
|
|
|
120
129
|
return new UpdateEntityPropertiesCommand(this, properties).execute()
|
|
121
130
|
}
|
|
122
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Send an animation command to the native layer.
|
|
134
|
+
*
|
|
135
|
+
* For `play`: registers event listeners for completion / stop / failure,
|
|
136
|
+
* sends the JSB command, and returns an `AnimateTransformResult` with
|
|
137
|
+
* `finished` and `stopped` promises.
|
|
138
|
+
*
|
|
139
|
+
* For `pause`, `resume`, `cancel``: sends the command and resolves when
|
|
140
|
+
* the bridge acknowledges it.
|
|
141
|
+
*/
|
|
142
|
+
animateTransform(
|
|
143
|
+
command: AnimateTransformCommand & { type: 'play' },
|
|
144
|
+
): Promise<AnimateTransformResult>
|
|
145
|
+
animateTransform(command: AnimateTransformCommand): Promise<void>
|
|
146
|
+
async animateTransform(
|
|
147
|
+
command: AnimateTransformCommand,
|
|
148
|
+
): Promise<AnimateTransformResult | void> {
|
|
149
|
+
const { animationId, type } = command
|
|
150
|
+
|
|
151
|
+
if (type === 'play') {
|
|
152
|
+
// Register event listeners BEFORE sending the play command
|
|
153
|
+
// to avoid race conditions where native fires before we listen.
|
|
154
|
+
let resolveFinished!: (val: TransformValues) => void
|
|
155
|
+
let resolveCancel!: (val: TransformValues) => void
|
|
156
|
+
let resolveFailed!: (err: AnimationError) => void
|
|
157
|
+
|
|
158
|
+
const finished = new Promise<TransformValues>(r => {
|
|
159
|
+
resolveFinished = r
|
|
160
|
+
})
|
|
161
|
+
const canceled = new Promise<TransformValues>(r => {
|
|
162
|
+
resolveCancel = r
|
|
163
|
+
})
|
|
164
|
+
const failed = new Promise<AnimationError>(r => {
|
|
165
|
+
resolveFailed = r
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const cleanup = () => {
|
|
169
|
+
SpatialWebEvent.removeEventReceiver(`${animationId}_completed`)
|
|
170
|
+
SpatialWebEvent.removeEventReceiver(`${animationId}_canceled`)
|
|
171
|
+
SpatialWebEvent.removeEventReceiver(`${animationId}_failed`)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
SpatialWebEvent.addEventReceiver(
|
|
175
|
+
`${animationId}_completed`,
|
|
176
|
+
(data: AnimationCompletedEventPayload) => {
|
|
177
|
+
cleanup()
|
|
178
|
+
const values = decomposeSRT(data.transform)
|
|
179
|
+
// Update local entity state to match the native final transform
|
|
180
|
+
if (values.position) this.position = values.position
|
|
181
|
+
if (values.rotation) this.rotation = values.rotation
|
|
182
|
+
if (values.scale) this.scale = values.scale
|
|
183
|
+
resolveFinished(values)
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
SpatialWebEvent.addEventReceiver(
|
|
188
|
+
`${animationId}_canceled`,
|
|
189
|
+
(data: AnimationCanceledEventPayload) => {
|
|
190
|
+
cleanup()
|
|
191
|
+
const values = decomposeSRT(data.transform)
|
|
192
|
+
if (values.position) this.position = values.position
|
|
193
|
+
if (values.rotation) this.rotation = values.rotation
|
|
194
|
+
if (values.scale) this.scale = values.scale
|
|
195
|
+
resolveCancel(values)
|
|
196
|
+
},
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
SpatialWebEvent.addEventReceiver(
|
|
200
|
+
`${animationId}_failed`,
|
|
201
|
+
(data: AnimationFailedEventPayload) => {
|
|
202
|
+
cleanup()
|
|
203
|
+
resolveFailed({
|
|
204
|
+
animationId: data.animationId,
|
|
205
|
+
command: data.command,
|
|
206
|
+
code: data.code,
|
|
207
|
+
reason: data.reason,
|
|
208
|
+
})
|
|
209
|
+
},
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
// Send the play command
|
|
213
|
+
const result = await new AnimateTransformJSBCommand(command).execute()
|
|
214
|
+
if (!result.success) {
|
|
215
|
+
cleanup()
|
|
216
|
+
throw new Error(
|
|
217
|
+
result.errorMessage ?? 'AnimateTransform play command failed',
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
animationId,
|
|
223
|
+
finished,
|
|
224
|
+
canceled,
|
|
225
|
+
failed,
|
|
226
|
+
} as AnimateTransformResult
|
|
227
|
+
} else {
|
|
228
|
+
// pause / resume / cancel — fire and wait for bridge ack
|
|
229
|
+
const result = await new AnimateTransformJSBCommand(command).execute()
|
|
230
|
+
if (!result.success) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
result.errorMessage ?? `AnimateTransform ${type} command failed`,
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Remove all animation event receivers for a given animationId.
|
|
240
|
+
* Called on entity unmount to prevent leaked listeners.
|
|
241
|
+
*/
|
|
242
|
+
cleanupAnimationListeners(animationId: string) {
|
|
243
|
+
SpatialWebEvent.removeEventReceiver(`${animationId}_completed`)
|
|
244
|
+
SpatialWebEvent.removeEventReceiver(`${animationId}_canceled`)
|
|
245
|
+
SpatialWebEvent.removeEventReceiver(`${animationId}_failed`)
|
|
246
|
+
}
|
|
247
|
+
|
|
123
248
|
async addEvent(type: SpatialEntityEventType, callback: (data: any) => void) {
|
|
124
249
|
if (this.events[type]) {
|
|
125
250
|
// replace if exist
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CreateSpatialGeometryCommand,
|
|
6
6
|
CreateSpatialModelEntityCommand,
|
|
7
7
|
CreateSpatialUnlitMaterialCommand,
|
|
8
|
+
CreateTextureCommand,
|
|
8
9
|
} from '../JSBCommand'
|
|
9
10
|
import {
|
|
10
11
|
ModelComponentOptions,
|
|
@@ -13,12 +14,13 @@ import {
|
|
|
13
14
|
SpatialModelEntityCreationOptions,
|
|
14
15
|
SpatialUnlitMaterialOptions,
|
|
15
16
|
SpatialEntityUserData,
|
|
17
|
+
SpatialTextureResourceOptions,
|
|
16
18
|
} from '../types/types'
|
|
17
19
|
import { SpatialEntity, SpatialModelEntity } from './entity'
|
|
18
20
|
import { ModelComponent } from './component'
|
|
19
21
|
import { SpatialGeometry } from './geometry'
|
|
20
22
|
import { SpatialUnlitMaterial } from './material'
|
|
21
|
-
import { SpatialModelAsset } from './resource'
|
|
23
|
+
import { SpatialModelAsset, SpatialTextureResource } from './resource'
|
|
22
24
|
|
|
23
25
|
export async function createSpatialEntity(
|
|
24
26
|
userData?: SpatialEntityUserData,
|
|
@@ -92,3 +94,15 @@ export async function createModelAsset(options: ModelAssetOptions) {
|
|
|
92
94
|
return new SpatialModelAsset(id, options)
|
|
93
95
|
}
|
|
94
96
|
}
|
|
97
|
+
|
|
98
|
+
export async function createSpatialTexture(
|
|
99
|
+
options: SpatialTextureResourceOptions,
|
|
100
|
+
) {
|
|
101
|
+
const result = await new CreateTextureCommand(options.url).execute()
|
|
102
|
+
if (!result.success) {
|
|
103
|
+
throw new Error('createSpatialTexture failed:' + result?.errorMessage)
|
|
104
|
+
} else {
|
|
105
|
+
const { id } = result.data
|
|
106
|
+
return new SpatialTextureResource(id, options)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SpatialObject } from '../../SpatialObject'
|
|
2
|
+
import { SpatialTextureResourceOptions } from '../../types/types'
|
|
3
|
+
import { UpdateTexturePropertiesCommand } from '../../JSBCommand'
|
|
4
|
+
|
|
5
|
+
export class SpatialTextureResource extends SpatialObject {
|
|
6
|
+
constructor(
|
|
7
|
+
public id: string,
|
|
8
|
+
public options: SpatialTextureResourceOptions,
|
|
9
|
+
) {
|
|
10
|
+
super(id)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
updateProperties(properties: Partial<SpatialTextureResourceOptions>) {
|
|
14
|
+
return new UpdateTexturePropertiesCommand(this, properties).execute()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when a runtime-gated JS API is invoked but `supports('<name>')` is false.
|
|
3
|
+
* See OpenSpec `runtime-capabilities/spec.md` (Unsupported behavior contracts).
|
|
4
|
+
*/
|
|
5
|
+
export class WebSpatialRuntimeError extends Error {
|
|
6
|
+
public readonly capability: string
|
|
7
|
+
|
|
8
|
+
constructor(capability: string, message?: string) {
|
|
9
|
+
super(
|
|
10
|
+
message ??
|
|
11
|
+
`Capability "${capability}" is not supported in this WebSpatial runtime`,
|
|
12
|
+
)
|
|
13
|
+
this.name = 'WebSpatialRuntimeError'
|
|
14
|
+
this.capability = capability
|
|
15
|
+
}
|
|
16
|
+
}
|