lecodes-sdk 0.19.2 → 0.20.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.
Files changed (67) hide show
  1. package/dist/global.d.ts +62 -0
  2. package/dist/host.d.ts +3 -0
  3. package/dist/types/audio/Bus.d.ts +45 -0
  4. package/dist/types/audio/Sound.d.ts +28 -0
  5. package/dist/types/audio/Voice.d.ts +27 -0
  6. package/dist/types/audio/audio.d.ts +83 -0
  7. package/dist/types/audio/support.d.ts +1 -0
  8. package/dist/types/gl/AudioSource.d.ts +60 -0
  9. package/dist/types/gl/AudioZone.d.ts +32 -0
  10. package/dist/types/gl/DecalSet.d.ts +103 -0
  11. package/dist/types/gl/Geometry.d.ts +5 -0
  12. package/dist/types/gl/Light.d.ts +7 -0
  13. package/dist/types/gl/Locomotion.d.ts +3 -1
  14. package/dist/types/gl/Material.d.ts +86 -2
  15. package/dist/types/gl/Mesh.d.ts +11 -0
  16. package/dist/types/gl/Scene.d.ts +23 -0
  17. package/dist/types/gl/SceneAudio.d.ts +11 -0
  18. package/dist/types/gl/Texture.d.ts +29 -1
  19. package/dist/types/gl/animation/AnimationClip.d.ts +25 -12
  20. package/dist/types/gl/animation/Animator.d.ts +51 -183
  21. package/dist/types/gl/animation/Feet.d.ts +85 -0
  22. package/dist/types/gl/animation/Warp.d.ts +53 -0
  23. package/dist/types/gl/animation/core.d.ts +61 -17
  24. package/dist/types/gl/state.d.ts +0 -1
  25. package/dist/types/inject.d.ts +17 -2
  26. package/dist/types/plugins/map.d.ts +174 -0
  27. package/dist/types/runtime/input.d.ts +11 -0
  28. package/dist/types/ui/UIImage.d.ts +15 -5
  29. package/dist/types.json +1 -1
  30. package/package.json +1 -1
  31. package/src/audio/Bus.ts +102 -0
  32. package/src/audio/Sound.ts +96 -0
  33. package/src/audio/Voice.ts +102 -0
  34. package/src/audio/audio.ts +161 -0
  35. package/src/audio/support.ts +6 -0
  36. package/src/bridges.d.ts +1481 -1345
  37. package/src/compile/__tests__/compile.test.ts +12 -0
  38. package/src/compile/compileProject.ts +35 -15
  39. package/src/compile/index.ts +3 -0
  40. package/src/core/Aspect.ts +34 -9
  41. package/src/g2/Scene2D.ts +7 -0
  42. package/src/gl/AudioSource.ts +113 -0
  43. package/src/gl/AudioZone.ts +75 -0
  44. package/src/gl/DecalSet.ts +233 -0
  45. package/src/gl/Geometry.ts +5 -0
  46. package/src/gl/Light.ts +16 -0
  47. package/src/gl/Lightmap.ts +3 -2
  48. package/src/gl/Locomotion.ts +7 -5
  49. package/src/gl/Material.ts +152 -4
  50. package/src/gl/Mesh.ts +20 -1
  51. package/src/gl/Particles.ts +3 -3
  52. package/src/gl/Scene.ts +42 -8
  53. package/src/gl/SceneAudio.ts +26 -0
  54. package/src/gl/Texture.ts +43 -3
  55. package/src/gl/Vehicle.ts +5 -5
  56. package/src/gl/animation/AnimationClip.ts +43 -20
  57. package/src/gl/animation/Animator.ts +138 -329
  58. package/src/gl/animation/Feet.ts +134 -0
  59. package/src/gl/animation/Loop.ts +3 -1
  60. package/src/gl/animation/Warp.ts +96 -0
  61. package/src/gl/animation/core.ts +741 -670
  62. package/src/gl/state.ts +6 -6
  63. package/src/host.d.ts +3 -0
  64. package/src/inject.ts +23 -2
  65. package/src/plugins/map.ts +396 -0
  66. package/src/runtime/input.ts +6 -1
  67. package/src/ui/UIImage.ts +21 -7
@@ -0,0 +1,134 @@
1
+ // Feet — `anim.feet`: which bones the feet are, and what the engine does with them after the clips are
2
+ // composited — the foot LOCK (a planted foot stays where it landed while the body moves on) and GROUND
3
+ // IK (each foot on the ground probed under it, the pelvis lowered). Docs: docs/animation-v2-plan.md §2.9.
4
+ //
5
+ // model.anim.feet.lock = true // (a Locomotion does this itself)
6
+ // model.anim.feet.set({ lock: true, ik: true, pelvis: 0.3 }) // stairs and slopes
7
+ // model.anim.feet.set({ left: 'LeftFoot', right: 'RightFoot' }) // a rig the classifier misses
8
+ // model.anim.feet.onStep(({ side, position }) => dust(position))
9
+ //
10
+ // The engine probes the ground itself (against what a character can stand on) and reads the
11
+ // CharacterController's ground state; nothing is fed per frame.
12
+
13
+ import { Vec3 } from "../../math/vec"
14
+ import type { Core, KneeAxisReport, StepHandler } from "./core"
15
+
16
+ /** The feet settings (`anim.feet.set()` / the properties of `anim.feet`). Distances are metres, times
17
+ * seconds. Every key is optional and only the keys given change. */
18
+ export type FeetOptions = {
19
+ /** The contact bones per side — `'LeftFoot'`, or with a toe / ball `['LeftFoot', 'LeftToeBase']`.
20
+ * Default: classified from the bone names (Mixamo / Unity / Blender / UE). Setting them re-bakes
21
+ * every clip's contacts and phase. */
22
+ left?: string | string[]
23
+ right?: string | string[]
24
+ /** FOOT LOCK: a foot the shown clip calls planted is pinned where it landed — heel to ball, rolling
25
+ * as the clip rolls — and the leg re-solved to keep it there while the body moves on. Off by default. */
26
+ lock?: boolean
27
+ /** GROUND IK: each foot is put on the ground the engine probes under it (stairs, a slope, a kerb),
28
+ * aligned to its normal, the pelvis lowered so the leg can reach. Needs a physics world to probe;
29
+ * without one the ground is the node's own plane. Off by default. */
30
+ ik?: boolean
31
+ /** How far the pelvis may drop for the ground (default 0.35). */
32
+ pelvis?: number
33
+ /** A locked foot never absorbs more residual than this — beyond it the anchor follows the animation
34
+ * instead of fighting it (default 0.10). */
35
+ unlockDistance?: number
36
+ /** The lock's ease in / out, seconds (default 0.08 / 0.12). */
37
+ lockIn?: number
38
+ lockOut?: number
39
+ /** 0..1: how much the foot tilts onto the ground normal (default 1). */
40
+ align?: number
41
+ /** The probe ray's reach above and below the ankle (default 0.6). */
42
+ probe?: number
43
+ /** The lock plants only once the animated ankle moves slower than this, m/s (default 0.2). Raise it
44
+ * to pin a foot a transition is still dragging. */
45
+ plantSpeed?: number
46
+ }
47
+
48
+ /** One foot after this frame's evaluation (`anim.feet.state(side)`): whether the lock holds it, the
49
+ * lock's weight (eased 0…1), where it was pinned and where the leg was asked to put the ankle — all world. */
50
+ export type FootState = { locked: boolean, weight: number, anchor: Vec3, target: Vec3 }
51
+
52
+ const P = { IK: 0, LOCK: 1, PELVIS: 2, UNLOCK_DIST: 3, LOCK_IN: 4, LOCK_OUT: 5, PELVIS_TIME: 6, ALIGN: 7, PROBE: 8, DETECT_SPEED: 9, DETECT_HEIGHT: 10, PLANT_SPEED: 11, COUNT: 12 }
53
+ const DEFAULTS = { pelvis: 0.35, unlockDistance: 0.10, lockIn: 0.08, lockOut: 0.12, align: 1, probe: 0.6, plantSpeed: 0.2 }
54
+ const footBuf = new Float32Array(8)
55
+
56
+ export class Feet {
57
+ private readonly _c: Core
58
+ private readonly _o: FeetOptions = {}
59
+ /** @internal — created by the Animator. */
60
+ constructor(core: Core) { this._c = core }
61
+
62
+ /** Change several settings at once; only the keys given change. Chainable. */
63
+ set(options: FeetOptions): this {
64
+ Object.assign(this._o, options)
65
+ if (options.left !== undefined || options.right !== undefined) this.pushBones()
66
+ this.push()
67
+ return this
68
+ }
69
+ /** The current settings (what was set; unset keys are the engine's defaults). */
70
+ get options(): Readonly<FeetOptions> { return this._o }
71
+
72
+ get lock(): boolean { return !!this._o.lock }
73
+ set lock(v: boolean) { this._o.lock = v; this.push() }
74
+ get ik(): boolean { return !!this._o.ik }
75
+ set ik(v: boolean) { this._o.ik = v; this.push() }
76
+ get pelvis(): number { return this._o.pelvis ?? DEFAULTS.pelvis }
77
+ set pelvis(v: number) { this._o.pelvis = v; this.push() }
78
+ get unlockDistance(): number { return this._o.unlockDistance ?? DEFAULTS.unlockDistance }
79
+ set unlockDistance(v: number) { this._o.unlockDistance = v; this.push() }
80
+ get lockIn(): number { return this._o.lockIn ?? DEFAULTS.lockIn }
81
+ set lockIn(v: number) { this._o.lockIn = v; this.push() }
82
+ get lockOut(): number { return this._o.lockOut ?? DEFAULTS.lockOut }
83
+ set lockOut(v: number) { this._o.lockOut = v; this.push() }
84
+ get align(): number { return this._o.align ?? DEFAULTS.align }
85
+ set align(v: number) { this._o.align = v; this.push() }
86
+ get probe(): number { return this._o.probe ?? DEFAULTS.probe }
87
+ set probe(v: number) { this._o.probe = v; this.push() }
88
+ get plantSpeed(): number { return this._o.plantSpeed ?? DEFAULTS.plantSpeed }
89
+ set plantSpeed(v: number) { this._o.plantSpeed = v; this.push() }
90
+ /** The contact bones (`undefined` = classified from the names). */
91
+ get left(): string | string[] | undefined { return this._o.left }
92
+ set left(v: string | string[] | undefined) { this._o.left = v; this.pushBones() }
93
+ get right(): string | string[] | undefined { return this._o.right }
94
+ set right(v: string | string[] | undefined) { this._o.right = v; this.pushBones() }
95
+
96
+ /** One foot's state after this frame's evaluation — where the lock holds it and with what weight
97
+ * (a debug beam under the foot). `undefined` on a host without the feet stage, or before anything played. */
98
+ state(side: "left" | "right"): FootState | undefined {
99
+ if (!this._c.footState(side === "left" ? 0 : 1, footBuf)) return undefined
100
+ return { locked: footBuf[0]! > 0.5, weight: footBuf[1]!, anchor: new Vec3(footBuf[2]!, footBuf[3]!, footBuf[4]!), target: new Vec3(footBuf[5]!, footBuf[6]!, footBuf[7]!) }
101
+ }
102
+ /** The skeleton's calibrated KNEE HINGE AXIS for a side (thigh-local, unit) with its confidence report —
103
+ * measured once over every bound clip's knee rotation track. `undefined` = no leg chain, or no knee
104
+ * motion bound to calibrate from. */
105
+ kneeAxis(side: "left" | "right"): KneeAxisReport | undefined { return this._c.kneeAxis(side) }
106
+
107
+ /** A foot planted (world position) — audio, dust, decals. Fires for what the BASE layer shows, from
108
+ * the clip's own contacts; a clip with no contacts fires nothing. */
109
+ onStep(cb: StepHandler): this { this._c.onStepHandler(cb); return this }
110
+ offStep(cb: StepHandler): this { this._c.offStepHandler(cb); return this }
111
+
112
+ private pushBones(): void {
113
+ const join = (v: string | string[] | undefined): string => v === undefined ? "" : Array.isArray(v) ? v.join("\n") : v
114
+ this._c.setFeet(join(this._o.left), join(this._o.right))
115
+ }
116
+ private push(): void {
117
+ const o = this._o
118
+ const p = new Float32Array(P.COUNT)
119
+ // the engine's own defaults (canimAnimatorFeetDefaults)
120
+ p[P.PELVIS] = DEFAULTS.pelvis; p[P.UNLOCK_DIST] = DEFAULTS.unlockDistance; p[P.LOCK_IN] = DEFAULTS.lockIn; p[P.LOCK_OUT] = DEFAULTS.lockOut
121
+ p[P.PELVIS_TIME] = 0.15; p[P.ALIGN] = DEFAULTS.align; p[P.PROBE] = DEFAULTS.probe; p[P.DETECT_SPEED] = 0.35; p[P.DETECT_HEIGHT] = 0.12
122
+ p[P.PLANT_SPEED] = DEFAULTS.plantSpeed
123
+ if (o.ik) p[P.IK] = 1
124
+ if (o.lock) p[P.LOCK] = 1
125
+ if (o.pelvis !== undefined) p[P.PELVIS] = o.pelvis
126
+ if (o.unlockDistance !== undefined) p[P.UNLOCK_DIST] = o.unlockDistance
127
+ if (o.lockIn !== undefined) p[P.LOCK_IN] = o.lockIn
128
+ if (o.lockOut !== undefined) p[P.LOCK_OUT] = o.lockOut
129
+ if (o.align !== undefined) p[P.ALIGN] = o.align
130
+ if (o.probe !== undefined) p[P.PROBE] = o.probe
131
+ if (o.plantSpeed !== undefined) p[P.PLANT_SPEED] = o.plantSpeed
132
+ this._c.setFeetParams(p)
133
+ }
134
+ }
@@ -1,6 +1,8 @@
1
1
  // Loop — a layer's LOOP: what it shows when no one-shot plays (`anim.playLoop('Idle')` — one looping clip,
2
2
  // or `anim.playLoop({ Idle: 0, Walking: 2, Run: 6 })` — a blend whose members cycle in phase and `value`
3
- // picks the mix: 1D linear between neighbours, `[x, y]` positions = a 2D gradient band). A one-shot takes
3
+ // picks the mix: 1D linear between neighbours, `[x, y]` positions = a 2D gradient band; a member given as
4
+ // `{ at, offset, cycles }` carries its gait cycle, measured offline from its foot marks; a bare position
5
+ // = normalized time, no cycle). A one-shot takes
4
6
  // the layer over and hands it back; `playLoop(next)` transitions to another; `stop()` removes it. The
5
7
  // object returned by `playLoop()` (also `anim.loop`) is the handle; a replaced loop's object goes dead.
6
8
 
@@ -0,0 +1,96 @@
1
+ // Warp — `anim.warp`: the pose fitted to what the body actually does, after the clips are composited and
2
+ // before the feet (docs/animation-v2-plan.md §2.7). `stride` scales each leg's step to the speed the body
3
+ // really travels at (a walk played at 1.9 m/s stops skating); `orientation` turns the lower body toward
4
+ // where the body really goes while the spine counter-turns (arcs and strafing without a clip per angle).
5
+ // Both need the body's motion, which a `Locomotion` feeds every frame; without one leave it off. Off by
6
+ // default. `step` is the STEP WARP: stride / lift / pitch / slope dials solved in the knee hinge plane.
7
+ //
8
+ // model.anim.warp.set(true) // both, with the defaults
9
+ // model.anim.warp.set({ stride: [0.7, 1.4], orientation: 45 })
10
+ // model.anim.warp.orientation = 12 // a lean only
11
+ // model.anim.warp.step = { slope: 15 } // an invisible staircase
12
+
13
+ import type { Core } from "./core"
14
+
15
+ /** What `anim.warp` turns on. Speeds are m/s, angles degrees, distances metres. */
16
+ export type WarpOptions = {
17
+ /** Fit the stride to the speed the body actually travels at. `[min, max]` clamps the scale (default
18
+ * 0.85…1.2). A CORRECTION: a pack whose takes already read right at the speeds it is played at wants
19
+ * none of this; open the range for a pack that must cover speeds it was never recorded at. */
20
+ stride?: boolean | [number, number]
21
+ /** Turn the lower body toward where the body really travels; a number caps the turn in degrees
22
+ * (default 20). The whole twist lives in one joint: a few degrees read as a lean, a lot as a broken
23
+ * back. Only applied while the gait LOOP shows — a start, a turn or a stop walks a path of its own. */
24
+ orientation?: boolean | number
25
+ /** Below this speed — the game's or the clip's — both warps are off (default 0.2). */
26
+ minSpeed?: number
27
+ /** How far the pelvis may drop to keep a stretched leg from locking straight (default 0.25). */
28
+ pelvis?: number
29
+ /** The stride scale's own spring, seconds (default 0.15): the shown clip's recorded speed steps at every
30
+ * switch, so the scale is smoothed rather than followed. */
31
+ strideTime?: number
32
+ }
33
+
34
+ /** STEP WARP dials (`anim.warp.step`): `stride` scales each foot's travel-direction offset from its hip,
35
+ * `lift` = metres ADDED to its height (swing-gated; negative = a shuffle; half of it raises the pelvis),
36
+ * `pitch` (degrees, + = toes up) rotates each foot about its lateral axis, `slope` (degrees, + = ascending)
37
+ * the invisible staircase — feet on the incline, auto pitch, the character raised to hold each planted
38
+ * foot on its tread. A tuning bench's dial; locomotion will drive this itself later. */
39
+ export type StepWarpOptions = { stride?: number, lift?: number, pitch?: number, slope?: number }
40
+
41
+ const P = { STRIDE: 0, STRIDE_MIN: 1, STRIDE_MAX: 2, ORIENT: 3, ORIENT_MAX: 4, ORIENT_TIME: 5, MIN_SPEED: 6, PELVIS: 7, STRIDE_TIME: 8, COUNT: 9 }
42
+ const DEFAULTS = { strideMin: 0.85, strideMax: 1.2, orientMax: 20, minSpeed: 0.2, pelvis: 0.25, strideTime: 0.15 }
43
+
44
+ export class Warp {
45
+ private readonly _c: Core
46
+ private _o: WarpOptions = {}
47
+ private _step: StepWarpOptions | null = null
48
+ /** @internal — created by the Animator. */
49
+ constructor(core: Core) { this._c = core }
50
+
51
+ /** Replace the settings: `true` = both warps with the defaults, `false` / `{}` = off, or the options.
52
+ * (Replaces, does not merge — what is not asked for is off.) Chainable. */
53
+ set(w: WarpOptions | boolean): this {
54
+ this._o = w === true ? { stride: true, orientation: true } : w === false ? {} : { ...w }
55
+ this.push()
56
+ return this
57
+ }
58
+ /** The current settings. */
59
+ get options(): Readonly<WarpOptions> { return this._o }
60
+
61
+ get stride(): boolean | [number, number] { return this._o.stride ?? false }
62
+ set stride(v: boolean | [number, number]) { this._o.stride = v; this.push() }
63
+ get orientation(): boolean | number { return this._o.orientation ?? false }
64
+ set orientation(v: boolean | number) { this._o.orientation = v; this.push() }
65
+ get minSpeed(): number { return this._o.minSpeed ?? DEFAULTS.minSpeed }
66
+ set minSpeed(v: number) { this._o.minSpeed = v; this.push() }
67
+ get pelvis(): number { return this._o.pelvis ?? DEFAULTS.pelvis }
68
+ set pelvis(v: number) { this._o.pelvis = v; this.push() }
69
+ get strideTime(): number { return this._o.strideTime ?? DEFAULTS.strideTime }
70
+ set strideTime(v: number) { this._o.strideTime = v; this.push() }
71
+
72
+ /** The step warp dials; `null` = off. */
73
+ get step(): StepWarpOptions | null { return this._step }
74
+ set step(v: StepWarpOptions | null | undefined) { this._step = v ?? null; this._c.setStepWarp(this._step) }
75
+
76
+ private push(): void {
77
+ const o = this._o
78
+ const p = new Float32Array(P.COUNT)
79
+ // the engine's own defaults (canimAnimatorWarpDefaults): what is not asked for stays neutral
80
+ p[P.STRIDE_MIN] = DEFAULTS.strideMin; p[P.STRIDE_MAX] = DEFAULTS.strideMax; p[P.ORIENT_MAX] = DEFAULTS.orientMax
81
+ p[P.ORIENT_TIME] = 0.15; p[P.MIN_SPEED] = DEFAULTS.minSpeed; p[P.PELVIS] = DEFAULTS.pelvis
82
+ p[P.STRIDE_TIME] = DEFAULTS.strideTime
83
+ if (o.stride) {
84
+ p[P.STRIDE] = 1
85
+ if (Array.isArray(o.stride)) { p[P.STRIDE_MIN] = o.stride[0]; p[P.STRIDE_MAX] = o.stride[1] }
86
+ }
87
+ if (o.orientation) {
88
+ p[P.ORIENT] = 1
89
+ if (typeof o.orientation === "number") p[P.ORIENT_MAX] = o.orientation
90
+ }
91
+ if (o.minSpeed !== undefined) p[P.MIN_SPEED] = o.minSpeed
92
+ if (o.pelvis !== undefined) p[P.PELVIS] = o.pelvis
93
+ if (o.strideTime !== undefined) p[P.STRIDE_TIME] = o.strideTime
94
+ this._c.setWarp(p)
95
+ }
96
+ }