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.
- 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/browser/sdk/browser.d.ts +2 -1
- 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/animate/tween/Timeline.ts +175 -175
- 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/CameraPlace.ts +52 -52
- package/src/gl/Light.ts +257 -257
- package/src/gl/Mesh.ts +120 -120
- 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/scenarios.ts +291 -291
- 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/plugins/gen/browser/sdk/browser.ts +11 -1
- 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
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
101
|
-
* position. Nothing happens when the
|
|
102
|
-
*
|
|
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
|
-
|
|
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
|
|
114
|
-
//
|
|
115
|
-
//
|
|
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
|
|
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;
|
|
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 }
|
package/src/gl/CameraPlace.ts
CHANGED
|
@@ -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
|
+
}
|