lecodes-sdk 2.4.1 → 2.4.2
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/dist/types/core/Aspect.d.ts +34 -5
- package/dist/types/g2/OneWay2D.d.ts +0 -1
- package/dist/types/g2/Physics2D.d.ts +8 -6
- package/dist/types/g2/Scene2D.d.ts +1 -1
- package/dist/types/g2/Shape2D.d.ts +43 -15
- package/dist/types/gl/Model.d.ts +3 -2
- package/dist/types/gl/Scene.d.ts +1 -1
- package/dist/types/gl/animation/DynamicBone.d.ts +99 -35
- package/dist/types/gl/animation/IK.d.ts +0 -1
- package/dist/types/gl/nav/NavAgent.d.ts +3 -2
- package/dist/types/gl/physics/Physics.d.ts +4 -5
- package/dist/types/gl/physics/Shape.d.ts +40 -15
- package/dist/types/gl/vehicle/Vehicle.d.ts +54 -35
- package/dist/types/gl/vehicle/Wheel.d.ts +31 -10
- package/dist/types/plugins/gen/ar/contract.d.ts +152 -0
- package/dist/types/plugins/gen/ar/sdk/ar.d.ts +47 -21
- package/dist/types/plugins/gen/ar/sdk/ar.gen.d.ts +17 -3
- package/dist/types/plugins/gen/audio-recorder/contract.d.ts +64 -0
- package/dist/types/plugins/gen/browser/contract.d.ts +108 -0
- package/dist/types/plugins/gen/camera/contract.d.ts +27 -0
- package/dist/types/plugins/gen/geolocation/contract.d.ts +52 -0
- package/dist/types/plugins/gen/map/contract.d.ts +144 -0
- package/dist/types/plugins/gen/push/contract.d.ts +83 -0
- package/dist/types/plugins/gen/qr-scanner/contract.d.ts +16 -0
- package/dist/types/plugins/gen/speech/contract.d.ts +67 -0
- package/dist/types/plugins/gen/webrtc/contract.d.ts +342 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types.json +1 -1
- package/package.json +1 -1
- package/src/bridges/gl.d.ts +5 -3
- package/src/compile/compileProject.ts +45 -10
- package/src/compile/index.ts +7 -0
- package/src/compile/webHalf.ts +255 -0
- package/src/core/Aspect.ts +118 -35
- package/src/g2/OneWay2D.ts +0 -2
- package/src/g2/Physics2D.ts +8 -16
- package/src/g2/Scene2D.ts +1 -1
- package/src/g2/Shape2D.ts +51 -22
- package/src/gl/Model.ts +3 -2
- package/src/gl/Scene.ts +1 -1
- package/src/gl/animation/DynamicBone.ts +549 -486
- package/src/gl/animation/IK.ts +0 -2
- package/src/gl/nav/NavAgent.ts +14 -12
- package/src/gl/physics/Physics.ts +4 -5
- package/src/gl/physics/Shape.ts +49 -23
- package/src/gl/vehicle/Vehicle.ts +102 -58
- package/src/gl/vehicle/Wheel.ts +45 -11
- package/src/plugins/gen/ar/contract.d.ts +35 -1
- package/src/plugins/gen/ar/sdk/ar.gen.ts +25 -6
- package/src/plugins/gen/ar/sdk/ar.ts +102 -35
- package/src/version.ts +1 -1
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// GENERATED by scripts/vendor-plugins.ts from lecodes-plugins/plugins/ar/sdk/ar.gen.ts — do not edit here.
|
|
2
2
|
// Change it in the plugin repo and run `bun run vendor:plugins`; `bun run check:plugins` fails when this copy is stale.
|
|
3
3
|
// GENERATED by `lecodes plugin gen` from contract.d.ts — do not edit.
|
|
4
|
-
// ar: the service "ar", contract version
|
|
4
|
+
// ar: the service "ar", contract version 2.
|
|
5
5
|
|
|
6
6
|
import { ServiceChannel, _fromEntity, _fromFile, _fromScene3D, _toEntity, _toFile, type Entity, type EventReaders, type File } from "../../../../plugin"
|
|
7
|
-
import type { AREvents, ARParams, HitResult, HitTarget, ImageTarget, Pose, StartOptions } from "../contract"
|
|
7
|
+
import type { AREvents, ARParams, HitResult, HitTarget, ImageTarget, Pose, QRTarget, StartOptions } from "../contract"
|
|
8
8
|
|
|
9
9
|
/** What the halves register under. */
|
|
10
10
|
export const NAME = "ar"
|
|
11
11
|
/** The contract's version: the highest `@since` of its members. */
|
|
12
|
-
export const VERSION =
|
|
12
|
+
export const VERSION = 2
|
|
13
13
|
|
|
14
|
-
const _fromStartOptions = (v: StartOptions): any => ({ ...v, images: v.images === undefined ? undefined : v.images.map((x: any) => _fromImageTarget(x)) })
|
|
14
|
+
const _fromStartOptions = (v: StartOptions): any => ({ ...v, images: v.images === undefined ? undefined : v.images.map((x: any) => _fromImageTarget(x)), codes: v.codes === undefined ? undefined : v.codes.map((x: any) => _fromQRTarget(x)) })
|
|
15
15
|
const _fromImageTarget = (v: ImageTarget): any => ({ ...v, image: _fromFile(v.image), entity: _fromEntity(v.entity) })
|
|
16
|
+
const _fromQRTarget = (v: QRTarget): any => ({ ...v, entity: _fromEntity(v.entity) })
|
|
16
17
|
const _fromARParams = (v: ARParams): any => ({ ...v, scene: v.scene === undefined ? undefined : _fromScene3D(v.scene), camera: v.camera === undefined ? undefined : _fromEntity(v.camera) })
|
|
17
18
|
|
|
18
19
|
/** The events whose payload holds a File: read before a listener sees it. */
|
|
@@ -42,6 +43,15 @@ export const stop = (service: ServiceChannel<AREvents>): Promise<void> =>
|
|
|
42
43
|
export const setImages = (service: ServiceChannel<AREvents>, images: ImageTarget[]): Promise<void> =>
|
|
43
44
|
service._call("setImages", [images.map((x: any) => _fromImageTarget(x))])
|
|
44
45
|
|
|
46
|
+
/** The twin of `setImages` for QR codes: replace the set of QR targets of a RUNNING session
|
|
47
|
+
* without restarting it; a code no longer in the set stops driving its entity (`tracked: false`
|
|
48
|
+
* once if it was tracked). Before `start`, the codes are `StartOptions.codes`. A half that tracks
|
|
49
|
+
* no codes yet (the native ones) rejects "failed".
|
|
50
|
+
* Contract version 2: an older half rejects the call — ask `supports("setCodes")`.
|
|
51
|
+
* Rejects with "notRunning" / "failed". */
|
|
52
|
+
export const setCodes = (service: ServiceChannel<AREvents>, codes: QRTarget[]): Promise<void> =>
|
|
53
|
+
service._call("setCodes", [codes.map((x: any) => _fromQRTarget(x))], 2)
|
|
54
|
+
|
|
45
55
|
/** What is under a point of the scene's view — in its touches' space (a scene touch's `clientX` /
|
|
46
56
|
* `clientY`: the units of the gl facade's viewport) — nearest first. Empty when nothing is, or on
|
|
47
57
|
* a host without surfaces (the web).
|
|
@@ -68,12 +78,14 @@ export const captureFrame = (service: ServiceChannel<AREvents>): Promise<File> =
|
|
|
68
78
|
// ---- what the host's half has --------------------------------------------------------------------
|
|
69
79
|
|
|
70
80
|
/** A method of the contract. */
|
|
71
|
-
export type Method = "start" | "stop" | "setImages" | "hitTest" | "anchor" | "release" | "captureFrame"
|
|
81
|
+
export type Method = "start" | "stop" | "setImages" | "setCodes" | "hitTest" | "anchor" | "release" | "captureFrame"
|
|
82
|
+
|
|
83
|
+
const SINCE: { [method: string]: number } = { setCodes: 2 }
|
|
72
84
|
|
|
73
85
|
/** Whether this host has the service "ar" — and, given a method, a half new enough for it
|
|
74
86
|
* (a method added after the first version of the contract is tagged `@since`). */
|
|
75
87
|
export const supports = (method?: Method): boolean =>
|
|
76
|
-
ServiceChannel.supports(NAME
|
|
88
|
+
ServiceChannel.supports(NAME, method === undefined ? 1 : SINCE[method] ?? 1)
|
|
77
89
|
|
|
78
90
|
// ---- the client -----------------------------------------------------------------------------------
|
|
79
91
|
|
|
@@ -94,6 +106,13 @@ export class ARBase extends ServiceChannel<AREvents> {
|
|
|
94
106
|
* `StartOptions.images`.
|
|
95
107
|
* Rejects with "notRunning" / "failed". */
|
|
96
108
|
setImages(images: ImageTarget[]): Promise<void> { return setImages(this, images) }
|
|
109
|
+
/** The twin of `setImages` for QR codes: replace the set of QR targets of a RUNNING session
|
|
110
|
+
* without restarting it; a code no longer in the set stops driving its entity (`tracked: false`
|
|
111
|
+
* once if it was tracked). Before `start`, the codes are `StartOptions.codes`. A half that tracks
|
|
112
|
+
* no codes yet (the native ones) rejects "failed".
|
|
113
|
+
* Contract version 2: an older half rejects the call — ask `supports("setCodes")`.
|
|
114
|
+
* Rejects with "notRunning" / "failed". */
|
|
115
|
+
setCodes(codes: QRTarget[]): Promise<void> { return setCodes(this, codes) }
|
|
97
116
|
/** What is under a point of the scene's view — in its touches' space (a scene touch's `clientX` /
|
|
98
117
|
* `clientY`: the units of the gl facade's viewport) — nearest first. Empty when nothing is, or on
|
|
99
118
|
* a host without surfaces (the web).
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
// horizontal plane the session reports, so the halves know no root.
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
|
-
Geometry, Mat4, Material, Mesh, Node, Presentable, Quat, Scene, System, Vec3, _ensurePermission, _navEpoch, _toFile,
|
|
19
|
+
Geometry, Mat4, Material, Mesh, Node, Presentable, Quat, Router, Scene, System, Vec3, _ensurePermission, _navEpoch, _toFile,
|
|
20
20
|
type ClickEvent, type DismissOptions, type FetchResponse, type File, type NodeEvents, type PresentOptions,
|
|
21
21
|
type QuatLike, type SceneOptions, type TouchStartEvent, type Vec3Like,
|
|
22
22
|
} from "../../../../plugin"
|
|
23
23
|
import { ARBase, supports } from "./ar.gen"
|
|
24
24
|
import { attachControls, type ControlsHandle, type ControlsOptions } from "./controls"
|
|
25
25
|
import type {
|
|
26
|
-
ARErrorCode, ARMode, HitTarget, ImageTarget, PlaneChange, PlaneDetection, PlaneType, Pose, StartOptions,
|
|
26
|
+
ARErrorCode, ARMode, HitTarget, ImageTarget, PlaneChange, PlaneDetection, PlaneType, Pose, QRTarget, StartOptions,
|
|
27
27
|
TrackingReason, TrackingState, WorldAlignment,
|
|
28
28
|
} from "../contract"
|
|
29
29
|
|
|
@@ -60,12 +60,12 @@ export type ARError = { code: ARErrorCode, message: string }
|
|
|
60
60
|
export type ARPlaneEvent = { plane: ARPlane, change: PlaneChange, mergedInto: ARPlane | null }
|
|
61
61
|
|
|
62
62
|
export type ARSceneOptions = SceneOptions & {
|
|
63
|
-
/** "world" (default): planes, hit tests, anchors, image targets. "images": image
|
|
64
|
-
* lighter on iOS; no planes, no hit test, no `root`. */
|
|
63
|
+
/** "world" (default): planes, hit tests, anchors, image and QR targets. "images": image and QR
|
|
64
|
+
* targets only — lighter on iOS; no planes, no hit test, no `root`. */
|
|
65
65
|
mode?: ARMode
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
export type AROpenOptions = PresentOptions & Omit<StartOptions, "mode" | "images"> & {
|
|
68
|
+
export type AROpenOptions = PresentOptions & Omit<StartOptions, "mode" | "images" | "codes"> & {
|
|
69
69
|
/** The scene's ambient (its `environmentIntensity`) follows the estimated light; turns
|
|
70
70
|
* `lightEstimation` on. */
|
|
71
71
|
followLight?: boolean
|
|
@@ -76,6 +76,13 @@ export type ARSceneEvents = {
|
|
|
76
76
|
plane: (event: ARPlaneEvent) => void
|
|
77
77
|
light: (estimate: ARLightEstimate) => void
|
|
78
78
|
error: (error: ARError) => void
|
|
79
|
+
/** The session ended on its own — the user left it (the back gesture of an immersive web session)
|
|
80
|
+
* or the system took it — and the scene leaves: popped when it is the router's top, else closed
|
|
81
|
+
* (`onClose` is where an app opens what comes next, as after `scene.close()`). Not an error. Sent
|
|
82
|
+
* before the scene leaves. (A `Router.pop()` of an AR scene by the app does NOT end its session:
|
|
83
|
+
* a covered scene comes back with it — on the web an immersive session then stays on; `close()`
|
|
84
|
+
* ends it.) */
|
|
85
|
+
end: (reason: "user" | "system") => void
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
export type AnchorEvents = NodeEvents & {
|
|
@@ -97,9 +104,10 @@ const wirePose = (p: ARPoseLike): Pose => {
|
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
/**
|
|
100
|
-
* A node the AR session drives: it follows a place in the room (`scene.anchor(pose)`, `scene.root`)
|
|
101
|
-
*
|
|
102
|
-
* holds it now; `track` / `untrack` fire when
|
|
107
|
+
* A node the AR session drives: it follows a place in the room (`scene.anchor(pose)`, `scene.root`),
|
|
108
|
+
* an image (`scene.createAnchor(image)`) or a QR code (`scene.createQRAnchor(text, size)`). Put
|
|
109
|
+
* content under it. `tracked` says whether the session holds it now; `track` / `untrack` fire when
|
|
110
|
+
* that changes.
|
|
103
111
|
*/
|
|
104
112
|
export class Anchor extends Node {
|
|
105
113
|
/** @internal */
|
|
@@ -134,13 +142,16 @@ export class Anchor extends Node {
|
|
|
134
142
|
}
|
|
135
143
|
|
|
136
144
|
/**
|
|
137
|
-
* An anchor that follows an image (`scene.createAnchor(image, physicalWidth)`)
|
|
138
|
-
*
|
|
139
|
-
*
|
|
145
|
+
* An anchor that follows an image (`scene.createAnchor(image, physicalWidth)`) or a printed QR code
|
|
146
|
+
* (`scene.createQRAnchor(text, size)`, `code` its text): while tracked it sits on it — a rigid pose
|
|
147
|
+
* in metres, no scale: its centre, Y out of it, the image in X (its width; a code's top edge) and Z
|
|
148
|
+
* (towards its bottom). How big it is, is `extent`.
|
|
140
149
|
*/
|
|
141
150
|
export class ImageAnchor extends Anchor {
|
|
142
151
|
/** @internal */
|
|
143
152
|
_extent: [number, number]
|
|
153
|
+
/** @internal The text of the QR code it follows; null for an image's. */
|
|
154
|
+
_code: string | null = null
|
|
144
155
|
|
|
145
156
|
constructor(physicalWidth: number) {
|
|
146
157
|
super()
|
|
@@ -149,8 +160,12 @@ export class ImageAnchor extends Anchor {
|
|
|
149
160
|
|
|
150
161
|
/** [width, height] in metres, along the anchor's X and Z: the session's estimate of the printed
|
|
151
162
|
* image, refined while it tracks it. Before the image is first found: [physicalWidth, 0] — the
|
|
152
|
-
* height comes with the image's proportions, which the session reads, at the first `track`.
|
|
163
|
+
* height comes with the image's proportions, which the session reads, at the first `track`. A QR
|
|
164
|
+
* code's is [size, size] from the start (a code is square). */
|
|
153
165
|
get extent(): [number, number] { return [this._extent[0], this._extent[1]] }
|
|
166
|
+
|
|
167
|
+
/** The text of the QR code the anchor follows (`createQRAnchor`); null for an image's. */
|
|
168
|
+
get code(): string | null { return this._code }
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
/** A surface the session found: a floor, a table, a wall. Its node sits at the plane's centre with Y
|
|
@@ -265,11 +280,15 @@ export class ARScene extends Scene {
|
|
|
265
280
|
private _shown: { promise: Promise<void>, resolve: () => void, reject: (error: Error) => void, epoch: number } | null = null
|
|
266
281
|
/** The open's start while it is out (`_begin`). `closed`: close() ended its session meanwhile — the
|
|
267
282
|
* half refuses a start its close cut short ("failed"), which is the close's doing: the open was
|
|
268
|
-
* superseded, not failed. `images`: the image targets changed meanwhile, which the
|
|
269
|
-
* carry (it read them when it was sent) — the set goes to the session once it runs. */
|
|
270
|
-
private _startOut: { session: ARBase, closed: boolean, images: boolean } | null = null
|
|
271
|
-
/** A `setImages` is due at the end of this turn (`
|
|
272
|
-
private
|
|
283
|
+
* superseded, not failed. `images` / `codes`: the image / QR targets changed meanwhile, which the
|
|
284
|
+
* start did not carry (it read them when it was sent) — the set goes to the session once it runs. */
|
|
285
|
+
private _startOut: { session: ARBase, closed: boolean, images: boolean, codes: boolean } | null = null
|
|
286
|
+
/** A `setImages` / `setCodes` is due at the end of this turn (`_setTargets`). */
|
|
287
|
+
private readonly _due = { images: false, codes: false }
|
|
288
|
+
/** The QR targets (`createQRAnchor`). */
|
|
289
|
+
private readonly _codes: { anchor: ImageAnchor, text: string, size: number }[] = []
|
|
290
|
+
/** This host's half is older than the QR targets: said once. */
|
|
291
|
+
private _codesWarned = false
|
|
273
292
|
private _options: AROpenOptions = {}
|
|
274
293
|
private _root: Anchor | null = null
|
|
275
294
|
/** The first horizontal plane's pose: where `root` is pinned. */
|
|
@@ -335,7 +354,34 @@ export class ARScene extends Scene {
|
|
|
335
354
|
this.add(anchor)
|
|
336
355
|
const id = (source as unknown as { _h: Handle })._h.id
|
|
337
356
|
this._images.push({ anchor, image: _toFile({ systemId: id, name: "image", size: 0 }), width: physicalWidth, source })
|
|
338
|
-
this.
|
|
357
|
+
this._setTargets("images")
|
|
358
|
+
return anchor
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/** An anchor that follows a printed QR code whose text is `text`: the session finds the symbol in
|
|
362
|
+
* the camera image and keeps the anchor on it, as on an image — a rigid pose in metres (its centre,
|
|
363
|
+
* Y out of the symbol, X along its top edge, Z towards its bottom), `anchor.extent` = [size, size].
|
|
364
|
+
* `size` = the printed side of the symbol in metres (its modules, no quiet zone): how far it is
|
|
365
|
+
* comes from it. Hidden while not tracked. Before `open()`, or any time: on a running scene the set
|
|
366
|
+
* of codes is updated in place. The web finds codes first (WebXR); on a host whose `ar` plugin does
|
|
367
|
+
* not track them the anchor is never tracked, and the console says so. `text` null or "" = ANY
|
|
368
|
+
* code: the first symbol decoded (a test, a plaque whose text the app does not know). */
|
|
369
|
+
createQRAnchor(text: string | null, size: number): ImageAnchor {
|
|
370
|
+
const anchor = new ImageAnchor(size)
|
|
371
|
+
anchor._code = text ?? ""
|
|
372
|
+
anchor._extent = [size, size]
|
|
373
|
+
anchor._scene = this
|
|
374
|
+
anchor._hideUntracked = true
|
|
375
|
+
anchor.visible = false
|
|
376
|
+
this.add(anchor)
|
|
377
|
+
// a half older than the codes (contract version 2) has no setCodes, and its start reads no codes
|
|
378
|
+
if (ARScene.isSupported && !supports("setCodes")) {
|
|
379
|
+
if (!this._codesWarned) console.warn('ARScene: this host\'s "ar" plugin tracks no QR codes (it is older than contract version 2) — their anchors are never tracked')
|
|
380
|
+
this._codesWarned = true
|
|
381
|
+
return anchor
|
|
382
|
+
}
|
|
383
|
+
this._codes.push({ anchor, text: text ?? "", size })
|
|
384
|
+
this._setTargets("codes")
|
|
339
385
|
return anchor
|
|
340
386
|
}
|
|
341
387
|
|
|
@@ -486,6 +532,7 @@ export class ARScene extends Scene {
|
|
|
486
532
|
const options: StartOptions = { ...rest, mode: this.mode }
|
|
487
533
|
if (followLight) options.lightEstimation = true
|
|
488
534
|
if (this._images.length) options.images = this._targets()
|
|
535
|
+
if (this._codes.length) options.codes = this._codeTargets()
|
|
489
536
|
return options
|
|
490
537
|
}
|
|
491
538
|
|
|
@@ -493,6 +540,10 @@ export class ARScene extends Scene {
|
|
|
493
540
|
return this._images.map(t => ({ image: t.image, physicalWidth: t.width, entity: t.anchor }))
|
|
494
541
|
}
|
|
495
542
|
|
|
543
|
+
private _codeTargets(): QRTarget[] {
|
|
544
|
+
return this._codes.map(t => ({ text: t.text, size: t.size, entity: t.anchor }))
|
|
545
|
+
}
|
|
546
|
+
|
|
496
547
|
private async _begin(): Promise<void> {
|
|
497
548
|
const epoch = _navEpoch()
|
|
498
549
|
const superseded = (why = "another destination was opened") => new Error(`ARScene.open() superseded: ${why} while preparing`)
|
|
@@ -524,9 +575,19 @@ export class ARScene extends Scene {
|
|
|
524
575
|
this._drop(session)
|
|
525
576
|
this._emit("error", { code: p.code, message: p.message })
|
|
526
577
|
})
|
|
578
|
+
session.on("ended", p => {
|
|
579
|
+
if (this._session !== session || !p) return
|
|
580
|
+
// over, not by close(): the scene goes with it — the user's back gesture, as the router's:
|
|
581
|
+
// popped when it is the router's top (the page under it shows), else closed (what it replaced
|
|
582
|
+
// comes back through its onClose — `open()` took that destination's place)
|
|
583
|
+
this._drop(session)
|
|
584
|
+
this._emit("end", p.reason)
|
|
585
|
+
if (Router.current === this) Router.pop()
|
|
586
|
+
else this.close()
|
|
587
|
+
})
|
|
527
588
|
this._session = session
|
|
528
589
|
this._baseIntensity = this.environmentIntensity
|
|
529
|
-
const out = { session, closed: false, images: false }
|
|
590
|
+
const out = { session, closed: false, images: false, codes: false }
|
|
530
591
|
this._startOut = out
|
|
531
592
|
try {
|
|
532
593
|
await session.start(this._startOptions())
|
|
@@ -545,8 +606,9 @@ export class ARScene extends Scene {
|
|
|
545
606
|
throw superseded()
|
|
546
607
|
}
|
|
547
608
|
this._pinAll()
|
|
548
|
-
// the image targets changed while the start was out: the running session takes the set now
|
|
549
|
-
if (out.images) this.
|
|
609
|
+
// the image / QR targets changed while the start was out: the running session takes the set now
|
|
610
|
+
if (out.images) this._setTargets("images")
|
|
611
|
+
if (out.codes) this._setTargets("codes")
|
|
550
612
|
}
|
|
551
613
|
|
|
552
614
|
/** The session is over (closed, failed): every anchor untracked, the planes gone. */
|
|
@@ -571,32 +633,34 @@ export class ARScene extends Scene {
|
|
|
571
633
|
this._planes.clear()
|
|
572
634
|
for (const anchor of this._pinned) anchor._setTracked(false)
|
|
573
635
|
for (const image of this._images) image.anchor._setTracked(false)
|
|
636
|
+
for (const code of this._codes) code.anchor._setTracked(false)
|
|
574
637
|
this._root?._setTracked(false)
|
|
575
638
|
if (this._options.followLight) this.environmentIntensity = this._baseIntensity
|
|
576
639
|
}
|
|
577
640
|
|
|
578
|
-
/** The image targets changed (one added or removed): a running session takes the
|
|
579
|
-
* (`setImages` — the tracking, the planes and the anchors stay). Sent
|
|
580
|
-
* targets added in a row are one set. While the open's start is out
|
|
581
|
-
* carried the set it read when it was sent); before a session there is
|
|
582
|
-
* carries the set. Nothing waits for it: a set the half refuses is a
|
|
583
|
-
* whose
|
|
584
|
-
private
|
|
641
|
+
/** The image targets or the QR targets changed (one added or removed): a running session takes the
|
|
642
|
+
* whole set in place (`setImages` / `setCodes` — the tracking, the planes and the anchors stay). Sent
|
|
643
|
+
* at the end of the turn: several targets added in a row are one set. While the open's start is out
|
|
644
|
+
* it waits for it (the start carried the set it read when it was sent); before a session there is
|
|
645
|
+
* nothing to tell — the start carries the set. Nothing waits for it: a set the half refuses is a
|
|
646
|
+
* console line, and an anchor whose target the session did not take never tracks. */
|
|
647
|
+
private _setTargets(kind: "images" | "codes"): void {
|
|
585
648
|
const session = this._session
|
|
586
649
|
if (!session) return
|
|
587
650
|
const out = this._startOut
|
|
588
|
-
if (out && out.session === session) { out
|
|
589
|
-
if (this.
|
|
590
|
-
this.
|
|
651
|
+
if (out && out.session === session) { out[kind] = true; return }
|
|
652
|
+
if (this._due[kind]) return
|
|
653
|
+
this._due[kind] = true
|
|
591
654
|
void Promise.resolve().then(() => {
|
|
592
|
-
this.
|
|
655
|
+
this._due[kind] = false
|
|
593
656
|
// closed meanwhile: a call on the closed channel would open a new session (the next open's start
|
|
594
657
|
// carries the set)
|
|
595
658
|
if (this._session !== session) return
|
|
596
|
-
session.setImages(this._targets()).
|
|
659
|
+
const sent = kind === "images" ? session.setImages(this._targets()) : session.setCodes(this._codeTargets())
|
|
660
|
+
sent.catch((e: unknown) => {
|
|
597
661
|
// a close while it was out: the half's refusal is the close's, nothing failed
|
|
598
662
|
if (this._session !== session) return
|
|
599
|
-
console.warn(`ARScene: the session did not take the image targets (${e instanceof Error ? e.message : String(e)}) — their anchors are not tracked`)
|
|
663
|
+
console.warn(`ARScene: the session did not take the ${kind === "images" ? "image targets" : "QR codes"} (${e instanceof Error ? e.message : String(e)}) — their anchors are not tracked`)
|
|
600
664
|
})
|
|
601
665
|
})
|
|
602
666
|
}
|
|
@@ -643,10 +707,13 @@ export class ARScene extends Scene {
|
|
|
643
707
|
if (anchor === this._root) this._root = null
|
|
644
708
|
const image = this._images.findIndex(t => t.anchor === anchor)
|
|
645
709
|
if (image >= 0) this._images.splice(image, 1)
|
|
710
|
+
const code = this._codes.findIndex(t => t.anchor === anchor)
|
|
711
|
+
if (code >= 0) this._codes.splice(code, 1)
|
|
646
712
|
this._wire("release", s => s.release(anchor)).catch(() => {})
|
|
647
713
|
anchor._setTracked(false)
|
|
648
714
|
this.remove(anchor)
|
|
649
|
-
if (image >= 0) this.
|
|
715
|
+
if (image >= 0) this._setTargets("images")
|
|
716
|
+
if (code >= 0) this._setTargets("codes")
|
|
650
717
|
}
|
|
651
718
|
|
|
652
719
|
private _onPlane(p: { change: PlaneChange, id: number, type: PlaneType, pose: Pose, extent: number[], polygon: number[], mergedInto?: number }): void {
|
package/src/version.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// same manifest). Its MAJOR is the bundle ↔ runtime contract: a bundle's `// sdk:` header line
|
|
5
5
|
// and a host's embedded version must agree on the major for the host to run the bundle; minor
|
|
6
6
|
// and patch never gate anything (features are detected, never versioned).
|
|
7
|
-
export const SDK_VERSION = "2.4.
|
|
7
|
+
export const SDK_VERSION = "2.4.2"
|
|
8
8
|
|
|
9
9
|
/** The major of a semver string, or null when it is not one. */
|
|
10
10
|
export const sdkMajor = (version: string | null | undefined): number | null => {
|