lecodes-sdk 2.4.1 → 2.4.3

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.
Files changed (58) hide show
  1. package/dist/types/core/Aspect.d.ts +34 -5
  2. package/dist/types/g2/OneWay2D.d.ts +0 -1
  3. package/dist/types/g2/Physics2D.d.ts +8 -6
  4. package/dist/types/g2/Scene2D.d.ts +1 -1
  5. package/dist/types/g2/Shape2D.d.ts +43 -15
  6. package/dist/types/gl/Model.d.ts +3 -2
  7. package/dist/types/gl/Scene.d.ts +1 -1
  8. package/dist/types/gl/animation/DynamicBone.d.ts +99 -35
  9. package/dist/types/gl/animation/IK.d.ts +0 -1
  10. package/dist/types/gl/nav/NavAgent.d.ts +3 -2
  11. package/dist/types/gl/physics/Physics.d.ts +4 -5
  12. package/dist/types/gl/physics/Shape.d.ts +40 -15
  13. package/dist/types/gl/vehicle/Vehicle.d.ts +54 -35
  14. package/dist/types/gl/vehicle/Wheel.d.ts +31 -10
  15. package/dist/types/plugins/gen/ar/contract.d.ts +152 -0
  16. package/dist/types/plugins/gen/ar/sdk/ar.d.ts +47 -21
  17. package/dist/types/plugins/gen/ar/sdk/ar.gen.d.ts +17 -3
  18. package/dist/types/plugins/gen/audio-recorder/contract.d.ts +64 -0
  19. package/dist/types/plugins/gen/browser/contract.d.ts +108 -0
  20. package/dist/types/plugins/gen/browser/sdk/browser.d.ts +2 -1
  21. package/dist/types/plugins/gen/camera/contract.d.ts +27 -0
  22. package/dist/types/plugins/gen/geolocation/contract.d.ts +52 -0
  23. package/dist/types/plugins/gen/map/contract.d.ts +144 -0
  24. package/dist/types/plugins/gen/push/contract.d.ts +83 -0
  25. package/dist/types/plugins/gen/qr-scanner/contract.d.ts +16 -0
  26. package/dist/types/plugins/gen/speech/contract.d.ts +67 -0
  27. package/dist/types/plugins/gen/webrtc/contract.d.ts +342 -0
  28. package/dist/types/version.d.ts +1 -1
  29. package/dist/types.json +1 -1
  30. package/package.json +1 -1
  31. package/src/animate/tween/Timeline.ts +175 -175
  32. package/src/bridges/gl.d.ts +5 -3
  33. package/src/compile/compileProject.ts +45 -10
  34. package/src/compile/index.ts +7 -0
  35. package/src/compile/webHalf.ts +255 -0
  36. package/src/core/Aspect.ts +118 -35
  37. package/src/g2/OneWay2D.ts +0 -2
  38. package/src/g2/Physics2D.ts +8 -16
  39. package/src/g2/Scene2D.ts +1 -1
  40. package/src/g2/Shape2D.ts +51 -22
  41. package/src/gl/CameraPlace.ts +52 -52
  42. package/src/gl/Light.ts +257 -257
  43. package/src/gl/Mesh.ts +120 -120
  44. package/src/gl/Model.ts +3 -2
  45. package/src/gl/Scene.ts +1 -1
  46. package/src/gl/animation/DynamicBone.ts +549 -486
  47. package/src/gl/animation/IK.ts +0 -2
  48. package/src/gl/nav/NavAgent.ts +14 -12
  49. package/src/gl/physics/Physics.ts +4 -5
  50. package/src/gl/physics/Shape.ts +49 -23
  51. package/src/gl/scenarios.ts +291 -291
  52. package/src/gl/vehicle/Vehicle.ts +102 -58
  53. package/src/gl/vehicle/Wheel.ts +45 -11
  54. package/src/plugins/gen/ar/contract.d.ts +35 -1
  55. package/src/plugins/gen/ar/sdk/ar.gen.ts +25 -6
  56. package/src/plugins/gen/ar/sdk/ar.ts +102 -35
  57. package/src/plugins/gen/browser/sdk/browser.ts +11 -1
  58. package/src/version.ts +1 -1
package/src/g2/Shape2D.ts CHANGED
@@ -12,11 +12,12 @@
12
12
  // a collider that wraps the art instead of one centred on the pivot (half of it underground), which
13
13
  // is why every character used to carry a hand-computed offset.
14
14
  //
15
- // RE-CONFIGURING REBUILDS IT IN PLACE: `node.aspect(Shape2D, { capsule: … })` on a live node swaps the
16
- // fixture while the body keeps its id, its velocity and its place in the world. That is what makes a
17
- // crouch (and a live editor edit) possible.
15
+ // EVERY DIMENSION IS LIVE: `node.shape.capsule = …` on a live node swaps the fixture at once while the
16
+ // body keeps its id, its velocity and its place in the world. That is what makes a crouch (and a
17
+ // live editor edit) possible.
18
18
 
19
19
  import { Aspect } from "../core/Aspect"
20
+ import type { FieldMeta } from "../core/fields"
20
21
  import { Vec2, cx, cy, type Vec2Like } from "../math/vec"
21
22
  import { ALL_GROUPS } from "./groups2d"
22
23
  import type { Node2D } from "./Node2D"
@@ -35,17 +36,36 @@ export type ShapeFixture2D = {
35
36
  export class Shape2D extends Aspect<"shape", Node2D> {
36
37
  static readonly aspect = "shape"
37
38
 
39
+ // Every dimension is LIVE and applies AT ONCE: a write swaps the fixture in place, the body keeping
40
+ // its id, its velocity and its place in the world (a crouch, a live editor edit) — synchronous,
41
+ // because the caller reads the result back right away (`controller.resizing`). A write that leaves
42
+ // the geometry's signature unchanged does nothing.
43
+ private _box?: Vec2Like
44
+ private _circle?: number
45
+ private _cap?: { from: Vec2Like, to: Vec2Like, radius: number } // `_capsule()` is the mover's view
46
+ private _segment?: { from: Vec2Like, to: Vec2Like }
47
+ private _polygon?: Vec2Like[]
48
+ private _chain?: Vec2Like[]
49
+ private _loop?: boolean
50
+ private _flip?: boolean
51
+ private _origin?: Vec2Like
52
+
38
53
  /** Box half-extents [hw, hh] (world units). */
39
- box?: Vec2Like
54
+ get box(): Vec2Like | undefined { return this._box }
55
+ set box(v: Vec2Like | undefined) { this._box = v; this._changed() }
40
56
  /** Circle radius. */
41
- circle?: number
57
+ get circle(): number | undefined { return this._circle }
58
+ set circle(v: number | undefined) { this._circle = v; this._changed() }
42
59
  /** Capsule between two local points, with a radius. */
43
- capsule?: { from: Vec2Like, to: Vec2Like, radius: number }
60
+ get capsule(): { from: Vec2Like, to: Vec2Like, radius: number } | undefined { return this._cap }
61
+ set capsule(v: { from: Vec2Like, to: Vec2Like, radius: number } | undefined) { this._cap = v; this._changed() }
44
62
  /** Thin segment (an edge) between two local points. */
45
- segment?: { from: Vec2Like, to: Vec2Like }
63
+ get segment(): { from: Vec2Like, to: Vec2Like } | undefined { return this._segment }
64
+ set segment(v: { from: Vec2Like, to: Vec2Like } | undefined) { this._segment = v; this._changed() }
46
65
  /** Convex polygon, up to 8 local points (a convex hull is computed — a CONCAVE outline silently
47
66
  * becomes its hull; use `chain` for those). */
48
- polygon?: Vec2Like[]
67
+ get polygon(): Vec2Like[] | undefined { return this._polygon }
68
+ set polygon(v: Vec2Like[] | undefined) { this._polygon = v; this._changed() }
49
69
  /**
50
70
  * A polyline of connected segments — the one shape that expresses a long CONCAVE surface (rolling
51
71
  * terrain, a cave wall) in one piece, seam-free. Pass only the points that should be solid; the
@@ -55,14 +75,23 @@ export class Shape2D extends Aspect<"shape", Node2D> {
55
75
  * must not self-intersect. It is ONE-SIDED: solid on the right of the point order — walk the points
56
76
  * so that the solid material is on your right, or set `flip`.
57
77
  */
58
- chain?: Vec2Like[]
78
+ get chain(): Vec2Like[] | undefined { return this._chain }
79
+ set chain(v: Vec2Like[] | undefined) { this._chain = v; this._changed() }
59
80
  /** `chain`: close the contour (an island / a room boundary). Needs at least 4 points. */
60
- loop?: boolean
81
+ get loop(): boolean | undefined { return this._loop }
82
+ set loop(v: boolean | undefined) { this._loop = v; this._changed() }
61
83
  /** `chain`: put the solid side on the other side of the line. */
62
- flip?: boolean
84
+ get flip(): boolean | undefined { return this._flip }
85
+ set flip(v: boolean | undefined) { this._flip = v; this._changed() }
63
86
  /** The collider's centre relative to the node, in world units. Applies to EVERY kind — it
64
87
  * translates a capsule's / segment's / polygon's / chain's points too, unlike the old `offset`. */
65
- origin?: Vec2Like
88
+ get origin(): Vec2Like | undefined { return this._origin }
89
+ set origin(v: Vec2Like | undefined) { this._origin = v; this._changed() }
90
+
91
+ /** Scene-editor inspector: the geometry fields (accessors, so they are listed here by name). */
92
+ static fields: FieldMeta<Shape2D> = {
93
+ box: {}, circle: {}, capsule: {}, segment: {}, polygon: {}, chain: {}, loop: {}, flip: {}, origin: {},
94
+ }
66
95
 
67
96
  /** @internal Geometry as of the last build — an unchanged signature means nothing to rebuild. */
68
97
  private _sig = ""
@@ -72,7 +101,7 @@ export class Shape2D extends Aspect<"shape", Node2D> {
72
101
  private _fx: ShapeFixture2D | null = null
73
102
  private _handle = 0
74
103
 
75
- /** @internal — the character claimed this shape; record the geometry so a later re-configure is
104
+ /** @internal — the character claimed this shape; record the geometry so a later write is
76
105
  * compared against it. */
77
106
  _claimedByCharacter(): void { this._sig = this._signature(); this._resizeRefused = false }
78
107
 
@@ -97,11 +126,11 @@ export class Shape2D extends Aspect<"shape", Node2D> {
97
126
  onDetach(): void { this._handle = 0; this._fx = null; this._sig = ""; this._resizeRefused = false }
98
127
 
99
128
  /**
100
- * Re-configuring the aspect swaps the fixture in place — same body, same id, same velocity, same
101
- * position. Nothing happens when the geometry is unchanged, so re-applying the same options in a
102
- * loop is free.
129
+ * A dimension was written: swap the fixture in place — same body, same id, same velocity, same
130
+ * position. Nothing happens when the signature is unchanged, so writing the same dimensions every
131
+ * frame is free.
103
132
  */
104
- onReconfigure(): void {
133
+ private _changed(): void {
105
134
  const sig = this._signature()
106
135
  if (sig === this._sig) return
107
136
 
@@ -110,9 +139,9 @@ export class Shape2D extends Aspect<"shape", Node2D> {
110
139
  if (this.node._xfKind === 1) {
111
140
  const cap = this._capsule()
112
141
  const ok = _creator2d.characterSetCapsule(this.node._xf, cap.x1, cap.y1, cap.x2, cap.y2, cap.radius)
113
- // On refusal NOTHING changed — so DON'T commit the signature. The next identical
114
- // `aspect(Shape2D, …)` then still sees a difference and retries; committing here would swallow
115
- // every retry for good, which is the whole trap in this design.
142
+ // On refusal NOTHING changed — so DON'T commit the signature. The next write of the same
143
+ // dimensions then still sees a difference and retries; committing here would swallow every
144
+ // retry for good, which is the whole trap in this design.
116
145
  this._resizeRefused = !ok
117
146
  if (ok) this._sig = sig
118
147
  return
@@ -218,7 +247,7 @@ export class Shape2D extends Aspect<"shape", Node2D> {
218
247
  _creator2d.physicsAddChain(handle, new Float32Array(p), p.length / 2, loop, fx.friction, fx.bounce, category, mask)
219
248
  }
220
249
 
221
- // Everything that changes the GEOMETRY, so a re-configure that only touches the material is free.
250
+ // Everything that changes the GEOMETRY, so a write that changed nothing is free.
222
251
  private _signature(): string {
223
252
  const o = this.origin ? `${cx(this.origin)},${cy(this.origin)}` : ""
224
253
  if (this.chain) return `chain:${this.chain.map(v => `${cx(v)},${cy(v)}`).join(";")}|${this.loop}|${this.flip}|${o}`
@@ -243,7 +272,7 @@ export class Shape2D extends Aspect<"shape", Node2D> {
243
272
  * Sprite anchor space is Y-DOWN while the world is Y-up (see docs/conventions.md), so `anchor: [.5, 1]`
244
273
  * ("feet") puts the art ABOVE the origin: its centre sits at +h/2. A node with no sprite falls back
245
274
  * to 8x8 at the origin. This is a SNAPSHOT taken when the fixture is built — growing the sprite later
246
- * does not resize the collider; re-configure the aspect to re-measure.
275
+ * does not resize the collider; write a dimension (`origin = undefined` will do) to re-measure.
247
276
  */
248
277
  private _autoBox(): { hw: number, hh: number, x: number, y: number } {
249
278
  const n = this.node as { size?: Vec2, anchor?: Vec2, scale?: Vec2 }
@@ -1,52 +1,52 @@
1
- // CameraPlace: "the camera as a place". A scene has ONE camera (`scene.camera`); a CameraPlace marks
2
- // a node as somewhere that camera can be — with the lens it uses there. Nothing is created engine-
3
- // side (no second camera, no ABI): it is a pose + a projection record on any node: an empty, an
4
- // empty mounted on a bone (`mount:`), a node a path aspect moves (a dolly shot), a model node.
5
- //
6
- // • In a scene FILE that runs (`open()` / `load()`), the `active: true` place drives
7
- // `scene.camera` (exactly `scene.camera.follow(node)`); exactly one per file.
8
- // • Inside a prefab or an `instantiate()`d subtree a place is inert DATA — the hosting scene
9
- // owns its camera. The host reads it (`inst.nodes.eye.get(CameraPlace)` → world pose + fov)
10
- // or anchors on it (`inst.alignTo(inst.nodes.eye)`).
11
- // • From code: `scene.camera.follow(dolly.get(CameraPlace))` — a cutscene shot; `follow(null)`
12
- // releases.
13
- // • Edit mode: draws an anchored frustum gizmo (the editor's camera preview reads the same place).
14
- // See docs/scene-camera-place-plan.md.
15
-
16
- import { Aspect } from "../core/Aspect"
17
- import type { FieldMeta } from "../core/fields"
18
- import { Gizmos } from "../scene/gizmos"
19
- import type { Camera } from "./Camera"
20
- import type { Node } from "./Node"
21
-
22
- export class CameraPlace extends Aspect<"cameraPlace", Node> {
23
- static readonly aspect = "cameraPlace"
24
- /** Vertical field of view in degrees (default 60) — smaller is a longer lens. */
25
- fov = 60
26
- /** Near clip distance. */
27
- near = 0.01
28
- /** Far clip distance = view range. */
29
- far = 1000
30
- /** The place that drives `scene.camera` when the file declaring it RUNS. Exactly one per file;
31
- * ignored inside prefabs / instantiated subtrees (the host scene owns its camera). */
32
- active = false
33
- /** Aspect ratio of the frustum gizmo only (the real aspect is the viewport's). */
34
- static fields: FieldMeta<CameraPlace> = {
35
- fov: { label: "FOV", min: 1, max: 179, step: 1 },
36
- near: { min: 0.001, max: 10, step: 0.01 },
37
- far: { min: 1, max: 100000, step: 1 },
38
- active: { label: "Active camera" },
39
- }
40
- static editor = { rebuild: true }
41
-
42
- /** Copy this place's projection onto a camera (`camera.follow(place)` does it for you). */
43
- applyTo(camera: Camera): void {
44
- camera.setProjection({ fov: this.fov, near: this.near, far: this.far })
45
- }
46
-
47
- /** Edit mode: the frustum marker (−Z = view), anchored on the node so it follows drags live and
48
- * clicking it selects the node. Play mode never calls this. */
49
- rebuild(): void {
50
- Gizmos.frustum(this.fov, { node: this.node, color: this.active ? "#ffffff" : "#9aa3b2" })
51
- }
52
- }
1
+ // CameraPlace: "the camera as a place". A scene has ONE camera (`scene.camera`); a CameraPlace marks
2
+ // a node as somewhere that camera can be — with the lens it uses there. Nothing is created engine-
3
+ // side (no second camera, no ABI): it is a pose + a projection record on any node: an empty, an
4
+ // empty mounted on a bone (`mount:`), a node a path aspect moves (a dolly shot), a model node.
5
+ //
6
+ // • In a scene FILE that runs (`open()` / `load()`), the `active: true` place drives
7
+ // `scene.camera` (exactly `scene.camera.follow(node)`); exactly one per file.
8
+ // • Inside a prefab or an `instantiate()`d subtree a place is inert DATA — the hosting scene
9
+ // owns its camera. The host reads it (`inst.nodes.eye.get(CameraPlace)` → world pose + fov)
10
+ // or anchors on it (`inst.alignTo(inst.nodes.eye)`).
11
+ // • From code: `scene.camera.follow(dolly.get(CameraPlace))` — a cutscene shot; `follow(null)`
12
+ // releases.
13
+ // • Edit mode: draws an anchored frustum gizmo (the editor's camera preview reads the same place).
14
+ // See docs/scene-camera-place-plan.md.
15
+
16
+ import { Aspect } from "../core/Aspect"
17
+ import type { FieldMeta } from "../core/fields"
18
+ import { Gizmos } from "../scene/gizmos"
19
+ import type { Camera } from "./Camera"
20
+ import type { Node } from "./Node"
21
+
22
+ export class CameraPlace extends Aspect<"cameraPlace", Node> {
23
+ static readonly aspect = "cameraPlace"
24
+ /** Vertical field of view in degrees (default 60) — smaller is a longer lens. */
25
+ fov = 60
26
+ /** Near clip distance. */
27
+ near = 0.01
28
+ /** Far clip distance = view range. */
29
+ far = 1000
30
+ /** The place that drives `scene.camera` when the file declaring it RUNS. Exactly one per file;
31
+ * ignored inside prefabs / instantiated subtrees (the host scene owns its camera). */
32
+ active = false
33
+ /** Aspect ratio of the frustum gizmo only (the real aspect is the viewport's). */
34
+ static fields: FieldMeta<CameraPlace> = {
35
+ fov: { label: "FOV", min: 1, max: 179, step: 1 },
36
+ near: { min: 0.001, max: 10, step: 0.01 },
37
+ far: { min: 1, max: 100000, step: 1 },
38
+ active: { label: "Active camera" },
39
+ }
40
+ static editor = { rebuild: true }
41
+
42
+ /** Copy this place's projection onto a camera (`camera.follow(place)` does it for you). */
43
+ applyTo(camera: Camera): void {
44
+ camera.setProjection({ fov: this.fov, near: this.near, far: this.far })
45
+ }
46
+
47
+ /** Edit mode: the frustum marker (−Z = view), anchored on the node so it follows drags live and
48
+ * clicking it selects the node. Play mode never calls this. */
49
+ rebuild(): void {
50
+ Gizmos.frustum(this.fov, { node: this.node, color: this.active ? "#ffffff" : "#9aa3b2" })
51
+ }
52
+ }